Skip to content

Commit 026befa

Browse files
committed
docker: Build AMD64+ARM64 multiarch images and push to GHCR.
In light of recent changes to Docker Hub, move our Docker images into GHCR which integrates more tightly with GitHub flows we already use throughout the Zulip org. Since it's near-trivial to do so at the same time, add officiallly-supported ARM64 builds. Resolves zulip#357.
1 parent ff07aa7 commit 026befa

7 files changed

+217
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
on:
3+
workflow_call:
4+
inputs:
5+
# N.B.: This behavior is not concurrency-safe and updates the mutable
6+
# :latest image tag
7+
push-latest:
8+
type: boolean
9+
primary-registry-tag:
10+
type: string
11+
skip-pull-check:
12+
type: boolean
13+
14+
jobs:
15+
multiarch-image:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v3
20+
- name: Set up QEMU
21+
uses: docker/setup-qemu-action@v1
22+
- name: Set up Docker Buildx
23+
id: buildx
24+
uses: docker/setup-buildx-action@v1
25+
- name: Login to GitHub Container Registry
26+
uses: docker/login-action@v1
27+
with:
28+
registry: ghcr.io
29+
username: ${{ github.repository_owner }}
30+
password: ${{ github.token }}
31+
- name: Set PUSH_LATEST_TAG in environment
32+
if: inputs.push-latest
33+
run: echo "PUSH_LATEST_TAG=1" >> $GITHUB_ENV
34+
- name: Set REGISTRY_TAG in environment
35+
if: inputs.primary-registry-tag != ""
36+
run: echo "REGISTRY_TAG=${{ inputs.primary-registry-tag }}" >> $GITHUB_ENV
37+
- name: Set SKIP_PULL_CHECK in environment
38+
if: inputs.skip-pull-check
39+
run: echo "SKIP_PULL_CHECK=1" >> $GITHUB_ENV
40+
- name: Build Images
41+
env:
42+
EXTERNAL_QEMU: "1"
43+
run: ./build_and_push_image.sh
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
name: Publish Docker Image to GHCR (versioned + :latest)
3+
4+
on:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
multiarch-image:
11+
uses: ./.github/workflows/called-workflow.yml
12+
secrets: inherit
13+
with:
14+
push-latest-tag: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
name: Publish Docker Image to GHCR (PR)
3+
4+
on:
5+
pull_request:
6+
branches:
7+
- main
8+
9+
jobs:
10+
multiarch-image:
11+
uses: ./.github/workflows/called-workflow.yml
12+
secrets: inherit
13+
with:
14+
# dz prefix to emphasize that the commit does not line up with any commit
15+
# in zulip/zulip
16+
primary-registry-tag: "dz-${{ github.sha }}"
17+
# There's no realistic chance of overwriting an existing SHA tag here, so
18+
# save the pull time
19+
skip-pull-check: true

Dockerfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ WORKDIR /home/zulip/zulip
3838

3939
ARG CUSTOM_CA_CERTIFICATES
4040

41-
# Finally, we provision the development environment and build a release tarball
41+
# Finally, we provision the development environment and build a release
42+
# tarball, after first bumping Yarn's network timeout to 5 minutes to account
43+
# for occasional glitches in QEMU environments (eg. multiarch builds).
44+
RUN echo 'network-timeout 300000' >> ~/.yarnrc
4245
RUN SKIP_VENV_SHELL_WARNING=1 ./tools/provision --build-release-tarball-only
4346
RUN . /srv/zulip-py3-venv/bin/activate && \
4447
./tools/build-release-tarball docker && \

IMAGE_TAG

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This should ~always be updated to match the Zulip Server version targeted,
2+
# with the trailing -N used to denote image versions within the series. Only
3+
# the final line of this file is read during publishing.
4+
#
5+
# Note that changes to the Dockerfile that are not bundled with a bump to this
6+
# number will never be published to GitHub Container Registry, as duplicates
7+
# aren't built.
8+
9+
# Changelog:
10+
#
11+
# 6.1-1: Add ARM64 support, publish to GHCR
12+
# <--> This file created here <-->
13+
# 6.1-0: final version published exclusively to Docker Hub
14+
15+
6.1-1

README.md

