Skip to content

Commit c803cd6

Browse files
authored
Build Docker images from source per architecture and publish a multi-arch manifest (#2605)
1 parent 8c3dede commit c803cd6

2 files changed

Lines changed: 114 additions & 51 deletions

File tree

.github/workflows/docker.yml

Lines changed: 100 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,55 +16,121 @@ defaults:
1616
run:
1717
shell: bash
1818

19+
env:
20+
REGISTRY_IMAGE: stellar/stellar-cli
21+
1922
jobs:
23+
# Resolve the ref to a single immutable SHA and compute the Docker tags once,
24+
# so both platform builds and the published manifest refer to one commit even
25+
# if the branch advances while the workflow runs.
26+
prepare:
27+
runs-on: ubuntu-latest
28+
permissions:
29+
contents: read
30+
outputs:
31+
sha: ${{ steps.resolve.outputs.sha }}
32+
tags: ${{ steps.resolve.outputs.tags }}
33+
steps:
34+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
35+
with:
36+
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}
37+
fetch-depth: 0
38+
39+
# Resolve the ref to a SHA and compute Docker tags.
40+
# - Version tag (e.g. v1.2.3): push versioned + latest tags.
41+
# - Any other ref: push a tag for the resolved commit SHA.
42+
- name: Resolve ref and tags
43+
id: resolve
44+
run: |
45+
ref="${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }}"
46+
sha="$(git rev-parse HEAD)"
47+
echo "sha=${sha}" >> $GITHUB_OUTPUT
48+
49+
if [[ "$ref" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
50+
version="${ref#v}"
51+
echo "tags=-t ${REGISTRY_IMAGE}:${version} -t ${REGISTRY_IMAGE}:latest" >> $GITHUB_OUTPUT
52+
elif [[ "${{ github.event_name }}" == "release" ]]; then
53+
echo "::error::Release tag '${ref}' is not a valid version tag (expected vX.Y.Z)."
54+
exit 1
55+
else
56+
echo "tags=-t ${REGISTRY_IMAGE}:${sha}" >> $GITHUB_OUTPUT
57+
fi
58+
59+
# Build each platform on a native runner and push the image by digest.
2060
build:
61+
needs: prepare
2162
strategy:
63+
fail-fast: false
2264
matrix:
2365
include:
2466
- runs-on: ubuntu-latest
25-
arch: amd64
67+
platform: linux/amd64
2668
- runs-on: ubuntu-24.04-arm
27-
arch: arm64
69+
platform: linux/arm64
2870
runs-on: ${{ matrix.runs-on }}
2971
permissions:
3072
contents: read
3173
steps:
74+
- name: Set platform pair
75+
run: |
76+
platform="${{ matrix.platform }}"
77+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
78+
3279
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3380
with:
34-
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}
81+
ref: ${{ needs.prepare.outputs.sha }}
82+
83+
- name: Set up Docker Buildx
84+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
3585

36-
- name: Install build dependencies
37-
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libudev-dev libdbus-1-dev
86+
- name: Log in to Docker Hub
87+
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
88+
with:
89+
username: ${{ secrets.DOCKERHUB_USERNAME }}
90+
password: ${{ secrets.DOCKERHUB_TOKEN }}
3891

39-
- name: Build binary
40-
run: cargo build --package stellar-cli --release
92+
- name: Build and push by digest
93+
id: build
94+
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
95+
with:
96+
context: .
97+
platforms: ${{ matrix.platform }}
98+
build-args: |
99+
STELLAR_CLI_REV=${{ needs.prepare.outputs.sha }}
100+
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
41101

42-
- name: Upload binary
102+
- name: Export digest
103+
run: |
104+
mkdir -p "${{ runner.temp }}/digests"
105+
digest="${{ steps.build.outputs.digest }}"
106+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
107+
108+
- name: Upload digest
43109
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
44110
with:
45-
name: stellar-${{ matrix.arch }}
46-
path: target/release/stellar
111+
name: digests-${{ env.PLATFORM_PAIR }}
112+
path: ${{ runner.temp }}/digests/*
113+
if-no-files-found: error
47114
retention-days: 1
48115

49-
docker:
50-
needs: build
116+
# Combine the per-platform digests into a single multi-arch manifest list
117+
# and push it under the final tags.
118+
merge:
119+
needs: [prepare, build]
51120
runs-on: ubuntu-latest
52121
permissions:
53122
contents: read
54123
steps:
55124
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
56125
with:
57-
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}
58-
fetch-depth: 0
126+
ref: ${{ needs.prepare.outputs.sha }}
59127

60-
- name: Download binaries
128+
- name: Download digests
61129
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
62130
with:
63-
pattern: stellar-*
64-
merge-multiple: false
65-
66-
- name: Set up QEMU
67-
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
131+
path: ${{ runner.temp }}/digests
132+
pattern: digests-*
133+
merge-multiple: true
68134

69135
- name: Set up Docker Buildx
70136
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
@@ -75,37 +141,24 @@ jobs:
75141
username: ${{ secrets.DOCKERHUB_USERNAME }}
76142
password: ${{ secrets.DOCKERHUB_TOKEN }}
77143

78-
# Compute Docker tags from the ref.
79-
# - Version tag (e.g. v1.2.3): push versioned + latest tags.
80-
# - Any other ref: push a tag for the resolved commit SHA.
81-
- name: Compute tags
144+
- name: Create manifest list and push
145+
working-directory: ${{ runner.temp }}/digests
146+
env:
147+
TAGS: ${{ needs.prepare.outputs.tags }}
82148
run: |
83-
ref="${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }}"
84-
85-
if [[ "$ref" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
86-
version="${ref#v}"
87-
echo "DOCKER_TAGS=stellar/stellar-cli:${version},stellar/stellar-cli:latest" >> $GITHUB_ENV
88-
elif [[ "${{ github.event_name }}" == "release" ]]; then
89-
echo "::error::Release tag '${ref}' is not a valid version tag (expected vX.Y.Z)."
90-
exit 1
91-
else
92-
commit="$(git rev-parse HEAD)"
93-
echo "DOCKER_TAGS=stellar/stellar-cli:${commit}" >> $GITHUB_ENV
94-
fi
95-
96-
- name: Build and push
97-
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
98-
with:
99-
context: .
100-
platforms: linux/amd64,linux/arm64
101-
push: true
102-
tags: ${{ env.DOCKER_TAGS }}
149+
docker buildx imagetools create ${TAGS} \
150+
$(printf "${REGISTRY_IMAGE}@sha256:%s " *)
103151
104152
- name: Update Docker Hub description
153+
env:
154+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
155+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
105156
run: |
106-
TOKEN=$(curl -s -X POST "https://hub.docker.com/v2/users/login/" \
107-
-H "Content-Type: application/json" \
108-
-d '{"username":"${{ secrets.DOCKERHUB_USERNAME }}","password":"${{ secrets.DOCKERHUB_TOKEN }}"}' \
157+
TOKEN=$(jq -n --arg u "$DOCKERHUB_USERNAME" --arg p "$DOCKERHUB_TOKEN" \
158+
'{username: $u, password: $p}' | \
159+
curl -s -X POST "https://hub.docker.com/v2/users/login/" \
160+
-H "Content-Type: application/json" \
161+
-d @- \
109162
| jq -r .token)
110163
111164
jq -n --arg desc "$(cat ./docker/README.md)" '{"full_description": $desc}' | \

Dockerfile

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,25 @@ FROM rust:latest
33
RUN rustup target add wasm32v1-none
44

55
RUN apt-get update && \
6-
apt-get install -y --no-install-recommends ca-certificates libdbus-1-3 libssl3 libudev1 && \
6+
apt-get install -y --no-install-recommends \
7+
build-essential \
8+
ca-certificates \
9+
git \
10+
libdbus-1-dev \
11+
libssl-dev \
12+
libudev-dev \
13+
pkg-config && \
714
rm -rf /var/lib/apt/lists/*
815

9-
ARG TARGETARCH
10-
COPY stellar-${TARGETARCH}/stellar /usr/local/bin/stellar
11-
RUN chmod +x /usr/local/bin/stellar
16+
ARG STELLAR_CLI_REV
17+
RUN cargo install --locked \
18+
--git https://github.com/stellar/stellar-cli.git \
19+
--rev "${STELLAR_CLI_REV}" \
20+
stellar-cli
1221

1322
ENV STELLAR_CONFIG_HOME=/config
1423
ENV STELLAR_DATA_HOME=/data
24+
ENV STELLAR_NO_UPDATE_CHECK=1
1525

1626
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
1727

0 commit comments

Comments
 (0)