feat: add git to Docker image (#6034)

This commit is contained in:
Dean Sheather 2023-02-07 03:30:35 +11:00 committed by GitHub
parent a655f03a1e
commit b45c445255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 196 additions and 48 deletions

53
.github/workflows/docker-base.yaml vendored Normal file
View File

@ -0,0 +1,53 @@
name: docker-base
on:
push:
branches:
- main
paths:
- Dockerfile.base
- Dockerfile
schedule:
# Run every week at 09:43 on Monday, Wednesday and Friday. We build this
# frequently to ensure that packages are up-to-date.
- cron: "43 9 * * 1,3,5"
workflow_dispatch:
# Avoid running multiple jobs for the same commit.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-docker-base
jobs:
build:
runs-on: ubuntu-latest
if: github.repository_owner == 'coder'
steps:
- uses: actions/checkout@v3
- name: Docker login
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create empty base-build-context directory
run: mkdir base-build-context
- name: Install depot.dev CLI
uses: depot/setup-action@v1
# This uses OIDC authentication, so no auth variables are required.
- name: Build base Docker image via depot.dev
uses: depot/build-push-action@v1
with:
project: wl5hnrrkns
context: base-build-context
file: Dockerfile.base
pull: true
no-cache: true
push: true
tags: |
ghcr.io/coder/coder-base:latest

View File

@ -112,17 +112,17 @@ jobs:
set -euo pipefail
wget -O /tmp/nfpm.deb https://github.com/goreleaser/nfpm/releases/download/v2.18.1/nfpm_amd64.deb
sudo dpkg -i /tmp/nfpm.deb
rm /tmp/nfpm.deb
- name: Install rcodesign
run: |
set -euo pipefail
# Install a prebuilt binary of rcodesign for linux amd64. Once the
# following PR is merged and released upstream, we can download
# directly from GitHub releases instead:
# https://github.com/indygreg/PyOxidizer/pull/635
wget -O /tmp/rcodesign https://cdn.discordapp.com/attachments/283356472258199552/1016767245717872700/rcodesign
sudo install --mode 755 /tmp/rcodesign /usr/local/bin/rcodesign
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
sudo tar -xzf /tmp/rcodesign.tar.gz \
-C /usr/bin \
--strip-components=1 \
apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign
rm /tmp/rcodesign.tar.gz
- name: Setup Apple Developer certificate and API key
run: |
@ -160,6 +160,39 @@ jobs:
- name: Delete Apple Developer certificate and API key
run: rm -f /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}
- name: Determine base image tag
id: image-base-tag
run: |
set -euo pipefail
if [[ "${CODER_RELEASE:-}" != *t* ]] || [[ "${CODER_DRY_RUN:-}" == *t* ]]; then
# Empty value means use the default and avoid building a fresh one.
echo "tag=" >> $GITHUB_OUTPUT
else
echo "tag=$(CODER_IMAGE_BASE=ghcr.io/coder/coder-base ./scripts/image_tag.sh)" >> $GITHUB_OUTPUT
fi
- name: Create empty base-build-context directory
if: steps.image-base-tag.outputs.tag != ''
run: mkdir base-build-context
- name: Install depot.dev CLI
if: steps.image-base-tag.outputs.tag != ''
uses: depot/setup-action@v1
# This uses OIDC authentication, so no auth variables are required.
- name: Build base Docker image via depot.dev
if: steps.image-base-tag.outputs.tag != ''
uses: depot/build-push-action@v1
with:
project: wl5hnrrkns
context: base-build-context
file: Dockerfile.base
pull: true
no-cache: true
push: true
tags: |
${{ steps.image-base-tag.outputs.tag }}
- name: Build Linux Docker images
run: |
set -euxo pipefail
@ -188,6 +221,8 @@ jobs:
--target "$(./scripts/image_tag.sh --version latest)" \
$(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
fi
env:
CODER_BASE_IMAGE_TAG: ${{ steps.image-base-tag.outputs.tag }}
- name: ls build
run: ls -lh build
@ -252,6 +287,14 @@ jobs:
./build/*.rpm
retention-days: 7
- name: Start Packer builds
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.CDRCI_GITHUB_TOKEN }}
repository: coder/packages
event-type: coder-release
client-payload: '{"coder_version": "${{ steps.version.outputs.version }}"}'
publish-winget:
name: Publish to winget-pkgs
runs-on: windows-latest
@ -333,11 +376,3 @@ jobs:
# For gh CLI. We need a real token since we're commenting on a PR in a
# different repo.
GH_TOKEN: ${{ secrets.CDRCI_GITHUB_TOKEN }}
- name: Start Packer builds
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.CDRCI_GITHUB_TOKEN }}
repository: coder/packages
event-type: coder-release
client-payload: '{"coder_version": "${{ needs.release.outputs.version }}"}'

View File

@ -96,8 +96,20 @@ jobs:
id: build
run: |
set -euo pipefail
image_job="build/coder_$(./scripts/version.sh)_linux_amd64.tag"
DOCKER_IMAGE_NO_PREREQUISITES=true make -j "$image_job"
version="$(./scripts/version.sh)"
image_job="build/coder_${version}_linux_amd64.tag"
# This environment variable force make to not build packages and
# archives (which the Docker image depends on due to technical reasons
# related to concurrent FS writes).
export DOCKER_IMAGE_NO_PREREQUISITES=true
# This environment variables forces scripts/build_docker.sh to build
# the base image tag locally instead of using the cached version from
# the registry.
export CODER_IMAGE_BUILD_BASE_TAG="$(CODER_IMAGE_BASE=coder-base ./scripts/image_tag.sh --version "$version")"
make -j "$image_job"
echo "image=$(cat "$image_job")" >> $GITHUB_OUTPUT
- name: Run Trivy vulnerability scanner

View File

@ -2,7 +2,11 @@
# 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
#
# If you need RUN commands (e.g. to install tools via apk), add them to
# Dockerfile.base instead, which supports "RUN" commands.
ARG BASE_IMAGE
FROM $BASE_IMAGE
# LABEL doesn't add any real layers so it's fine (and easier) to do it here than
# in the build script.
@ -14,17 +18,7 @@ LABEL \
org.opencontainers.image.source="https://github.com/coder/coder" \
org.opencontainers.image.version="$CODER_VERSION"
# 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=0:0 --chmod=644 group passwd /etc/
COPY --chown=1000:1000 --chmod=700 empty-dir /home/coder
# The coder binary is injected by scripts/build_docker.sh.
COPY --chown=1000:1000 --chmod=755 coder /opt/coder
USER 1000:1000
ENV HOME=/home/coder
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
WORKDIR /home/coder
ENTRYPOINT [ "/opt/coder", "server" ]

27
Dockerfile.base Normal file
View File

@ -0,0 +1,27 @@
# This is the base image used for Coder images. It's a multi-arch image that is
# built in depot.dev for all supported architectures. Since it's built on real
# hardware and not cross-compiled, it can have "RUN" commands.
FROM alpine:latest
# We use a single RUN command to reduce the number of layers in the image.
RUN apk add --no-cache \
curl \
wget \
bash \
git \
openssh-client && \
addgroup \
-g 1000 \
coder && \
adduser \
-D \
-s /bin/bash \
-h /home/coder \
-u 1000 \
-G coder \
coder
USER 1000:1000
ENV HOME=/home/coder
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt
WORKDIR /home/coder

View File

@ -164,6 +164,12 @@ RUN apt-get update --quiet && apt-get install --yes \
# Configure FIPS-compliant policies
update-crypto-policies --set FIPS
# Install the docker buildx component.
RUN DOCKER_BUILDX_VERSION=$(curl -s "https://api.github.com/repos/docker/buildx/releases/latest" | grep '"tag_name":' | sed -E 's/.*"(v[^"]+)".*/\1/') && \
mkdir -p /usr/local/lib/docker/cli-plugins && \
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" && \
chmod a+x /usr/local/lib/docker/cli-plugins/docker-buildx
# See https://github.com/cli/cli/issues/6175#issuecomment-1235984381 for proof
# the apt repository is unreliable
RUN curl -L https://github.com/cli/cli/releases/download/v2.14.7/gh_2.14.7_linux_amd64.deb -o gh.deb && \

View File

@ -3,12 +3,19 @@
# This script builds a Docker image of Coder containing the given binary, for
# the given architecture. Only linux binaries are supported at this time.
#
# Usage: ./build_docker.sh --arch amd64 [--version 1.2.3] [--target image_tag] [--push] path/to/coder
# Usage: ./build_docker.sh --arch amd64 [--version 1.2.3] [--target image_tag] [--build-base image_tag] [--push] path/to/coder
#
# The --arch parameter is required and accepts a Golang arch specification. It
# will be automatically mapped to a suitable architecture that Docker accepts
# before being passed to `docker buildx build`.
#
# The --build-base parameter is optional and specifies to build the base image
# in Dockerfile.base instead of pulling a copy from the registry. The string
# value is the tag to use for the built image (not pushed). This also consumes
# $CODER_IMAGE_BUILD_BASE_TAG for easily forcing a fresh build in CI.
#
# The default base image can be controlled via $CODER_BASE_IMAGE_TAG.
#
# The image will be built and tagged against the image tag returned by
# ./image_tag.sh unless a --target parameter is supplied.
#
@ -22,12 +29,15 @@ set -euo pipefail
# shellcheck source=scripts/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
DEFAULT_BASE="${CODER_BASE_IMAGE_TAG:-ghcr.io/coder/coder-base:latest}"
arch=""
image_tag=""
build_base="${CODER_IMAGE_BUILD_BASE_TAG:-}"
version=""
push=0
args="$(getopt -o "" -l arch:,target:,version:,push -- "$@")"
args="$(getopt -o "" -l arch:,target:,build-base:,version:,push -- "$@")"
eval set -- "$args"
while true; do
case "$1" in
@ -43,6 +53,10 @@ while true; do
version="$2"
shift 2
;;
--build-base)
build_base="$2"
shift
;;
--push)
push=1
shift
@ -98,31 +112,37 @@ fi
cdroot
temp_dir="$(TMPDIR="$(dirname "$input_file")" mktemp -d)"
ln "$input_file" "$temp_dir/coder"
ln Dockerfile.base "$temp_dir/"
ln Dockerfile "$temp_dir/"
cd "$temp_dir"
export DOCKER_BUILDKIT=1
base_image="$DEFAULT_BASE"
if [[ "$build_base" != "" ]]; then
log "--- Building base Docker image for $arch ($build_base)"
docker build \
--platform "$arch" \
--tag "$build_base" \
--no-cache \
-f Dockerfile.base \
. 1>&2
base_image="$build_base"
else
docker pull --platform "$arch" "$base_image" 1>&2
fi
log "--- Building Docker image for $arch ($image_tag)"
# 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
mkdir ./empty-dir
docker buildx build \
docker build \
--platform "$arch" \
--build-arg "BASE_IMAGE=$base_image" \
--build-arg "CODER_VERSION=$version" \
--no-cache \
--tag "$image_tag" \
-f Dockerfile \
. 1>&2
cdroot

View File

@ -47,8 +47,9 @@ rcodesign encode-app-store-connect-api-key \
# The notarization process is very fragile and heavily dependent on Apple's
# notarization server not returning server errors, so we retry this step twice
# with a delay of 30 seconds between attempts.
NOTARY_SUBMIT_ATTEMPTS=2
rc=0
for i in $(seq 1 2); do
for i in $(seq 1 $NOTARY_SUBMIT_ATTEMPTS); do
# -v is quite verbose, the default output is pretty good on it's own. Adding
# -v makes it dump the credentials used for uploading to Apple's S3 bucket.
rcodesign notary-submit \
@ -58,7 +59,7 @@ for i in $(seq 1 2); do
1>&2 && rc=0 && break || rc=$?
log "rcodesign exit code: $rc"
if [[ $i -lt 5 ]]; then
if [[ $i -lt $NOTARY_SUBMIT_ATTEMPTS ]]; then
log
log "Retrying notarization in 30 seconds"
log