Skip to content

命令行参考:opendsecctl ​

opendsecctl 是 OpenDsec 的命令行工具,管理员和调用方都用它:创建和操作 sandbox、管理镜像、项目、身份和 token、查看集群、签发证书、管理集群版本(fleet)。

opendsecctl <命令> [参数] [选项]
opendsecctl help                 # 列出全部命令
opendsecctl fleet                # fleet 子命令的帮助
  • 安装后在 /usr/local/bin/opendsecctl(单机安装)或 /opt/opendsec/current/bin/opendsecctl(集群节点);运维机上是 $OPENDSEC_OPS/current/bin/opendsecctl。
  • 选项可以写在位置参数前面或后面,例如 opendsecctl sandbox stop <id> -addr x 和 opendsecctl sandbox stop -addr x <id> 等价。
  • 除特别说明外,命令的输出是 JSON(protobuf 的 JSON 形式,值为默认值的字段省略)。
  • 命令成功时退出码为 0,失败时打印 error: <reason>: <说明> 并以非 0 退出。exec 以命令自己的退出码退出。

连接与环境变量 ​

选项环境变量默认说明
-addrOPENDSEC_ADDR—apiserver 地址,多个用逗号分隔
-tokenOPENDSEC_TOKEN—token。建议用环境变量,避免出现在 shell 历史和进程列表里
-projectOPENDSEC_PROJECTroot默认项目
-caOPENDSEC_CA—集群 CA 证书,设置后使用 TLS
-storeOPENDSEC_IMAGE_STORE—镜像库的挂载点(image import、image gc、image store-check)
-deadline—5m整个命令的时限;image import 默认不限

单机安装后,管理员和调用方的环境分别在:

sh
. /root/opendsec-ops/env         # 管理员:admin token,项目 root
. /root/opendsec-ops/demo.env    # 调用方:项目 root/demo 的 token,以及 E2B SDK 的变量

sandbox ​

sandbox create ​

opendsecctl sandbox create -backend <后端> [-image I] [-cpu N] [-mem MB] [-disk MB] [-gpus N]
                           [-task T] [-ttl-idle S] [-ttl-max S] [-net 规则,...] [-count N]
选项默认说明
-backendsimmicrovm、container、fncall、fullvm、sim。默认 sim 只模拟,实际使用必须指定
-image—镜像,例如 root/py:3.12
-cpu1CPU 核数
-mem1024内存 MB
-disk0可写盘 MB,0 为后端默认
-gpus0GPU 个数
-task—任务名
-ttl-idle0空闲超时(秒),0 为集群默认
-ttl-max0最长寿命(秒),0 为集群默认
-net—网络规则,逗号分隔;!规则 表示收回集群默认里的一项,例如 -net 'pypi,github.com:443,!npm'
-count1批量创建的个数

-count 1 时输出 sandbox 的 JSON;-count 大于 1 时每行输出一个结果(序号<TAB>id,失败的是 序号<TAB>error<TAB>原因: 说明),最后一行是汇总:

$ opendsecctl sandbox create -backend microvm -image root/py:3.12 -count 3 -task job-1
0	node-a1.4k2m…
1	node-b1.9xq1…
2	node-a1.p0zz…
created 3/3 in 412ms; failures: map[]

在脚本里取 id:

sh
ID=$(opendsecctl sandbox create -backend microvm -image root/py:3.12 | grep -m1 '"id"' | cut -d'"' -f4)

sandbox get | stop | pause | resume | touch <id> ​

查看、停止、暂停、恢复、刷新空闲计时。输出更新后的 sandbox。

sandbox list [-task T] [-all] ​

列出 -project 及其子项目里的 sandbox;-task 只列这个任务的,-all 包括最近结束的。

sandbox fork <id> [-count N] [-task T] [-ttl-idle S] [-ttl-max S] ​

把运行中的 sandbox 复制成 N 个(1 到 256),输出格式同批量创建。

sandbox network <id> <规则>... [-replace] ​

修改网络规则:pypi 放行,!pypi 收回。默认合并进现有规则,-replace 整体替换。

sh
opendsecctl sandbox network $ID pypi github.com:443
opendsecctl sandbox network $ID '!github.com:443'
opendsecctl sandbox network $ID '*' -replace          # 只放行全部公网

