Skip to content

集群配置参考 ​

整个集群共用一份 JSON 配置文件,部署后在每台节点的 /etc/opendsec/opendsec.json。所有组件都读它,各自取用与自己相关的部分。这一页逐个说明它的字段和默认值。

  • 完整的生产示例:deploy/prod/cluster.example.json;单机安装生成的配置在 /root/opendsec-ops/opendsec.json。
  • 时长字段的单位都是秒(可以是小数)。
  • 大部分数值字段写 0 或不写表示用默认值;有些字段写 -1 表示关闭,下表会注明。
  • 修改配置:由 fleet 管理的集群用 opendsecctl fleet config put 和 fleet rollout create -config-gen <代数> 下发(见运维手册 §6.2);还没交给 fleet 的用 opendsecops push-config all 和 opendsecops restart。
  • 校验一份配置:opendsecctl pki init -config <文件> -out $(mktemp -d),能通过说明格式和约束都没问题。

顶层结构 ​

json
{
  "tls":            { ... },   // 组件间 mTLS 和公共 API 的 TLS
  "service_token":  "...",     // 仅开发:没有 TLS 时组件间的认证
  "iam":            { ... },
  "watcher":        { ... },
  "apiserver":      [ ... ],
  "placement":      { ... },
  "admission":      { ... },
  "image_store":    { ... },
  "network":        { ... },
  "edges":          [ ... ],   // 逐台列出的 edge
  "edge_template":  { ... },   // 其他所有 edge(新加的机器、Kubernetes)
  "fleet":          { ... },
  "e2b":            { ... },
  "extensions":     { ... }    // 构建里包含的扩展(开源版没有)
}

tls.dir 和 service_token 至少设置一个,生产环境必须用 tls。

tls ​

字段说明
dir证书目录,例如 /etc/opendsec/pki。里面是 ca.crt 和各组件的 <角色>-<id>.crt、.key(opendsecctl pki init 或 opendsecops certs 生成)。设置后组件之间使用 mTLS,公共 API 使用 TLS

service_token ​

开发集群用:没有 TLS 时,组件之间用这个共享密钥认证。生产集群不要设置;交给 fleet 下发的配置里不能有它。

iam ​

字段默认说明
replicas—Raft 副本列表,每项 {"id", "addr", "raft_addr", "data_dir"}。设置后 addr 和 state 不再使用,并且必须设置 admin_token 或 admin_token_file
replicas[].id—副本 id,唯一,不能含 /、.、空格
replicas[].addr—gRPC 地址,例如 10.0.0.1:7001
replicas[].raft_addr—Raft 复制地址,例如 10.0.0.1:7011
replicas[].data_dir—Raft 日志和快照目录,例如 /var/lib/opendsec/iam,放在本地 SSD 上
addr—单副本(不复制)时的地址
state内存单副本时的状态文件;不设置则只在内存里,重启丢失
admin_idadmin自举时创建的管理员身份
admin_token—管理员 token,格式 dsk.<admin_id>.<secret>。含 change-me 的占位值会被拒绝
admin_token_file—从这个文件读管理员 token,配置文件里就不必写密钥。只有 IAM 节点需要这个文件
root_quota不限root 项目的配额,例如 {"sandboxes": 10000}
max_token_ttl_s0(不限)签发的 token 最长有效期。设置后不能再签发永不过期的 token

管理员 token 只在 IAM 第一次启动(自举)时使用:创建 admin_id 这个身份,在 root 上授予全部权限。

watcher ​

字段默认说明
replicas—多个 watcher,每项 {"id", "addr"}。全部都探测 edge、提供快照;持有 IAM 锁的那个负责对账
addr—单个 watcher 时的地址
probe_interval1探测每个 edge 的间隔
probe_timeout0.5单次探测的超时
unhealthy_after3连续失败几次判定为不健康
reconcile_interval30与 IAM 对账配额的间隔
reconcile_min_age60比这个更新的租约在对账时不会被释放
lost_edge_grace120edge 不健康超过这么久,释放它上面 sandbox 的配额
unbound_max_age600没有任何 edge 认领的租约,过这么久后释放
lock_ttl10对账锁的租期

