diff --git a/.dockerignore b/.dockerignore index 95d7144..e8deeed 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,5 @@ Dockerfile .git/ +# Binaries and logs from the host: the image must contain only what its own +# build stage produces. +ctrld-* diff --git a/docker/Dockerfile b/docker/Dockerfile index e89b4fe..b15e42a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,7 +8,11 @@ # - Non-cgo ctrld binary. # # CI_COMMIT_TAG is used to set the version of ctrld binary. -FROM golang:1.27-bookworm AS base +# The build stage runs on the build host's own platform and cross-compiles +# ctrld for the target platform, so no build step runs under qemu emulation. +# buildx sets BUILDPLATFORM and the TARGET* arguments from --platform, e.g. +# linux/arm/v7 gives TARGETOS=linux, TARGETARCH=arm, TARGETVARIANT=v7. +FROM --platform=$BUILDPLATFORM golang:1.27-bookworm AS base WORKDIR /app @@ -19,7 +23,19 @@ COPY . . ARG tag=master ENV CI_COMMIT_TAG=$tag -RUN CTRLD_NO_QF=yes CGO_ENABLED=0 ./scripts/build.sh +ARG TARGETOS TARGETARCH TARGETVARIANT +# scripts/build.sh takes linux/amd64, linux/arm64 or linux/armv7, and names the +# binary after it: ctrld-linux-amd64-nocgo, ctrld-linux-armv7-nocgo, ... +RUN CGO_ENABLED=0 ./scripts/build.sh "${TARGETOS}/${TARGETARCH}${TARGETVARIANT}" + +# Move the binary built for this target to one fixed path, and fail the build +# if it is not there. Check its exact name rather than a glob: a glob can also +# match a binary built for another target, and a COPY glob that matches nothing +# does not fail, which would ship an image without ctrld. +RUN set -eu; \ + bin="ctrld-${TARGETOS}-${TARGETARCH}${TARGETVARIANT}-nocgo"; \ + [ -x "$bin" ] || { echo >&2 "missing build artifact: $bin"; exit 1; }; \ + mv -- "$bin" /ctrld FROM scratch @@ -28,6 +44,6 @@ COPY --from=base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=base /etc/passwd /etc/passwd COPY --from=base /etc/group /etc/group -COPY --from=base /app/ctrld-linux-*-nocgo ctrld +COPY --from=base /ctrld ctrld ENTRYPOINT ["./ctrld", "run"] diff --git a/docker/Dockerfile.debug b/docker/Dockerfile.debug index 25d8b89..de455f7 100644 --- a/docker/Dockerfile.debug +++ b/docker/Dockerfile.debug @@ -8,7 +8,11 @@ # - Non-cgo ctrld binary. # # CI_COMMIT_TAG is used to set the version of ctrld binary. -FROM golang:1.27-bookworm AS base +# The build stage runs on the build host's own platform and cross-compiles +# ctrld for the target platform, so no build step runs under qemu emulation. +# buildx sets BUILDPLATFORM and the TARGET* arguments from --platform, e.g. +# linux/arm/v7 gives TARGETOS=linux, TARGETARCH=arm, TARGETVARIANT=v7. +FROM --platform=$BUILDPLATFORM golang:1.27-bookworm AS base WORKDIR /app @@ -19,7 +23,19 @@ COPY . . ARG tag=master ENV CI_COMMIT_TAG=$tag -RUN CTRLD_NO_QF=yes CGO_ENABLED=0 ./scripts/build.sh +ARG TARGETOS TARGETARCH TARGETVARIANT +# scripts/build.sh takes linux/amd64, linux/arm64 or linux/armv7, and names the +# binary after it: ctrld-linux-amd64-nocgo, ctrld-linux-armv7-nocgo, ... +RUN CGO_ENABLED=0 ./scripts/build.sh "${TARGETOS}/${TARGETARCH}${TARGETVARIANT}" + +# Move the binary built for this target to one fixed path, and fail the build +# if it is not there. Check its exact name rather than a glob: a glob can also +# match a binary built for another target, and a COPY glob that matches nothing +# does not fail, which would ship an image without ctrld. +RUN set -eu; \ + bin="ctrld-${TARGETOS}-${TARGETARCH}${TARGETVARIANT}-nocgo"; \ + [ -x "$bin" ] || { echo >&2 "missing build artifact: $bin"; exit 1; }; \ + mv -- "$bin" /ctrld FROM alpine @@ -28,6 +44,6 @@ COPY --from=base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=base /etc/passwd /etc/passwd COPY --from=base /etc/group /etc/group -COPY --from=base /app/ctrld-linux-*-nocgo ctrld +COPY --from=base /ctrld ctrld ENTRYPOINT ["./ctrld", "run"] diff --git a/scripts/build.sh b/scripts/build.sh index 2faeddc..bd4056d 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -72,8 +72,8 @@ build() { if [ "$CGO_ENABLED" = "0" ]; then binary=${binary}-nocgo fi - GOOS=${goos} GOARCH=${goarch} GOARM=${3} "$go" generate ./... - GOOS=${goos} GOARCH=${goarch} GOARM=${3} "$go" build -ldflags="$ldflags" -o "$binary" ./cmd/ctrld + GOOS=${goos} GOARCH=${goarch} GOARM=${3} "$go" generate ./... || exit 1 + GOOS=${goos} GOARCH=${goarch} GOARM=${3} "$go" build -ldflags="$ldflags" -o "$binary" ./cmd/ctrld || exit 1 compress "$binary" ;; *) @@ -82,8 +82,8 @@ build() { if [ "$CGO_ENABLED" = "0" ]; then binary=${binary}-nocgo fi - GOOS=${goos} GOARCH=${goarch} GOMIPS=softfloat "$go" generate ./... - GOOS=${goos} GOARCH=${goarch} GOMIPS=softfloat "$go" build -ldflags="$ldflags" -o "$binary" ./cmd/ctrld + GOOS=${goos} GOARCH=${goarch} GOMIPS=softfloat "$go" generate ./... || exit 1 + GOOS=${goos} GOARCH=${goarch} GOMIPS=softfloat "$go" build -ldflags="$ldflags" -o "$binary" ./cmd/ctrld || exit 1 compress "$binary" ;; esac