Skip to content

Commit dde5e95

Browse files
committed
feat: add git to Docker image
1 parent 77fd34b commit dde5e95

File tree

7 files changed

+170
-32
lines changed

7 files changed

+170
-32
lines changed

.github/workflows/docker-base.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
# Avoid running multiple jobs for the same commit.
17+
concurrency:
18+
group: ${{ github.workflow }}-${{ github.ref }}-docker-base
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-latest
23+
if: github.repository_owner == 'coder'
24+
steps:
25+
- uses: actions/checkout@v3
26+
27+
- name: Docker login
28+
uses: docker/login-action@v2
29+
with:
30+
registry: ghcr.io
31+
username: ${{ github.actor }}
32+
password: ${{ secrets.GITHUB_TOKEN }}
33+
34+
- name: Create empty base-build-context directory
35+
run: mkdir base-build-context
36+
37+
- name: Install depot.dev CLI
38+
uses: depot/setup-action@v1
39+
40+
# This uses OIDC authentication, so no auth variables are required.
41+
- name: Build base Docker image via depot.dev
42+
uses: depot/build-push-action@v1
43+
with:
44+
project: wl5hnrrkns
45+
context: base-build-context
46+
file: Dockerfile.base
47+
push: true
48+
tags: |
49+
ghcr.io/coder/coder-base:latest

.github/workflows/release.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,37 @@ 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=ghcr.io/coder/coder-base:${{ steps.version.outputs.version }}" >> $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+
push: true
191+
tags: |
192+
${{ steps.image-base-tag.outputs.tag }}
193+
163194
- name: Build Linux Docker images
164195
run: |
165196
set -euxo pipefail
@@ -188,6 +219,8 @@ jobs:
188219
--target "$(./scripts/image_tag.sh --version latest)" \
189220
$(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
190221
fi
222+
env:
223+
CODER_IMAGE_BUILD_BASE_TAG: ${{ steps.image-base-tag.outputs.tag }}
191224

192225
- name: ls build
193226
run: ls -lh build

.github/workflows/security.yaml

Lines changed: 14 additions & 2 deletions
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-base:$version"
111+
112+
make -j "$image_job"
101113
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
102114
103115
- name: Run Trivy vulnerability scanner

Dockerfile

Lines changed: 5 additions & 11 deletions
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

Lines changed: 27 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
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+
#
1217
# The image will be built and tagged against the image tag returned by
1318
# ./image_tag.sh unless a --target parameter is supplied.
1419
#
@@ -18,16 +23,19 @@
1823
#
1924
# Prints the image tag on success.
2025

21-
set -euo pipefail
26+
set -euxo pipefail
2227
# shellcheck source=scripts/lib.sh
2328
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
2429

30+
DEFAULT_BASE="ghcr.io/coder/coder-base:latest"
31+
2532
arch=""
2633
image_tag=""
34+
build_base="${CODER_IMAGE_BUILD_BASE_TAG:-}"
2735
version=""
2836
push=0
2937

30-
args="$(getopt -o "" -l arch:,target:,version:,push -- "$@")"
38+
args="$(getopt -o "" -l arch:,target:,build_base:,version:,push -- "$@")"
3139
eval set -- "$args"
3240
while true; do
3341
case "$1" in
@@ -43,6 +51,10 @@ while true; do
4351
version="$2"
4452
shift 2
4553
;;
54+
--build-base)
55+
build_base="$2"
56+
shift
57+
;;
4658
--push)
4759
push=1
4860
shift
@@ -98,30 +110,35 @@ fi
98110
cdroot
99111
temp_dir="$(TMPDIR="$(dirname "$input_file")" mktemp -d)"
100112
ln "$input_file" "$temp_dir/coder"
113+
ln Dockerfile.base "$temp_dir/"
101114
ln Dockerfile "$temp_dir/"
102115

103116
cd "$temp_dir"
104117

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
118+
export DOCKER_BUILDKIT=1
119+
120+
base_image="$DEFAULT_BASE"
121+
if [[ "$build_base" != "" ]]; then
122+
log "--- Building base Docker image for $arch ($build_base)"
123+
docker build \
124+
--platform "$arch" \
125+
--tag "$build_base" \
126+
--no-cache \
127+
-f Dockerfile.base \
128+
. 1>&2
129+
130+
base_image="$build_base"
131+
else
132+
docker pull --platform "$arch" "$base_image" 1>&2
133+
fi
117134

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

122-
docker buildx build \
137+
docker build \
123138
--platform "$arch" \
139+
--build-arg "BASE_IMAGE=$base_image" \
124140
--build-arg "CODER_VERSION=$version" \
141+
--no-cache \
125142
--tag "$image_tag" \
126143
. 1>&2
127144

0 commit comments

Comments
 (0)