apiserver ​

数组,每项是一个 apiserver 实例;opendsec-apiserver -index N 运行第 N 项。

字段默认说明
addr—监听地址,例如 10.0.0.1:7100
audit_dir关闭审计日志目录,例如 /var/log/opendsec/audit
audit_max_mb256单个审计日志文件达到这个大小后轮转
audit_keep8保留的文件个数(包括当前文件),最旧的先删
audit_runtimefalse也审计运行时调用(执行命令、文件、HTTP、进程、端口)和只读查询(查看、列出 sandbox,集群状态,项目、用量、token 列表)。默认审计其余全部调用:创建、fork、停止、暂停、恢复、改网络、镜像发布和删除、项目、身份、权限、token、集群操作。执行命令只记录命令的长度和 SHA-256,不记录命令内容
snapshot_refresh1从 watcher 刷新集群快照的间隔

placement ​

调度参数,每个 apiserver 执行。

字段默认说明
k2power-of-k:每次随机取 k 个候选节点,选负载最低的
max_attempts3被 edge 拒绝后换节点重试的次数
reject_penalty2拒绝过的节点在这段时间内被降低优先级
overlay_grace2刚放上去的 sandbox 在快照反映出来之前,按这么久计入节点负载
usage_floor0.2节点实际的 CPU、内存使用率低于这个比例时不计入负载(主机自身的基础占用);-1 表示总是计入
burst_threshold0.8只对 burst_eligible_images 里的镜像、container 后端生效:本地(onprem)节点的利用率超过这个比例后,按超出的程度以一定概率优先放到 zone: cloud 的节点上;没超过时云上节点只作为本地放不下时的后备。≤0 关闭
burst_eligible_images—允许放到云上节点的镜像(这些镜像的层已同步到云上)。其他镜像和后端从不放到云上节点

admission ​

每个 apiserver 执行的准入策略。超时字段:0 表示用内置默认值,-1 表示不设。限流按每个身份、每个 apiserver 实例计算(N 个 apiserver 合计最多是 N 倍);-1 关闭。

字段默认说明
default_ttl_running_stop_s3600请求没有设置空闲超时时使用
default_ttl_max_s86400请求没有设置最长寿命时使用
max_ttl_max_s604800(7 天)请求允许的最长寿命,超过返回 invalid
request_rate10000每个身份每秒的调用数(包括执行命令和文件调用)
request_burst2 × request_rate突发
create_rate2000每个身份每秒创建的 sandbox 数
create_burst32768突发:允许一整个批量请求立即开始
auth_fail_rate5每个客户端地址每秒允许的认证失败次数,超过后暂时不再为它认证新 token
max_inflight_creates2048每个 apiserver 同时进行的创建数

单个创建超速返回 rate_limited;批量创建在服务端按速率排队,不会因为限流部分失败。apiserver 在负载均衡后面时,请让负载均衡保留客户端源地址,否则认证失败会全部算到负载均衡的地址上。

image_store ​

字段说明
root共享镜像库的挂载点,例如 /mnt/opendsec-images。所有 apiserver 和 edge 节点都要在同一路径挂载。没有设置时只能使用 edge 上配置的本地镜像(edges[].images)

文件系统的要求见镜像与快照 §5。

network ​

全集群的网络策略。

字段说明
rule_sets规则集:名字 → 目标列表(域名、IPv4 地址或网段,可带 :端口[/协议])。例如 {"pypi": ["pypi.org", "files.pythonhosted.org"], "github": ["github.com", "codeload.github.com", "objects.githubusercontent.com"]}
default_rules每个 sandbox 默认带的规则,sandbox 自己的 network_rules 叠加在上面。例如 {"*": true} 让所有 sandbox 默认能访问公网,{"pypi": true} 默认只放行 PyPI
upstream_dnsedge 上 DNS 代理使用的上游解析服务器,默认用宿主机的 /etc/resolv.conf

