diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 92d9b881a4bbe..c767cc908032e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -102,7 +102,7 @@ jobs: # build and (maybe) push Docker images for each architecture images=() - for arch in amd64; do + for arch in amd64 armv7 arm64; do img="$( ./scripts/build_docker.sh \ ${{ (!github.event.inputs.dry_run && !github.event.inputs.snapshot) && '--push' || '' }} \ diff --git a/Dockerfile b/Dockerfile index 6dcdcc21205bf..b28d92b3cb1dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,8 @@ -FROM alpine +# This is the multi-arch Dockerfile used for Coder. Since it's multi-arch and +# cross-compiled, it cannot have ANY "RUN" commands. All binaries are built +# using the go toolchain on the host and then copied into the build context by +# scripts/build_docker.sh. +FROM alpine:latest # LABEL doesn't add any real layers so it's fine (and easier) to do it here than # in the build script. @@ -11,12 +15,12 @@ LABEL \ org.opencontainers.image.version="$CODER_VERSION" \ org.opencontainers.image.licenses="AGPL-3.0" +# Create coder group and user. We cannot use `addgroup` and `adduser` because +# they won't work if we're building the image for a different architecture. +COPY --chown=root:root --chmod=644 group passwd /etc/ + # The coder binary is injected by scripts/build_docker.sh. -ADD coder /opt/coder +COPY --chown=coder:coder --chmod=755 coder /opt/coder -# Create coder group and user. -RUN addgroup -g 1000 coder && \ - adduser -D -g "" -h /home/coder -G coder -u 1000 -S -s /bin/sh coder USER coder:coder - ENTRYPOINT [ "/opt/coder", "server" ] diff --git a/scripts/build_docker.sh b/scripts/build_docker.sh index 3ac8c311dd347..de5c3c0dbdd48 100755 --- a/scripts/build_docker.sh +++ b/scripts/build_docker.sh @@ -95,14 +95,27 @@ ln -P Dockerfile "$temp_dir/" cd "$temp_dir" -build_args=( - --platform "$arch" - --build-arg "CODER_VERSION=$version" - --tag "$image_tag" -) - log "--- Building Docker image for $arch ($image_tag)" -docker buildx build "${build_args[@]}" . 1>&2 + +# Pull the base image, copy the /etc/group and /etc/passwd files out of it, and +# add the coder group and user. We have to do this in a separate step instead of +# using the RUN directive in the Dockerfile because you can't use RUN if you're +# building the image for a different architecture than the host. +docker pull --platform "$arch" alpine:latest 1>&2 + +temp_container_id="$(docker create --platform "$arch" alpine:latest)" +docker cp "$temp_container_id":/etc/group ./group 1>&2 +docker cp "$temp_container_id":/etc/passwd ./passwd 1>&2 +docker rm "$temp_container_id" 1>&2 + +echo "coder:x:1000:coder" >>./group +echo "coder:x:1000:1000::/:/bin/sh" >>./passwd + +docker buildx build \ + --platform "$arch" \ + --build-arg "CODER_VERSION=$version" \ + --tag "$image_tag" \ + . 1>&2 cdroot rm -rf "$temp_dir"