This repository is a self-building Docker image demonstration. The result of the build is another copy of this builder image. A one-time host bootstrap creates a minimal builder image; when that image runs, it invokes Docker against the mounted checkout and creates the final image itself.
For a hands-on explanation, follow the five-step tutorial.
Prerequisite: Docker Desktop (or Docker Engine) is running.
On PowerShell:
./scripts/run-build.ps1On macOS/Linux/Git Bash:
sh scripts/run-build.shBoth commands use the host to bootstrap dockerasbuilder:bootstrap, then run
that image to produce dockerasbuilder:local. The second build command is run
by the container, not by the local script.
To see that each successor image uses current source, edit
container/build-message and run the command again. The bootstrap container
builds the next image, then launches that new image with --identity; its
message appears in the build log as [self-built image] ....
The workflow bootstraps an image, then runs it with the runner's Docker socket
mounted at /var/run/docker.sock. docker run attaches the container's
standard output and error streams to the workflow step, including the nested
docker build output. The final image is dockerasbuilder:ci.
No image registry is needed here. A GitHub Actions runner has a Docker daemon for the duration of the job, so the final image is available to later steps in that job. For separate jobs, reusable images, or a large expensive-to-build environment, publish the image to GHCR (or Docker Hub) and pull it instead. Do not commit Docker image tarballs to the repository; the Dockerfile is the portable, reviewable source of the image.
Dockerfile defines tools and OS dependencies. container/project-build
defines how the running image builds its successor. The repository is
bind-mounted at runtime, which means the build uses the same source tree that
the developer or Actions runner checked out.
Mounting the Docker socket gives the container near-root control of the Docker host. It is appropriate for this contained learning exercise and trusted CI, but should not be used with untrusted code. In production, pin base-image digests and package versions for stronger reproducibility.