外观
配置参考(Configuration Reference)
本文是 DN42 控制面后端全部配置项的唯一真相源(single source of truth):Control Server(主控制面 TS 面 + 温备控制面 Python 面)与 Node Agent(节点代理)。所有条目均逐字对照源码列出,未在代码中出现的配置不会记录于此。
- Control Server(Python 温备面)配置类:
apps/control-server/app/core/config.py(ControlServerConfig/load())。 - Control Server(TS 主控制面 / Workers)配置载体:
apps/control-server-ts/wrangler.jsonc+wrangler secret,解析入口src/env.ts(见 §1.5)。 - Node Agent 配置类:
apps/node-agent/agent/core/config.py(AgentConfig/load_agent_config())与 CLIapps/node-agent/agent/main.py(_build_parser())。
1. Control Server
适用范围:§1.1–§1.4 的环境变量 / TOML 载体仅适用于 Python 温备控制面(
apps/control-server,入口https://legacy.api.natlan.io)。主控制面(TS 面)不读DN42_CONTROL_*任何变量,配置全部走 wrangler 载体,见 §1.5;配置项语义(类型 / 默认 / fail-closed 行为)两面一致,下表兼作 TS 面同语义项的释义。
Control Server 是一个 dataclass ControlServerConfig,所有字段都有内置默认值;生产入口 ControlServerConfig.load() 按两层来源依次覆盖,优先级从高到低:
环境变量 (DN42_CONTROL_*) > TOML 配置文件 > 内置默认值TOML 配置文件是推荐的主载体(直观、可注释、单文件成套),环境变量留作覆盖通道——既有的纯 env 部署不受影响,env 里设置的项永远压过文件同名项。文件的加载规则、与环境变量的逐项对照、以及仅文件可调的 [flap] 段见 §1.1;下表按环境变量列出配置项语义(类型 / 默认 / fail-closed 行为对两种载体一致)。环境变量统一以 DN42_CONTROL_ 为前缀(唯一例外:TURNSTILE_SECRET_KEY,变量名是与前端契约锁死的)。
| 环境变量 | 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
DN42_CONTROL_DATABASE_URL | database_url | str (SQLAlchemy 异步 DSN) | sqlite+aiosqlite:///<仓库根>/control.db | SQLAlchemy 异步 DSN。默认锚定在仓库根目录下的 control.db(config.py:16-17,避免随 cwd 漂移),适合本地与 CI。生产改用 Postgres(postgresql+asyncpg://user:pass@host:5432/db)或 MySQL(mysql+asyncmy://...)。同一变量也被 Alembic 迁移读取(见 §1.4)。详见 部署指南。 |
DN42_CONTROL_ENROLLMENT_TOKEN | enrollment_token | str | None | None | 全局 bootstrap 注册 token;agent register 时与 enrollment_tokens 表中按节点签发的 token 并行接受。fail-closed:未设置 / 设为空字符串都视为 None(from_env 把空值归一为 None,config.py:139)——此时全局 token 关闭,只允许表内按节点签发的一次性 token 注册。本地练手需显式设置(如 enroll-token)才能照教程示例注册。 |
DN42_CONTROL_ADMIN_TOKEN | admin_token | str | None | None | Admin API 的 Bearer token(机器 / 自动化凭据,与账号登录签发的会话令牌并行接受)。fail-closed:值为 None(变量未设置或为空字符串,config.py:126)时 Admin API 整体拒绝(一律 403),账号登录同样锁定。生产必须显式配置。 |
TURNSTILE_SECRET_KEY | turnstile_secret_key | str | None | None | Cloudflare Turnstile 服务端校验 secret(CF 面板 → Turnstile → widget 查看)。账号登录(POST /api/v1/auth/login)对前端透传的 turnstile_token 调 siteverify 硬校验。fail-closed:未配置时登录一律 400(静态 admin token 不受影响)。 |
DN42_CONTROL_BOOTSTRAP_ADMIN | bootstrap_admin | str | None | None | user:password——仅当 admin_users 表为空时创建首个管理员账号(幂等:已有账号则跳过,变量残留不会覆盖改过的密码)。密码以 argon2id 散列入库,明文不落库。 |
DN42_CONTROL_SESSION_TTL_SECONDS | session_ttl_seconds | float(秒) | 86400.0 | 账号登录会话令牌 TTL(默认 24h)。过期后任意接口 401(前端全局登出);改密时该用户全部存活会话立即吊销。解析同 _env_float。 |
DN42_CONTROL_SEED_BOOTSTRAP_NODE | seed_bootstrap_node | bool | False | 是否在 DB 为空时播种内置 demo 节点。布尔解析见 _env_flag(config.py:20-26):1/true/yes/on(大小写不敏感)为真,其余为假。默认 False 表示启动即空库,节点数据应由导入 / provision 流程写入。 |
DN42_CONTROL_BOOTSTRAP_NODE_ID | bootstrap_node_id | str | "edge1" | 内置 demo 节点的 node_id,仅在 seed_bootstrap_node 开启时使用。 |
DN42_CONTROL_BOOTSTRAP_AGENT_TOKEN | bootstrap_agent_token | str | "mvp-agent-token" | 与 bootstrap 节点关联的初始 Bearer token,便于本地联调。仅在 seed_bootstrap_node 开启时有意义。 |
DN42_CONTROL_RECOVERY_PUBLIC_KEY | recovery_public_key_pem | str | None | None | 离线托管「恢复公钥」。取值既可是内联 PEM(以 -----BEGIN 开头),也可是PEM 文件路径(_load_recovery_public_key,config.py:52-68)。节点用它封装 WG 私钥后上报;控制面只存密文、永不持有恢复私钥。None(未设置)表示未启用托管——节点仍上报公钥做一致性校验,但不产生托管密文。注意:若给的是文件路径且文件不存在,启动期会抛 FileNotFoundError(fail-fast,config.py:64-67)。 |
DN42_CONTROL_CORS_ORIGINS | cors_origins | tuple[str, …](逗号分隔) | ("http://localhost:5173", "http://127.0.0.1:5173") | 浏览器管理面(独立仓库 dn42-control-webui)跨源直连本服务的 CORS 白名单。解析见 _parse_cors_origins(config.py:41-49):逗号分隔、各项去空白、丢弃空项。未设置时返回默认(放行本地 Vite dev server);显式设为空字符串表示关闭跨源(白名单为空元组)。生产填管理面真实源(或 *)。 |
DN42_CONTROL_HEALTH_STALE_AFTER | health_stale_after_seconds | float(秒) | 900.0 | 健康判定失联阈值:在此时长内未上报的 ok 节点降为 stale。浮点解析见 _env_float(config.py:29-38):缺失、空白或非法值回退默认。 |
DN42_CONTROL_HEALTH_DOWN_AFTER | health_down_after_seconds | float(秒) | 3600.0 | 健康判定宕机阈值:超过此时长完全无上报判为 down,覆盖任何已知状态。解析同 _env_float。 |
DN42_CONTROL_REDIS_URL | redis_url | str | None | None | Redis 缓存 DSN(如 redis://redis:6379/0)。缓存 desired-state(generation 键)/ 节点健康(10s)/ 路由聚合(30s)等高频读,写时主动失效。None(未设置)即不启用缓存——所有读直接走 DB(缓存层全程 no-op);Redis 不可用时同样自动回落 DB,缓存是旁路、不影响正确性。docker 全栈方案内置 redis 并已注入此变量。 |
DN42_CONTROL_DB_AUTO_MIGRATE | db_auto_migrate | bool | False | 启动时是否跑 alembic upgrade head。False(dev/CI)走 Base.metadata.create_all 直接建表(只建缺表、不应用 ALTER);生产置 True:经迁移链建表 / 升级,迁移失败即启动中止(fail-fast)。既有 create_all 库首次切换前需手动 alembic stamp(见 升级与迁移)。布尔解析同 _env_flag。 |
DN42_CONTROL_AGENT_RELEASES_DIR | agent_releases_dir | Path | /data/agent-releases | 首方 wheel 发布库目录(agent 自更新分发源)。admin 上传 build_wheels.sh 产物到这里,agent 经鉴权通道拉取;默认落 docker 全栈的 control-data 持久卷。见 升级与迁移。 |
DN42_CONTROL_REGISTRY_TOKEN | registry_token | str | None | None | DN42 registry 同步的只读 access token(在 git.dn42.dev 签发;registry 仓库匿名访问全被拒)。None = 不启用同步(UI 的 registry 查询端点仍可用,但表为空;手动 sync 返 409)。 |
DN42_CONTROL_REGISTRY_BASE_URL | registry_base_url | str | https://git.dn42.dev | registry 同步源 Gitea 实例。 |
DN42_CONTROL_REGISTRY_REPO | registry_repo | str | dn42/registry | registry 仓库路径。 |
1.1 TOML 配置文件
加载规则(ControlServerConfig.load()):
- 路径:
DN42_CONTROL_CONFIG_FILE显式指定(文件必须存在,否则启动即失败);未指定时查默认路径/etc/dn42-control/control-server.toml(不存在则静默跳过,纯 env 部署不受影响)。 - 未知的段 / 键 / 类型不符一律启动期报错(
ConfigFileError,与 agent.toml 同纪律)——拼写错误不会静默失效。 - token 类键(下表标 †)设空字符串与不设置等价(归一为
None,fail-closed 语义与 env 一致);环境变量显式设空同样是关闭,不会回落文件值。 - 模板:
docker/control-server.example.toml(compose 部署把control-server.toml挂载到容器/etc/dn42-control/,见docker/docker-compose.yml注释)。含 token / 密码,宿主侧建议chmod 600。
段.键 ↔ 环境变量对照(语义 / 默认见上表):
| TOML 键 | 环境变量 |
|---|---|
server.admin_token † | DN42_CONTROL_ADMIN_TOKEN |
server.enrollment_token † | DN42_CONTROL_ENROLLMENT_TOKEN |
server.cors_origins(字符串数组) | DN42_CONTROL_CORS_ORIGINS(逗号分隔) |
server.agent_releases_dir | DN42_CONTROL_AGENT_RELEASES_DIR |
server.recovery_public_key(内联 PEM 或路径) | DN42_CONTROL_RECOVERY_PUBLIC_KEY |
database.url | DN42_CONTROL_DATABASE_URL |
database.auto_migrate | DN42_CONTROL_DB_AUTO_MIGRATE |
redis.url † | DN42_CONTROL_REDIS_URL |
health.stale_after_seconds | DN42_CONTROL_HEALTH_STALE_AFTER |
health.down_after_seconds | DN42_CONTROL_HEALTH_DOWN_AFTER |
registry.token † | DN42_CONTROL_REGISTRY_TOKEN |
registry.base_url | DN42_CONTROL_REGISTRY_BASE_URL |
registry.repo | DN42_CONTROL_REGISTRY_REPO |
auth.turnstile_secret_key † | TURNSTILE_SECRET_KEY |
auth.session_ttl_seconds | DN42_CONTROL_SESSION_TTL_SECONDS |
auth.bootstrap_admin † | DN42_CONTROL_BOOTSTRAP_ADMIN |
dev.seed_bootstrap_node | DN42_CONTROL_SEED_BOOTSTRAP_NODE |
dev.bootstrap_node_id | DN42_CONTROL_BOOTSTRAP_NODE_ID |
dev.bootstrap_agent_token | DN42_CONTROL_BOOTSTRAP_AGENT_TOKEN |
[flap] 段——抖动检测调参(仅文件可调,无对应环境变量)。默认值即代码内置值;三个评估方(会话打分 / 前缀榜单 / 告警循环)装配时从同一份配置取值,自动同参:
| TOML 键 | 默认 | 说明 |
|---|---|---|
flap.session_half_life_s | 1800 | 会话级(P0)衰减半衰期(秒)。~5min 快照节奏下 30min 半衰期 ≈ 连续 4 份抖动快照才过线。 |
flap.session_threshold | 3.0 | 会话级「抖动中」判定线(榜单 flapping 标记 + 告警开单线;消警线自动取一半做迟滞)。 |
flap.prefix_list_threshold | 20 | 前缀级(P1)榜单「抖动中」线(徽章 / 标黄,可观测层)。 |
flap.prefix_alert_threshold | 100 | 前缀级告警开单线(P2),与榜单线分层(低烈度背景抖动是 DN42 常态,按榜单线开单会告警疲劳);消警线自动取一半。 |
⚠️ 刻意不开放的两个结构性常量:前缀级衰减半衰期(600s,必须与全 fleet agent
flapfeed_scoring.HALF_LIFE_S同参,控制面单方面改 = 打分口径分叉)与速率存档桶宽(60s,改了会毁历史 rollup 的语义)。见apps/control-server/app/services/prefix_flaps.py头注释。
1.2 解析助手(parsing helpers)
| 助手 | 位置 | 行为 |
|---|---|---|
_env_flag(name, default) | config.py:20 | 布尔:未设置返回 default;否则 1/true/yes/on(去空白、小写)为真。 |
_env_float(name, default) | config.py:29 | 浮点:未设置 / 纯空白 / 解析失败 → default。 |
_parse_cors_origins(raw, default) | config.py:41 | None → default;否则逗号分隔、去空白、丢空项;"" → 空元组(关闭跨源)。 |
_load_recovery_public_key(raw) | config.py:52 | 空 → None;以 -----BEGIN 开头 → 视为内联 PEM 原样返回;否则当作文件路径读取(ASCII),不存在则 FileNotFoundError。 |
1.3 fail-closed / 空字符串语义速查
| 变量 | 「未设置」 | 「设为空字符串 ""」 |
|---|---|---|
DN42_CONTROL_ENROLLMENT_TOKEN | None → 全局 token 关闭(仅表内 token) | None → 全局 token 关闭(仅表内 token) |
DN42_CONTROL_ADMIN_TOKEN | None → Admin API 全 403(含账号登录) | None → Admin API 全 403(含账号登录) |
TURNSTILE_SECRET_KEY | None → 账号登录全 400 | None → 账号登录全 400 |
DN42_CONTROL_BOOTSTRAP_ADMIN | None → 不自动建账号 | None → 不自动建账号 |
DN42_CONTROL_CORS_ORIGINS | 默认本地白名单 | 空元组 → 关闭跨源 |
DN42_CONTROL_RECOVERY_PUBLIC_KEY | None → 不托管 | None → 不托管 |
DN42_CONTROL_REGISTRY_TOKEN | None → 不同步 registry | None → 不同步 registry |
1.4 数据库 URL 与迁移
Alembic 迁移与运行时共享同一变量 DN42_CONTROL_DATABASE_URL:
migrations/env.py:36-51(_resolve_url())优先读该环境变量,缺失时退回alembic.ini的sqlalchemy.url(默认sqlite+aiosqlite:///./control.db,仅为alembic --help的无害占位)。- 迁移期把异步驱动替换为同步驱动:
+aiosqlite→ 去除、+asyncpg→+psycopg2、+asyncmy→+pymysql(env.py:43-47)。 - 从仓库根运行:
alembic upgrade head。Postgres / MySQL 生产部署的完整步骤见 部署指南。
1.5 生产 TS 面(Cloudflare Workers)的配置载体
主控制面(TS 面,apps/control-server-ts,生产入口 https://api.natlan.io;见 ../internals/control-server-ts.md)没有 env 文件与 TOML——配置分三种载体,均以 wrangler.jsonc / wrangler CLI 为事实源,类型定义与 fail-closed 语义集中在 src/env.ts:
绑定(
wrangler.jsonc:36-68):HYPERDRIVE(PostgreSQL 边缘连接池,取代database_url)、CACHE_KV(Workers KV,取代 Redis,同样是优雅降级的旁路缓存)、RELEASES_R2(R2 桶,取代agent_releases_dir持久卷目录)、DOORBELL/PROBE_HUB(Durable Objects,取代 Python 面进程内EventBus(app/core/events.py)与ProbeHub)、triggers.crons(取代 Python lifespan 背景循环:"* * * * *"每分钟 flap 告警边沿评估 + dashboard routing 块预计算,"0 */6 * * *"每 6h registry 同步)。非机密 vars(
wrangler.jsonc:70-86的vars,随部署生效;Workers vars 一律字符串,数值项在使用处解析):var 对应 Python 项 默认( wrangler.jsonc)HEALTH_STALE_AFTERDN42_CONTROL_HEALTH_STALE_AFTER900HEALTH_DOWN_AFTERDN42_CONTROL_HEALTH_DOWN_AFTER3600CORS_ORIGINSDN42_CONTROL_CORS_ORIGINS*REGISTRY_BASE_URLDN42_CONTROL_REGISTRY_BASE_URLhttps://git.dn42.devREGISTRY_REPODN42_CONTROL_REGISTRY_REPOdn42/registrySESSION_TTL_SECONDSDN42_CONTROL_SESSION_TTL_SECONDS86400FLAP_SESSION_HALF_LIFE_Sflap.session_half_life_s1800FLAP_SESSION_THRESHOLDflap.session_threshold3FLAP_PREFIX_LIST_THRESHOLDflap.prefix_list_threshold20FLAP_PREFIX_ALERT_THRESHOLDflap.prefix_alert_threshold100机密(
wrangler secret put <NAME>,不落仓库;src/env.ts:33-43)——与 Python 面逐项对应,语义与 fail-closed 行为一致:ADMIN_TOKEN(←DN42_CONTROL_ADMIN_TOKEN)、ENROLLMENT_TOKEN(←DN42_CONTROL_ENROLLMENT_TOKEN)、RECOVERY_PUBLIC_KEY(←DN42_CONTROL_RECOVERY_PUBLIC_KEY;仅内联 PEM——Workers 无文件系统,不支持 Python 面的文件路径形态)、REGISTRY_TOKEN(←DN42_CONTROL_REGISTRY_TOKEN)、TURNSTILE_SECRET_KEY(同名)、BOOTSTRAP_ADMIN(←DN42_CONTROL_BOOTSTRAP_ADMIN)。
与 Python 面的差异:前缀级衰减半衰期(600s)在 TS 面同样是刻意不开放的 agent 耦合不变量(src/env.ts:27 注释:必须与全 fleet agent flapfeed_scoring.HALF_LIFE_S 同参,单方面改动即打分口径分叉);seed_bootstrap_node 等 dev 项与 DN42_CONTROL_DB_AUTO_MIGRATE 不存在(TS 面 SQL 迁移手动应用);无 /docs OpenAPI。部署操作见 ../guides/deployment.md。
2. Node Agent
2.1 三来源与优先级
Agent 配置有三个来源,优先级从高到低(apps/node-agent/agent/core/config.py:4-6):
CLI 参数 > 环境变量 (DN42_AGENT_*) > TOML 文件 > 内置默认值加载流程:
load_agent_config(toml_path)(config.py:67):先AgentConfig()取默认,若 TOML 文件存在则_apply_toml覆盖(config.py:107),再_apply_env用环境变量覆盖(config.py:145),最后_validate_choices校验枚举。- CLI 层
_config_from_args(main.py:100)在上一步结果之上叠加命令行覆盖(仅覆盖非None的项)。
补充约定:
- TOML 文件不存在不报错,相当于跳过该来源(
config.py:75)。文件路径由--config指定;约定默认/etc/dn42-control/agent.toml。 - TOML 顶层可用
[agent]表,也可直接平铺(agent_section = payload.get("agent", payload),config.py:111)。 - TOML 只识别白名单字段(
_ALLOWED_KEYS,config.py:89-104),出现未知键会抛ConfigError,避免静默拼写错误。 with_overrides仅应用非 None 的覆盖项(config.py:60-64),所以低优先级来源不会被高优先级来源的「未提供」清空。
2.2 CLI 参数
CLI 全参数、运行模式、互斥约束与退出码的单一事实源是 cli-and-scripts.md,此处不再重复。要点:CLI 只暴露身份 / 模式类参数(--controller-url / --enrollment-token / --state-dir / --mode / 诊断三选一等);下表 http_timeout_seconds 及其后的全部调优项(间隔、阈值、socket 路径)只能通过环境变量或 TOML 设置。
2.3 环境变量
由 _ENV_KEYS 映射(config.py:128-142),统一以 DN42_AGENT_ 为前缀。下表「字段」对应 AgentConfig(config.py:28),默认值即字段默认。
| 环境变量 | 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|---|
DN42_AGENT_CONTROLLER_URL | controller_url | str | None | None | Control Server 基础 URL。常驻模式必需。 |
DN42_AGENT_ENROLLMENT_TOKEN | enrollment_token | str | None | None | 一次性 enrollment token。 |
DN42_AGENT_REQUESTED_NODE_ID | requested_node_id | str | None | None | 希望绑定的 node_id。 |
DN42_AGENT_HOSTNAME | hostname | str | None | None | 覆盖 inventory hostname。 |
DN42_AGENT_STATE_DIR | state_dir | Path | /var/lib/dn42-control | 本地状态目录(解析为 Path,config.py:151-152)。 |
DN42_AGENT_RENDERED_DIR | rendered_dir | Path | None | None(派生) | 渲染输出目录(解析为 Path)。留空则从节点目录派生(见 §2.4)。 |
DN42_AGENT_MODE | mode | apply/write-rendered/plan-only | apply | reconcile 深度;非法值在 _validate_choices 抛 ConfigError(config.py:82-86)。 |
DN42_AGENT_LOG_LEVEL | log_level | str | INFO | 日志级别。 |
DN42_AGENT_HTTP_TIMEOUT_SECONDS | http_timeout_seconds | float | 10.0 | HTTP 请求超时(秒)。解析为 float,非数字抛 ConfigError(config.py:158-161)。 |
DN42_AGENT_LOCAL_CONVERGENCE | local_convergence | bool | True | 是否执行本机收敛。1/true/yes/on(去空白、小写)为真(config.py:162-163)。 |
DN42_AGENT_ROUTING_INTERVAL_SECONDS | routing_interval_seconds | float | 300.0 | 路由全表周期采集间隔(秒),独立于 reconcile 的纯观测。设 0 关闭采集。 |
DN42_AGENT_TRAFFIC_INTERVAL_SECONDS | traffic_interval_seconds | float | 30.0 | WG 流量轻量采集间隔(秒):wg show all transfer 求和上报,供控制面细粒度吞吐曲线。设 0 关闭。 |
DN42_AGENT_FLAPFEED_INTERVAL_SECONDS | flapfeed_interval_seconds | float | 60.0 | 前缀级 flap 计分的上报 tick(秒):flapfeed 进程内 BGP 采集会话持续收 UPDATE,按此间隔把衰减计分快照上报控制面(见 ../internals/flap-detection.md);exabgp 库不可导入的节点自动旁路。设 0 关闭 flapfeed 旁路(config.py:78,177)。 |
DN42_AGENT_RERESOLVE_INTERVAL_SECONDS | reresolve_interval_seconds | float | 45.0 | WG endpoint 周期重解析间隔(秒),自愈对端动态 DNS 漂移后内核钉死旧 IP。设 0 关闭。 |
DN42_AGENT_L3_HEAL_INTERVAL_SECONDS | l3_heal_interval_seconds | float | 60.0 | L3 漂移自愈间隔(秒):比对期望接口(WG + dummy)与 netns 实际接口,缺失即重跑 apply-all-wg 补齐(容器 Up 但接口被删的运行时漂移,config_hash 看不见)。设 0 关闭。 |
DN42_AGENT_SELF_MONITOR_INTERVAL_SECONDS | self_monitor_interval_seconds | float | 60.0 | 进程自观测间隔(秒):采集 agent 自身 CPU% / RSS 写 metrics 文件,持续高 CPU 告警。设 0 关闭。 |
DN42_AGENT_HEARTBEAT_INTERVAL_SECONDS | heartbeat_interval_seconds | float | 30.0 | WS 心跳间隔(秒):上行 AgentHeartbeat(报活 + 报版本 + 报 apply 态),并写本地健康文件供自更新器健康门轮询。设 0 关闭心跳与自更新(dev / 无 systemd 场景)。 |
DN42_AGENT_CPU_WARN_PERCENT | cpu_warn_percent | float | 80.0 | 自身 CPU% 告警阈值:单次自观测窗口 CPU 占用 ≥ 此值即 WARN(多核可 >100)。 |
DN42_AGENT_BIRD_SOCKET_PATH | bird_socket_path | str | None | None(派生) | BIRD 控制 socket 路径的显式覆盖。留空则从渲染目录推导 <rendered_dir>/run/bird/bird.ctl;仅非常规部署 / 联调需要指向别处时设置。 |
DN42_AGENT_EXABGP_BIN | exabgp_bin | str | None | None | 已废弃(≤1.0.190 的 ExaBGP 子进程路径覆盖)。取值不再被读取;键保留仅为容忍存量配置里的残留——配置加载对未知键报错,删掉字段会让带旧键的节点起不来(config.py:81,178)。 |
说明:CLI 只暴露身份 / 模式类参数——上表
http_timeout_seconds及其后的全部调优项(间隔、阈值、socket 路径)只能通过环境变量或 TOML 设置。
2.4 状态目录布局
由 AgentPaths(apps/node-agent/agent/core/paths.py)定义,所有节点级文件落在 <state_dir>/nodes/<node_id>/ 之下:
| 路径 | 内容 |
|---|---|
nodes/<node_id>/identity.json | 持久化 agent 身份与世代信息。 |
nodes/<node_id>/desired-state.json | 最近一次成功 Desired State 的本地副本。 |
nodes/<node_id>/rendered/ | 渲染输出(配置文件与镜像构建上下文根;rendered_dir 留空时即此处)。 |
nodes/<node_id>/snapshots/ | RuntimeSnapshot 与 ReconciliationReport 历史归档。 |
nodes/<node_id>/metrics.json | reconcile 运行指标(次数 / 失败 / 时长 / 最近状态)。 |
nodes/<node_id>/containers/ | 已应用容器定义记录(字段级 diff reason 数据源)。 |
nodes/<node_id>/secrets/ | 节点本地密钥目录(0700),含 secrets/wireguard/node.key(0600,一节点一把 WG 私钥)。不进渲染产物、不上报、不入 file plan。 |
Agent 内部机制与完整 CLI 见 Node Agent 内部说明 与 CLI 与脚本参考。
3. 示例
3.1 Control Server 最小 control-server.toml(推荐)
toml
[server]
admin_token = "change-me-admin"
enrollment_token = "change-me"
cors_origins = ["https://panel.example.dn42"]
[database]
url = "postgresql+asyncpg://dn42:secret@127.0.0.1:5432/dn42_control"
auto_migrate = true放到 /etc/dn42-control/control-server.toml(或 compose 挂载到该路径,chmod 600)即生效;完整模板见 docker/control-server.example.toml。等价的纯环境变量形态:
dotenv
# 异步 SQLAlchemy DSN;生产建议 Postgres,见 ../guides/deployment.md
DN42_CONTROL_DATABASE_URL=postgresql+asyncpg://dn42:secret@127.0.0.1:5432/dn42_control
# 全局 enrollment token(agent 首次注册用);设为空字符串可只走 per-node token
DN42_CONTROL_ENROLLMENT_TOKEN=change-me
# Admin API Bearer——不设置则 /admin 一律 403(fail-closed),生产必填
DN42_CONTROL_ADMIN_TOKEN=change-me-admin
# 可选:浏览器管理面跨源白名单(逗号分隔)
DN42_CONTROL_CORS_ORIGINS=https://panel.example.dn42
# 可选:离线恢复公钥(内联 PEM 或文件路径),启用 WG 私钥托管
# DN42_CONTROL_RECOVERY_PUBLIC_KEY=/etc/dn42-control/recovery.pub.pem跑迁移(与运行时共享同一 DSN):
bash
DN42_CONTROL_DATABASE_URL=postgresql+asyncpg://dn42:secret@127.0.0.1:5432/dn42_control \
alembic upgrade head3.2 Node Agent 最小 agent.toml
toml
[agent]
controller_url = "https://control.example.dn42"
enrollment_token = "change-me"
requested_node_id = "edge1"
state_dir = "/var/lib/dn42-control"
log_level = "INFO"
# 可选调参
# http_timeout_seconds = 10.0
# routing_interval_seconds = 300.0 # 0 关闭路由采集
# reresolve_interval_seconds = 45.0 # 0 关闭 WG endpoint 重解析
# flapfeed_interval_seconds = 60.0 # 0 关闭前缀级 flap 采集上报3.3 Node Agent systemd env-file(生产推荐)
模板单元 deploy/systemd/dn42-node-agent@.service 用 %i 作为 node_id,并读取 /etc/dn42-control/%i.env。节点专属 env 文件示例:
dotenv
# /etc/dn42-control/edge1.env
DN42_AGENT_CONTROLLER_URL=https://control.example.dn42
DN42_AGENT_ENROLLMENT_TOKEN=change-me
# STATE_DIR 与 REQUESTED_NODE_ID 已由 unit 注入(=/var/lib/dn42-control、=%i)启用:sudo systemctl enable --now dn42-node-agent@edge1。
完整生产部署(venv、PYTHONPATH、Postgres、加固选项)见 部署指南。