From 87526bcf7f02787cb7917203b4ad3b3baf88c02d Mon Sep 17 00:00:00 2001 From: ced4568 Date: Wed, 26 Aug 2026 12:59:23 -0500 Subject: [PATCH] feat(labs): add a nested Docker Engine to the Lab image for ROOT 04 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Installs docker.io + a static docker-compose v2 binary (same "curl a static binary" pattern already used for k3s) inside the same already-Privileged Lab container that runs k3s. scripts/entrypoint.sh starts dockerd (vfs storage driver, to avoid nesting overlay-on-overlay) non-blockingly right after k3s's own API server is confirmed up — a Docker daemon failure only logs a warning and never breaks the Kubernetes-only Labs that are the vast majority of usage. This does not weaken the security boundary: the container was already Privileged (required for k3s, the existing accepted threat model), so a second runtime inside it grants no new host capability, and the Lab Host's own real Docker socket is never touched — the nested dockerd listens on its own /var/run/docker.sock entirely inside the guest's filesystem namespace. Tested empirically against the real production resource caps (2 vCPU, 4096MB, 512 PIDs, Privileged: true) before merging: k3s + dockerd + a running nginx:alpine container (with a published port, curled successfully) + a real docker build all together used 884MB/4096MB and 160/512 PIDs — comfortable headroom in every dimension. See docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §3 for the full test log. Co-Authored-By: Claude Sonnet 5 --- Dockerfile | 19 +++++++++++++++++++ scripts/entrypoint.sh | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Dockerfile b/Dockerfile index b47fc9a..eb8f3c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,25 @@ RUN set -eux && \ ln -sf /usr/local/bin/k3s /usr/local/bin/kubectl && \ ln -sf /usr/local/bin/k3s /usr/local/bin/crictl +# ── Docker Engine (ROOT 04) + DNS tooling (ROOT 02) ────────────────────────── +# A second, independent container runtime nested inside this already-Privileged Lab container +# (see docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §3 for the security/resource evaluation and the +# real test results this decision is based on) — its own dockerd, its own +# /var/run/docker.sock, entirely separate from the Lab Host's real Docker socket, which is +# never mounted into this image. docker-compose v2 isn't bundled by Ubuntu's docker.io package, +# so fetch the static binary the same way k3s's own binary is fetched above, rather than adding +# a whole new apt repository for one plugin. +RUN apt-get update && apt-get install -y docker.io dnsutils && rm -rf /var/lib/apt/lists/* +RUN set -eux && \ + case "$(uname -m)" in \ + x86_64) COMPOSE_ARCH="x86_64" ;; \ + aarch64) COMPOSE_ARCH="aarch64" ;; \ + *) echo "Unsupported arch: $(uname -m)" && exit 1 ;; \ + esac && \ + mkdir -p /usr/local/lib/docker/cli-plugins && \ + curl -fsSL "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-${COMPOSE_ARCH}" \ + -o /usr/local/lib/docker/cli-plugins/docker-compose && \ + chmod +x /usr/local/lib/docker/cli-plugins/docker-compose # ── App files ───────────────────────────────────────────────────────────────── WORKDIR /app diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 6ae9a31..657cf0a 100644 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -58,6 +58,28 @@ for i in $(seq 1 60); do done OK "k3s API server is up" +# ── 1b. Start a nested Docker daemon (ROOT 04) ─────────────────────────────── +# A second, independent runtime for Docker/container-fundamentals labs — see +# docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §3. vfs storage driver deliberately avoids nesting +# overlay-on-overlay under this container's own overlay filesystem. Best-effort and +# non-blocking: a Docker daemon failure must never break the Kubernetes-only Labs that are the +# vast majority of usage, so this never calls `exit 1` — only a log line. +if command -v dockerd >/dev/null 2>&1; then + LOG "Starting nested Docker daemon (ROOT 04 labs)..." + dockerd --storage-driver=vfs --host=unix:///var/run/docker.sock &>/var/log/dockerd.log & + DOCKERD_PID=$! + for i in $(seq 1 30); do + if docker version >/dev/null 2>&1; then + OK "Docker daemon is up" + break + fi + sleep 1 + if [ $i -eq 30 ]; then + LOG "⚠ Docker daemon did not become ready in time — ROOT 04 labs will be unavailable this session, everything else is unaffected" + fi + done +fi + # Symlink kubeconfig to the standard location for convenience mkdir -p /root/.kube cp "$KUBECONFIG_PATH" /root/.kube/config