Files
WechatOnCloud/.github/workflows/release.yml
Gloridust fe964925c1 fix(ci): 改用原生 arm64 runner 分架构构建,根治 QEMU apt OOM
QEMU 模拟下 arm64 的 apt-get update 反复 OOM(getline: Cannot allocate memory),
让实例镜像 1.4.1/1.4.3 都发不出去;源精简只降概率不治本(1.4.3 又栽在 snapshot InRelease)。
公开仓库可用免费 ubuntu-24.04-arm 原生 runner——彻底不走 QEMU:
- 每个 (镜像 × 架构) 在各自原生 runner 上按 digest 推送到 GHCR;
- merge job 从两个 arch digest 合成多架构 manifest,一条 imagetools create 打全部 tag
  (blob 由 GHCR 复制到 Docker Hub,双仓库一并覆盖);
- 冒烟门禁保留在 wechat+amd64(原生 x86 可 docker run)。
actionlint 通过。
2026-07-08 03:25:10 +08:00

196 lines
8.3 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: release
# 推送 vX.Y.Z 标签或发布 Release 时构建并推送多架构镜像GHCR + 可选 Docker Hub
# workflow_dispatch 可手动触发(只打 latest用于验证流水线本身。
#
# 关键v1.4.3 之后重写):改用【原生 arm64 runner】分架构构建不再用 QEMU 模拟。
# 教训QEMU 下 arm64 的 apt-get update 会 OOMgetline: Cannot allocate memory
# 让实例镜像反复发不出去1.4.1 / 1.4.3 均折在这)。原生 runner 从根上消除该问题,也更快。
# 模式:每个 (镜像 × 架构) 在各自原生 runner 上按 digest 推送 → merge job 合成多架构 manifest 打 tag。
on:
push:
tags:
- 'v*.*.*'
release:
types: [published]
workflow_dispatch:
env:
REGISTRY: ghcr.io
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- { name: wechat, image: wechat-on-cloud, context: ./docker, dockerfile: ./docker/Dockerfile, platform: linux/amd64, arch: amd64, runner: ubuntu-latest }
- { name: wechat, image: wechat-on-cloud, context: ./docker, dockerfile: ./docker/Dockerfile, platform: linux/arm64, arch: arm64, runner: ubuntu-24.04-arm }
- { name: panel, image: woc-panel, context: ./panel, dockerfile: ./panel/Dockerfile, platform: linux/amd64, arch: amd64, runner: ubuntu-latest }
- { name: panel, image: woc-panel, context: ./panel, dockerfile: ./panel/Dockerfile, platform: linux/arm64, arch: arm64, runner: ubuntu-24.04-arm }
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Resolve build version
id: ver
run: |
if [ "${{ github.ref_type }}" = "tag" ]; then
echo "version=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
else
echo "version=dev-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
fi
# ── 产物门禁:仅在 wechat + amd64原生 x86可 docker run上跑冒烟探针 ──
# 「验证的东西和发布的东西必须是同一个 artifact」DPI/CEF 类问题与架构无关amd64 探针即可覆盖。
- name: Build amd64 image for smoke test (instance only)
if: matrix.name == 'wechat' && matrix.arch == 'amd64'
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
load: true
tags: woc-probe:ci
cache-from: type=gha,scope=${{ matrix.name }}-${{ matrix.arch }}
- name: Smoke probes (DPI / CEF 两次启动 / 崩溃循环 / 微信模式)
if: matrix.name == 'wechat' && matrix.arch == 'amd64'
run: |
set -eu
fail() { echo "::error::$1"; docker logs probe 2>&1 | tail -40 || true; exit 1; }
docker run -d --name probe --security-opt seccomp=unconfined --shm-size=1g \
-e PUID=1000 -e PGID=1000 -e WOC_APP_TYPE=chromium woc-probe:ci
for i in $(seq 1 30); do docker exec probe pgrep xsettingsd >/dev/null 2>&1 && break; sleep 3; done
docker exec probe bash -c 'DISPLAY=:1 dump_xsettings | grep -q "Xft/DPI 98304"' || fail "DPI 探针失败"
echo "① DPI ✓"
docker exec probe bash -c '
for round in 1 2; do
DISPLAY=:1 timeout 8 chromium --no-sandbox --disable-gpu --user-data-dir=/tmp/probe-profile about:blank >/dev/null 2>&1 &
p=$!; sleep 7
kill -0 $p 2>/dev/null || exit 1
kill -9 $p 2>/dev/null; pkill -9 chromium 2>/dev/null; sleep 1
done' || fail "CEF 探针崩溃(第 1 或第 2 次启动)"
echo "② CEF 两次启动 ✓"
sleep 30
exits=$(docker logs --since 30s probe 2>&1 | grep -c '已退出' || true)
[ "$exits" -eq 0 ] || fail "autostart 崩溃循环30s 内退出 $exits 次"
echo "③ 零崩溃 ✓"
docker rm -f probe
docker run -d --name probe --security-opt seccomp=unconfined --shm-size=1g \
-e PUID=1000 -e PGID=1000 -e WOC_APP_TYPE=wechat woc-probe:ci
ok=0
for i in $(seq 1 30); do docker logs probe 2>&1 | grep -q "尚未安装" && ok=1 && break; sleep 3; done
[ "$ok" = "1" ] || fail "微信模式未到达等待安装"
echo "④ 微信模式 ✓"
docker rm -f probe
# ── 按 digest 推送到 GHCR不打 tag。同一内容跨仓库 digest 相同merge 时再复制到 Docker Hub ──
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
platforms: ${{ matrix.platform }}
build-args: ${{ matrix.name == 'panel' && format('WOC_VERSION={0}', steps.ver.outputs.version) || '' }}
cache-from: type=gha,scope=${{ matrix.name }}-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.name }}-${{ matrix.arch }}
outputs: type=image,name=${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.image }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digest-${{ matrix.name }}-${{ matrix.arch }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- { name: wechat, image: wechat-on-cloud }
- { name: panel, image: woc-panel }
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digest-${{ matrix.name }}-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
if: vars.DOCKERHUB_USERNAME != ''
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker metadata (tags + labels)
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.image }}
${{ vars.DOCKERHUB_USERNAME != '' && format('docker.io/{0}/{1}', vars.DOCKERHUB_USERNAME, matrix.image) || '' }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
# 从两个 arch 的 digest都在 GHCR合成多架构 manifest一条命令打上所有 tag含 Docker Hub
# imagetools 会把 blob 从 GHCR 复制到 Docker Hub
- name: Create and push multi-arch manifest
working-directory: /tmp/digests
run: |
set -eux
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
srcs=""
for f in *; do srcs="$srcs ${REGISTRY}/${{ github.repository_owner }}/${{ matrix.image }}@sha256:$f"; done
docker buildx imagetools create $tags $srcs
- name: Verify multi-arch manifest
run: |
set -eux
docker buildx imagetools inspect "${REGISTRY}/${{ github.repository_owner }}/${{ matrix.image }}:${{ steps.meta.outputs.version }}"