规则的语法和行为见网络策略。

edges 与 edge_template ​

edges 逐台列出 edge;edge_template 用于没有列出的 edge(opendsec-edge -id <id> 启动时找不到同名项就用模板)。新加的机器通常不必写进 edges。

字段默认说明
id—edge id,只能是 [a-z0-9-],1 到 32 个字符;edges 里必填
addr—监听地址,例如 0.0.0.0:7201
advertise实际监听的地址向 watcher 登记的地址
zoneonpremonprem 或 cloud,只能是这两个值。cloud 的节点只在本地负载超过 burst_threshold 时使用
capacity自动{"cpu_cores", "memory_mb", "gpus", "disk_mb"}。有真实后端时:cpu_cores 和 memory_mb 都不写则取本机的 CPU 数和内存总量(只写其中一个时另一个不会自动填);disk_mb 不写则取 state_dir 所在文件系统的大小。超配倍数在此基础上计算
cpu_overcommit8CPU 超配倍数
mem_overcommit1内存超配倍数
disk_overcommit1可写盘超配倍数
mem_reserve_mb自动本机 MemAvailable 低于这个值时拒绝创建。0 表示自动(内存的 10%,至少 128 MB);-1 关闭
disk_reserve_mb自动状态目录剩余空间低于这个值时拒绝创建。0 表示自动(文件系统的 5%,至少 1024 MB);-1 关闭
cpu_pressure_limit0(关闭)CPU 压力(/proc/pressure/cpu 的 some avg10,百分比)高于这个值时拒绝创建。批量创建本身也会推高压力,请按本机的实测值设置,例如 50
paused_mem_charge1暂停时释放了内存的 sandbox(microVM;开了 pause_reclaim 的容器)仍按这个比例计入内存占用,取值 0 到 1
persist_state有真实后端时开启把 sandbox 记录写到磁盘,edge 重启后重新接管
keep_sandboxes_on_exitfalseedge 退出时不停止 sandbox。滚动升级需要开启
stopped_retention600已结束的 sandbox 记录保留多久
state_dir/var/lib/opendsecsandbox 的磁盘、快照、记录放在这里,应当是本地 NVMe;XFS 可以用 reflink 复制
agent_diredge 程序所在目录opendsec-aether 和 opendsec-chronus 所在的目录
images—本地静态镜像:镜像名 → overlay 下层目录列表(最上层在前)。有共享镜像库时一般不需要
network关闭sandbox 网络,见下文
gpu—GPU 设备,见下文
backends{"sim": {...}}这台 edge 提供的后端,见下文

edges[].network ​

字段默认说明
enabledfalse启用 sandbox 网络。关闭时 sandbox 只有回环接口
subnet10.88.0.0/16sandbox 地址池,每个 sandbox 占一个 /30
dns_port15353edge 的 DNS 代理在宿主机上的端口

同一台机器上运行多个 edge 时,它们的 subnet 和 dns_port 要各不相同。

edges[].gpu ​

字段说明
devicesGPU 设备节点,例如 ["/dev/nvidia0", "/dev/nvidia1"]。capacity.gpus 默认是设备个数
extra每个 GPU sandbox 都需要的其他设备,例如 /dev/nvidiactl、/dev/nvidia-uvm
mounts以只读方式挂进 sandbox 的宿主机文件或目录(驱动库、nvidia-smi)
shared_slotsgpu_mode: shared 时每块卡最多几个 sandbox,默认 4
pci直通给 fullvm sandbox 的 PCI 设备,例如 ["0000:3b:00.0"](VFIO)

edges[].backends ​

后端名 → 后端配置。后端名就是创建时 backend 的取值,例如:

