Skip to content

Commit b45c445

Browse files
authored
feat: add git to Docker image (coder#6034)
1 parent a655f03 commit b45c445

File tree

8 files changed

+196
-48
lines changed

8 files changed

+196
-48
lines changed

.github/workflows/docker-base.yaml

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: docker-base
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- Dockerfile.base
9+
- Dockerfile
10+
11+
schedule:
12+
# Run every week at 09:43 on Monday, Wednesday and Friday. We build this
13+
# frequently to ensure that packages are up-to-date.
14+
- cron: "43 9 * * 1,3,5"
15+
16+
workflow_dispatch:
17+
18+
# Avoid running multiple jobs for the same commit.
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}-docker-base
21+
22+
jobs:
23+
build:
24+
runs-on: ubuntu-latest
25+
if: github.repository_owner == 'coder'
26+
steps:
27+
- uses: actions/checkout@v3
28+
29+
- name: Docker login
30+
uses: docker/login-action@v2
31+
with:
32+
registry: ghcr.io
33+
username: ${{ github.actor }}
34+
password: ${{ secrets.GITHUB_TOKEN }}
35+
36+
- name: Create empty base-build-context directory
37+
run: mkdir base-build-context
38+
39+
- name: Install depot.dev CLI
40+
uses: depot/setup-action@v1
41+
42+
# This uses OIDC authentication, so no auth variables are required.
43+
- name: Build base Docker image via depot.dev
44+
uses: depot/build-push-action@v1
45+
with:
46+
project: wl5hnrrkns
47+
context: base-build-context
48+
file: Dockerfile.base
49+
pull: true
50+
no-cache: true
51+
push: true
52+
tags: |
53+
ghcr.io/coder/coder-base:latest

.github/workflows/release.yaml

+50-15
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,17 @@ jobs:
112112
set -euo pipefail
113113
wget -O /tmp/nfpm.deb https://github.com/goreleaser/nfpm/releases/download/v2.18.1/nfpm_amd64.deb
114114
sudo dpkg -i /tmp/nfpm.deb
115+
rm /tmp/nfpm.deb
115116
116117
- name: Install rcodesign
117118
run: |
118119
set -euo pipefail
119-
120-
# Install a prebuilt binary of rcodesign for linux amd64. Once the
121-
# following PR is merged and released upstream, we can download
122-
# directly from GitHub releases instead:
123-
# https://github.com/indygreg/PyOxidizer/pull/635
124-
wget -O /tmp/rcodesign https://cdn.discordapp.com/attachments/283356472258199552/1016767245717872700/rcodesign
125-
sudo install --mode 755 /tmp/rcodesign /usr/local/bin/rcodesign
120+
wget -O /tmp/rcodesign.tar.gz https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-x86_64-unknown-linux-musl.tar.gz
121+
sudo tar -xzf /tmp/rcodesign.tar.gz \
122+
-C /usr/bin \
123+
--strip-components=1 \
124+
apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign
125+
rm /tmp/rcodesign.tar.gz
126126
127127
- name: Setup Apple Developer certificate and API key
128128
run: |
@@ -160,6 +160,39 @@ jobs:
160160
- name: Delete Apple Developer certificate and API key
161161
run: rm -f /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}
162162

