feat(dind): preload + default-on host-image passthrough for the nested daemon (issue #94)#95
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #94
The nested dockerd starts with an empty image store, so a fresh box-dind container re-downloads images the host already has on the first inner 'docker run'. Add a documented startup preload hook to dind-entrypoint.sh: - DIND_PRELOAD_TARBALL: docker load 'docker save' tarballs and/or directories of *.tar into the inner daemon once it is ready. - DIND_PRELOAD_IMAGES: docker pull registry/mirror references, skipping any image already present. Preload is non-fatal, daemon-gated, and skipped when DIND_SKIP_DAEMON=1. Documented in docs/dind/USAGE.md and README, covered by tests/dind/example-preload-images.sh (wired into pr-test-dind CI) and experiments/preload-unit-test.sh. Fixes #94
Working session summaryI've implemented the fix and pushed it. Let me summarize the work while CI runs in the background. SummaryI implemented option 1 from issue #94 — a documented startup preload hook for the Root causeEach Changes
Verification
PR #95 is updated and marked ready for review: #95 I'll report the CI result for the This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $4.544200📊 Context and tokens usage:
Total: (1.8K new + 169.6K cache writes + 5.1M cache reads) input tokens, 36.8K output tokens, $4.544200 cost 🤖 Models used:
📎 Log file uploaded as Gist (2017KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
|
We need to configure our CI/CD, so we always skip CI/CD execution when new commit arrives, it will have reduce resources waste, and allow us to iterate faster, that should work for both main branch and pull requests. Also double check #94 and that we fully implemented everything as I wrote in the comment to the actual issue. Use all the best practices from CI/CD templates (check full file tree to compare for all GitHub workflow and CI/CD scripts file), if the same issue is found in template report issue also in templates:
We should compare all files, so we don't have more CI/CD errors in the future and reuse all the best practices from these templates. |
|
🤖 AI Work Session Started Starting automated work session at 2026-06-09T21:59:58.436Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. |
…ty filter Implements the issue #94 follow-up: copy images the host daemon already has into the nested daemon at startup so they are not re-pulled, on by default but safe and opt-out-able. - DIND_HOST_PASSTHROUGH (default 'public'): 'public' copies only host images carrying a RepoDigest from an allowlisted public registry (freely re-pullable, so no local build secrets or private credentials leak); 'all' copies every tagged image; 'off' disables it. - DIND_HOST_DOCKER_SOCK (default /var/run/host-docker.sock): a NON-default path, mounted read-only, used only to seed images at startup so the inner daemon keeps its own isolated socket (preserves issue #80 isolation). - DIND_HOST_PASSTHROUGH_REGISTRIES: the public-registry allowlist. - Quiet no-op when no host socket is mounted, so the normal --privileged run is unchanged. Tests: unit test sources the entrypoint and drives the passthrough branches with a mock docker + real AF_UNIX socket (public filter, all mode, skip-present, off, registry detection); the integration example stands up a throwaway host daemon and asserts 'all' copies a local fixture while 'public' refuses it. Docs updated in USAGE.md, README.md, the issue-94 case study, and the changeset.
Working session summaryEverything is verified and finalized on my end:
The only thing outstanding is CI, which is stuck in the GitHub runner queue (run A background monitor ( This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $9.726514📊 Context and tokens usage:Claude Opus 4.8: (3 sub-sessions)
Total: (33.6K new + 345.4K cache writes + 8.9M cache reads) input tokens, 118.5K output tokens, $9.726514 cost 🤖 Models used:
📎 Log file uploaded as Gist (3819KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🔄 Auto-restart triggered (iteration 1)Reason: CI failures detected Starting new session to address the issues. Auto-restart-until-mergeable mode is active. This run will stop after 5 restart iterations. |
Working session summaryThe run is still in progress. I'll wait for the background monitor (
I'll report back once the re-run finishes. This summary was automatically extracted from the AI working session output. |
🔄 Auto-restart-until-mergeable Log (iteration 1)This log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $1.530905📊 Context and tokens usage:
Total: (3.0K new + 65.2K cache writes + 1.5M cache reads) input tokens, 13.7K output tokens, $1.530905 cost 🤖 Models used:
📎 Log file uploaded as Gist (4788KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🔄 Auto-restart triggered (iteration 2)Reason: CI failures detected Starting new session to address the issues. Auto-restart-until-mergeable mode is active. This run will stop after 5 restart iterations. |
The example-preload-images.sh test waited only for the inner dockerd to answer 'docker info' (wait_for_inner_docker), then immediately asserted the seeded images were present. But the entrypoint loads images *after* dockerd reports ready, so the assertion raced the asynchronous 'docker load' and intermittently failed with the image showing up in the diagnostic dump a fraction of a second later. Emit an 'image preload/passthrough complete' marker once every preload path finishes, and have the test wait for that marker before asserting (positive and negative cases alike). Deterministic sync instead of a readiness race.
Working session summaryBoth monitors are watching the run. I'll wait for the completion notification rather than polling further. This summary was automatically extracted from the AI working session output. |
🔄 Auto-restart-until-mergeable Log (iteration 2)This log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $2.079068📊 Context and tokens usage:
Total: (3.9K new + 71.9K cache writes + 2.4M cache reads) input tokens, 17.2K output tokens, $2.079069 cost 🤖 Models used:
📎 Log file uploaded as Gist (6679KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Summary
Fixes #94: the
box-dindnested daemon boots with an empty image store, so a fresh container re-pulls
images the host already has (the classic Docker-in-Docker cache pitfall).
This PR seeds the inner daemon at startup via two complementary paths, both
daemon-gated, idempotent (skip images already present), and non-fatal
(a bad path / failed copy logs a warning and the shell still starts):
1. Explicit preload
DIND_PRELOAD_TARBALLdocker savetarballs and/or directories of*.tar,docker load-ed into the inner daemon. Zero-network host-image reuse.DIND_PRELOAD_IMAGESdocker pull, skipping any already present.2. Host-image passthrough — on by default, opt-out-able (issue follow-up)
Addresses the owner's follow-up: "by default add host-image passthrough … possible
to turn it off … do passthrough only for images that are available in docker hub
and so on, so these are safe from tokens and baked in configuration … also have an
option to pass through them all."
DIND_HOST_PASSTHROUGHpublicpublic: copy only host images carrying aRepoDigestfrom an allowlisted public registry (freely re-pullable → no local secrets/credentials leak).all: copy every tagged image.off/0/false/no: disable.DIND_HOST_DOCKER_SOCK/var/run/host-docker.sock/var/run/docker.sock.DIND_HOST_PASSTHROUGH_REGISTRIESpublicmode.Enable it by mounting the host socket; otherwise it is a quiet no-op, so the
normal
--privilegedrun is unchanged:Why this preserves isolation (issue #80): the host socket is read only at
startup to seed images and is deliberately not mounted at
/var/run/docker.sock. The inner daemon stays the container's runtime, so theper-container
docker psscoping is intact and we never adopt theDocker-outside-of-Docker security model the project rejects. Why
publicis thesafe default: a
RepoDigestfrom a public registry proves the image is freelyre-pullable, so copying it leaks no build secrets and needs no credential; local
builds (no RepoDigest) and private-registry images are excluded unless you opt into
all.How to reproduce / verify
vfs-only and cannotbuild the overlay-backed dind image):
bash experiments/preload-unit-test.shsources the real entrypoint and drives load/pull/skip/daemon-down/no-op plus the
passthrough branches (public filter,
all, skip-present,off, registrydetection) with a mock
dockerand a real AF_UNIX socket → 26 assertions, all pass.pr-test-dind, privileged):tests/dind/example-preload-images.shasserts the single-file and directorytarball forms seed the inner daemon,
DIND_PRELOAD_IMAGESskips the redundantpull, and — using a throwaway second dind-box as a controlled host daemon —
allmode copies a local fixture whilepublicmode correctly refuses it(no RepoDigest). Wired into CI alongside the other documented dind examples.
CI/CD review (PR #95 follow-up request)
satisfied: both
release.ymlandmeasure-disk-space.ymluseconcurrency: { group: ${{ github.workflow }}-${{ github.ref }}, cancel-in-progress: true }.The per-
github.refgroup cancels superseded runs on PR branches (each PR hasits own group) and on
main.js/rust/python/csharppipeline templates use
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}to protect main-branch releases from mid-flight cancellation. Box uses the
unconditional form per the explicit "both main and PRs" request. Trade-off:
a new push to
maincan cancel an in-progress release onmain. If protectingreleases is preferred, switch to the conditional form — flag if you'd like that.
only shared CI gap found is that the js template's
links.ymlis missing aconcurrency:block its sibling workflows have. Reported upstream as authorized:ci: links.yml is missing a concurrency block (redundant runs not cancelled on new commits) js-ai-driven-development-pipeline-template#73.
Files changed
ubuntu/24.04/dind/dind-entrypoint.sh— preload hook + host passthrough + env docs.tests/dind/example-preload-images.sh— executable example (CI), incl. passthrough.experiments/preload-unit-test.sh— isolated branch coverage (preload + passthrough).docs/dind/USAGE.md,README.md,docs/case-studies/issue-94/CASE-STUDY.md— docs..changeset/dind-preload-images.md—bump: minor(release trigger; VERSION isbumped by CI, not manually).
Fixes #94