@@ -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