From bac1c27e72e592aa6d3ff7ee70fc2057621aaec5 Mon Sep 17 00:00:00 2001 From: JustMe Date: Thu, 8 Oct 2026 20:47:38 +0800 Subject: [PATCH] fix: compose passes .env through env_file; clearer name and channel messages [CI] podman-compose does not substitute defaults inside "environment:" (a value like ${MOSHIRO_NAME:-} reached the node as the literal text), so the node was enrolled with an invalid name and reported the wrong network scope. The three compose files now read .env with env_file and only interpolate image and network_mode; the Backend .env keys are the container's own names (MoShiro__PublicUrl, MoShiro__ClaimCode). - The generated .env no longer carries a comment line for MOSHIRO_NAME; the dialog says how to choose a name instead. - The container entrypoint prints the name it enrolls with and defaults MOSHIRO_NETWORK_SCOPE to host (Docker Desktop sets container in .env). - The overview and line pages say "measurement channel not established" instead of "not connected": the agent can be reachable and pingable while the measurement TCP/UDP path is not. --- .../Admin/JoinTokenService.cs | 1 - .../tests/MoShiro.Backend.Tests/InstallTests.cs | 3 +++ docs/ops/deployment.md | 5 ++--- packaging/compose/agent/compose.yaml | 11 ++++------- packaging/compose/backend/compose.yaml | 16 ++++++++-------- packaging/compose/probe/compose.yaml | 13 ++++--------- packaging/container/entrypoint.sh | 3 +++ web/admin/src/pages/JoinTokenCreated.tsx | 2 +- web/display/src/pages/Line.tsx | 2 +- web/display/src/pages/Overview.tsx | 2 +- 10 files changed, 27 insertions(+), 31 deletions(-) diff --git a/backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs b/backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs index 108c128..b7d7f94 100644 --- a/backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs +++ b/backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs @@ -134,7 +134,6 @@ public sealed class JoinTokenService lines.Add("MOSHIRO_NETWORK_SCOPE=container"); } - lines.Add("# MOSHIRO_NAME=节点名字(不写就用主机名;名字被占用时在这里改)"); return string.Join('\n', lines); } diff --git a/backend/tests/MoShiro.Backend.Tests/InstallTests.cs b/backend/tests/MoShiro.Backend.Tests/InstallTests.cs index 27be2e0..0f506a8 100644 --- a/backend/tests/MoShiro.Backend.Tests/InstallTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/InstallTests.cs @@ -107,6 +107,9 @@ public sealed class InstallTests Assert.Contains("no-new-privileges:true", body, StringComparison.Ordinal); Assert.Contains("- ALL", body, StringComparison.Ordinal); // cap_drop Assert.DoesNotContain("jt_", body, StringComparison.Ordinal); // 没有任何一次性的值 + // 参数只从 .env 原样传进容器:podman-compose 不替换环境变量里的默认值,写成 ${变量:-默认值} 会把字面量传给节点 + Assert.Contains("env_file:", body, StringComparison.Ordinal); + Assert.DoesNotContain(":-}", body, StringComparison.Ordinal); } [Theory] diff --git a/docs/ops/deployment.md b/docs/ops/deployment.md index 490f40d..9f06c22 100644 --- a/docs/ops/deployment.md +++ b/docs/ops/deployment.md @@ -48,8 +48,8 @@ Backend 使用 OCI 标准镜像,通过 `registry.oeo.one/moshiro/moshiro-backe mkdir moshiro-backend && cd moshiro-backend curl -fsSL https://git.oeo.one/justme/MoShiro/releases/download/<版本>/moshiro-compose-backend.yaml -o compose.yaml cat > .env <<'EOF' -MOSHIRO_PUBLIC_URL=https://panel.example.com # 面板对外的地址;passkey 绑定在这个域名上,改了会让已注册的 passkey 失效 -# MOSHIRO_CLAIM_CODE= # 认领码,不写就随机生成并打印在日志里 +MoShiro__PublicUrl=https://panel.example.com # 面板对外的地址;passkey 绑定在这个域名上,改了会让已注册的 passkey 失效 +# MoShiro__ClaimCode= # 认领码(可选),不写就随机生成并打印在日志里 EOF podman compose up -d # Docker 用 docker compose ``` @@ -232,7 +232,6 @@ MOSHIRO_JOIN=jt_… MOSHIRO_GENESIS=… MOSHIRO_CONTROLLERS=… MOSHIRO_IMAGE=registry.oeo.one/moshiro/moshiro-probe -# MOSHIRO_NAME=节点名字(不写就用主机名) EOF chmod 600 .env && curl -fsSL 'https://panel.example.com/install/compose/probe.yaml' -o compose.yaml && echo " compose.yaml" | sha256sum -c - && podman compose up -d ``` diff --git a/packaging/compose/agent/compose.yaml b/packaging/compose/agent/compose.yaml index 5bce5d0..021d989 100644 --- a/packaging/compose/agent/compose.yaml +++ b/packaging/compose/agent/compose.yaml @@ -6,6 +6,7 @@ # podman compose up -d # Docker 用 docker compose # 更新:podman compose pull && podman compose up -d (身份和配置在命名卷里,不会动) # 固定版本:在 .env 里写 MOSHIRO_VERSION=0.3.3;想要更严,写成 MOSHIRO_VERSION=0.3.3@sha256:。 +# .env 里的 MOSHIRO_SERVER、MOSHIRO_JOIN(只在第一次启动用来注册,之后可以删掉)、MOSHIRO_GENESIS、MOSHIRO_CONTROLLERS、MOSHIRO_NAME 原样传进容器。 # 说明见 docs/ops/deployment.md。 services: agent: @@ -23,14 +24,10 @@ services: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/host/root:ro + # .env 里的变量原样传进容器(不用带默认值的变量替换:有的 compose 提供者,比如 podman-compose,不替换环境变量里的默认值) + env_file: + - .env environment: - # 只在第一次启动时用来注册(身份写进 agent-config 卷之后,.env 里的 MOSHIRO_JOIN 就可以删掉) - MOSHIRO_SERVER: ${MOSHIRO_SERVER:-} - MOSHIRO_JOIN: ${MOSHIRO_JOIN:-} - MOSHIRO_NAME: ${MOSHIRO_NAME:-} - MOSHIRO_GENESIS: ${MOSHIRO_GENESIS:-} - MOSHIRO_CONTROLLERS: ${MOSHIRO_CONTROLLERS:-} - MOSHIRO_ALLOW_NO_OWNER: ${MOSHIRO_ALLOW_NO_OWNER:-} MOSHIRO_NETWORK_SCOPE: host HOST_PROC: /host/proc HOST_SYS: /host/sys diff --git a/packaging/compose/backend/compose.yaml b/packaging/compose/backend/compose.yaml index 6e752ba..d7af60b 100644 --- a/packaging/compose/backend/compose.yaml +++ b/packaging/compose/backend/compose.yaml @@ -2,9 +2,10 @@ # # 用法: # mkdir moshiro-backend && cd moshiro-backend -# 下载本文件为 compose.yaml;写一个 .env(可选): -# MOSHIRO_PUBLIC_URL=https://panel.example.com # 面板对外的地址;passkey 绑定在这个域名上,改了会让已注册的 passkey 失效 -# MOSHIRO_CLAIM_CODE= # 认领码,不写就随机生成并打印在日志里(podman logs moshiro-backend) +# 下载本文件为 compose.yaml;再写一个 .env,键是容器里直接用的名字: +# MoShiro__PublicUrl=https://panel.example.com # 面板对外的地址;passkey 绑定在这个域名上,改了会让已注册的 passkey 失效 +# MoShiro__ClaimCode= # 认领码(可选),不写就随机生成并打印在日志里(podman logs moshiro-backend) +# (没有 .env 也要先建一个空文件:touch .env) # podman compose up -d # Docker 用 docker compose # 第一次打开面板按页面引导认领:没有默认管理员。面板监听 127.0.0.1:8080,对外请放在反向代理(HTTPS)后面。 # 更新:先备份数据卷,再 podman compose pull && podman compose up -d。新版会自动迁移数据库, @@ -12,19 +13,18 @@ # 说明见 docs/ops/deployment.md。 services: backend: - image: registry.oeo.one/${MOSHIRO_IMAGE_NAMESPACE:-moshiro}/moshiro-backend:${MOSHIRO_VERSION:-latest} + image: ${MOSHIRO_IMAGE:-registry.oeo.one/moshiro/moshiro-backend}:${MOSHIRO_VERSION:-latest} container_name: moshiro-backend restart: unless-stopped init: true ports: - "127.0.0.1:8080:8080" + # .env 里的变量原样传进容器(MoShiro__PublicUrl、MoShiro__ClaimCode 等)(不用带默认值的变量替换:有的 compose 提供者,比如 podman-compose,不替换环境变量里的默认值) + env_file: + - .env environment: ASPNETCORE_HTTP_PORTS: "8080" MoShiro__DataDirectory: /data - MoShiro__UpdateChannel: ${MOSHIRO_UPDATE_CHANNEL:-auto} - MoShiro__ImageNamespace: ${MOSHIRO_IMAGE_NAMESPACE:-moshiro} - MoShiro__PublicUrl: "${MOSHIRO_PUBLIC_URL:-}" - MoShiro__ClaimCode: "${MOSHIRO_CLAIM_CODE:-}" volumes: - moshiro-backend-data:/data - moshiro-backend-status:/data/update-status:ro diff --git a/packaging/compose/probe/compose.yaml b/packaging/compose/probe/compose.yaml index 82fd9f8..5993902 100644 --- a/packaging/compose/probe/compose.yaml +++ b/packaging/compose/probe/compose.yaml @@ -7,6 +7,7 @@ # 更新:podman compose pull && podman compose up -d (身份和配置在命名卷里,不会动) # 固定版本:在 .env 里写 MOSHIRO_VERSION=0.3.3;想要更严,写成 MOSHIRO_VERSION=0.3.3@sha256:。 # macOS、Windows 的 Docker Desktop 没有宿主网络:面板给的 .env 里已经写了 MOSHIRO_NETWORK_MODE=bridge。 +# .env 里的 MOSHIRO_SERVER、MOSHIRO_JOIN(只在第一次启动用来注册,之后可以删掉)、MOSHIRO_GENESIS、MOSHIRO_CONTROLLERS、MOSHIRO_NAME 原样传进容器。 # 说明见 docs/ops/deployment.md。 services: probe: @@ -15,15 +16,9 @@ services: restart: unless-stopped init: true network_mode: ${MOSHIRO_NETWORK_MODE:-host} - environment: - # 只在第一次启动时用来注册(身份写进 probe-config 卷之后,.env 里的 MOSHIRO_JOIN 就可以删掉) - MOSHIRO_SERVER: ${MOSHIRO_SERVER:-} - MOSHIRO_JOIN: ${MOSHIRO_JOIN:-} - MOSHIRO_NAME: ${MOSHIRO_NAME:-} - MOSHIRO_GENESIS: ${MOSHIRO_GENESIS:-} - MOSHIRO_CONTROLLERS: ${MOSHIRO_CONTROLLERS:-} - MOSHIRO_ALLOW_NO_OWNER: ${MOSHIRO_ALLOW_NO_OWNER:-} - MOSHIRO_NETWORK_SCOPE: ${MOSHIRO_NETWORK_SCOPE:-host} + # .env 里的变量原样传进容器(不用带默认值的变量替换:有的 compose 提供者,比如 podman-compose,不替换环境变量里的默认值) + env_file: + - .env volumes: - probe-config:/etc/moshiro - probe-status:/etc/moshiro/update-status:ro diff --git a/packaging/container/entrypoint.sh b/packaging/container/entrypoint.sh index b291fce..08de46f 100644 --- a/packaging/container/entrypoint.sh +++ b/packaging/container/entrypoint.sh @@ -4,6 +4,8 @@ set -eu role="${MOSHIRO_ROLE:?MOSHIRO_ROLE is set by the image}" +# compose 默认用宿主网络;Docker Desktop(没有宿主网络)的 .env 里写 MOSHIRO_NETWORK_SCOPE=container +export MOSHIRO_NETWORK_SCOPE="${MOSHIRO_NETWORK_SCOPE:-host}" dir=/etc/moshiro identity="$dir/$role-id" config="$dir/$role.json" @@ -15,6 +17,7 @@ if [ ! -f "$identity/node.json" ]; then echo "first start: set MOSHIRO_SERVER and MOSHIRO_JOIN in .env (the panel shows the complete content)" >&2 exit 1 fi + echo "enrolling as '$MOSHIRO_NAME' (1-64 letters, digits, . _ - ; set MOSHIRO_NAME in .env to choose another)" >&2 # 每个节点都必须有属主(passkey):信任根指纹和属主缺一个就不注册 if [ -z "${MOSHIRO_GENESIS:-}" ] || [ -z "${MOSHIRO_CONTROLLERS:-}" ]; then if [ "${MOSHIRO_ALLOW_NO_OWNER:-}" != 1 ]; then diff --git a/web/admin/src/pages/JoinTokenCreated.tsx b/web/admin/src/pages/JoinTokenCreated.tsx index 0c719e7..b19822d 100644 --- a/web/admin/src/pages/JoinTokenCreated.tsx +++ b/web/admin/src/pages/JoinTokenCreated.tsx @@ -30,7 +30,7 @@ export function JoinTokenCreated({ created, kind, onClose }: { created: CreatedJ
一次性码只显示这一次,请现在就复制。下面只有公开的值(面板地址、一次性码、信任根指纹和属主),没有任何私钥。
diff --git a/web/display/src/pages/Line.tsx b/web/display/src/pages/Line.tsx index c57fa6c..5e8cf15 100644 --- a/web/display/src/pages/Line.tsx +++ b/web/display/src/pages/Line.tsx @@ -278,7 +278,7 @@ export function Line() { {line.data ? (
- {line.data.online ? (line.data.probe_connected ? '在线' : 'Agent 在线,Probe 未连接') : 'Agent 离线'} + {line.data.online ? (line.data.probe_connected ? '在线' : 'Agent 在线,测量通道未建立(Probe 没能和它建立测量会话;机器可能是通的,ping 通不代表测量用的 TCP 和 UDP 通道可用)') : 'Agent 离线'} Agent diff --git a/web/display/src/pages/Overview.tsx b/web/display/src/pages/Overview.tsx index 01ba734..55ae9bf 100644 --- a/web/display/src/pages/Overview.tsx +++ b/web/display/src/pages/Overview.tsx @@ -102,7 +102,7 @@ function Card({ agent, host, range, infos }: { agent: AgentCard; host: HostItem {l.probe_name} {infos.get(l.probe_id)?.isp_key ? : null} - {!l.probe_connected && l.online ? 未连接 : {OVERVIEW_RANGES.find((r) => r.value === range)?.label ?? range}} + {!l.probe_connected && l.online ? 测量通道未建立 : {OVERVIEW_RANGES.find((r) => r.value === range)?.label ?? range}}