ci: compile on scratch before assembling the runtime image

This commit is contained in:
codex 2026-10-04 06:25:27 -05:00
parent 8b6195c2e6
commit e9f24b1053
3 changed files with 54 additions and 6 deletions

6
Dockerfile.runtime Normal file
View File

@ -0,0 +1,6 @@
# Jenkins compiles on its scratch PVC; image assembly needs no toolchain layers.
FROM gcr.io/distroless/static-debian12:nonroot@sha256:afa5c872c891853ca7fcf1f12c3edb23f7eeef36189728842dd51042ff57f7ab
COPY soteria /soteria
USER 65532:65532
EXPOSE 8080
ENTRYPOINT ["/soteria"]

42
Jenkinsfile vendored
View File

@ -49,7 +49,7 @@ spec:
resources:
requests:
cpu: 100m
memory: 1Gi
memory: 512Mi
limits:
cpu: 1500m
memory: 2Gi
@ -63,6 +63,19 @@ spec:
command:
- cat
tty: true
resources:
requests: {cpu: 200m, memory: 512Mi}
limits: {cpu: 1500m, memory: 2Gi}
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: ui-builder
image: node:22-alpine@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402
command: [cat]
tty: true
resources:
requests: {cpu: 25m, memory: 64Mi}
limits: {cpu: 1000m, memory: 512Mi}
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
@ -545,6 +558,26 @@ PY
}
}
}
stage('Build release on scratch') {
when {
expression { return params.PUBLISH_IMAGES }
}
steps {
container('ui-builder') {
sh 'cd web && npm ci && npm run build'
}
container('tester') {
// Reuse the tested Go cache and put compiler writes on the workspace PVC.
sh '''
set -eu
mkdir -p build/image internal/server/ui-dist
cp -R web/dist/. internal/server/ui-dist/
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -p 2 -buildvcs=false -trimpath -ldflags="-s -w" -o build/image/soteria ./cmd/soteria
cp Dockerfile.runtime build/image/Dockerfile
'''
}
}
}
stage('Build & push image') {
when {
expression { return params.PUBLISH_IMAGES }
@ -561,11 +594,8 @@ PY
printf '{"auths":{"registry.bstein.dev":{"auth":"%s"}}}\\n' "${auth}" > /kaniko/.docker/config.json
trap 'rm -f /kaniko/.docker/config.json' EXIT
/kaniko/executor \
--context "${WORKSPACE}" \
--dockerfile "${WORKSPACE}/Dockerfile" \
--build-arg BUILDPLATFORM=linux/arm64 \
--build-arg TARGETOS=linux \
--build-arg TARGETARCH=arm64 \
--context "${WORKSPACE}/build/image" \
--dockerfile "${WORKSPACE}/build/image/Dockerfile" \
--destination "registry.bstein.dev/bstein/soteria:${VERSION_TAG}" \
--destination registry.bstein.dev/bstein/soteria:latest
'''

View File

@ -14,3 +14,15 @@ RoleBindings in each backup/restore target namespace: Job creation and the
credential-copy operations in `internal/k8s/jobs.go`. Those grants are not part
of this Longhorn deployment. Review credential distribution before enabling
restic; Kubernetes RBAC cannot restrict Secret creation by resource name.
## CI image construction
Jenkins compiles the UI and ARM64 Go binary in its `ci-scratch` workspace PVC.
Compiler and package caches also use that PVC. The final Kaniko step receives
only `build/image/` and `Dockerfile.runtime`, so it packages the binary without
unpacking Node/Go toolchains or compiling on the node's runtime filesystem.
The ordinary multistage `Dockerfile` remains available for workstation builds.
Keep `CGO_ENABLED=0`, the UI embedding step and the runtime architecture aligned.
The runtime image stays nonroot and exposes the same port and entrypoint. Image
publication still requires all existing quality and supply-chain gates.