exec <id> [-session S] [-user U] [-timeout S] [--] <命令...> ​

在 sandbox 里执行命令,实时输出 stdout 和 stderr,以命令的退出码退出。

  • 只有一个参数时,它是一整条 shell 命令,由 sandbox 里的 shell 解释:opendsecctl exec $ID 'cd /srv && make test | tail'。
  • 多个参数时,像 ssh 和 docker exec 一样,每个参数各自加引号后拼成命令:opendsecctl exec $ID python3 -c 'print(6*7)' 在 sandbox 里执行的就是 python3 -c 'print(6*7)'。
  • 参数里有以 - 开头的(例如 ls -la),在命令前加 --,避免被当成 opendsecctl 的选项:opendsecctl exec $ID -- ls -la /。
  • -session:会话名,默认 default;-user:会话第一次执行时的用户;-timeout:秒,超时后打印 opendsecctl: command timed out。

0.11 之前的版本把多个参数直接用空格连接,不加引号。当时为了绕开这个问题多加的一层引号(例如 "'print(6*7)'")现在要去掉。

cp <id>:<路径> <本地文件> / cp <本地文件> <id>:<路径> ​

在本机和 sandbox 之间复制单个文件。一次最多复制 64 MB;更大的文件用 SDK 分段读写。

任务 ​

opendsecctl task pause|resume|stop <任务名>

对 -project 里这个任务的所有 sandbox 执行操作,输出成功和失败的个数。

镜像 ​

image import <来源> -as <项目>/<名字>:<标签> -store <镜像库> ​

把镜像导入共享镜像库并登记。要在挂载了镜像库的机器上以 root 运行,并且需要目标项目上的 layer.publish。

来源可以是:

来源例子
公共仓库docker.io/library/python:3.12、python:3.12、ghcr.io/org/image:tag
私有仓库harbor.example.com/team/app:1.0
不带 TLS 的仓库加 -plain-http
OCI layout 目录或 tar./python-3.12.oci.tar
docker save 生成的 tar./app.tar;文件里有多个镜像时用 文件#名字 选一个

本地文件路径要以 / 或 . 开头,文件不存在时直接报错(不会去仓库下载)。

私有仓库的凭据,按以下顺序查找:

  1. -username U -password-stdin:密码或访问令牌从标准输入读,例如 echo "$TOKEN" | opendsecctl image import ... -username 'robot$ci' -password-stdin;
  2. -registry-auth FILE:docker 格式的凭据文件;
  3. $REGISTRY_AUTH_FILE、$DOCKER_CONFIG/config.json、~/.docker/config.json(docker login 保存的凭据)。

导入不设总时限(大镜像可能要很久),进度打印到标准错误。

image save <来源> -out <文件> ​

把仓库里的镜像保存为 OCI tar,供不能上网的机器用 image import ./文件 导入。不需要连接集群。支持 -plain-http、-username、-password-stdin。

image compose <新镜像> <part>... [-overwrite] ​

把多个镜像从底到顶叠成一个,不复制数据:

sh
opendsecctl image compose root/rl/swe-4821:v1 root/rl/python:3.12 root/rl/django-ws:a1b2 root/tools/agent-kit:3

image list [-project P]、image get <名字>、image delete <名字> ​

列出项目及其子项目的镜像;查看一个镜像;删除镜像的登记(层由 image gc 回收)。

image pack <sandbox-id> <新镜像> [-scrub a,b] [-overwrite] ​

即 pack_diff:把 container sandbox 相对它启动镜像的改动保存为新镜像,默认清理 /tmp、缓存和 shell 历史,-scrub 追加路径(相对 / 的 glob)。

image snapshot <sandbox-id> <新镜像> [-memory] [-overwrite] ​

把 sandbox 原样保存为镜像。microVM 必须加 -memory(连同内存)。

image gc -store <镜像库> [-grace 24h] [-dry-run] ​

删除没有任何镜像引用的层和快照。比 -grace 新的不删(默认 24 小时),避免删掉正在导入或刚创建的数据。先用 -dry-run 看会删什么。需要设置连接参数,但只在镜像库上操作。

image store-check -store <目录> ​

