Dockerfile partials and devcontainer bake files for re-use across multiple applications.
- dockerfile-partials
The github-cache-bake.hcl bake config file
provides a basic bake configuration for use in repos that produce container images using
GitHub Actions and targeted to the
GitHub container registry.
The file configures registry outputs and registry cache-to and cache-from, all directed to the specified registry. It infers naming and tagging config for the image based on the context (local vs. CI, protected vs. development versions), such that while each context can push both image and cache content, development and local contexts do not collide with each other or with releases.
The configuration of the bake file requires the use of a Docker builder with the docker-container driver. To set one up, use the following command:
docker builder create --use --bootstrap --driver docker-containerThe bake file requires at least IMAGE_NAME variable to be set, and REGISTRY should nearly always
be overridden (see GitHub cache bake file inputs). Export them:
REGISTRY=ghcr.io/[your account]
IMAGE_NAME=[image name]By default, the github-cache-bake.hcl file expects a Dockerfile in the bake command execution
directory (via cwd://Dockerfile), which is used for the build. It sets the default
context to BAKE_CMD_CONTEXT such
that the filesystem local to the bake execution are available to the image build.
To build your image using the GitHub cache bake file via remote bake definition, run this command:
REGISTRY=ghcr.io/[your account] IMAGE_NAME=[image name] docker buildx bake --file github-cache-bake.hcl https://github.com/rcwbr/dockerfile-partials.git#0.13.0The GitHub cache bake file can be configured using the following inputs:
| Variable | Required | Default | Effect |
|---|---|---|---|
IMAGE_NAME |
✓ | N/A | The name of the image, specifically not fully-qualified. This is the reference loaded to the host Docker daemon. |
GITHUB_REF_NAME |
✗ | "local-${HOST}" |
The human-friendly ref name for the GitHub context. Used to inform the image tag. |
GITHUB_REF_PROTECTED |
✗ | "false" |
Indicates if the CI context is for a protected (vs. development) ref. Indicates whether to append a unique version ID to the tag |
GITHUB_SHA |
✗ | "local" |
The commit SHA of the CI context. Appended to tags after VERSION unless GITHUB_REF_PROTECTED is true. |
HOST |
✗ | $HOSTNAME |
The name of the host device. Used to qualify image and cache names and avoid collisions between users. |
HOSTNAME |
✗ | N/A | The name of the host device, for some OSs. |
REGISTRY |
✗ | "ghcr.io/" |
The registry to which to push remote content. Generally, "ghcr.io/[user/org]/". |
IMAGE_REF |
✗ | "${REGISTRY}${IMAGE_NAME}" |
The fully-qualified image name used as the base for version and cache references. |
VERSION |
✗ | ${GITHUB_REF_NAME}, sanitized |
This is the default tag for the image. |
Each Dockerfile partial is accompanied by a devcontainer-bake.hcl
bake config file, and a common bake file is
defined at the repository root. These are intended to make composition of devcontainer image
contents trivial. They are designed to work with the
devcontainer-cache-build initialize script.
Using these bake files remotely requires setting the primary build context to this repo by remote definition. Because of this limitation of remote bake build contexts
We don't currently support reading a remote Dockerfile with a local context when doing a remote invocation because we automatically derive the dockerfile from the context atm
this means that any build contexts required by the Dockerfile partial must be provided via a
local directory contexts context
rather than the primary build context. For example, the pre-commit Dockerfile
reads from the local_context context
set to BAKE_CMD_CONTEXT.
This allows it to consume contents of the downstream build context.
In a devcontainer.json leveraging the
devcontainer-cache-build initialize script,
several fields must be configured to fully integrate. These include:
- The
initializeCommand(see Devcontainer bake files devcontainer-cache-build initializeCommand config) - For some images, such as pre-commit and Zsh, map
onCreateCommandto"/opt/devcontainers/on_create_command" - For some images, map
postCreateCommandto"/opt/devcontainers/post_create_command"
Add the following configuration to the script called by initializeCommand before the curl to the
initialize script:
# .devcontainer/initialize
export DEVCONTAINER_DEFINITION_TYPE=bake
export DEVCONTAINER_DEFINITION_FILES="devcontainer-bake.hcl [path to each desired partial bake file] cwd://.devcontainer/devcontainer-bake.hcl"
export DEVCONTAINER_BUILD_ADDITIONAL_ARGS=https://github.com/rcwbr/dockerfile-partials.git#0.13.0
curl https://raw.githubusercontent.com/rcwbr/devcontainer-cache-build/0.13.0/devcontainer-cache-build-initialize | bashDEVCONTAINER_DEFINITION_FILES must begin with devcontainer-bake.hcl and end with
cwd://.devcontainer/devcontainer-bake.hcl (see
Devcontainer bake files devcontainer-cache-build .devcontainer/devcontainer-bake.hcl config),
and with each desired partial bake file in between (ordering is important for override priority).
For example:
export DEVCONTAINER_DEFINITION_FILES="devcontainer-bake.hcl useradd/devcontainer-bake.hcl pre-commit/devcontainer-bake.hcl cwd://.devcontainer/devcontainer-bake.hcl"To join the devcontainer partial bake files, you must define a bake file local to your project that
configures targets from each partial you select. It must define at least the devcontainer_layers
variable as a list with the names of each selected partial, and override the base_context for at
least the first partial target. For example:
variable "devcontainer_layers" {
default = [
"useradd",
"pre-commit"
]
}
target "useradd" {
contexts = {
base_context = "docker-image://python:3.12.4"
}
}Optionally, targets may be configured for each layer. Values provided to these will override those
defined in the partials devcontainer-bake.hcl.
The partial bake files may be used manually through a command like this:
docker buildx bake --file devcontainer-bake.hcl [--file arg for each desired partial bake file] --file cwd://.devcontainer/devcontainer-bake.hcl https://github.com/rcwbr/dockerfile-partials.git#0.13.0The docker-client Dockerfile defines steps to install the Docker CLI client in a Docker image. It copies the CLI executable from the Docker docker image.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the docker-client installation. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "docker-client/Dockerfile"
contexts = {
base_context = "target:base"
}
}The args accepted by the Dockerfile include:
| Variable | Required | Default | Effect |
|---|---|---|---|
DOCKER_GID |
✗ | 800 |
Group ID of the docker user group |
USER |
✗ | "root" |
Username to grant access to the Docker daemon |
The docker-client partial contains a devcontainer bake config file. See Devcontainer bake files for general usage. The docker-client bake config file accepts the following inputs:
| Variable | Required | Default | Effect |
|---|---|---|---|
DOCKER_GID |
✗ | 800 |
See docker-client Dockerfile |
USER |
✗ | "root" |
See docker-client Dockerfile |
The docker-client partial installs only the client CLI by default. To leverage the container host's
Docker daemon, the relevant socket must be mounted at runtime. In a
devcontainer.json, the following content
must be included:
The pre-commit layer defines steps to install pre-commit and install the hooks required by a repo configuration.
This layer produces an accompanying tool image that contains pre-commit executions, while the main image presents that tool image as the pre-commit executable:
graph TD;
pl[_prior layers..._] --> tool[pre-commit-tool-image]
pl --> pre-commit[pre-commit]
tool -.-> pre-commit
pre-commit --> nl[_next layers..._]
⚠️ Use of the pre-commit layer requires that the variableDEVCONTAINER_HOST_WORKSPACE_MOUNTbe provided and set to the path of the workspace on the host filesystem. This informs the workspace mount for the pre-commit-tool-image container.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the pre-commit installation, and the
local_context to the directory from which the .pre-commit-config.yaml can be loaded (generally
BAKE_CMD_CONTEXT).
Additionally, provide appropriate values for the USER build arg. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "pre-commit/Dockerfile"
contexts = {
base_context = "target:base"
local_context = BAKE_CMD_CONTEXT
}
args = {
USER = "myuser"
}
}The args accepted by the Dockerfile include:
| Variable | Required | Default | Effect |
|---|---|---|---|
USER |
✗ | "root" |
Username to assume for hook pre-loading |
The pre-commit partial contains a devcontainer bake config file. See Devcontainer bake files for general usage. The pre-commit bake config file accepts the following inputs:
| Variable | Required | Default | Effect |
|---|---|---|---|
USER |
✗ | "root" |
See pre-commit Dockerfile |
DEVCONTAINER_REGISTRY |
✓ | "" |
The registry to which the pre-commit-tool-image belongs |
DEVCONTAINER_IMAGE |
✓ | "" |
The base devcontainer image name to which naming for the pre-commit image will be appended |
GIT_BRANCH_SANITIZED |
✓ | "" |
The context Git branch name, sanitized for use as a Docker image tag |
PRE_COMMIT_TOOL_IMAGE_NAME |
✗ | "${DEVCONTAINER_REGISTRY}/${DEVCONTAINER_IMAGE}-pre-commit:${GIT_BRANCH_SANITIZED}" |
The name of the pre-commit-tool-image |
The
devcontainer-bake.hcl config devcontainer_layers variable
must list each of the pre-commit targets; pre-commit-base, pre-commit-tool-image, and
pre-commit.
For example:
variable "devcontainer_layers" {
default = [
"docker-client",
"useradd",
"pre-commit-base",
"pre-commit-tool-image",
"pre-commit"
]
}For use in Codespaces devcontainers, the build args must be set to the following values:
USER:codespace
These values may be hard-coded in the Bake config file, or may be exposed as variables for compatibility with local environments.
variable "USER" {
default = "root"
}
...
args = {
USER = "${USER}"
}
...If exposed as variables, the appropriate values for Codespaces use must be set as secrets so as to be available during Codespace provisioning.
In a devcontainer.json for a Codespace, the DEVCONTAINER_HOST_WORKSPACE_MOUNT var should be set
to /var/lib/docker/codespacemount/workspace/[repo name], e.g.:
{
"containerEnv": {
"DEVCONTAINER_HOST_WORKSPACE_MOUNT": "/var/lib/docker/codespacemount/workspace/dockerfile-partials"
},
}The pyenv layer defines steps to install pyenv, leverage it to install a specified version of Python, and prepare a virtualenv based on that Python installation.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the pyenv installation. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "pyenv/Dockerfile"
contexts = {
base_context = "target:base"
}
}The args accepted by the Dockerfile include:
| Variable | Required | Default | Effect |
|---|---|---|---|
PYTHON_VERSION |
✗ | 3.12.4 |
The version of Python to install |
VIRTUALENV_NAME |
✗ | venv |
The name of the virtualenv to create |
PYENV_ROOT |
✗ | /opt/devcontainers/pyenv |
The path in which to install Pyenv |
The pyenv partial contains a devcontainer bake config file. See Devcontainer bake files for general usage.
The tmux Dockerfile defines steps to install tmux in a Docker image.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the tmux installation. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "tmux/Dockerfile"
contexts = {
base_context = "target:base"
}
}The tmux partial contains a devcontainer bake config file. See Devcontainer bake files for general usage. The tmux bake config file accepts no inputs.
The useradd Dockerfile defines steps to add a user to the image, with configurable user name, id, and group id.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the user addition. Additionally, provide
appropriate values for the USER, USER_UID, and USER_GID build args. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "useradd/Dockerfile"
contexts = {
base_context = "target:base"
}
args = {
USER = "myuser"
USER_UID = 1000
USER_GID = 1000
}
}The args accepted by the Dockerfile include:
| Variable | Required | Default | Effect |
|---|---|---|---|
USER |
✓ | N/A | Username of the user to create |
EXTRA_GID_ARGS |
✗ | "" |
Extra --gid [id] args to apply to the useradd command |
USER_UID |
✗ | 1000 |
User UID for the user to create |
USER_GID |
✗ | $USER_UID |
User GID for the user to create |
The useradd partial contains a devcontainer bake config file. See Devcontainer bake files for general usage. The useradd bake config file accepts the following inputs:
| Variable | Required | Default | Effect |
|---|---|---|---|
USER |
✗ | "root" |
See useradd Dockerfile |
EXTRA_GID_ARGS |
✗ | "" or DOCKER_CLIENT_EXTRA_GID_ARGS if defined |
See useradd Dockerfile |
UID |
✗ | 0 |
Maps to USER_UID. See useradd Dockerfile |
GID |
✗ | ${UID} |
Maps to USER_GID.See useradd Dockerfile |
For use in Codespaces devcontainers, the build args must be set to the following values:
USER:codespaceUID:1000
These values may be hard-coded in the Bake config file, or may be exposed as variables for compatibility with local environments.
variable "USER" {
default = "root"
}
variable "UID" {
default = 0
}
variable "GID" {
// Use the user id as group id unless set
default = "${UID}"
}
...
args = {
USER = "${USER}"
USER_UID = "${UID}"
USER_GID = "${GID}"
}
...If exposed as variables, the appropriate values for Codespaces use must be set as secrets so as to be available during Codespace provisioning.
The uv-project Dockerfile defines steps to prepare an environment to work with a Python project, using the uv tool.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the uv-project installation, the
local_context to the directory in which the Python project is defined, and the UV_PACKAGE_NAME
build arg to the name of the package. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "uv-project/Dockerfile"
contexts = {
base_context = "target:base"
local_context = BAKE_CMD_CONTEXT
}
args = {
UV_PACKAGE_NAME = "<your package name>"
}
}The uv-project partial contains a devcontainer bake config file. See Devcontainer bake files for general usage. The uv-project bake config file accepts no inputs.
The uv-project partial contains a bake config file for providing. The uv-project bake config file
accepts no inputs directly, but the UV_PACKAGE_NAME build arg should be specified (see
uv-project Dockerfile usage), similarly to this:
// docker-bake.hcl
target "uv-project" {
args = {
UV_PACKAGE_NAME = "<your package name>"
}
}Then the local bake config may be used alongside the partial by executing this command:
docker buildx bake \
-f uv-project/docker-bake.hcl \
-f cwd://docker-bake.hcl \
https://github.com/rcwbr/dockerfile_partials.git#0.13.0The Zsh Dockerfile defines steps to install Zsh, Oh My Zsh, fzf, and thefuck to the image.
The recommended usage is via the Devcontainer bake files. It is also possible to use the Dockerfile partial directly.
Use a Bake config file, and set the
base_context context as the image to which to apply the Zsh installation. For example:
target "base" {
dockerfile = "Dockerfile"
}
target "zsh-thefuck-pyenv" {
dockerfile = "pyenv/Dockerfile"
contexts = {
base_context = "target:base"
}
args = {
PYTHON_VERSION = "3.8.20"
VIRTUALENV_NAME = "thefuck"
}
}
target "default" {
context = "https://github.com/rcwbr/dockerfile_partials.git#0.13.0"
dockerfile = "zsh/Dockerfile"
contexts = {
base_context = "target:base"
pyenv_context = "target:zsh-thefuck-pyenv"
}
}The Zsh partial contains a devcontainer bake config file. See Devcontainer bake files for general usage. The Zsh bake config file accepts no inputs.
The
devcontainer-bake.hcl config devcontainer_layers variable
must list each of the Zsh targets; zsh-base, zsh-thefuck-pyenv, and zsh.
For example:
variable "devcontainer_layers" {
default = [
"docker-client",
"zsh-base",
"zsh-thefuck-pyenv",
"zsh",
]
}The .github/workflows/pre-commit.yaml reusable workflow defines steps to execute pre-commit CI
checks by leveraging the pre-commit-tool-image layer.
Basic usage of the workflow consists of including it in a GitHub workflow:
on:
pull_request:
jobs:
pre-commit:
if: github.event_name == 'pull_request'
uses: rcwbr/dockerfile-partials/.github/workflows/pre-commit.yaml@0.13.0ℹ️ Often, pre-commit configurations require the commit context of a pull request as input. To apply the pre-commit workflow to other contexts, omit or modify the
if: github.event_name == 'pull_request'condition.
If using the pre-commit workflow alongside a devcontainer-cache-build workflow, the pre-commit image generated by that workflow should be provided as input to the pre-commit workflow. For example:
...
jobs:
pre-commit:
if: github.event_name == 'pull_request'
uses: rcwbr/dockerfile-partials/.github/workflows/pre-commit.yaml@0.13.0
needs: devcontainer-cache-build
with:
pre-commit-image: ${{ fromJSON(needs.devcontainer-cache-build.outputs.devcontainer-cache-image-all_configs).target.pre-commit.args.DEVCONTAINER_PRE_COMMIT_IMAGE }}| Variable | Required | Default | Effect |
|---|---|---|---|
pre-commit-image |
✗ | pre-commit |
The image used for pre-commit execution in the workflow. |
This repo contains a devcontainer definition in the .devcontainer
folder. It leverages the
devcontainer cache build tool and the
Dockerfile partials defined in this repo.
The devcontainer cache build tool requires
authentication to the GitHub package registry, as a token stored as
DOCKERFILE_PARTIALS_DEVCONTAINER_INITIALIZE (see
instructions).
For use with Codespaces, the DOCKERFILE_PARTIALS_DEVCONTAINER_INITIALIZE token (see
devcontainer basic usage) must be stored as a Codespaces secret (see
instructions),
as must values for USER, and UID (see useradd Codespaces usage).
By default, the devcontainer configures pre-commit hooks in the repository to ensure commits pass basic testing. This includes enforcing conventional commit messages as the standard for this repository, via commitlint.
This repo uses the release-it-gh-workflow, with the conventional-changelog image defined at any given ref, as its automation. It leverages the devcontainer-cache-build workflow to pre-generate devcontainer images, which are also used for the pre-commit workflow. Finally, a Dive Docker image efficiency analysis job first builds an image with all partials layers included, then analyses the storage efficiency of the resulting image.
The GitHub repo settings for this repo are defined as code using the
Probot settings GitHub App. Settings values are defined
in the .github/settings.yml file. Enabling automation of settings via this file requires
installing the app.
The settings applied are as recommended in the release-it-gh-workflow usage, including tag and branch protections, GitHub App and environment authentication, and required checks.
{ "image": "[image including docker-client layers]", "mounts": [ { "source": "/var/run/docker.sock", "target": "/var/run/docker.sock", "type": "bind" } ] }