Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
echo "repository=ghcr.io/${owner}/imagesilo" >> "$GITHUB_OUTPUT"

quality:
name: Release quality
needs: preflight
runs-on: ubuntu-24.04
timeout-minutes: 20
Expand All @@ -72,7 +73,8 @@ jobs:
- name: Run release quality gate
run: make check e2e

platform-image:
release-smoke:
name: Release smoke and publish (${{ matrix.suffix }})
needs: [preflight, quality]
permissions:
contents: read
Expand All @@ -86,11 +88,13 @@ jobs:
architecture: amd64
suffix: amd64
port: 18100
benchmark_port: 18110
- runner: ubuntu-24.04-arm
platform: linux/arm64
architecture: arm64
suffix: arm64
port: 18101
benchmark_port: 18111
runs-on: ${{ matrix.runner }}
timeout-minutes: 35
env:
Expand All @@ -105,6 +109,17 @@ jobs:
with:
go-version-file: .go-version
cache: true
- name: Benchmark delivery index
run: |
output="delivery-index-benchmark-${{ matrix.suffix }}.jsonl"
go run ./tests/performance/delivery_index_benchmark | tee "$output"
jq --exit-status --slurp 'all(.[]; .lookupFailures == 0 and .bytesPerPath < 1024)' "$output" >/dev/null
{
echo "### Native ${{ matrix.suffix }} delivery index benchmark"
echo '```json'
cat "$output"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Resolve immutable image references
id: image
shell: bash
Expand Down Expand Up @@ -171,6 +186,28 @@ jobs:
PORT: ${{ matrix.port }}
SMOKE_SUFFIX: release-${{ matrix.suffix }}
run: bash scripts/container-smoke.sh
- name: Benchmark native processing at concurrency 1
if: steps.state.outputs.mode == 'build'
env:
IMAGE: ${{ steps.image.outputs.content_target }}
PLATFORM: ${{ matrix.platform }}
PORT: ${{ matrix.benchmark_port }}
BENCH_SUFFIX: release-${{ matrix.suffix }}
CONCURRENCIES: "1"
CPU_LIMIT: "1"
MEMORY_LIMIT: 768m
PIDS_LIMIT: "256"
MAX_MEMORY_PEAK_BYTES: "536870912"
MAX_P95_MILLISECONDS: "20000"
run: |
output="processing-benchmark-${{ matrix.suffix }}.jsonl"
bash scripts/processing-benchmark.sh | tee "$output"
{
echo "### Native ${{ matrix.suffix }} processing benchmark (concurrency 1)"
echo '```json'
cat "$output"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Publish new immutable platform content
if: steps.state.outputs.mode == 'build'
shell: bash
Expand Down Expand Up @@ -209,7 +246,8 @@ jobs:
echo "digest=$platform_digest" >> "$GITHUB_OUTPUT"

manifest:
needs: [preflight, platform-image]
name: Publish release manifest
needs: [preflight, release-smoke]
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
Expand Down
72 changes: 2 additions & 70 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Verify
name: Quick verify

on:
pull_request:
Expand Down Expand Up @@ -29,73 +29,5 @@ jobs:
cache-dependency-path: web/package-lock.json
- name: Install frontend dependencies
run: npm --prefix web ci
- name: Run quality gate
- name: Run quick quality gate
run: make check e2e

container-smoke:
needs: quality
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
platform: linux/amd64
suffix: amd64
port: 18080
benchmark_port: 18090
- runner: ubuntu-24.04-arm
platform: linux/arm64
suffix: arm64
port: 18081
benchmark_port: 18091
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: .go-version
cache: true
- name: Benchmark delivery index
run: |
output="delivery-index-benchmark-${{ matrix.suffix }}.jsonl"
go run ./tests/performance/delivery_index_benchmark | tee "$output"
jq --exit-status --slurp 'all(.[]; .lookupFailures == 0 and .bytesPerPath < 1024)' "$output" >/dev/null
{
echo "### Native ${{ matrix.suffix }} delivery index benchmark"
echo '```json'
cat "$output"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Build native container image
run: docker build --platform "${{ matrix.platform }}" --file deploy/docker/Dockerfile --tag "imagesilo:smoke-${{ matrix.suffix }}" .
- name: Run login, upload, delivery, and restart smoke test
env:
IMAGE: imagesilo:smoke-${{ matrix.suffix }}
PLATFORM: ${{ matrix.platform }}
PORT: ${{ matrix.port }}
SMOKE_SUFFIX: ${{ matrix.suffix }}
run: bash scripts/container-smoke.sh
- name: Benchmark native processing at concurrency 1
env:
IMAGE: imagesilo:smoke-${{ matrix.suffix }}
PLATFORM: ${{ matrix.platform }}
PORT: ${{ matrix.benchmark_port }}
BENCH_SUFFIX: ${{ matrix.suffix }}
CONCURRENCIES: "1"
CPU_LIMIT: "1"
MEMORY_LIMIT: 768m
PIDS_LIMIT: "256"
MAX_MEMORY_PEAK_BYTES: "536870912"
MAX_P95_MILLISECONDS: "20000"
run: |
output="processing-benchmark-${{ matrix.suffix }}.jsonl"
bash scripts/processing-benchmark.sh | tee "$output"
{
echo "### Native ${{ matrix.suffix }} processing benchmark (concurrency 1)"
echo '```json'
cat "$output"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
29 changes: 19 additions & 10 deletions docs/ci.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
# 自动化验证

`.github/workflows/verify.yml` 使用固定 commit SHA 的官方 Actions:
## 快速校验

`.github/workflows/verify.yml` 是 PR、`main` push 和手动运行使用的快速门禁,并使用固定 commit SHA 的官方 Actions:

- `actions/checkout` 7.0.1
- `actions/setup-go` 7.0.0
- `actions/setup-node` 7.0.0

`quality` job 执行与本地一致的 `make check`。`container-smoke` 分别在 GitHub 官方 `ubuntu-24.04`(amd64)和 `ubuntu-24.04-arm`(arm64)原生 runner 上执行:
唯一的 `quality` job 执行 `make check e2e`,覆盖 Go、React、OpenAPI 生成一致性、Lint、类型检查、单元/集成测试和单 worker 浏览器闭环。该工作流不构建容器镜像、不运行容器 smoke,也不接触 GHCR;`quality` check 名称保持不变。

## Release smoke

`.github/workflows/release.yml` 只接受属于 `origin/main` 的 `v*` Tag。Release 重新运行质量门后,分别在 GitHub 官方 `ubuntu-24.04`(amd64)和 `ubuntu-24.04-arm`(arm64)原生 runner 上执行:

1. 构建目标架构镜像。
2. 通过 `--password-stdin` 创建临时管理员,密码不进入进程参数。
3. 登录并取得 Session Cookie。
4. 流式上传确定性 JPEG。
5. 核对公开 URL 的 SHA-256、非 root 用户和健康检查。
6. 停止容器、使用同一 named volume 重启并再次核对 URL。
7. 无论成功或失败都删除临时容器、volume、Cookie 和响应文件。
1. 执行原生 Delivery Index benchmark。
2. 构建目标架构镜像。
3. 通过 `--password-stdin` 创建临时管理员,密码不进入进程参数。
4. 登录并取得 Session Cookie。
5. 流式上传确定性 JPEG。
6. 核对公开 URL 的 SHA-256、非 root 用户和健康检查。
7. 停止容器、使用同一 named volume 重启并再次核对 URL。
8. 对同一镜像执行并发 `1` 的原生图片处理 benchmark。
9. 无论成功或失败都删除临时容器、volume、Cookie 和响应文件。
10. 只有该架构全部 smoke/benchmark 成功后才推送对应的不可变平台镜像;只有两个架构都成功后才创建版本与 `latest` manifest。

本地可使用相同脚本:

Expand All @@ -26,4 +35,4 @@ SMOKE_SUFFIX=local-arm64 \
bash scripts/container-smoke.sh
```

首次原生双架构运行证据为 [Verify run 30447890938](https://github.com/Willxup/imagesilo/actions/runs/30447890938):质量门、amd64 容器闭环和 arm64 容器闭环全部成功。Git 推送通过仓库 SSH 远程完成;后续正常开发提交按相同工作流持续验证
首次原生双架构运行证据为 [Verify run 30447890938](https://github.com/Willxup/imagesilo/actions/runs/30447890938):质量门、amd64 容器闭环和 arm64 容器闭环全部成功。该记录保留为历史证据;当前开发提交只运行快速校验,双架构容器 smoke 已收敛到 Release Tag 流程
2 changes: 1 addition & 1 deletion docs/development-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

阶段 7 已完成。GitHub Actions [Release image run 30505989284](https://github.com/Willxup/imagesilo/actions/runs/30505989284) 由 `v0.1.0-rc.1` tag push 自动触发并全部成功;公开 GHCR 多架构镜像和 [GitHub Pre-release](https://github.com/Willxup/imagesilo/releases/tag/v0.1.0-rc.1) 均已验证。

`.github/workflows/verify.yml` `scripts/container-smoke.sh` 已成为后续提交的固定阶段门。脚本在本机和 GitHub 均确认成功/失败结束后不遗留临时容器或 named volume。
`.github/workflows/verify.yml` 是后续提交的快速质量门;双架构 `scripts/container-smoke.sh` 只在 Release Tag 流程执行,并在对应架构 smoke 成功后才允许发布平台镜像。脚本在本机和 GitHub 均确认成功/失败结束后不遗留临时容器或 named volume。

## 阶段门

Expand Down
6 changes: 4 additions & 2 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

## 质量门

`make check e2e` 覆盖全部 Go 包、React、OpenAPI 生成一致性和单 worker 浏览器闭环。`Verify` 工作流随后在原生 amd64、原生 arm64 各构建一次镜像、执行容器 smoke,并只运行并发 `1`、总计 `16` 个请求的图片处理 benchmark。Benchmark 容器限制为 1 CPU、768 MiB 和 256 PID,并强制要求全部请求成功、无 busy 响应、p95 不超过 20 秒且 cgroup 峰值不超过 512 MiB
PR 的 `Quick verify` 工作流只执行 `make check e2e`覆盖全部 Go 包、React、OpenAPI 生成一致性和单 worker 浏览器闭环,不构建容器镜像。推送 Release Tag 后,`Release image` 工作流重新执行质量门,再在原生 amd64、原生 arm64 执行 Delivery Index benchmark、构建镜像、容器 smoke 和并发 `1` 的图片处理 benchmark。只有全部验证成功的同一镜像才会推送对应平台标签;两个架构都成功后才创建版本与 `latest` manifest

容器 smoke 还会验证:
图片处理 benchmark 每个架构总计 `16` 个请求,容器限制为 1 CPU、768 MiB 和 256 PID,并强制要求全部请求成功、无 busy 响应、p95 不超过 20 秒且 cgroup 峰值不超过 512 MiB。

Release smoke 还会验证:

- 公开标准 URL 和别名的 Range、条件请求、HEAD 与相同 ETag。
- 固定 `10001:10001`、exec-form ENTRYPOINT 和内置健康检查。
Expand Down