检查一个文件系统(例如新挂的 NAS)能否用作镜像库:权限、硬链接、重命名、xattr、稀疏文件等。必需项全部为 ok 才能使用。不需要连接集群。

$ opendsecctl image store-check -store /mnt/opendsec-images
ok    write, sync and read back a file
ok    files a root process creates are root's (no root squash)
ok    chown to another user (image files keep their owners)
ok    exclusive create (one edge builds a VM disk at a time)
ok    rename a file over another (manifests, records)
ok    rename a directory (layers are published so)
ok    hard links (snapshots link their disks)
ok    symbolic links
ok    finds the holes of sparse files (snapshots move only their data; NFS needs vers=4.2)
ok    0:0 character devices (layer whiteouts)
ok    overlay over layers kept here, whiteouts honored
ok    trusted.* xattrs
ok    user.* xattrs
/mnt/opendsec-images can hold the image store

不是必需的项(例如稀疏文件的空洞、trusted.* xattr)失败时只给出提示,仍然可以使用;必需项失败时不能用作镜像库。

项目、身份、权限与 token ​

命令说明
project create <上级> <名字> [-quota k=v,...]建子项目,例如 project create root team-a -quota sandboxes=1000,cpu_cores=4000,memory_mb=4096000
project get <路径>项目详情:配额、当前用量、各身份的权限、子项目
project delete <路径>删除空项目
principal create <项目> <id> [-kind agent|user|service] [-ttl S]建身份,输出里的 token 只显示这一次
principal delete <id>删除身份及其全部 token
grant <项目> <身份> <权限>[,<权限>...]授予权限,例如 grant root/team-a trainer sandbox.create,sandbox.operate
revoke <项目> <身份> [<权限>,...]收回权限,不写权限时收回全部
token create [<身份>] [-ttl S] [-desc D]签发 token,默认给自己
token list [<身份>]列出 token(不含密钥)
token revoke <身份> <token-id>撤销,约 1 秒内全集群生效。primary 指旧格式的主 token
whoami当前 token 对应的身份
usage [<项目>] [-from YYYY-MM-DD] [-to YYYY-MM-DD] [-daily] [-csv]用量:默认每个项目在这段时间的合计;-daily 按天、按项目;-csv 输出 CSV

配额的键:sandboxes、cpu_cores、memory_mb、gpus。权限的含义见项目、身份与权限。

集群 ​

命令说明需要
status集群快照:每个 edge 的健康、排空、容量、已分配、sandbox 数、内存和磁盘余量、压力—
edge drain <edge-id> [-undo]停止(-undo 恢复)往这台 edge 调度新 sandbox,已有的照常运行root 上的 project.admin
iam backup -out FILE备份 IAM(gzip 的 JSON,权限 0600):身份、项目、权限、配额、token 哈希root 上的 project.admin
iam restore FILE用备份替换 IAM 的内容(正在运行的 sandbox 的配额租约保留)同上
iam members列出 IAM 的 Raft 副本同上
iam member add <id> -raft-addr H:P -iam-addr H:P加入一个以 opendsec-iam -join 启动的副本同上
iam member remove <id>移除一个副本(例如机器已经不在了)同上
version本程序的版本—

证书 ​

不需要连接集群。

命令说明
pki init -config opendsec.json -out DIR [-days 365] [-ca-days 3650] [-hosts h1,h2]生成集群 CA 和配置里每个组件的证书。-hosts 给每张证书加上额外的主机名或 IP
pki ca -out DIR [-days N]只生成新 CA(用于轮换 CA)
pki issue -ca DIR -role <角色> -id <id> [-hosts ip1,ip2] -out DIR [-days 365]给一个组件签证书。角色:edge、apiserver、watcher、iam、fleet、node、ops

生产集群一般用 opendsecops certs,它会调用这些命令,见多机集群部署。

本地集群与基准 ​

命令说明
cluster up在当前进程里运行一整个集群,用于开发和测试
bench在进程内的模拟集群上做调度基准;-compare 对比随机放置和 power-of-2

cluster up 的选项:

