From 39b322a2f031dcf134b8d62b28013a8ff36191f4 Mon Sep 17 00:00:00 2001 From: Shihaam Abdul Rahman Date: Thu, 5 Nov 2026 19:49:53 +0500 Subject: [PATCH] new update new dependecies --- Dockerfile | 16 ++++++++++++++ README.md | 13 ++++++++++++ entrypoint.sh | 47 +++++++++++++++++++++++++++++++++++++++++- sandbox-prompt-dind.md | 17 +++++++++++++++ sandbox-prompt.md | 2 +- 5 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 sandbox-prompt-dind.md diff --git a/Dockerfile b/Dockerfile index 2b575c2..739dcb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,9 +16,25 @@ RUN apt-get update \ python3-pycryptodome \ python3-cryptography +# Docker Engine for docker-in-docker. Only started when CCC_DIND=1 (needs --privileged). +RUN install -m 0755 -d /etc/apt/keyrings \ + && curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \ + > /etc/apt/sources.list.d/docker.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + docker-ce \ + docker-ce-cli \ + containerd.io \ + docker-buildx-plugin \ + docker-compose-plugin \ + iptables \ + kmod + RUN npm install -g @anthropic-ai/claude-code && npm cache clean --force COPY sandbox-prompt.md /etc/ccc/sandbox-prompt.md +COPY sandbox-prompt-dind.md /etc/ccc/sandbox-prompt-dind.md COPY entrypoint.sh /usr/local/bin/ccc-entrypoint RUN chmod +x /usr/local/bin/ccc-entrypoint diff --git a/README.md b/README.md index f57bf2f..7378054 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,19 @@ claude --resume # claude --resume claude -p "hello" # claude -p "hello" ``` +## Docker in Docker (optional) + +To let Claude build and run containers, start ccc with `CCC_DIND=1` and `--privileged`. The entrypoint starts a separate Docker daemon *inside* the container, so Claude gets `docker`, `docker compose` and `docker buildx` without ever touching your host's daemon, containers or images. When it is running, an extra section is added to the system prompt telling Claude how that daemon differs from your host's. + +```bash +alias claude-dind='docker run --rm -it --privileged -e CCC_DIND=1 -v /var/lib/docker -v ~/.claude:/root/.claude -v ~/.claude.json:/root/.claude.json -v $PWD:$PWD -w $PWD git.shihaam.dev/dockerfiles/ccc' +``` + +- `-v /var/lib/docker` gives the inner daemon an anonymous volume so it can use overlay2 instead of the slow vfs driver. `--rm` deletes it on exit, so images are gone after the session. +- Do **not** mount the host socket (`-v /var/run/docker.sock:...`) instead. That hands Claude root on your host and defeats the whole point of ccc. +- `--privileged` does weaken the kernel boundary compared to a normal container, so only turn this on when you need it. Without `CCC_DIND=1` nothing extra runs. +- If dockerd fails to start, ccc prints the last lines of `/var/log/dockerd.log` and carries on without docker. + For a shell in the container instead, override the entrypoint: ```bash diff --git a/entrypoint.sh b/entrypoint.sh index f017bc8..91fadec 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,9 +2,48 @@ # Prepend the sandbox system prompt so Claude knows it is containerised and asks # the user to run host-side commands. Skipped for subcommands and for # --help/--version, which do not take the flag. +# +# With CCC_DIND=1 (and --privileged), a Docker daemon is started inside the +# container first so Claude gets its own docker, isolated from the host's. set -e PROMPT_FILE=/etc/ccc/sandbox-prompt.md +DIND_PROMPT_FILE=/etc/ccc/sandbox-prompt-dind.md +DIND_LOG=/var/log/dockerd.log + +start_dind() { + # cgroup v2: move ourselves out of the root cgroup and delegate all + # controllers, otherwise dockerd cannot create cgroups for its containers. + # Same trick as the official docker:dind entrypoint. + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs 2>/dev/null || : + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control 2>/dev/null || : + fi + + dockerd > "$DIND_LOG" 2>&1 & + + i=0 + until docker info > /dev/null 2>&1; do + i=$((i + 1)) + if [ "$i" -ge 30 ] || ! kill -0 "$!" 2>/dev/null; then + echo "ccc: dockerd failed to start (is the container --privileged?). Last log lines:" >&2 + tail -n 20 "$DIND_LOG" >&2 + return 1 + fi + sleep 1 + done +} + +DIND_OK= +if [ "$CCC_DIND" = 1 ]; then + if start_dind; then + DIND_OK=1 + else + echo "ccc: continuing without docker-in-docker" >&2 + fi +fi case "$1" in agents|attach|auth|auto-mode|doctor|gateway|import|install|logs|mcp|plugin|plugins|project|respawn|rm|setup-token|stop|kill|ultrareview|update|upgrade|-h|--help|-v|--version) @@ -13,7 +52,13 @@ case "$1" in esac if [ -r "$PROMPT_FILE" ]; then - exec claude --append-system-prompt "$(cat "$PROMPT_FILE")" "$@" + PROMPT="$(cat "$PROMPT_FILE")" + if [ -n "$DIND_OK" ] && [ -r "$DIND_PROMPT_FILE" ]; then + PROMPT="$PROMPT + +$(cat "$DIND_PROMPT_FILE")" + fi + exec claude --append-system-prompt "$PROMPT" "$@" fi exec claude "$@" diff --git a/sandbox-prompt-dind.md b/sandbox-prompt-dind.md new file mode 100644 index 0000000..b60073a --- /dev/null +++ b/sandbox-prompt-dind.md @@ -0,0 +1,17 @@ +# Docker-in-docker is enabled + +This container runs its own Docker daemon, so `docker`, `docker compose` and +`docker buildx` work here. It is a separate daemon from the user's host Docker: + +- The host's containers, images, volumes and networks are not visible. Do not + try to inspect or control the user's host containers; ask them as usual. +- Images and containers you create live inside this container and vanish when + the session ends. Anything that must persist belongs in the project (a + Dockerfile, `compose.yml`) or must be pushed by the user from the host. +- Bind mounts resolve against this container's filesystem. The project is + mounted at the same path as on the host, so `-v "$PWD:..."` works as expected. +- Published ports (`-p 8080:80`) are reachable at this container's `localhost`, + not the user's host `localhost`. +- No registry credentials are configured. Public pulls work; for private + registries or pushes, ask the user. +- Daemon logs are in `/var/log/dockerd.log` if docker misbehaves. diff --git a/sandbox-prompt.md b/sandbox-prompt.md index ac61fd6..1ec1dc0 100644 --- a/sandbox-prompt.md +++ b/sandbox-prompt.md @@ -10,7 +10,7 @@ Not reachable from here, no matter how the command is written: repos, the user's dotfiles, their global git config. - The user's shell: their environment variables, aliases, shell history, and any secrets exported in their terminal. -- The host's installed toolchains, databases, `docker`, `systemctl`, editors, GUI +- The host's installed toolchains, databases, Docker daemon, `systemctl`, editors, GUI or browser. - Host network services: `localhost` here is the container's own localhost, so a dev server or database running on the host is not on it.