Skip to content

Commit 1bd53af

Browse files
committed
ci(release): build amd64 + arm64 ipkgs and Docker images
Existing release workflow only produced an amd64 ipkg + amd64 Docker image tarball. iKuai routers ship in both x86_64 and arm64 variants, so users on arm64 hardware had no way to install the packaged build. Refactor build-docker into a strategy.matrix over [amd64, arm64]. Each matrix run now: - sets up QEMU + Docker buildx - cross-builds the image with `docker buildx build --platform linux/<arch> --load` - exports as `docker-image-<arch>.tar.gz` - packages into `hy2scale-<version>-<arch>.ipkg` with the per-arch image embedded as the same `hy2scale:ikuai` tag (so iKuai's bootstrap script doesn't need to know about arch — it just loads whichever tarball the user-installed ipkg shipped) Also: when the source-side `Version` const carries a prerelease suffix (e.g. `1.3.4-rc1`), the ipkg manifest gets the X.Y.Z prefix only — iKuai's parser rejects suffixed versions. The asset filename keeps the full tag so candidate builds remain visually distinguishable. Release-notes table updated to list both arch variants for ipkg and Docker image.
1 parent a2eddaf commit 1bd53af

1 file changed

Lines changed: 69 additions & 27 deletions

File tree

.github/workflows/release.yml

Lines changed: 69 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,26 @@ jobs:
9999
name: ${{ env.ARTIFACT_NAME }}
100100
path: ${{ env.ASSET }}
101101

102-
# ─── Docker image + iKuai ipkg (amd64) ────────────────────────
102+
# ─── Docker image + iKuai ipkg (per-arch) ─────────────────────
103+
# Matrix builds amd64 + arm64 in parallel, each emitting:
104+
# docker-image-{arch}.tar.gz (offline-loadable image)
105+
# hy2scale-{version}-{arch}.ipkg (iKuai package with image embedded)
106+
# Both archs run on amd64 GitHub runners; arm64 uses QEMU emulation
107+
# via docker buildx. The ipkg's manifest.json `image: hy2scale:ikuai`
108+
# tag is the same name on both archs so iKuai's bootstrap script does
109+
# not need per-arch logic — it just `docker load`s the per-arch tarball
110+
# the user installed and the embedded image runs natively.
103111
build-docker:
104-
name: Build Docker image + ipkg
112+
name: Build Docker + ipkg (${{ matrix.arch }})
105113
runs-on: ubuntu-latest
114+
strategy:
115+
fail-fast: false
116+
matrix:
117+
include:
118+
- arch: amd64
119+
platform: linux/amd64
120+
- arch: arm64
121+
platform: linux/arm64
106122
steps:
107123
- uses: actions/checkout@v4
108124

@@ -117,6 +133,14 @@ jobs:
117133
echo "tag=${TAG}" >> $GITHUB_OUTPUT
118134
echo "version=${TAG#v}" >> $GITHUB_OUTPUT
119135
136+
- name: Set up QEMU
137+
uses: docker/setup-qemu-action@v3
138+
with:
139+
platforms: arm64
140+
141+
- name: Set up Docker Buildx
142+
uses: docker/setup-buildx-action@v3
143+
120144
- uses: actions/setup-node@v4
121145
with:
122146
node-version: 20
@@ -130,53 +154,64 @@ jobs:
130154
with:
131155
go-version: ${{ env.GO_VERSION }}
132156

