Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ jobs:
"build-essential",
"claude-code",
"cypress-deps",
"docker-in",
"docker-out",
"dotnet",
"eclipse-deps",
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Below is a list with included features, click on the link for more details.
| [build-essential](./features/src/build-essential/README.md) | Installs build essentials like gcc. |
| [claude-code](./features/src/claude-code/README.md) | Installs Claude Code, Anthropic's AI coding assistant CLI. |
| [cypress-deps](./features/src/cypress-deps/README.md) | Installs all dependencies required to run Cypress. |
| [docker-in](./features/src/docker-in/README.md) | Installs and runs a full Docker daemon. |
| [docker-out](./features/src/docker-out/README.md) | Installs a Docker client which re-uses the host Docker socket. |
| [dotnet](./features/src/dotnet/README.md) | A package which installs .NET SDKs, runtimes and workloads. |
| [eclipse-deps](./features/src/eclipse-deps/README.md) | Installs all dependencies required to run the Eclipse IDE. |
Expand Down
4 changes: 4 additions & 0 deletions build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ func init() {
gotaskr.Task("Feature:cypress-deps:Package", func() error { return packageFeature("cypress-deps") })
gotaskr.Task("Feature:cypress-deps:Test", func() error { return testFeature("cypress-deps") })

////////// docker-in
gotaskr.Task("Feature:docker-in:Package", func() error { return packageFeature("docker-in") })
gotaskr.Task("Feature:docker-in:Test", func() error { return testFeature("docker-in") })

////////// docker-out
gotaskr.Task("Feature:docker-out:Package", func() error { return packageFeature("docker-out") })
gotaskr.Task("Feature:docker-out:Test", func() error { return testFeature("docker-out") })
Expand Down
39 changes: 39 additions & 0 deletions features/src/docker-in/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Docker inside Docker (docker-in)

Installs and runs a full Docker daemon.

## Example Usage

```json
"features": {
"ghcr.io/postfinance/devcontainer-features/docker-in:1.0.0": {
"version": "latest",
"composeVersion": "latest",
"buildxVersion": "latest",
"configPath": "",
"downloadUrl": "",
"versionsUrl": "",
"composeDownloadUrl": "",
"buildxDownloadUrl": ""
}
}
```

## Options

| Option | Description | Type | Default Value | Proposals |
|-----|-----|-----|-----|-----|
| version | The version of the Docker Engine and CLI to install. | string | latest | latest, 28.3.3, 20.10 |
| composeVersion | The version of the Compose plugin to install. | string | latest | latest, none, 2.39.1, 2.29 |
| buildxVersion | The version of the buildx plugin to install. | string | latest | latest, none, 0.26.1, 0.10 |
| configPath | Path or URL to a custom Docker client config.json file to copy into the container. | string | <empty> | /home/user/.docker/config.json, https://raw.githubusercontent.com/devcontainers/features/main/src/docker-in/config.json, none |
| downloadUrl | The download URL to use for Docker binaries (engine, CLI, containerd). | string | <empty> | |
| versionsUrl | The URL to use for checking available versions. | string | <empty> | |
| composeDownloadUrl | The download URL to use for Docker Compose binaries. | string | <empty> | |
| buildxDownloadUrl | The download URL to use for Docker Buildx binaries. | string | <empty> | |

## Customizations

### VS Code Extensions

- `ms-azuretools.vscode-containers`
91 changes: 91 additions & 0 deletions features/src/docker-in/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"id": "docker-in",
"version": "1.0.0",
"name": "Docker inside Docker",
"description": "Installs and runs a full Docker daemon.",
"options": {
"version": {
"type": "string",
"proposals": [
"latest",
"28.3.3",
"20.10"
],
"default": "latest",
"description": "The version of the Docker Engine and CLI to install."
},
"composeVersion": {
"type": "string",
"proposals": [
"latest",
"none",
"2.39.1",
"2.29"
],
"default": "latest",
"description": "The version of the Compose plugin to install."
},
"buildxVersion": {
"type": "string",
"proposals": [
"latest",
"none",
"0.26.1",
"0.10"
],
"default": "latest",
"description": "The version of the buildx plugin to install."
},
"configPath": {
"type": "string",
"default": "",
"description": "Path or URL to a custom Docker client config.json file to copy into the container.",
"proposals": [
"/home/user/.docker/config.json",
"https://raw.githubusercontent.com/devcontainers/features/main/src/docker-in/config.json",
"none"
]
},
"downloadUrl": {
"type": "string",
"default": "",
"description": "The download URL to use for Docker binaries (engine, CLI, containerd)."
},
"versionsUrl": {
"type": "string",
"default": "",
"description": "The URL to use for checking available versions."
},
"composeDownloadUrl": {
"type": "string",
"default": "",
"description": "The download URL to use for Docker Compose binaries."
},
"buildxDownloadUrl": {
"type": "string",
"default": "",
"description": "The download URL to use for Docker Buildx binaries."
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-azuretools.vscode-containers"
]
}
},
"mounts": [
{
"source": "dind-var-lib-docker-${devcontainerId}",
"target": "/var/lib/docker",
"type": "volume"
},
{
"source": "dind-var-lib-containerd-${devcontainerId}",
"target": "/var/lib/containerd",
"type": "volume"
}
],
"entrypoint": "/usr/local/share/dind-init.sh",
"privileged": true
}
76 changes: 76 additions & 0 deletions features/src/docker-in/dind-init.sh.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
set -e

