From 383afa777b69eff26a193d4eff66f7ddf912cf67 Mon Sep 17 00:00:00 2001 From: JustMe Date: Tue, 6 Oct 2026 16:14:50 +0800 Subject: [PATCH 1/5] ci: publish main amd64 images to dev Zot [CI SKIP] --- .woodpecker/main-amd64-build.yml | 12 +++++++ ci/build-main-amd64.sh | 54 +++++++++++++++++++++++++++++--- ci/release-linux.sh | 20 +++++++++--- docs/deployment.md | 2 +- 4 files changed, 79 insertions(+), 9 deletions(-) diff --git a/.woodpecker/main-amd64-build.yml b/.woodpecker/main-amd64-build.yml index 18b0a1c..51a2fbd 100644 --- a/.woodpecker/main-amd64-build.yml +++ b/.woodpecker/main-amd64-build.yml @@ -20,6 +20,10 @@ steps: image: bash environment: NUGET_PACKAGES: /home/justme/.nuget/packages + ZOT_REGISTRY: registry.oeo.one + ZOT_USERNAME: justme + ZOT_SECRET: + from_secret: zot_secret commands: - bash ci/build-main-amd64.sh backend depends_on: [] @@ -28,6 +32,10 @@ steps: image: bash environment: NUGET_PACKAGES: /home/justme/.nuget/packages + ZOT_REGISTRY: registry.oeo.one + ZOT_USERNAME: justme + ZOT_SECRET: + from_secret: zot_secret commands: - bash ci/build-main-amd64.sh agent depends_on: [] @@ -36,6 +44,10 @@ steps: image: bash environment: NUGET_PACKAGES: /home/justme/.nuget/packages + ZOT_REGISTRY: registry.oeo.one + ZOT_USERNAME: justme + ZOT_SECRET: + from_secret: zot_secret commands: - bash ci/build-main-amd64.sh probe depends_on: [] diff --git a/ci/build-main-amd64.sh b/ci/build-main-amd64.sh index 8d0fe54..3615e73 100644 --- a/ci/build-main-amd64.sh +++ b/ci/build-main-amd64.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Build one Linux amd64 runtime image locally for an opt-in main commit. +# Build and push one opt-in main Linux amd64 image to the dev repository in Zot. set -euo pipefail [[ "${CI_PIPELINE_EVENT:-}" == push && "${CI_COMMIT_BRANCH:-}" == main && "${CI_COMMIT_MESSAGE:-}" == *"[CI]"* ]] || { @@ -12,14 +12,31 @@ case "$component" in backend|agent|probe) ;; *) echo "unsupported component: $component" >&2; exit 2 ;; esac +[[ -n "${ZOT_USERNAME:-}" && -n "${ZOT_SECRET:-}" ]] || { + echo "Zot credentials are required" >&2 + exit 2 +} +[[ "${CI_COMMIT_SHA:-}" =~ ^[0-9a-fA-F]{40}$ ]] || { + echo "CI_COMMIT_SHA must be a full commit SHA" >&2 + exit 2 +} root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +registry="${ZOT_REGISTRY:-registry.oeo.one}" +repository="$registry/monitor-dev/monitor-$component" work="$root/.release/main-amd64-build" base_home="/home/justme/woodpecker/buildah-home/main-amd64-build-$component" +short_sha="${CI_COMMIT_SHA:0:12}" +dev_tag="dev-$short_sha" mkdir -p "$work" "$base_home" if [[ "$component" == backend ]]; then - BUILDAH_HOME="$base_home" IMAGE_PUBLISH=false bash "$root/ci/release-linux.sh" amd64 backend + BUILDAH_HOME="$base_home" \ + ZOT_REGISTRY="$registry" \ + ZOT_IMAGE_REPOSITORY="$repository" \ + IMAGE_TAGS="latest,$dev_tag" \ + IMAGE_PUBLISH=true \ + bash "$root/ci/release-linux.sh" amd64 backend exit 0 fi @@ -27,10 +44,39 @@ export HOME="$base_home" export BUILDAH_HOME="$base_home" export REGISTRY_AUTH_FILE="$work/$component-auth.json" context="$work/$component" +local_image="localhost/monitor-$component:main-amd64-check" python3 "$root/ci/stage-node-image.py" "$component" "$context" buildah bud --layers --network host --tls-verify=true --arch amd64 \ --build-arg APP_VERSION=main \ -f "$context/Containerfile" \ - -t "localhost/monitor-$component:main-amd64-check" "$context" -echo "built local Linux amd64 $component image; not publishing it" + -t "$local_image" "$context" + +logged_in=false +for attempt in 1 2 3 4; do + if buildah login --tls-verify=true --username "$ZOT_USERNAME" --password-stdin "$registry" <<< "$ZOT_SECRET" >/dev/null; then + logged_in=true + break + fi + if [[ "$attempt" -lt 4 ]]; then + echo "Zot login attempt $attempt failed; retrying in 3 seconds" >&2 + sleep 3 + fi +done +[[ "$logged_in" == true ]] || { echo "could not authenticate to Zot after 4 attempts" >&2; exit 1; } + +for tag in latest "$dev_tag"; do + pushed=false + for attempt in 1 2 3; do + if buildah push --tls-verify=true "$local_image" "docker://$repository:$tag"; then + pushed=true + break + fi + if [[ "$attempt" -lt 3 ]]; then + echo "Zot push for $component:$tag attempt $attempt failed; retrying in 5 seconds" >&2 + sleep 5 + fi + done + [[ "$pushed" == true ]] || { echo "could not push $repository:$tag after 3 attempts" >&2; exit 1; } + echo "pushed development image $repository:$tag" +done diff --git a/ci/release-linux.sh b/ci/release-linux.sh index 0996019..9843aeb 100644 --- a/ci/release-linux.sh +++ b/ci/release-linux.sh @@ -39,7 +39,7 @@ if [[ -n "$tag" && "$version" != "$project_version" ]]; then fi registry="${ZOT_REGISTRY:-registry.oeo.one}" -image="$registry/monitor/monitor-backend" +image="${ZOT_IMAGE_REPOSITORY:-$registry/monitor/monitor-backend}" output="$root/.release/linux-$arch/backend" build_root="$root/.release/build/linux-$arch-backend" container_context="$root/.release/container/linux-$arch" @@ -100,7 +100,19 @@ push_tag() { echo "pushed Zot image $image:$target_tag" } -push_tag "$version-$arch" -if [[ -z "$tag" ]]; then - push_tag "$version" +if [[ -n "${IMAGE_TAGS:-}" ]]; then + IFS=',' read -r -a image_tags <<< "$IMAGE_TAGS" + ((${#image_tags[@]} > 0)) || { echo "IMAGE_TAGS must contain at least one tag" >&2; exit 2; } + for image_tag in "${image_tags[@]}"; do + [[ "$image_tag" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]] || { + echo "invalid image tag: $image_tag" >&2 + exit 2 + } + push_tag "$image_tag" + done +else + push_tag "$version-$arch" + if [[ -z "$tag" ]]; then + push_tag "$version" + fi fi diff --git a/docs/deployment.md b/docs/deployment.md index e8f524d..24aa8c0 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -38,7 +38,7 @@ Compose 将容器端口只绑定到宿主机 `127.0.0.1:8080`,适合由同机 Woodpecker 在 `vMAJOR.MINOR.PATCH` tag 上,由 Windows runner 使用 AotAnywhere 并行构建 Agent/Probe 的 Linux glibc、Linux musl、macOS 和 Windows 产物。Agent 包还包含一次性注册工具 `fleet-enroll`。Linux 归档带有安装脚本和 systemd/OpenWrt 单元;Windows 产物为 `.zip`,Linux/macOS 产物为 `.tar.gz`。Linux glibc 的 Agent 与 Probe 二进制还会打包为 OCI 镜像,支持 `linux/amd64` 和 `linux/arm64`;musl、macOS、Windows 仍通过对应平台归档分发。所有平台产物和 OCI 镜像发布成功后,CI 会创建对应的 Gitea Release,并附上压缩包和 SHA-256 校验文件。macOS 产物目前未签名/公证。安装说明见 [`../backend/agent/README.md`](../backend/agent/README.md) 与 [`../backend/probe/README.md`](../backend/probe/README.md)。 -推送到 `main` 或 feature PR 合入 `main` 后会触发 Linux/amd64 快车道;关闭但未合入的 PR 会跳过。CI 根据变更文件所在项目及 `.csproj` 的传递引用,只构建受影响的 Backend、Agent 或 Probe 镜像;Agent 镜像也包含 `fleet-enroll`。例如只改 Probe 时只构建 Probe;改动 `Monitor.Protocol` 等被多个程序引用的库时,会构建所有受影响镜像。结果推送到对应镜像的 `main` 和 `main-amd64` 标签,不改写 release 版本和 `latest`。只改 Web、文档或部署配置时,流程会正常完成但不会构建容器。完整多架构和跨平台构建仍由版本 tag 流水线负责。 +当推送到 `main` 的提交信息包含 `[CI]` 时,Woodpecker 会并行构建 Backend、Agent 和 Probe 的 Linux/amd64 镜像,并推送到同一个 Zot Registry 的开发仓库 `registry.oeo.one/monitor-dev/`。每个镜像更新 `latest`,并保留 `dev-<提交SHA>` 标签用于回滚;例如 `registry.oeo.one/monitor-dev/monitor-agent:latest`。开发镜像仅包含 amd64,不创建 Gitea Release,也不改动正式镜像仓库 `monitor/`。不带 `[CI]` 的 main push 不会启动此构建。版本 tag 流水线仍负责全平台构建,并发布正式镜像和 Gitea Release。 Agent 和 Probe 镜像分别发布为 `registry.oeo.one/monitor/monitor-agent:` 与 `registry.oeo.one/monitor/monitor-probe:`,包含 amd64、arm64 多架构索引;也可指定 `:-amd64` 或 `:-arm64`。稳定版本同时更新 `latest`。镜像以非 root 用户(UID/GID 1654)运行,默认读取 `/etc/monitor/agent.json` 或 `/etc/monitor/probe.json`。运行容器时挂载对应配置目录;Probe 还会在该目录写入 `agents.json`,因此目录需可由 1654 用户写入。Agent、Probe 需使用宿主网络以保持节点端口和测量流量行为,并按需添加 `NET_RAW` 能力以执行 ICMP 测量: From e67d3294a29f94fdd098938b0bd3c7f84bbbb786 Mon Sep 17 00:00:00 2001 From: JustMe Date: Tue, 6 Oct 2026 16:18:59 +0800 Subject: [PATCH 2/5] ci: allow skipping verify with CI SKIP suffix [CI SKIP] --- .woodpecker/verify.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.woodpecker/verify.yml b/.woodpecker/verify.yml index 0b19941..91f773e 100644 --- a/.woodpecker/verify.yml +++ b/.woodpecker/verify.yml @@ -8,10 +8,13 @@ clone: settings: lfs: false +# Append [CI SKIP] to a commit message to bypass PR/dev verification when a change does not need tests. when: - event: pull_request + evaluate: 'not (CI_COMMIT_MESSAGE contains "[CI SKIP]")' - event: push branch: dev + evaluate: 'not (CI_COMMIT_MESSAGE contains "[CI SKIP]")' steps: - name: backend-tests From 1da8d083c1b67c56338e0f40011427488eb9fd75 Mon Sep 17 00:00:00 2001 From: JustMe Date: Tue, 6 Oct 2026 16:21:04 +0800 Subject: [PATCH 3/5] ci: skip backend tests only with CI SKIP suffix [CI SKIP] --- .woodpecker/verify.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.woodpecker/verify.yml b/.woodpecker/verify.yml index 91f773e..8f1888f 100644 --- a/.woodpecker/verify.yml +++ b/.woodpecker/verify.yml @@ -8,17 +8,17 @@ clone: settings: lfs: false -# Append [CI SKIP] to a commit message to bypass PR/dev verification when a change does not need tests. when: - event: pull_request - evaluate: 'not (CI_COMMIT_MESSAGE contains "[CI SKIP]")' - event: push branch: dev - evaluate: 'not (CI_COMMIT_MESSAGE contains "[CI SKIP]")' steps: - name: backend-tests image: bash + # [CI SKIP] omits tests only; web-build still runs. + when: + - evaluate: 'not (CI_COMMIT_MESSAGE contains "[CI SKIP]")' environment: NUGET_PACKAGES: /home/justme/.nuget/packages commands: From 56d80e8c809a2e0ea882b78daa58f3bad494bdba Mon Sep 17 00:00:00 2001 From: JustMe Date: Tue, 6 Oct 2026 16:23:13 +0800 Subject: [PATCH 4/5] ci: build web after tests and allow skipping tests [CI SKIP] --- .woodpecker/verify.yml | 10 ---------- .woodpecker/web-build.yml | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 .woodpecker/web-build.yml diff --git a/.woodpecker/verify.yml b/.woodpecker/verify.yml index 8f1888f..7c108a6 100644 --- a/.woodpecker/verify.yml +++ b/.woodpecker/verify.yml @@ -23,13 +23,3 @@ steps: NUGET_PACKAGES: /home/justme/.nuget/packages commands: - cd backend && dotnet test --solution Monitor.slnx -c Release - - - name: web-build - image: bash - environment: - NPM_CONFIG_CACHE: /home/justme/.npm - commands: - - npm ci --prefix web --prefer-offline - - npm run build --prefix web - - npm run lint:css --prefix web - depends_on: [] diff --git a/.woodpecker/web-build.yml b/.woodpecker/web-build.yml new file mode 100644 index 0000000..a364415 --- /dev/null +++ b/.woodpecker/web-build.yml @@ -0,0 +1,27 @@ +labels: + ci: domain-linux-native + platform: linux/amd64 + +clone: + - name: git + image: plugin-git + settings: + lfs: false + +when: + - event: pull_request + - event: push + branch: dev + +depends_on: + - verify + +steps: + - name: web-build + image: bash + environment: + NPM_CONFIG_CACHE: /home/justme/.npm + commands: + - npm ci --prefix web --prefer-offline + - npm run build --prefix web + - npm run lint:css --prefix web From efa17b44854c859f8ef1e6cfa48fe0dade4d8201 Mon Sep 17 00:00:00 2001 From: JustMe Date: Tue, 6 Oct 2026 16:26:57 +0800 Subject: [PATCH 5/5] ci: use SKIP TESTS marker for backend tests [SKIP TESTS] --- .woodpecker/verify.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.woodpecker/verify.yml b/.woodpecker/verify.yml index 7c108a6..b8b2958 100644 --- a/.woodpecker/verify.yml +++ b/.woodpecker/verify.yml @@ -13,12 +13,13 @@ when: - event: push branch: dev +# On Gitea PR events, CI_COMMIT_MESSAGE is the PR title. steps: - name: backend-tests image: bash - # [CI SKIP] omits tests only; web-build still runs. + # [SKIP TESTS] omits Backend tests only; web-build remains a dependent workflow. when: - - evaluate: 'not (CI_COMMIT_MESSAGE contains "[CI SKIP]")' + - evaluate: 'not (CI_COMMIT_MESSAGE contains "[SKIP TESTS]")' environment: NUGET_PACKAGES: /home/justme/.nuget/packages commands: