ci: build image daemonless with Kaniko (no Docker)
Replace the docker buildx / build-push-action build job with Kaniko running as the job container: it builds the Dockerfile from the git context and pushes to the forge registry, with no Docker daemon, no buildx, and no privileged DinD. Kaniko cannot handle BuildKit `RUN --mount=type=cache`, so drop the two cache mounts on the cargo build layer (plain `cargo build` now). Document the pipeline and this gotcha (plus the node20-only runner and full-github-URL action rules) in the README so it isn't reintroduced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
168b674efe
commit
423ddc7870
3 changed files with 67 additions and 31 deletions
60
.github/workflows/deploy.yml
vendored
60
.github/workflows/deploy.yml
vendored
|
|
@ -67,32 +67,36 @@ jobs:
|
|||
name: Build & Publish
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check]
|
||||
# Build the image DAEMONLESS with Kaniko — no Docker, no buildx, no
|
||||
# privileged DinD. The job runs *inside* the Kaniko executor image, which
|
||||
# builds the Dockerfile and pushes straight to the forge registry.
|
||||
container:
|
||||
image: gcr.io/kaniko-project/executor:v1.24.0-debug
|
||||
defaults:
|
||||
run:
|
||||
# The kaniko -debug image is busybox-only (no bash).
|
||||
shell: sh
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://github.com/actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: https://github.com/docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to the forge container registry
|
||||
uses: https://github.com/docker/login-action@v3
|
||||
with:
|
||||
# Forgejo auto-provides GITHUB_TOKEN to the job; it can push packages
|
||||
# for this repo's owner (uberbau). No external registry / PAT needed.
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push container
|
||||
uses: https://github.com/docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
# `dev` is the moving branch tag; the commit SHA is the immutable
|
||||
# reference. The moby Deployment pins the image by digest, so bump it
|
||||
# there per release (a floating tag never re-rolls the pod on its own).
|
||||
tags: |
|
||||
${{ env.IMAGE }}:${{ github.sha }}
|
||||
${{ env.IMAGE }}:dev
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Build and push (Kaniko)
|
||||
env:
|
||||
# Forgejo auto-provides GITHUB_TOKEN; it can push packages for this
|
||||
# repo's owner (uberbau) and read this (private-context) git repo.
|
||||
FORGE_USER: ${{ github.actor }}
|
||||
FORGE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Kaniko reads these to clone the `--context` git URL.
|
||||
GIT_USERNAME: ${{ github.actor }}
|
||||
GIT_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -eu
|
||||
# Registry auth for the push (docker config.json format).
|
||||
AUTH=$(printf '%s:%s' "$FORGE_USER" "$FORGE_TOKEN" | base64 | tr -d '\n')
|
||||
mkdir -p /kaniko/.docker
|
||||
printf '{"auths":{"%s":{"auth":"%s"}}}' "$REGISTRY" "$AUTH" > /kaniko/.docker/config.json
|
||||
# Kaniko clones the context itself (this job has no node for JS actions
|
||||
# like checkout). `dev` is the moving branch tag; the commit SHA is the
|
||||
# immutable ref the moby Deployment pins by digest.
|
||||
/kaniko/executor \
|
||||
--context "git://${REGISTRY}/uberbau/brewlog.git#refs/heads/dev" \
|
||||
--dockerfile Dockerfile \
|
||||
--destination "${IMAGE}:${GITHUB_SHA}" \
|
||||
--destination "${IMAGE}:dev"
|
||||
|
|
|
|||
|
|
@ -30,9 +30,10 @@ RUN mkdir -p /usr/local/bin \
|
|||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/app/target \
|
||||
cargo build --release --locked \
|
||||
# NB: no `RUN --mount=type=cache` here on purpose. The CI image builder is
|
||||
# Kaniko (daemonless, no Docker/BuildKit), which does not support BuildKit cache
|
||||
# mounts — it errors on them. Keep this RUN plain. See README "CI / build".
|
||||
RUN cargo build --release --locked \
|
||||
&& mkdir -p /out \
|
||||
&& cp target/release/brewlog /out/brewlog
|
||||
|
||||
|
|
|
|||
31
README.md
31
README.md
|
|
@ -162,6 +162,37 @@ cargo build # Build
|
|||
|
||||
See [CLAUDE.md](CLAUDE.md) for architecture, code patterns, and development conventions.
|
||||
|
||||
## CI / build pipeline (this fork)
|
||||
|
||||
This fork lives on the **zo** Forgejo forge
|
||||
(`git.ziemlichoptimal.de/uberbau/brewlog`, default branch **`dev`**) and is
|
||||
deployed to the **moby** homelab via Flux GitOps. `.github/workflows/deploy.yml`
|
||||
runs on every push to `dev`: it lints/tests (`check`), then builds and publishes
|
||||
the container image to the forge's own registry as
|
||||
`git.ziemlichoptimal.de/uberbau/brewlog:{dev,<sha>}`. The moby deployment pins
|
||||
that image by digest and bumps it per release.
|
||||
|
||||
The build is **daemonless — it does not use Docker**. It runs
|
||||
[Kaniko](https://github.com/GoogleContainerTools/kaniko) as the job container,
|
||||
building the `Dockerfile` (context pulled straight from git) and pushing to the
|
||||
registry. No `docker`, no buildx, no privileged Docker-in-Docker.
|
||||
|
||||
### Gotchas (learned the hard way)
|
||||
|
||||
- **Kaniko does not support BuildKit `RUN --mount=type=cache`.** The build fails
|
||||
on it. Keep every `RUN` in the `Dockerfile` plain — no BuildKit cache mounts.
|
||||
(This is why the Rust build layer is a plain `cargo build`; we have been bitten
|
||||
by this before, so do not "re-add caching" to the Dockerfile.)
|
||||
- **The forge's Actions runner is node20-only.** Pin JS actions to their node20
|
||||
generation (`actions/checkout@v4`, `actions/cache@v4`, and if you reintroduce
|
||||
docker actions, `@v3`/`@v6`) — the newer `@v5/@v6/@v7` releases declare
|
||||
`runs.using: node24`, which the runner rejects (`must be one of [… node20 …]`).
|
||||
- **Reference actions by full `github.com` URL**
|
||||
(`uses: https://github.com/owner/repo@ref`). The runner's default action
|
||||
mirror (`code.forgejo.org`) is incomplete/flaky and aborts clones mid-run.
|
||||
- The `check` job installs only Rust via mise (`install_args: rust`); the full
|
||||
`mise.toml` toolchain pulls tools from the GitHub API, which 401s on the runner.
|
||||
|
||||
## License
|
||||
|
||||
[Apache License 2.0](LICENSE)
|
||||
|
|
|
|||
Loading…
Reference in a new issue