json
"backends": {
  "microvm":   {"runtime": "firecracker", "max_sandboxes": 4000, "default_disk_mb": 2048,
                "kernel": "/opt/opendsec/current/vm/vmlinux-6.1.167-opendsec",
                "firecracker": "/opt/opendsec/current/bin/firecracker",
                "jailer": "/opt/opendsec/current/bin/jailer",
                "image_pmem": true, "erofs_images": true, "free_page_reporting": true, "cold_age_s": 120},
  "container": {"runtime": "linux", "max_sandboxes": 8000, "default_disk_mb": 1024},
  "fncall":    {"runtime": "linux", "max_sandboxes": 4000, "default_disk_mb": 1024,
                "warm_pool": {"root/py:3.12": 64}}
}

通用字段:

字段默认说明
runtimesimlinux(容器)、firecracker(microVM)、qemu(完整虚拟机)、sim(模拟)
max_sandboxes—这个后端在本机最多同时运行几个 sandbox
default_disk_mb10240请求没有设置 disk_mb 时的可写盘大小
disk_io不限每个 sandbox 的磁盘 IO 上限:{"read_mbps", "write_mbps", "read_iops", "write_iops"},0 为不限
core_sched内核支持时开启每个 sandbox 一个核心调度 cookie:两个 sandbox 不会同时运行在同一个物理核的两个超线程上,关闭超线程侧信道,也让延迟敏感的 sandbox 不受 BE 负载干扰。true 要求内核支持,false 关闭

linux 运行时(container、fncall):

字段默认说明
pids_max4096每个 sandbox 的进程数上限
pause_reclaimfalse暂停时把内存换出到 swap,恢复时提前读回。需要宿主机有 swap,且 vm.swappiness 大于 0
warm_pool—镜像 → 预先启动的个数(fncall 后端)。没有快照、用户、工作目录、路径限制、GPU,并使用默认磁盘的请求直接取一个,几毫秒就能用
layer_cachetrue容器使用镜像层在节点本地的副本(首次使用时复制),镜像库(NFS)中断时运行中的容器不受影响

firecracker 运行时(microvm):

字段默认说明
kernel必填guest 内核(vmlinux)路径
firecracker、jailerPATH 上的同名程序Firecracker 和 jailer 的路径
uid_base1000000000每个 VM 以独立的 uid 运行,取自 [uid_base, uid_base+65536)
vm_overhead_mb64加在 guest 内存上作为 VM 的 cgroup 内存上限(VMM 自身、页表、设备缓冲)
erofs_imagesfalse镜像以 EROFS 盘的形式在镜像库里构建一次,复制到各节点,而不是在每个节点上展平成 ext4。需要支持 EROFS 的 guest 内核和节点上的 mkfs.erofs(erofs-utils)
image_pmemfalse镜像以 virtio-pmem 挂载并用 DAX:同一镜像的 VM 共享宿主机页缓存
free_page_reportingfalseguest 释放的内存通过 virtio-balloon 还给宿主机
cold_age_s0(关闭)大于 0 时,guest 里的 DAMON 把闲置这么久的内存换出到压缩的 zram
zram_pct100zram 大小,占 VM 内存的百分比(0 到 400)
cold_boot_dirty_trackingtrue冷启动的 VM 记录脏页,暂停时只写改动过的页。false 时内存写入更快(宿主机大页),但第一次暂停或快照要写全部内存

image_pmem、free_page_reporting、cold_age_s 需要 OpenDsec 的 guest 内核(deploy/guest-kernel,发布在 GitHub Release)。

qemu 运行时(fullvm):

字段默认说明
qemuPATH 上的 qemu-system-x86_64QEMU 路径
kernel—guest 内核
full_initfalse把 PID 1 交给镜像自己的 /sbin/init(aether 在旁边运行)

sim 运行时:create_latency_ms(创建耗时的中位数,对数正态分布)、latency_sigma、failure_rate,用于调度压测。

fleet ​

集群管理服务,可选。

