Skip to content

Commit 338ca16

Browse files
Add arm image to publishing (#1422)
* Replace `ADD` with `curl+run+rm` (rust) * Build each architecture on its own runner This is similar to what docs.docker.com recommends, except without all of the places where they suggest bad practices, including: * using `${{}}` inside `run:` statements * needlessly introducing steps to parse variables * failing to declare permissions for jobs * Merge some docker steps into a single layer * Clean up dockerfile --------- Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> Co-authored-by: Vladislav Ivanov <vlad@ivanov.email>
1 parent 6cada55 commit 338ca16

File tree

3 files changed

+176
-53
lines changed

3 files changed

+176
-53
lines changed

.github/workflows/release.yml

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,24 @@ on:
55
types: [published]
66
pull_request:
77
types: [labeled]
8+
env:
9+
REGISTRY_IMAGE: ${{ secrets.DOCKERHUB_TOKEN == '' && format('ghcr.io/{0}', github.repository) || 'joshproject/josh-proxy' }}
810
jobs:
911
build:
10-
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
include:
16+
- os: linux
17+
arch: amd64
18+
runner: ubuntu-latest
19+
- os: linux
20+
arch: arm64
21+
runner: ubuntu-24.04-arm
22+
runs-on: ${{ matrix.runner }}
23+
permissions:
24+
contents: read
25+
packages: write
1126
if: ${{ github.event_name == 'release' || (github.event_name == 'pull_request' && github.event.label.name == 'build-release-container') }}
1227
steps:
1328
- name: Setup BuildX
@@ -23,25 +38,91 @@ jobs:
2338
uses: docker/metadata-action@v5
2439
with:
2540
images: |
26-
joshproject/josh-proxy
41+
${{ env.REGISTRY_IMAGE }}
2742
tags: |
2843
type=ref,event=tag
29-
- name: Login to DockerHub
44+
- name: Login to Docker Hub
3045
uses: docker/login-action@v3
3146
with:
32-
username: initcrash
33-
password: ${{ secrets.DOCKERHUB_TOKEN }}
47+
registry: ${{ secrets.DOCKERHUB_TOKEN == '' && 'ghcr.io' || '' }}
48+
username: ${{ secrets.DOCKERHUB_TOKEN == '' && github.actor || vars.DOCKERHUB_USER || 'initcrash' }}
49+
password: ${{ secrets.DOCKERHUB_TOKEN == '' && github.token || secrets.DOCKERHUB_TOKEN }}
3450
- name: Build docker image
51+
id: build
3552
uses: docker/build-push-action@v6
3653
with:
3754
context: .
3855
file: Dockerfile
3956
cache-from: type=gha
4057
cache-to: type=gha,mode=max
58+
platforms: ${{ matrix.os }}/${{ matrix.arch}}
4159
build-contexts: |
4260
git=.git
4361
docker=docker
4462
target: run
4563
push: ${{ github.event_name == 'release' && 'true' || 'false' }}
46-
tags: ${{ steps.meta.outputs.tags }}
4764
labels: ${{ steps.meta.outputs.labels }}
65+
tags: ${{ env.REGISTRY_IMAGE }}
66+
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
67+
- name: Export digest
68+
env:
69+
digest: ${{ steps.build.outputs.digest }}
70+
run: |
71+
: Create digests directory with a file whose name matches the digest env with the 'sha256:' prefix removed
72+
mkdir -p "$RUNNER_TEMP/digests"
73+
touch "$RUNNER_TEMP/digests/${digest#sha256:}"
74+
75+
- name: Upload digest
76+
uses: actions/upload-artifact@v4
77+
with:
78+
name: digests-${{ matrix.os }}-${{ matrix.arch }}
79+
path: ${{ runner.temp }}/digests/*
80+
if-no-files-found: error
81+
retention-days: 1
82+
83+
merge:
84+
runs-on: ubuntu-latest
85+
permissions:
86+
packages: write
87+
needs:
88+
- build
89+
steps:
90+
- name: Download digests
91+
uses: actions/download-artifact@v4
92+
with:
93+
path: ${{ runner.temp }}/digests
94+
pattern: digests-*
95+
merge-multiple: true
96+
97+
- name: Login to Docker Hub
98+
uses: docker/login-action@v3
99+
with:
100+
registry: ${{ secrets.DOCKERHUB_TOKEN == '' && 'ghcr.io' || '' }}
101+
username: ${{ secrets.DOCKERHUB_TOKEN == '' && github.actor || vars.DOCKERHUB_USER || 'initcrash' }}
102+
password: ${{ secrets.DOCKERHUB_TOKEN == '' && github.token || secrets.DOCKERHUB_TOKEN }}
103+
104+
- name: Set up Docker Buildx
105+
uses: docker/setup-buildx-action@v3
106+
107+
- name: Docker meta
108+
id: meta
109+
uses: docker/metadata-action@v5
110+
with:
111+
images: ${{ env.REGISTRY_IMAGE }}
112+
tags: |
113+
type=ref,event=branch
114+
type=ref,event=pr
115+
type=semver,pattern={{version}}
116+
type=semver,pattern={{major}}.{{minor}}
117+
118+
- name: Create manifest list and push
119+
working-directory: ${{ runner.temp }}/digests
120+
run: |
121+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
122+
$(printf "$REGISTRY_IMAGE"'@sha256:%s ' *)
123+
124+
- name: Inspect image
125+
env:
126+
version: ${{ steps.meta.outputs.version }}
127+
run: |
128+
docker buildx imagetools inspect $REGISTRY_IMAGE:$version

Dockerfile

Lines changed: 89 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# syntax=docker/dockerfile:1.8@sha256:d6d396f3780b1dd56a3acbc975f57bd2fc501989b50164c41387c42d04e780d0
22

33
ARG ALPINE_VERSION=3.21
4-
ARG ARCH=x86_64
4+
ARG ARCH=${TARGETARCH}
55

66
FROM alpine:${ALPINE_VERSION} AS rust-base
77

@@ -18,18 +18,37 @@ ARG RUSTUP_VERSION=1.27.1
1818

1919
# Update check: https://github.com/rust-lang/rust/tags
2020
ARG RUST_VERSION=1.85.0
21-
ARG RUST_ARCH=${ARCH}-unknown-linux-musl
2221

2322
# https://github.com/sfackler/rust-openssl/issues/1462
2423
ENV RUSTFLAGS="-Ctarget-feature=-crt-static"
2524

26-
ADD --chmod=755 https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${RUST_ARCH}/rustup-init /tmp
27-
RUN /tmp/rustup-init \
25+
RUN <<EOF
26+
set -eux
27+
28+
apk add --no-cache curl
29+
30+
if [ "$ARCH" = amd64 ]; then
31+
rust_arch=x86_64;
32+
elif [ "$ARCH" = arm64 ]; then
33+
rust_arch=aarch64;
34+
else
35+
echo "Unsupported arch";
36+
exit 1
37+
fi
38+
39+
rust_arch=${rust_arch}-unknown-linux-musl
40+
41+
curl -sSL https://static.rust-lang.org/rustup/archive/${RUSTUP_VERSION}/${rust_arch}/rustup-init -o /tmp/rustup-init
42+
chmod +x /tmp/rustup-init
43+
/tmp/rustup-init \
2844
-y \
2945
--no-modify-path \
3046
--profile minimal \
3147
--default-toolchain ${RUST_VERSION} \
32-
--default-host ${RUST_ARCH}
48+
--default-host ${rust_arch}
49+
rm /tmp/rustup-init
50+
apk del curl
51+
EOF
3352

3453
FROM rust-base AS dev-planner
3554

@@ -51,8 +70,8 @@ RUN apk add --no-cache \
5170

5271
WORKDIR /usr/src/josh
5372
RUN rustup component add rustfmt
54-
RUN cargo install --version 0.1.71 cargo-chef
55-
RUN cargo install --verbose --version 0.10.0 graphql_client_cli
73+
RUN cargo install --version 0.1.71 cargo-chef &&\
74+
cargo install --verbose --version 0.10.0 graphql_client_cli
5675

5776
RUN apk add --no-cache \
5877
bash \
@@ -73,11 +92,13 @@ RUN apk add --no-cache \
7392

7493
# Update check: https://github.com/git/git/tags
7594
ARG GIT_VERSION=2.45.2
95+
ENV PATH=${PATH}:/opt/git-install/bin
7696
WORKDIR /usr/src/git
7797
RUN <<EOF
7898
set -e
7999
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-${GIT_VERSION}.tar.gz
80100
tar --extract --gzip --file git-${GIT_VERSION}.tar.gz
101+
rm git-${GIT_VERSION}.tar.gz
81102
cd git-${GIT_VERSION}
82103
make configure
83104
./configure \
@@ -86,13 +107,11 @@ make configure
86107
--exec-prefix=/opt/git-install
87108
make -j$(nproc)
88109
make install
110+
mkdir /opt/git-install/etc
111+
git config -f /opt/git-install/etc/gitconfig --add safe.directory "*"
112+
git config -f /opt/git-install/etc/gitconfig protocol.file.allow "always"
89113
EOF
90114

91-
ENV PATH=${PATH}:/opt/git-install/bin
92-
RUN mkdir /opt/git-install/etc
93-
RUN git config -f /opt/git-install/etc/gitconfig --add safe.directory "*" && \
94-
git config -f /opt/git-install/etc/gitconfig protocol.file.allow "always"
95-
96115
# Update check: https://github.com/prysk/prysk/releases
97116
ARG PRYSK_VERSION=0.20.0
98117

@@ -109,20 +128,23 @@ RUN cd lfs-test-server && GOPATH=/opt/git-lfs go install
109128

110129
ENV PATH=${PATH}:/opt/git-lfs/bin
111130

112-
RUN git clone https://github.com/git-lfs/git-lfs.git /usr/src/git-lfs
113-
WORKDIR /usr/src/git-lfs
114-
RUN make
115-
RUN cp bin/git-lfs /opt/git-lfs/bin
131+
RUN <<EOF
132+
set -eux
133+
git clone https://github.com/git-lfs/git-lfs.git /usr/src/git-lfs
134+
cd /usr/src/git-lfs
135+
make
136+
cp bin/git-lfs /opt/git-lfs/bin
137+
EOF
116138

117139
WORKDIR /usr/src/josh
118140

119141
FROM dev AS dev-local
120142

121-
RUN mkdir -p /opt/cache && \
122-
chmod 777 /opt/cache
123-
124-
RUN mkdir -p /josh/static && \
125-
chmod 777 /josh/static
143+
RUN <<EOF
144+
set -eux
145+
mkdir -p /opt/cache /josh/static
146+
chmod 777 /opt/cache /josh/static
147+
EOF
126148

127149
VOLUME /opt/cache
128150

@@ -136,19 +158,21 @@ RUN npm config set cache /opt/cache/npm-cache --global
136158
ARG USER_GID
137159
ARG USER_UID
138160

139-
RUN \
140-
if [ ! $(getent group ${USER_GID}) ] ; then \
141-
addgroup \
142-
-g ${USER_GID} dev ; \
143-
fi
161+
RUN <<EOF
162+
set -eux
163+
164+
if [ ! $(getent group ${USER_GID}) ] ; then
165+
addgroup -g ${USER_GID} dev
166+
fi
144167

145-
RUN adduser \
146-
-u ${USER_UID} \
147-
-G $(getent group ${USER_GID} | cut -d: -f1) \
148-
-D \
149-
-H \
150-
-g '' \
151-
dev
168+
adduser \
169+
-u ${USER_UID} \
170+
-G $(getent group ${USER_GID} | cut -d: -f1) \
171+
-D \
172+
-H \
173+
-g '' \
174+
dev
175+
EOF
152176

153177
FROM dev AS dev-cache
154178

@@ -201,16 +225,40 @@ COPY --from=build --link=false /opt/cargo-target/release/josh-ssh-shell /usr/bin
201225
COPY --from=build --link=false /usr/src/josh/static/ /josh/static/
202226

203227
ARG S6_OVERLAY_VERSION=3.1.2.1
204-
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
205-
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
206228
ARG ARCH
207-
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${ARCH}.tar.xz /tmp
208-
RUN tar -C / -Jxpf /tmp/s6-overlay-${ARCH}.tar.xz
229+
RUN <<EOF
230+
set -eux
231+
232+
apk add --no-cache curl
233+
234+
curl -sSL https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz \
235+
-o /tmp/s6-overlay-noarch.tar.xz
236+
tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
237+
rm /tmp/s6-overlay-noarch.tar.xz
238+
239+
if [ "$ARCH" = amd64 ]; then
240+
s6_arch=x86_64;
241+
elif [ "$ARCH" = arm64 ]; then
242+
s6_arch=aarch64;
243+
else
244+
echo "Unsupported arch";
245+
exit 1
246+
fi
247+
248+
curl -sSL https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${s6_arch}.tar.xz \
249+
-o /tmp/s6-overlay-arch.tar.xz
250+
tar -C / -Jxpf /tmp/s6-overlay-arch.tar.xz
251+
rm /tmp/s6-overlay-arch.tar.xz
252+
253+
apk del curl
254+
EOF
209255

210256
ARG GIT_GID_UID=2001
211257

212-
RUN addgroup -g ${GIT_GID_UID} git
213-
RUN adduser \
258+
RUN <<EOF
259+
set -eux
260+
addgroup -g ${GIT_GID_UID} git
261+
adduser \
214262
-h /home/git \
215263
-s /usr/bin/josh-ssh-shell \
216264
-G git \
@@ -219,7 +267,8 @@ RUN adduser \
219267
git
220268

221269
# https://unix.stackexchange.com/a/193131/336647
222-
RUN usermod -p '*' git
270+
usermod -p '*' git
271+
EOF
223272

224273
COPY --from=docker --link=false etc/ssh/sshd_config.template /etc/ssh/sshd_config.template
225274

tester.sh

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ else
2222
TESTS="$*"
2323
fi
2424

25-
ARCH=$(arch)
26-
27-
if [ "$ARCH" = "arm64" ]; then
28-
ARCH="aarch64"
29-
fi
30-
3125
echo "running: ${TESTS}"
3226

3327
if (( ! NO_BUILD_CONTAINER )); then
@@ -36,7 +30,6 @@ if (( ! NO_BUILD_CONTAINER )); then
3630
--tag=josh-dev-local \
3731
--build-arg USER_UID="$(id -u)" \
3832
--build-arg USER_GID="$(id -g)" \
39-
--build-arg ARCH="${ARCH}" \
4033
.
4134
fi
4235

0 commit comments

Comments
 (0)