163+
- name: Determine base image tag
164+
id: image-base-tag
165+
run: |
166+
set -euo pipefail
167+
if [[ "${CODER_RELEASE:-}" != *t* ]] || [[ "${CODER_DRY_RUN:-}" == *t* ]]; then
168+
# Empty value means use the default and avoid building a fresh one.
169+
echo "tag=" >> $GITHUB_OUTPUT
170+
else
171+
echo "tag=$(CODER_IMAGE_BASE=ghcr.io/coder/coder-base ./scripts/image_tag.sh)" >> $GITHUB_OUTPUT
172+
fi
173+
174+
- name: Create empty base-build-context directory
175+
if: steps.image-base-tag.outputs.tag != ''
176+
run: mkdir base-build-context
177+
178+
- name: Install depot.dev CLI
179+
if: steps.image-base-tag.outputs.tag != ''
180+
uses: depot/setup-action@v1
181+
182+
# This uses OIDC authentication, so no auth variables are required.
183+
- name: Build base Docker image via depot.dev
184+
if: steps.image-base-tag.outputs.tag != ''
185+
uses: depot/build-push-action@v1
186+
with:
187+
project: wl5hnrrkns
188+
context: base-build-context
189+
file: Dockerfile.base
190+
pull: true
191+
no-cache: true
192+
push: true
193+
tags: |
194+
${{ steps.image-base-tag.outputs.tag }}
195+
163196
- name: Build Linux Docker images
164197
run: |
165198
set -euxo pipefail
@@ -188,6 +221,8 @@ jobs:
188221
--target "$(./scripts/image_tag.sh --version latest)" \
189222
$(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
190223
fi
224+
env:
225+
CODER_BASE_IMAGE_TAG: ${{ steps.image-base-tag.outputs.tag }}
191226

192227
- name: ls build
193228
run: ls -lh build
@@ -252,6 +287,14 @@ jobs:
252287
./build/*.rpm
253288
retention-days: 7
254289

290+
- name: Start Packer builds
291+
uses: peter-evans/repository-dispatch@v2
292+
with:
293+
token: ${{ secrets.CDRCI_GITHUB_TOKEN }}
294+
repository: coder/packages
295+
event-type: coder-release
296+
client-payload: '{"coder_version": "${{ steps.version.outputs.version }}"}'
297+
255298
publish-winget:
256299
name: Publish to winget-pkgs
257300
runs-on: windows-latest
@@ -333,11 +376,3 @@ jobs:
333376
# For gh CLI. We need a real token since we're commenting on a PR in a
334377
# different repo.
335378
GH_TOKEN: ${{ secrets.CDRCI_GITHUB_TOKEN }}
336-
337-
- name: Start Packer builds
338-
uses: peter-evans/repository-dispatch@v2
339-
with:
340-
token: ${{ secrets.CDRCI_GITHUB_TOKEN }}
341-
repository: coder/packages
342-
event-type: coder-release
343-
client-payload: '{"coder_version": "${{ needs.release.outputs.version }}"}'

.github/workflows/security.yaml

+14-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,20 @@ jobs:
9696
id: build
9797
run: |
9898
set -euo pipefail
99-
image_job="build/coder_$(./scripts/version.sh)_linux_amd64.tag"
100-
DOCKER_IMAGE_NO_PREREQUISITES=true make -j "$image_job"
99+
100+
version="$(./scripts/version.sh)"
101+
image_job="build/coder_${version}_linux_amd64.tag"
102+
103+
# This environment variable force make to not build packages and
104+
# archives (which the Docker image depends on due to technical reasons
105+
# related to concurrent FS writes).
106+
export DOCKER_IMAGE_NO_PREREQUISITES=true
107+
# This environment variables forces scripts/build_docker.sh to build
108+
# the base image tag locally instead of using the cached version from
109+
# the registry.
110+
export CODER_IMAGE_BUILD_BASE_TAG="$(CODER_IMAGE_BASE=coder-base ./scripts/image_tag.sh --version "$version")"
111+
112+
make -j "$image_job"
101113
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
102114
103115
- name: Run Trivy vulnerability scanner

Dockerfile

+5-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
# cross-compiled, it cannot have ANY "RUN" commands. All binaries are built
33
# using the go toolchain on the host and then copied into the build context by
44
# scripts/build_docker.sh.
5-
FROM alpine:latest
5+
#
6+
# If you need RUN commands (e.g. to install tools via apk), add them to
7+
# Dockerfile.base instead, which supports "RUN" commands.
8+
ARG BASE_IMAGE
9+
FROM $BASE_IMAGE
610

711
# LABEL doesn't add any real layers so it's fine (and easier) to do it here than
812
# in the build script.
@@ -14,17 +18,7 @@ LABEL \
1418
org.opencontainers.image.source="https://github.com/coder/coder" \
1519
org.opencontainers.image.version="$CODER_VERSION"
1620

17-
# Create coder group and user. We cannot use `addgroup` and `adduser` because
18-
# they won't work if we're building the image for a different architecture.
19-
COPY --chown=0:0 --chmod=644 group passwd /etc/
20-
COPY --chown=1000:1000 --chmod=700 empty-dir /home/coder
21-
2221
# The coder binary is injected by scripts/build_docker.sh.
2322
COPY --chown=1000:1000 --chmod=755 coder /opt/coder
2423

25-
USER 1000:1000
26-
ENV HOME=/home/coder
27-
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
28-
WORKDIR /home/coder
29-
3024
ENTRYPOINT [ "/opt/coder", "server" ]

Dockerfile.base

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This is the base image used for Coder images. It's a multi-arch image that is
2+
# built in depot.dev for all supported architectures. Since it's built on real
3+
# hardware and not cross-compiled, it can have "RUN" commands.
4+
FROM alpine:latest
5+
6+
# We use a single RUN command to reduce the number of layers in the image.
7+
RUN apk add --no-cache \
8+
curl \
9+
wget \
10+
bash \
11+
git \
12+
openssh-client && \
13+
addgroup \
14+
-g 1000 \
15+
coder && \
16+
adduser \
17+
-D \
18+
-s /bin/bash \
19+
-h /home/coder \
20+
-u 1000 \
21+
-G coder \
22+
coder
23+
24+
USER 1000:1000
25+
ENV HOME=/home/coder
26+
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
27+
WORKDIR /home/coder

dogfood/Dockerfile

+6
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ RUN apt-get update --quiet && apt-get install --yes \
164164
# Configure FIPS-compliant policies
165165
update-crypto-policies --set FIPS
166166

167+
# Install the docker buildx component.
168+
RUN DOCKER_BUILDX_VERSION=$(curl -s "https://api.github.com/repos/docker/buildx/releases/latest" | grep '"tag_name":' | sed -E 's/.*"(v[^"]+)".*/\1/') && \
169+
mkdir -p /usr/local/lib/docker/cli-plugins && \
170+
curl -Lo /usr/local/lib/docker/cli-plugins/docker-buildx "https://github.com/docker/buildx/releases/download/${DOCKER_BUILDX_VERSION}/buildx-${DOCKER_BUILDX_VERSION}.linux-amd64" && \
171+
chmod a+x /usr/local/lib/docker/cli-plugins/docker-buildx
172+
167173
# See https://github.com/cli/cli/issues/6175#issuecomment-1235984381 for proof
168174
# the apt repository is unreliable
169175
RUN curl -L https://github.com/cli/cli/releases/download/v2.14.7/gh_2.14.7_linux_amd64.deb -o gh.deb && \

scripts/build_docker.sh

+38-18
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@
33
# This script builds a Docker image of Coder containing the given binary, for
44
# the given architecture. Only linux binaries are supported at this time.
55
#
6-
# Usage: ./build_docker.sh --arch amd64 [--version 1.2.3] [--target image_tag] [--push] path/to/coder
6+
# Usage: ./build_docker.sh --arch amd64 [--version 1.2.3] [--target image_tag] [--build-base image_tag] [--push] path/to/coder
77
#
88
# The --arch parameter is required and accepts a Golang arch specification. It
99
# will be automatically mapped to a suitable architecture that Docker accepts
1010
# before being passed to `docker buildx build`.
1111
#
12+
# The --build-base parameter is optional and specifies to build the base image
13+
# in Dockerfile.base instead of pulling a copy from the registry. The string
14+
# value is the tag to use for the built image (not pushed). This also consumes
15+
# $CODER_IMAGE_BUILD_BASE_TAG for easily forcing a fresh build in CI.
16+
#
17+
# The default base image can be controlled via $CODER_BASE_IMAGE_TAG.
18+
#
1219
# The image will be built and tagged against the image tag returned by
1320
# ./image_tag.sh unless a --target parameter is supplied.
1421
#
@@ -22,12 +29,15 @@ set -euo pipefail
2229
# shellcheck source=scripts/lib.sh
2330
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
2431

32+
DEFAULT_BASE="${CODER_BASE_IMAGE_TAG:-ghcr.io/coder/coder-base:latest}"
33+
2534
arch=""
2635
image_tag=""
36+
build_base="${CODER_IMAGE_BUILD_BASE_TAG:-}"
2737
version=""
2838
push=0
2939

30-
args="$(getopt -o "" -l arch:,target:,version:,push -- "$@")"
40+
args="$(getopt -o "" -l arch:,target:,build-base:,version:,push -- "$@")"
3141
eval set -- "$args"
3242
while true; do
3343
case "$1" in
@@ -43,6 +53,10 @@ while true; do
4353
version="$2"
4454
shift 2
4555
;;
56+
--build-base)
57+
build_base="$2"
58+
shift
59+
;;
4660
--push)
4761
push=1
4862
shift
@@ -98,31 +112,37 @@ fi
98112
cdroot
99113
temp_dir="$(TMPDIR="$(dirname "$input_file")" mktemp -d)"
100114
ln "$input_file" "$temp_dir/coder"
115+
ln Dockerfile.base "$temp_dir/"
101116
ln Dockerfile "$temp_dir/"
102117