字段默认说明
replicas—每项 {"id", "addr", "data_dir"};addr 例如 10.0.0.1:7300,data_dir 默认 /var/lib/opendsec/fleet
heartbeat_s10节点代理上报的间隔
lock_ttl10leader 锁的租期
max_downloads64每个副本同时提供的版本下载数
keep_releases10除了正在使用的,额外保留的版本数
edge_port7201edge 在节点私网地址上监听的端口
ready_portsiam 9461、watcher 9462、apiserver 9463、edge 9464、fleet 9465、e2b 9467各角色的 /readyz 端口,节点代理重启服务后用它判断就绪
prometheus_url—发布闸门使用的 Prometheus 地址
gates—发布闸门:[{"name", "query", "max"}]。每批的观察期内,每个 PromQL 的值都必须不大于 max,否则暂停
json
"fleet": {
  "replicas": [{"id": "0", "addr": "10.0.0.1:7300"}, {"id": "1", "addr": "10.0.0.2:7300"}, {"id": "2", "addr": "10.0.0.3:7300"}],
  "heartbeat_s": 10,
  "prometheus_url": "http://10.0.0.3:9090",
  "gates": [{"name": "create errors", "query": "sum(rate(opendsec_apiserver_create_seconds_count{reason!=\"ok\"}[5m]))", "max": 1}]
}

e2b ​

E2B 兼容网关,可选。

字段默认说明
gateways—网关实例:[{"addr", "tls_cert", "tls_key"}]。addr 例如 10.0.0.1:7400;tls_cert 和 tls_key 要么都设置(网关自己提供 HTTPS),要么都不设置(明文 HTTP,在前面的负载均衡上终止 TLS)
project有网关时必填sandbox 创建在这个项目里。请求可以用 X-OpenDsec-Project 头指定别的项目
domain—返回给 SDK 的 sandbox 域名,SDK 会访问 <端口>-<id>.<domain>(需要泛域名解析和证书指向网关)。不设置时客户端设置 E2B_SANDBOX_URL
templates—E2B template id → sandbox 规格。SDK 默认用 base。含 / 的 template id 直接当作镜像名,其余设置取 default_template
default_template—同上,作为默认值
max_timeout_s0(只受准入上限约束)sandbox 超时的上限

template 的字段:

字段默认说明
image必填镜像
backendmicrovm后端
cpu2CPU 核数
memory_mb512内存。镜像是带内存的快照时必须和快照一致
disk_mb后端默认可写盘
start_cmd—每个新 sandbox 里用 bash -l -c 启动的命令(E2B template 的 start command)
ready_port—交给调用方之前等这个端口开始监听
ready_timeout_s60最多等多久

详见从 E2B 迁移。

各组件的启动参数 ​

一般由 systemd unit(deploy/systemd/)传入,不需要手动设置。

程序参数
opendsec-iam-config、-replica <id>(复制模式下运行哪个副本)、-join(新副本:不自举,等 opendsecctl iam member add 加入)、-metrics、-log
opendsec-watcher-config、-replica <id>、-metrics、-log
opendsec-apiserver-config、-index <N>(运行 apiserver 数组的第 N 项)、-drain-delay(收到 SIGTERM 后先让 /readyz 失败、继续服务这么久,默认 6s)、-grace(再给进行中的调用这么久,默认 30s)、-metrics、-pprof、-log
opendsec-edge-config、-id <id>[,<id>...](all 表示配置里的全部;没有列出的 id 用 edge_template)、-addr、-advertise、-metrics、-pprof、-log
opendsec-fleet-config、-replica <id>、-metrics、-log
opendsec-e2b-config、-index <N>、-ca(默认 tls.dir/ca.crt)、-drain-delay(默认 5s)、-metrics、-log
opendsec-nodeagent-config(默认 /etc/opendsec/opendsec.json)、-name、-addr、-fleet、-root(默认 /opt/opendsec)、-check、-metrics、-log

-metrics <地址> 同时提供 /metrics、/healthz 和 /readyz。各角色的默认端口见监控与告警。

基于论文 DeepSeek Elastic Compute (DSec)(arXiv:2609.22978)实现。本项目独立开发,与 DeepSeek 没有关系。