One directory per image, one Dockerfile each. The directory name is the image name: build/
becomes ghcr.io/projecteru2/footstone/build. Adding an image means adding a directory and listing
it in the IMAGES variable of the Makefile and in the workflow matrix of
.github/workflows/docker-image.yml.
ghcr.io/projecteru2/footstone/build — the toolchain image for compiling Eru components and
packaging them as .rpm or .deb.
Base: golang:1.27-alpine, matching the go 1.27.0 directive in core, agent and cli.
Installed on top of the base:
| Package | Why |
|---|---|
alpine-sdk, gcc, libc-dev, linux-headers |
C toolchain for cgo builds and for gem native extensions |
git |
version stamping (git describe) during a build |
libgit2, libgit2-dev |
headers for git bindings that link against libgit2 |
ruby, ruby-dev |
runtime for fpm |
fpm (gem) |
builds .rpm and .deb packages from a binary |
rpm, dpkg |
the packagers fpm shells out to |
Compile a component by mounting a checkout into the image:
docker run --rm -v "$PWD:/src" -w /src \
ghcr.io/projecteru2/footstone/build \
go build -o eru-core .
The Go build cache lives inside the container and is discarded with it. For repeated builds, mount a cache directory as well:
docker run --rm -v "$PWD:/src" -w /src \
-v "$HOME/.cache/go-build:/root/.cache/go-build" \
-v "$HOME/go/pkg/mod:/go/pkg/mod" \
ghcr.io/projecteru2/footstone/build \
make build
ghcr.io/projecteru2/footstone/run-lambda — a base image for Eru lambda workloads, which run a
one-shot command and exit rather than staying up as a service.
Base: alpine:3.22.
It adds sudo and a lambda user with uid and gid 65530, home directory /home/lambda, and a
/etc/sudoers entry granting that user passwordless sudo. A workload image derives from it and
switches to that user:
FROM ghcr.io/projecteru2/footstone/run-lambda
COPY task.sh /usr/local/bin/task.sh
USER lambda
CMD ["/usr/local/bin/task.sh"]
The passwordless sudo rule means the lambda user can escalate to root inside the container. Use
this image only where that is acceptable — that is, where the container itself is the security
boundary.
.github/workflows/docker-image.yml builds and pushes every image in its matrix. Tags come from
docker/metadata-action:
| Trigger | Tags |
|---|---|
push to master |
latest, plus the full commit sha |
push of a v* tag |
the tag name (for example v1.0.0), plus the full commit sha |
Both platforms, linux/amd64 and linux/arm64, go into one manifest list per tag. The workflow
authenticates to GHCR with the workflow’s own GITHUB_TOKEN, so it needs no configured secrets.
make check # docker build --check on every Dockerfile
make build # docker build for the local platform only
make push # docker buildx build --push for linux/amd64,linux/arm64
make push needs a buildx builder that can produce multi-platform output — the default docker
driver cannot. Create one once:
docker buildx create --name multi --driver docker-container --use
Pushing also needs a GHCR login with write:packages:
echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_USER" --password-stdin