选项默认说明
-config生成的模拟集群集群配置文件
-sim-edges4没有 -config 时模拟的 edge 个数
-apiservers1没有 -config 时 apiserver 的个数
-runtimesim生成的集群里 container 后端的运行时:sim 或 linux(真实容器,需要 root)
-microvm-kernel—同时提供 microvm 后端,使用这个 guest 内核
-image-store—共享镜像库目录(启用镜像库、pack_diff)
-state-dir/var/lib/opendsecsandbox 状态目录(linux 运行时)
-host-imagetrue提供开发用的 host 镜像(宿主机的 / 作为只读底层,会暴露宿主机文件,只用于开发)
-disk-reserve-mb512状态目录剩余空间低于此值时拒绝创建,-1 关闭
-tlsfalse生成 CA 和证书,以 mTLS 运行
-audit-dir—apiserver 审计日志目录
-metrics—Prometheus 指标地址,例如 :9464
-write-config—把实际使用的配置(含绑定的地址)写到这个文件
-loginfo日志级别
sh
./bin/opendsecctl cluster up -sim-edges 1 -runtime linux -image-store /mnt/opendsec-images \
    -microvm-kernel /opt/opendsec/vm/vmlinux-6.1.167-opendsec
# 按输出设置 OPENDSEC_ADDR、OPENDSEC_TOKEN、OPENDSEC_PROJECT

fleet:集群版本和配置 ​

经 apiserver 访问,需要 root 上的 fleet.view(查看)或 fleet.operate(操作);project.admin 两者都包括。所有操作都写入审计日志。

命令说明
fleet nodes [-state S] [-role R] [-domain D]列出机器:状态、故障域、角色、期望版本、实际版本、单元就绪数、最后心跳
fleet node get <名字>一台机器的详情
fleet node accept <名字> -roles edge=<id>[,...] [-domain D] [-addr-ip IP] [-labels k=v,...]接纳新上报的机器,下发当前版本和配置并启动
fleet node set <名字> [-roles ...] [-domain D] [-addr-ip IP] [-labels k=v,k=]修改角色、故障域、标签(k= 删除标签)。只改记录,不部署
fleet node sync <名字>把这台机器同步到它应有的版本、配置和角色
fleet node cordon | uncordon <名字>暂停、恢复往它调度
fleet node evacuate <名字> [-deadline 1h]cordon,然后等它上面的 sandbox 全部结束
fleet node retire <名字>下线:停止并禁用它的组件
fleet node pin <名字> [-reason R]、unpin <名字>锁定、解锁:锁定的机器不参与 rollout
fleet import -inventory FILE -release V [-config-gen G] [-domain D]登记已经在运行版本 V 的机器(从 opendsecops 迁移时用)
fleet releases已上传的版本
fleet release pack -bin DIR -units DIR [-deps DIR] -out DIR打包版本目录(通常用 opendsecops release)
fleet release push <版本目录> [-notes N]上传版本到 fleet 的所有副本
fleet config put <cluster.json> [-note N]上传新的集群配置,生成新的配置代数
fleet config get [-gen N] [-out FILE]取出某一代配置
fleet rollout create [-release V] [-config-gen G] [...]发起升级或配置变更,见下表
fleet rollout status [<id>] [-steps]查看进度,默认最新的一次;-steps 列出每台机器
fleet rollout pause | resume | abort | rollback <id>暂停、继续、中止、回滚
fleet rollouts历次 rollout

fleet rollout create 的选项:

选项说明
-release V、-config-gen G目标版本、目标配置代数(至少一个)
-roles、-domains、-nodes、-labels只对这些角色、故障域、机器、标签的机器做
-canary N先单独升级的试点台数,默认 1;-1 表示不要试点
-bake S试点和每批升级后的观察时间(秒),默认 300;-1 表示不观察
-batch N每批的台数,默认非控制面机器数的 5%(至少 1,最多 100)
-max-per-domain N每批里同一故障域最多几台,默认每批台数的一半(至少 1)
-pause S批与批之间的间隔(秒),默认 60;-1 表示不间隔
-max-failures N允许失败的台数,超过就暂停;默认 0,即第一台失败就暂停
-step-timeout S单台机器的超时(秒),默认 600
-note N备注

apiserver 全部不可用时,在运维机上用 ops 证书直连 fleet:

sh
opendsecctl fleet nodes -direct -fleet 10.0.0.1:7300,10.0.0.2:7300 -pki $OPENDSEC_OPS/pki -ops-id ops

完整的发版流程见运维手册 §6。

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