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
|
name: Build & Publish
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [check]
|
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:
|
steps:
|
||||||
- name: Checkout
|
- name: Build and push (Kaniko)
|
||||||
uses: https://github.com/actions/checkout@v4
|
env:
|
||||||
|
# Forgejo auto-provides GITHUB_TOKEN; it can push packages for this
|
||||||
- name: Set up Docker Buildx
|
# repo's owner (uberbau) and read this (private-context) git repo.
|
||||||
uses: https://github.com/docker/setup-buildx-action@v3
|
FORGE_USER: ${{ github.actor }}
|
||||||
|
FORGE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Login to the forge container registry
|
# Kaniko reads these to clone the `--context` git URL.
|
||||||
uses: https://github.com/docker/login-action@v3
|
GIT_USERNAME: ${{ github.actor }}
|
||||||
with:
|
GIT_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||||
# Forgejo auto-provides GITHUB_TOKEN to the job; it can push packages
|
run: |
|
||||||
# for this repo's owner (uberbau). No external registry / PAT needed.
|
set -eu
|
||||||
registry: ${{ env.REGISTRY }}
|
# Registry auth for the push (docker config.json format).
|
||||||
username: ${{ github.actor }}
|
AUTH=$(printf '%s:%s' "$FORGE_USER" "$FORGE_TOKEN" | base64 | tr -d '\n')
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
mkdir -p /kaniko/.docker
|
||||||
|
printf '{"auths":{"%s":{"auth":"%s"}}}' "$REGISTRY" "$AUTH" > /kaniko/.docker/config.json
|
||||||
- name: Build and push container
|
# Kaniko clones the context itself (this job has no node for JS actions
|
||||||
uses: https://github.com/docker/build-push-action@v6
|
# like checkout). `dev` is the moving branch tag; the commit SHA is the
|
||||||
with:
|
# immutable ref the moby Deployment pins by digest.
|
||||||
context: .
|
/kaniko/executor \
|
||||||
push: true
|
--context "git://${REGISTRY}/uberbau/brewlog.git#refs/heads/dev" \
|
||||||
# `dev` is the moving branch tag; the commit SHA is the immutable
|
--dockerfile Dockerfile \
|
||||||
# reference. The moby Deployment pins the image by digest, so bump it
|
--destination "${IMAGE}:${GITHUB_SHA}" \
|
||||||
# there per release (a floating tag never re-rolls the pod on its own).
|
--destination "${IMAGE}:dev"
|
||||||
tags: |
|
|
||||||
${{ env.IMAGE }}:${{ github.sha }}
|
|
||||||
${{ env.IMAGE }}:dev
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,10 @@ RUN mkdir -p /usr/local/bin \
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
# NB: no `RUN --mount=type=cache` here on purpose. The CI image builder is
|
||||||
--mount=type=cache,target=/app/target \
|
# Kaniko (daemonless, no Docker/BuildKit), which does not support BuildKit cache
|
||||||
cargo build --release --locked \
|
# mounts — it errors on them. Keep this RUN plain. See README "CI / build".
|
||||||
|
RUN cargo build --release --locked \
|
||||||
&& mkdir -p /out \
|
&& mkdir -p /out \
|
||||||
&& cp target/release/brewlog /out/brewlog
|
&& 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.
|
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
|
## License
|
||||||
|
|
||||||
[Apache License 2.0](LICENSE)
|
[Apache License 2.0](LICENSE)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue