feat: switch container builds from Docker to ko#280
Conversation
Replace the multi-stage Dockerfile with ko for production container builds. ko produces smaller distroless images with built-in SBOM generation and native multi-platform support, eliminating the need for QEMU and Docker Buildx in CI. - Add .ko.yaml with Chainguard static base image - Rename Dockerfile to Dockerfile.legacy for local docker-compose dev - Update release.yml and pre-release.yml CI workflows to use ko - Add ko-build Makefile target for local builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates the project’s production container build pipeline from a multi-stage Dockerfile to ko, while keeping a legacy Dockerfile for local docker-compose development.
Changes:
- Add
.ko.yamlto definekobuild settings (static Chainguard base,CGO_ENABLED=0, stripped binary). - Update GitHub Actions release/snapshot workflows to build and push images via
ko(including SPDX SBOM generation). - Keep local compose working by referencing
Dockerfile.legacyand add amake ko-buildhelper target.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
deploy/docker-compose/docker-compose.yml |
Switch compose build to Dockerfile.legacy for local dev. |
Makefile |
Add ko-build target for local image builds. |
Dockerfile.legacy |
Rebrand Dockerfile as legacy/local-dev oriented. |
.ko.yaml |
Introduce ko build configuration for the server image. |
.github/workflows/release.yml |
Replace Docker Buildx flow with ko build + SBOM for releases. |
.github/workflows/pre-release.yml |
Replace snapshot Docker build with ko build + SBOM. |
| ko build ./cmd/server \ | ||
| --platform=linux/amd64,linux/arm64 \ | ||
| --tags="${TAG_NAME},${VERSION},${MAJOR_MINOR},sha-${SHA_SHORT}" \ | ||
| --sbom=spdx \ | ||
| --image-refs=/tmp/image-refs.txt |
There was a problem hiding this comment.
This ko build ./cmd/server invocation likely publishes the image under a path-suffixed repository (e.g. ${KO_DOCKER_REPO}/cmd/server or ${KO_DOCKER_REPO}/server, depending on ko config), which would contradict the stated goal of keeping the Helm image repository as ghcr.io/.../workflow. Adjust the ko invocation/config so the pushed image name remains the existing repo (no extra suffix).
| ko build ./cmd/server \ | ||
| --platform=linux/amd64,linux/arm64 \ | ||
| --tags="snapshot,main-sha-${SHA_SHORT}" \ | ||
| --sbom=spdx |
There was a problem hiding this comment.
Same concern as release.yml: ko build ./cmd/server will typically publish to a path-suffixed image name under ${KO_DOCKER_REPO}. If the intent is to keep publishing ghcr.io/.../workflow (as referenced by the Helm chart), ensure the ko config/flags produce the existing image name without an extra suffix.
| # Build container image with ko (requires ko: brew install ko) | ||
| ko-build: | ||
| KO_DOCKER_REPO=ko.local ko build ./cmd/server --platform=linux/$(shell go env GOARCH) | ||
|
|
There was a problem hiding this comment.
ko-build runs ko build ./cmd/server, which typically results in an image name that includes a package/id suffix under KO_DOCKER_REPO (e.g. ko.local/cmd/server). If this target is meant to mirror the production image name (ko.local/workflow-server or similar), consider adjusting the ko flags/config so the local image name matches expectations.
⏱ Benchmark Results✅ No significant performance regressions detected. benchstat comparison (baseline → PR)
|
- Pin base image to digest instead of mutable :latest tag - Add --bare flag to all ko build invocations so image publishes to ghcr.io/<repo> without path suffix (matches Helm chart) - Fix MAJOR_MINOR tag computation for pre-release versions - Remove unused id-token: write permission Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Dockerfile.legacyfor local docker-compose developmentChanges
.ko.yaml— ko config using Chainguard static base image, CGO_ENABLED=0, stripped binaryDockerfile.legacy— renamed from Dockerfile, still works for docker-compose.github/workflows/release.yml— docker job now usesko-build/setup-ko@v0.9+ko buildwith semver tags and SPDX SBOM.github/workflows/pre-release.yml— docker-snapshot job uses ko for snapshot/sha tagsdeploy/docker-compose/docker-compose.yml— referencesDockerfile.legacyMakefile— addedko-buildtarget for local buildsWhat doesn't change
ghcr.io/gocodealong/workflow)Test plan
ko build ./cmd/serverproduces working imagedocker run --entrypoint shfails as expected)Dockerfile.legacy🤖 Generated with Claude Code