103118
cd "$temp_dir"
104119

105-
log "--- Building Docker image for $arch ($image_tag)"
106-
107-
# Pull the base image, copy the /etc/group and /etc/passwd files out of it, and
108-
# add the coder group and user. We have to do this in a separate step instead of
109-
# using the RUN directive in the Dockerfile because you can't use RUN if you're
110-
# building the image for a different architecture than the host.
111-
docker pull --platform "$arch" alpine:latest 1>&2
112-
113-
temp_container_id="$(docker create --platform "$arch" alpine:latest)"
114-
docker cp "$temp_container_id":/etc/group ./group 1>&2
115-
docker cp "$temp_container_id":/etc/passwd ./passwd 1>&2
116-
docker rm "$temp_container_id" 1>&2
120+
export DOCKER_BUILDKIT=1
121+
122+
base_image="$DEFAULT_BASE"
123+
if [[ "$build_base" != "" ]]; then
124+
log "--- Building base Docker image for $arch ($build_base)"
125+
docker build \
126+
--platform "$arch" \
127+
--tag "$build_base" \
128+
--no-cache \
129+
-f Dockerfile.base \
130+
. 1>&2
131+
132+
base_image="$build_base"
133+
else
134+
docker pull --platform "$arch" "$base_image" 1>&2
135+
fi
117136

