From c645851c0eed0a7eb4a09d44cd8852ded666be21 Mon Sep 17 00:00:00 2001 From: JustMe Date: Tue, 6 Oct 2026 21:43:57 +0800 Subject: [PATCH] fix(ci): build native node images and add compose files [CI] Restore with PublishAot so agent and probe images contain NativeAOT binaries instead of a launcher that needs a .dll, fail the build when the binary is too small, add agent and probe compose files, and document the [CI] marker in AGENTS.md. --- AGENTS.md | 1 + packaging/compose/.gitignore | 1 + packaging/compose/agent/compose.yaml | 33 +++++++++++++++++++ packaging/compose/probe/compose.yaml | 28 ++++++++++++++++ .../container/Agent.NativeBuild.Containerfile | 9 +++-- .../container/Probe.NativeBuild.Containerfile | 7 ++-- 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 packaging/compose/.gitignore create mode 100644 packaging/compose/agent/compose.yaml create mode 100644 packaging/compose/probe/compose.yaml diff --git a/AGENTS.md b/AGENTS.md index a4ebeba..5379688 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,7 @@ Monitor is a self-hosted network path quality monitor. Backend coordinates Agent ## Branch and workspace safety - Treat `main` as the stable release branch and `dev` as the integration branch. Keep ordinary implementation work on `dev` or a feature branch; integrate into `main` through a pull request. +- A push to `main` builds images only if its commit message contains `[CI]` (for a merged PR, put it in the PR or merge commit title). Without `[CI]` nothing is built; use `[CI SKIP]` to skip the pipeline entirely. When squashing or pushing to `main`, add `[CI]` unless a build is explicitly not wanted. - Before editing, inspect `git status`. Preserve pre-existing user changes: do not reset, clean, stash, or include unrelated files in a commit. - Do not commit credentials, API keys, registry passwords, or generated runtime data. CI credentials belong in Woodpecker secrets. - Keep development OCI images in the `monitor-dev/` repository path and release images in `monitor/`. Do not let a development build overwrite release tags such as `latest`. diff --git a/packaging/compose/.gitignore b/packaging/compose/.gitignore new file mode 100644 index 0000000..d071829 --- /dev/null +++ b/packaging/compose/.gitignore @@ -0,0 +1 @@ +.data/ diff --git a/packaging/compose/agent/compose.yaml b/packaging/compose/agent/compose.yaml new file mode 100644 index 0000000..48cad7c --- /dev/null +++ b/packaging/compose/agent/compose.yaml @@ -0,0 +1,33 @@ +# Agent:配置和身份都放在同目录的 .data/(挂载到容器的 /etc/monitor)。 +# +# 第一次使用: +# mkdir -p .data && sudo chown 1654:1654 .data # 容器以 UID/GID 1654 运行 +# MONITOR_JOIN_TOKEN=<加入令牌> MONITOR_SERVER=https:// MONITOR_AGENT_NAME=<名字> \ +# docker compose run --rm --entrypoint /usr/local/bin/fleet-enroll agent \ +# --server "$MONITOR_SERVER" --join "$MONITOR_JOIN_TOKEN" --name "$MONITOR_AGENT_NAME" --identity-dir /etc/monitor/agent-id +# 再在 .data/agent.json 里写(fleet.identity_dir 要和上面一致): +# {"fleet":{"server":"https://","identity_dir":"/etc/monitor/agent-id"},"listen":{"bind":"0.0.0.0"},"limits":{"max_total_mbps":100,"max_total_pps":10000}} +# docker compose up -d +# +# 更新:改 MONITOR_VERSION(或 MONITOR_IMAGE),再 docker compose pull && docker compose up -d。.data 不动,身份和历史都保留。 +services: + agent: + image: ${MONITOR_IMAGE:-registry.oeo.one/monitor/monitor-agent}:${MONITOR_VERSION:-0.1.1} + container_name: monitor-agent + restart: unless-stopped + init: true + # Probe 要直连 Agent 的 7443(TCP+UDP)和 7444(TCP),用宿主网络,不做端口映射 + network_mode: host + volumes: + - ./.data:/etc/monitor + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid,size=64m,mode=1777 + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + # 要做 ICMP 测量时打开: + # cap_add: + # - NET_RAW + stop_grace_period: 20s diff --git a/packaging/compose/probe/compose.yaml b/packaging/compose/probe/compose.yaml new file mode 100644 index 0000000..7c1a2a8 --- /dev/null +++ b/packaging/compose/probe/compose.yaml @@ -0,0 +1,28 @@ +# Probe:身份配置 probe.json 和 Agent 列表缓存 agents.json 都放在同目录的 .data/(挂载到容器的 /etc/monitor)。 +# +# 第一次使用: +# mkdir -p .data && sudo chown 1654:1654 .data # 容器以 UID/GID 1654 运行,需要读写这个目录 +# 在管理端创建 Probe,下载一次性身份配置,保存为 .data/probe.json(含私钥,权限 600,不要提交到版本控制) +# docker compose up -d +# +# 更新:改 MONITOR_VERSION(或 MONITOR_IMAGE),再 docker compose pull && docker compose up -d。.data 不动。 +services: + probe: + image: ${MONITOR_IMAGE:-registry.oeo.one/monitor/monitor-probe}:${MONITOR_VERSION:-0.1.1} + container_name: monitor-probe + restart: unless-stopped + init: true + network_mode: host + volumes: + - ./.data:/etc/monitor + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid,size=64m,mode=1777 + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + # 要做 ICMP 测量时打开: + # cap_add: + # - NET_RAW + stop_grace_period: 20s diff --git a/packaging/container/Agent.NativeBuild.Containerfile b/packaging/container/Agent.NativeBuild.Containerfile index 2bcbc6d..d5967f9 100644 --- a/packaging/container/Agent.NativeBuild.Containerfile +++ b/packaging/container/Agent.NativeBuild.Containerfile @@ -7,8 +7,9 @@ ARG MONITOR_COMMIT= ARG MONITOR_BUILT_AT= ENV MONITOR_TAG=$MONITOR_TAG MONITOR_COMMIT=$MONITOR_COMMIT MONITOR_BUILT_AT=$MONITOR_BUILT_AT COPY restore/backend/ ./ -RUN dotnet restore agent/src/Monitor.Agent -r linux-x64 --artifacts-path /artifacts \ - && dotnet restore fleet/tools/fleet-enroll -r linux-x64 --artifacts-path /artifacts +# restore 也要带 PublishAot:不然不会还原 ILCompiler,之后 --no-restore 的发布就悄悄变成「裁剪过的框架依赖程序」 +RUN dotnet restore agent/src/Monitor.Agent -r linux-x64 -p:PublishAot=true --artifacts-path /artifacts \ + && dotnet restore fleet/tools/fleet-enroll -r linux-x64 -p:PublishAot=true --artifacts-path /artifacts COPY source/backend/ ./ RUN dotnet publish agent/src/Monitor.Agent -m:3 -c Release -r linux-x64 \ @@ -19,7 +20,9 @@ RUN dotnet publish agent/src/Monitor.Agent -m:3 -c Release -r linux-x64 \ --self-contained true --no-restore -p:PublishAot=true -p:UseAotAnywhere=false \ -p:UseAppHost=true -p:StripSymbols=true \ -p:DebugType=none -p:DebugSymbols=false --artifacts-path /artifacts -o /out/enroll -RUN test -x /out/agent/monitor-agent && test -x /out/enroll/fleet-enroll +# 原生程序有几 MB;几十 KB 的是只会去找 .dll 的启动器 +RUN test -x /out/agent/monitor-agent && test -x /out/enroll/fleet-enroll \ + && test "$(stat -c%s /out/agent/monitor-agent)" -gt 2000000 && test "$(stat -c%s /out/enroll/fleet-enroll)" -gt 2000000 FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled-extra diff --git a/packaging/container/Probe.NativeBuild.Containerfile b/packaging/container/Probe.NativeBuild.Containerfile index a87fbcf..5bd3592 100644 --- a/packaging/container/Probe.NativeBuild.Containerfile +++ b/packaging/container/Probe.NativeBuild.Containerfile @@ -7,14 +7,17 @@ ARG MONITOR_COMMIT= ARG MONITOR_BUILT_AT= ENV MONITOR_TAG=$MONITOR_TAG MONITOR_COMMIT=$MONITOR_COMMIT MONITOR_BUILT_AT=$MONITOR_BUILT_AT COPY restore/backend/ ./ -RUN dotnet restore probe/src/Monitor.Probe -r linux-x64 --artifacts-path /artifacts +# restore 也要带 PublishAot:不然不会还原 ILCompiler,之后 --no-restore 的发布就悄悄变成「裁剪过的框架依赖程序」 +RUN dotnet restore probe/src/Monitor.Probe -r linux-x64 -p:PublishAot=true --artifacts-path /artifacts COPY source/backend/ ./ RUN dotnet publish probe/src/Monitor.Probe -m:3 -c Release -r linux-x64 \ --self-contained true --no-restore -p:PublishAot=true -p:UseAotAnywhere=false \ -p:UseAppHost=true -p:StripSymbols=true \ -p:DebugType=none -p:DebugSymbols=false --artifacts-path /artifacts -o /out/probe -RUN test -x /out/probe/monitor-probe +# 原生程序有几 MB;几十 KB 的是只会去找 .dll 的启动器 +RUN test -x /out/probe/monitor-probe \ + && test "$(stat -c%s /out/probe/monitor-probe)" -gt 2000000 FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled-extra