+12-7
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,20 @@ This is a container image for running [Zulip](https://zulip.com)
1010

1111
Current Zulip version: `6.1`
1212
Current Docker image version: `6.1-0`
13+
Current architectures supported: `amd64`
1314

14-
Project status: **Alpha**. While this project works and is
15-
used by many sites in production, configuring is substantially more
16-
error-prone than the [normal Zulip installer][normal-install] (which
17-
Just Works). We recommend this project if you want to host Zulip
18-
using Docker, but both setting up and maintaining a Zulip server is
19-
simpler and less error-prone with the normal installer than with Docker.
15+
<!-- Remove when https://github.com/zulip/docker-zulip/issues/357 resolved -->
16+
> `arm64` support is experimental, and is not provided in the Docker Hub
17+
> images. To build an `arm64` image yourself, see `make help` locally.
2018
21-
[normal-install]: https://zulip.readthedocs.io/en/latest/production/install.html
19+
Project status: **Alpha**. While these images work and are used by many sites
20+
in production, configuring is substantially more error-prone than the [bare
21+
metal Zulip installer][bare-metal-install] (which Just Works, though generally
22+
expects a dedicated node). We're actively working to improve the situation, but
23+
for now recommend these containers and orchestrator recipes primarily to those
24+
comfortable being early adopters, and who are ready to report bugs.
25+
26+
[bare-metal-install]: https://zulip.readthedocs.io/en/latest/production/install.html
2227

2328
## Overview
2429

build_and_push_image.sh

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env bash
2+
3+
# This script wraps Docker and Docker BuildX to build multiarch Zulip images.
4+
# Make sure a recent Docker and BuildX are installed on your system - Docker
5+
# Desktop users (on any OS) should be good to go, those using Linux
6+
# distribution's builds of Docker will need to find the correct packages.
7+
#
8+
# To use locally, override the environment variables REGISTRY, REGISTRY_TAG
9+
# (perhaps to 'local'), and optionally BUILDX_PLATFORMS. Additionally,
10+
# PUSH_LATEST_TAG can be set to 1 to additonally tag :latest when pushing to
11+
# the registry. Then, run the script without arguments. For example:
12+
#
13+
# REGISTRY=docker.example.com/myorg/zulip REGISTRY_TAG=local PUSH_LATEST_TAG=1
14+
# ./build_and_push_image.sh
15+
#
16+
# Note: EXTERNAL_QEMU=1 is required when it's unsafe or undesired to manage
17+
# binfmt helpers, for example within CI systems like GitHub Actions (use
18+
# docker/setup-buildx-action@v1 instead).
19+
#
20+
# By default, REGISTRY:REGISTRY_TAG will be built for linux/amd64 and
21+
# linux/arm64. Adding other platforms to this list is unsupported and will
22+
# almost certainly not work, but the list can be shrunk. REGISTRY must be set
23+
# to something the builder has push access to, because BuildX images and
24+
# manifests are not loaded into the host's Docker registry (an upstream
25+
# limitation).
26+
#
27+
# If building for architectures other than that the host runs on, ne can expect
28+
# this step to take many multiples of the time it takes to build the Zulip
29+
# image for just the native architecture. If it takes 10 minutes to build the
30+
# amd64 image by itself, expect cross-compiling the arm64 image to take 30-60
31+
# minutes on most currently-common hardware. Currently, distributing the image
32+
# builds to multiple machines (perhaps to allow the arm64 image to build on a
33+
# native arm64 host for efficiency) is unsupported.
34+
#
35+
# Assuming all goes well, REGISTRY:REGISTRY_TAG will point to a multiarch
36+
# manifest referring to an image for each of BUILDX_PLATFORMS, which can then
37+
# be rolled out to your infrastructure, used in Docker Compose, etc.
38+
#
39+
# Please report bugs with this script or anything it runs, or with running
40+
# Zulip on arm64 in general, at https://github.com/zulip/docker-zulip and/or at
41+
# https://chat.zulip.org
42+
43+
set -ex
44+
45+
REGISTRY="${REGISTRY:-ghcr.io/zulip/zulip}"
46+
REGISTRY_TAG="${REGISTRY_TAG:-$(tail -n 1 < "$(git rev-parse --show-toplevel)/IMAGE_TAG")}"
47+
PRIMARY_IMAGE="${REGISTRY}:${REGISTRY_TAG}"
48+
49+
if [ "${SKIP_PULL_CHECK}" != "1" ]; then
50+
if docker pull "${PRIMARY_IMAGE}"; then
51+
echo "Image ${PRIMARY_IMAGE} already exists, refusing to overwrite!" > /dev/stderr
52+
exit 1
53+
fi
54+
fi
55+
56+
PUSH_LATEST_TAG="${PUSH_LATEST_TAG:-0}"
57+
58+
if [ "${PUSH_LATEST_TAG}" = "1" ]; then
59+
PUSH_LATEST_TAG_ARG=("-t" "${REGISTRY}:latest")
60+
fi
61+
62+
# Default to creating our own buildx context, as "default", using the native
63+
# "docker" driver, can result in errors like the following when using Linux
64+
# distros' Docker and not Docker Desktop:
65+
#
66+
# ERROR: multiple platforms feature is currently not supported for docker
67+
# driver. Please switch to a different driver (eg. "docker buildx create
68+
# --use")
69+
BUILDX_BUILDER="${BUILDX_BUILDER:-zulip}"
70+
BUILDX_PLATFORMS="${BUILDX_PLATFORMS:-linux/amd64,linux/arm64}"
71+
72+
if [ "${EXTERNAL_QEMU}" != "1" ]; then
73+
# --credential yes is required to run sudo within qemu, without it the
74+
# effective UID after a call to sudo will not be 0 and sudo in cross-built
75+
# containers (eg. the arm64 build if running on an amd64 host) will fail.
76+
# See also: https://github.com/crazy-max/ghaction-docker-buildx/issues/213.
77+
#
78+
# We're allowing failures here (|| true) for two main reasons:
79+
#
80+
# - BUILDX_PLATFORMS can be overridden to a single, native platform
81+
# (meaning this QEMU reset won't be necessary anyway)
82+
# - On ZFS<2.2 root filesystems, this incantation can fail due to
83+
# Docker-side dataset teardown issues as documented in
84+
# https://github.com/moby/moby/issues/40132. The QEMU reset may have
85+
# succeeded despite the Docker daemon errors, so we'll try to power
86+
# through.
87+
docker run \
88+
--rm \
89+
--privileged \
90+
multiarch/qemu-user-static \
91+
--reset \
92+
-p yes \
93+
--credential yes \
94+
|| true
95+
fi
96+
97+
(docker buildx ls | grep "${BUILDX_BUILDER}" >/dev/null 2>&1) || {
98+
docker buildx create \
99+
--name "${BUILDX_BUILDER}" \
100+
--platform "${BUILDX_PLATFORMS}" \
101+
--bootstrap \
102+
--use
103+
}
104+
105+
docker buildx build \
106+
--platform "${BUILDX_PLATFORMS}" \
107+
-t "${PRIMARY_IMAGE}" \
108+
"${PUSH_LATEST_TAG_ARG[@]}" \
109+
--push \
110+
.

0 commit comments

Comments
 (0)