133-
- name: Build Docker image
157+
- name: Build Docker image (${{ matrix.platform }})
134158
run: |
135-
# Tag the built image with the same name users get from Docker
136-
# Hub (frankoong/hy2scale:<version>) so `docker load < tarball`
137-
# lands under the expected name, avoiding a rename step before
138-
# `docker run`. The local `hy2scale:ikuai` alias is kept so the
139-
# ipkg script below and any other consumer that assumed that
140-
# name keep working.
141-
DOCKER_BUILDKIT=0 docker build \
142-
-t frankoong/hy2scale:${{ steps.ver.outputs.version }} \
143-
-t hy2scale:ikuai .
159+
# buildx --load brings the cross-built image into the local
160+
# docker daemon so subsequent `docker save` works the same way
161+
# the legacy single-arch path did. We tag with both
162+
# frankoong/hy2scale:<version> (what users see when they
163+
# `docker load` the tarball) AND hy2scale:ikuai (what the ipkg
164+
# bootstrap expects).
165+
docker buildx build \
166+
--platform ${{ matrix.platform }} \
167+
--tag frankoong/hy2scale:${{ steps.ver.outputs.version }} \
168+
--tag hy2scale:ikuai \
169+
--load \
170+
.
144171
145172
- name: Export Docker image
146173
run: |
147174
docker save frankoong/hy2scale:${{ steps.ver.outputs.version }} \
148-
| gzip > docker-image-amd64.tar.gz
149-
echo "DOCKER_SIZE=$(du -h docker-image-amd64.tar.gz | cut -f1)" >> $GITHUB_ENV
175+
| gzip > docker-image-${{ matrix.arch }}.tar.gz
176+
echo "DOCKER_SIZE=$(du -h docker-image-${{ matrix.arch }}.tar.gz | cut -f1)" >> $GITHUB_ENV
150177
151178
- name: Build ipkg
152179
run: |
153-
# ipkg version must be X.Y.Z (no rc/beta suffix) — read from Go source
154-
IPKG_VERSION=$(grep 'const Version' internal/api/server.go | sed 's/.*"\(.*\)".*/\1/')
155-
echo "ipkg version: ${IPKG_VERSION}"
156-
157-
# Update manifest version
180+
# ipkg version must be plain X.Y.Z (iKuai's parser rejects suffixes
181+
# like -rc1). Read from Go source then strip any prerelease suffix
182+
# so the manifest stays installable even on rc-tagged releases.
183+
RAW_VERSION=$(grep 'const Version' internal/api/server.go | sed 's/.*"\(.*\)".*/\1/')
184+
IPKG_VERSION=$(echo "$RAW_VERSION" | sed 's/-.*//')
185+
echo "Source Version: ${RAW_VERSION} -> ipkg manifest: ${IPKG_VERSION}"
186+
187+
# The release-asset filename uses the FULL tag (with -rc1 suffix
188+
# if present) so users can tell candidate builds apart, but the
189+
# internal manifest version stays plain X.Y.Z.
190+
ASSET_VERSION="${{ steps.ver.outputs.version }}"
191+
192+
# Update manifest version (in-tree, not committed)
158193
sed -i "s/\"version\": *\"[^\"]*\"/\"version\": \"${IPKG_VERSION}\"/" ipkg/hy2scale/manifest.json
159194
160195
# Embed Docker image (iKuai bootstrap expects hy2scale:ikuai tag).
161196
docker save hy2scale:ikuai | gzip > ipkg/hy2scale/docker_image.tar.gz
162197
163-
# Package ipkg
198+
# Package ipkg with arch suffix
164199
cd ipkg
165-
tar czf "hy2scale-${IPKG_VERSION}.ipkg" hy2scale/
200+
tar czf "hy2scale-${ASSET_VERSION}-${{ matrix.arch }}.ipkg" hy2scale/
166201
167202
# Clean embedded image
168203
rm -f hy2scale/docker_image.tar.gz
169204
170-
echo "IPKG_FILE=ipkg/hy2scale-${IPKG_VERSION}.ipkg" >> $GITHUB_ENV
205+
echo "IPKG_FILE=ipkg/hy2scale-${ASSET_VERSION}-${{ matrix.arch }}.ipkg" >> $GITHUB_ENV
171206
172207
- uses: actions/upload-artifact@v4
173208
with:
174-
name: docker-image
175-
path: docker-image-amd64.tar.gz
209+
name: docker-image-${{ matrix.arch }}
210+
path: docker-image-${{ matrix.arch }}.tar.gz
176211

177212
- uses: actions/upload-artifact@v4
178213
with:
179-
name: ipkg
214+
name: ipkg-${{ matrix.arch }}
180215
path: ${{ env.IPKG_FILE }}
181216

182217
# ─── Create GitHub Release ─────────────────────────────────────
@@ -270,14 +305,21 @@ jobs:
270305
271306
### Docker Image
272307
273-
Offline image (amd64): `docker-image-amd64.tar.gz`
308+
Offline images (one per arch):
274309
```bash
310+
# amd64 (x86_64)
275311
docker load < docker-image-amd64.tar.gz
312+
# arm64 (aarch64)
313+
docker load < docker-image-arm64.tar.gz
276314
```
277315
278316
### iKuai Package
279317
280-
`hy2scale-${{ steps.version.outputs.version }}.ipkg` — install via the iKuai web UI (Advanced Apps → App Market → Local Install).
318+
Pick the package matching your iKuai router's CPU architecture:
319+
- `hy2scale-${{ steps.version.outputs.version }}-amd64.ipkg` — for x86 / x86_64 iKuai
320+
- `hy2scale-${{ steps.version.outputs.version }}-arm64.ipkg` — for arm64 / aarch64 iKuai
321+
322+
Install via the iKuai web UI (Advanced Apps → App Market → Local Install).
281323
282324
### Verify checksums
283325
```

0 commit comments

Comments
 (0)