fix(docker): publish verified multi-platform images

- Build linux/amd64 and linux/arm64 on native GitHub runners
- Assemble version manifests from platform digests and promote latest only after verification
- Add release/tag validation, manual republishing, timeouts, and health smoke tests
- Make Docker build mirrors configurable via build args and remove unnecessary runtime apk upgrades
- Update DOCKER.md documentation
This commit is contained in:
DaDecky
2026-09-21 20:27:03 +07:00
parent c7df895bbb
commit f67d5a0c93
3 changed files with 496 additions and 43 deletions

View File

@@ -100,6 +100,12 @@ docker rm -f 9router
# re-run the quick start command
```
To pin a specific version instead of following `latest`, use a numbered image tag:
```bash
docker pull decolua/9router:0.5.81
```
---
# 🛠 For Developers
@@ -107,7 +113,7 @@ docker rm -f 9router
## Build image locally (test)
```bash
cd app && docker build -t 9router .
docker build -t 9router .
docker run --rm -p 20128:20128 \
-v "$HOME/.9router:/app/data" \
@@ -115,18 +121,67 @@ docker run --rm -p 20128:20128 \
9router
```
The Dockerfile uses the official Alpine and npm registries by default. Regional mirrors can be supplied when needed:
```bash
docker build \
--build-arg ALPINE_MIRROR=mirrors.aliyun.com \
--build-arg NPM_REGISTRY=https://registry.npmmirror.com/ \
-t 9router .
```
## Publish (automatic via CI)
Push a git tag `v*` → GitHub Actions builds multi-platform (amd64+arm64) and pushes to:
- `ghcr.io/decolua/9router:v{version}` + `:latest`
- `decolua/9router:v{version}` + `:latest`
Push a Docker-safe semver git tag `vX.Y.Z` (or a prerelease such as `vX.Y.Z-rc.1`) → GitHub Actions builds `linux/amd64` and `linux/arm64` on native runners, health-checks each platform image, verifies the resulting manifest and `/api/health`, then publishes:
- `ghcr.io/decolua/9router:X.Y.Z` + `:latest`
- `decolua/9router:X.Y.Z` + `:latest`
The `v` prefix is used only for the git tag; image tags omit it. A stable tag push promotes `latest`, but a prerelease tag such as `vX.Y.Z-rc.1` publishes only its numbered image by default. Prereleases require an explicit manual `promote_latest` opt-in. Promotion happens only after both native platform builds, both platform health checks, manifest inspection, and the resolved-manifest smoke test succeed. A failed or timed-out platform build therefore cannot move `latest`.
The workflow rejects SemVer build metadata such as `v1.2.3+build.7` because the `+` form is not a valid Docker image tag. The git tag and both `package.json` versions must match exactly.
```bash
# Use scripts/release.js (recommended)
node scripts/release.js "Release title" "Notes"
# Or manually
git tag v0.4.x && git push origin v0.4.x
git tag v0.5.81 && git push origin v0.5.81
```
Workflow: `app/.github/workflows/docker-publish.yml`
To republish an existing tag, run the `Build and Push Docker Image` workflow manually and provide the exact tag, for example `v0.5.81`, in the `release_tag` input. Manual runs publish the numbered tag but leave `latest` unchanged by default:
```text
release_tag: v0.5.81
promote_latest: false
```
The `promote_latest` checkbox is an explicit opt-in for changing `latest`. Use it when a deliberate rollback or recovery should make that version the current default:
```text
release_tag: v0.5.75
promote_latest: true
```
Numbered image tags are mutable because a republish can replace their manifest. For a deployment that must be immutable, pin the image digest instead:
```bash
docker pull decolua/9router@sha256:<verified-digest>
```
The release workflow runs `/api/health` on each native `amd64` and `arm64` platform image before it uploads the digest artifact or assembles the multi-platform manifest. It then runs a second health check against the resolved version manifest before any requested `latest` promotion.
During recovery, the selected tag remains the application source while the Dockerfile from the workflow revision is used, so an older tag can be rebuilt with the current publishing fixes.
The workflow is tag-driven. Creating a git tag does not automatically create a GitHub Release, so the Releases page and the published package/image tags can be at different versions unless a maintainer creates a release separately.
The upstream repository needs these repository secrets for Docker Hub publishing:
- `DOCKERHUB_USERNAME`
- `DOCKERHUB_TOKEN`
GHCR publishing uses the workflow's `GITHUB_TOKEN` with package write permission. Forks can publish to their own GHCR namespace, but Docker Hub publication is restricted to the upstream `decolua/9router` repository.
The optional repository variables `ALPINE_MIRROR` and `NPM_REGISTRY` can override the default package mirrors used by the CI Docker build.
Workflow: `.github/workflows/docker-publish.yml`