118-
echo "coder:x:1000:coder" >>./group
119-
echo "coder:x:1000:1000::/:/bin/sh" >>./passwd
120-
mkdir ./empty-dir
137+
log "--- Building Docker image for $arch ($image_tag)"
121138

122-
docker buildx build \
139+
docker build \
123140
--platform "$arch" \
141+
--build-arg "BASE_IMAGE=$base_image" \
124142
--build-arg "CODER_VERSION=$version" \
143+
--no-cache \
125144
--tag "$image_tag" \
145+
-f Dockerfile \
126146
. 1>&2
127147

128148
cdroot

scripts/notarize_darwin.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ rcodesign encode-app-store-connect-api-key \
4747
# The notarization process is very fragile and heavily dependent on Apple's
4848
# notarization server not returning server errors, so we retry this step twice
4949
# with a delay of 30 seconds between attempts.
50+
NOTARY_SUBMIT_ATTEMPTS=2
5051
rc=0
51-
for i in $(seq 1 2); do
52+
for i in $(seq 1 $NOTARY_SUBMIT_ATTEMPTS); do
5253
# -v is quite verbose, the default output is pretty good on it's own. Adding
5354
# -v makes it dump the credentials used for uploading to Apple's S3 bucket.
5455
rcodesign notary-submit \
@@ -58,7 +59,7 @@ for i in $(seq 1 2); do
5859
1>&2 && rc=0 && break || rc=$?
5960

6061
log "rcodesign exit code: $rc"
61-
if [[ $i -lt 5 ]]; then
62+
if [[ $i -lt $NOTARY_SUBMIT_ATTEMPTS ]]; then
6263
log
6364
log "Retrying notarization in 30 seconds"
6465
log

0 commit comments

Comments
 (0)