# Wrapper function to only use sudo if not already root
sudoIf() {
if [ "$(id -u)" -ne 0 ]; then
sudo "$@"
else
"$@"
fi
}

# Setup logging
LOG_DIR=/var/log/feat-docker-in
LOG_FILE=$LOG_DIR/entrypoint.log
sudoIf mkdir -p "$LOG_DIR"
sudoIf chmod 755 "$LOG_DIR"

# Redirect all stdout/stderr to log
exec > >(sudoIf tee -a "$LOG_FILE") 2>&1

echo "=== Entrypoint Start $(date -Is) ==="
echo "[entrypoint] Running with args: $*"

# Determine the correct user
USERNAME="{{ .User }}"
if [ "${USERNAME}" = "" ]; then
USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)
fi

echo "[entrypoint] Running for user: ${USERNAME}"

# Ensure runtime directories exist
sudoIf mkdir -p /run/docker /var/lib/docker /var/lib/containerd
sudoIf rm -f /run/docker.pid

# Start the Docker daemon
echo "[entrypoint] Starting dockerd..."
sudoIf dockerd \
--host=unix:///var/run/docker.sock \
--storage-driver=overlay2 \
--log-level=debug &

DOCKERD_PID=$!
echo "[entrypoint] dockerd pid $DOCKERD_PID"

# Wait for daemon to become ready
TRIES=0
until sudoIf docker info >/dev/null 2>&1 || [ $TRIES -ge 60 ]; do
sleep 1
TRIES=$((TRIES+1))
echo "[entrypoint] waiting for dockerd... ($TRIES)"
done

# Verify the daemon is running
if sudoIf docker info >/dev/null 2>&1; then
echo "[entrypoint] Docker daemon is ready"
else
echo "[entrypoint] ERROR: Docker daemon never started!"
echo "[entrypoint] Check $LOG_FILE for details"
exit 1
fi

# Ensure group exists
getent group docker || sudoIf groupadd docker

# Ensure user is in group
sudoIf usermod -aG docker dev || true

# Finish up
echo "=== Entrypoint Complete $(date -Is) ==="

# Execute whatever commands were passed in (if any). This allows us
# to set this script to ENTRYPOINT while still executing the default CMD.
set +e
exec "$@"
11 changes: 11 additions & 0 deletions features/src/docker-in/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
. ./functions.sh

"./installer_$(detect_arch)" \
-version="${VERSION:-"latest"}" \
-composeVersion="${COMPOSEVERSION:-"latest"}" \
-buildxVersion="${BUILDXVERSION:-"latest"}" \
-configPath="${CONFIGPATH:-""}" \
-downloadUrl="${DOWNLOADURL:-""}" \
-versionsUrl="${VERSIONSURL:-""}" \
-composeDownloadUrl="${COMPOSEDOWNLOADURL:-""}" \
-buildxDownloadUrl="${BUILDXDOWNLOADURL:-""}"
Loading