DeerFlow lark-cli init 镜像(Pattern A):用 init 容器 + emptyDir 为 Kubernetes 沙箱预置 lark-cli 运行时
2026/9/5 21:01:43 网站建设 项目流程

DeerFlow lark-cli init 镜像(Pattern A):用 init 容器 + emptyDir 为 Kubernetes 沙箱预置 lark-cli 运行时

【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow

DeerFlow 是一个开源的长程 SuperAgent harness,其飞书/Lark 集成依赖沙箱内可用的lark-cli运行时。本文以 docker/lark-cli-init/README.md 为核心,完整讲解 “Pattern A” 方案:在镜像构建期下载并校验官方larksuite/cliLinux 二进制,在运行期通过 init 容器把运行时复制到共享emptyDir,从而让 Gateway 免去“安装时从 GitHub 下载二进制 + hostPath/PVC 挂载”的环节。读完本文,你能掌握该镜像的构建与版本发布方式、如何把 init 容器接入 provisioner,以及沙箱 PATH 契约(/mnt/integrations/lark-cli/runtime/bin/lark-cli)为何保持不变。

1. Pattern A 要解决什么问题

传统的做法(legacy 路径)是:Gateway 在安装阶段从 GitHub 下载 Linux 二进制,然后通过 hostPath/PVC 把运行时目录挂进沙箱 Pod。这种方式有两个弱点——每次安装都依赖外网下载,并且运行时目录强依赖宿主机路径或 PVC 的可用性。

Pattern A 的思路是把下载前移到镜像构建期,把挂载前移到 init 容器

  • 构建时(有网络):下载官方larksuite/cli的 Linux 发布版二进制并做 SHA-256 校验,把运行时布局暂存到镜像内的/opt/lark-cli

    /opt/lark-cli/bin/lark-cli # 架构分发启动器(按 uname -m 选择) /opt/lark-cli/linux-amd64/lark-cli /opt/lark-cli/linux-arm64/lark-cli /opt/lark-cli/.deerflow-lark-cli-runtime.json # {"version": "vX.Y.Z"}
  • 运行时(无网络依赖):init 容器执行cp -a /opt/lark-cli/. -> ${LARK_CLI_RUNTIME_DEST}(默认/mnt/integrations/lark-cli/runtime),然后以退出码0结束。

这个布局与 Gateway 侧的写入函数_write_lark_cli_sandbox_launcher的产物字节级一致,并且满足_validate_lark_cli_sandbox_runtime的校验,因此无论运行时是由 Gateway 下载写入,还是由 init 容器复制而来,沙箱内的 PATH 契约(/mnt/integrations/lark-cli/runtime/bin/lark-cli)都不变。

2. 镜像构建:源码级剖析

构建入口是 docker/lark-cli-init/Dockerfile,采用多阶段构建:

  1. builder 阶段:基于debian:bookworm-slim,安装ca-certificatescurl,执行 build-runtime.sh 完成二进制下载与暂存。支持APT_MIRROR构建参数替换 Debian 源地址(便于网络受限环境)。
  2. 最终阶段:只从 builder 复制/opt/lark-cli目录和入口脚本 entrypoint.sh,镜像极小、不含网络工具。

2.1 构建期脚本 build-runtime.sh 做了什么

build-runtime.sh 是保证二进制可信的关键,其流程为:

  • 接收LARK_CLI_VERSION(必填,可带或不带前导v,脚本会归一化为vX.Y.Z形式的 tag);

  • larksuite/cli的 GitHub releases 下载checksums.txt,以及lark-cli-<version>-linux-{amd64,arm64}.tar.gz两个资产;

  • 逐个校验 SHA-256:从checksums.txt中查找对应资产的期望哈希,与本地sha256sum结果比对,不一致即报错退出——这是“SHA-256-verifies”这一说法的实现落点;

  • 从压缩包中只提取lark-cli可执行文件,install -m 0755<dest>/linux-<arch>/lark-cli

  • 生成架构分发启动器<dest>/bin/lark-cli

    #!/bin/sh set -eu case "$(uname -m)" in x86_64|amd64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; *) echo "Unsupported sandbox architecture: $(uname -m)" >&2; exit 126 ;; esac script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) exec "$script_dir/../linux-$arch/lark-cli" "$@"

    该启动器按uname -mx86_64/amd64 → amd64aarch64/arm64 → arm64之间分发,未知架构以退出码126失败。脚本注释明确要求它与 Gateway 中LARK_CLI_SANDBOX_LAUNCHER_SCRIPT(定义于 backend/packages/harness/deerflow/integrations/lark_cli.py)保持字节级一致,并且 backend/tests/test_lark_cli_integration.py 中的单元测试会断言两者永不漂移(drift)。

  • 最后写出清单文件.deerflow-lark-cli-runtime.json(内容形如{"version": "v1.0.65"}),供 Gateway 的运行时校验识别版本。

2.2 运行期入口 entrypoint.sh

entrypoint.sh 逻辑非常短小且防御式:

  • /opt/lark-cli/bin/lark-cli不存在或不可执行,打印错误并exit 1(init 容器失败会阻塞整个 Pod 启动,快速失败优于静默缺二进制);
  • mkdir -p目标目录后cp -a "${SRC}/." "${DEST}/",注意/.会把点文件清单.deerflow-lark-cli-runtime.json)一并复制;
  • 打印ls -R输出便于通过kubectl logs排查。

目标目录由环境变量LARK_CLI_RUNTIME_DEST指定,Dockerfile 中默认值为/mnt/integrations/lark-cli/runtime

3. 构建与发布镜像

按 README 的说明,本地构建命令为:

docker build -t deer-flow/lark-cli-init:v1.0.65 \ --build-arg LARK_CLI_VERSION=v1.0.65 \ docker/lark-cli-init

两个值得注意的版本策略:

  • 镜像 tag 编码 lark-cli 版本(如v1.0.65),这样 lark-cli 升级可以独立于上游all-in-one-sandbox沙箱镜像单独 bump;
  • CI 发布多架构镜像.github/workflows/lark-cli-images.yaml(该 workflow 文件确实存在于仓库.github/workflows/lark-cli-images.yaml)会以linux/amd64,linux/arm64双架构发布到ghcr.io/<owner>/deer-flow-lark-cli-init:<lark-cli-version>。触发方式为手动传入lark_cli_version输入,或推送lark-cli-v*形式的 tag。该发布流程与 DeerFlow 自身的v*release 解耦,因为镜像追踪的是上游larksuite/cli的版本——RELEASING.md 也确认该镜像有自己的verify-versions版本门禁,且版本号取 lark-cli 发布版而非 DeerFlow 发布版。

4. 接入 provisioner:opt-in 且默认关闭

init 容器路径是显式 opt-in:不配置就是旧行为,零风险。接入方式:

  1. 在 provisioner 服务上设置LARK_CLI_INIT_IMAGE,指向已发布的 tag,例如deer-flow/lark-cli-init:v1.0.65。留空(默认)⇒ 走 legacy 的 hostPath / Gateway 下载路径,行为完全不变。
  2. 配置后 provisioner 的行为变化(源码位于 docker/provisioner/app.py):
    • 环境变量读取:LARK_CLI_INIT_IMAGE = os.environ.get("LARK_CLI_INIT_IMAGE", ""),同时定义运行时容器路径常量LARK_CLI_RUNTIME_CONTAINER_PATH = "/mnt/integrations/lark-cli/runtime"与卷名lark-cli-runtime
    • 使能判断:_lark_cli_runtime_enabled()返回bool(LARK_CLI_INIT_IMAGE) and provision_lark_cli_runtime——即“镜像已配置”且“创建请求带provision_lark_cli_runtime: true”两个条件同时成立才生效(Gateway 在托管 Lark 技能包安装后会自动发送该标志,见 docker/provisioner/README.md);
    • 满足条件时,provisioner 会添加:一个lark-cli-runtimeemptyDir卷、一个名为lark-cli-init的 init 容器(image_pull_policy=IfNotPresent,注入LARK_CLI_RUNTIME_DEST环境变量并挂载该卷、使用安全加固的 security context),以及沙箱主容器上的只读运行时挂载;
    • 此时会忽略任何指向/mnt/integrations/lark-cli/runtime的 hostPath/PVC extra mount(init 容器路径取代它);而 per-user 的config/data凭据挂载不受影响,照旧挂入沙箱;
    • 若同时配置了 Pattern B 的 broker 镜像,broker 优先_build_lark_cli_init_containers中 broker 分支先于 runtime 分支返回)。
  3. 就绪信号上报:provisioner 通过GET /api/capabilities报告{"lark_cli_init_image": true|false}(源码中该端点返回lark_cli_init_imagelark_cli_broker_image两个布尔值);Gateway 把它作为 Lark 集成的沙箱运行时就绪信号,暴露在GET /api/integrations/lark/status上。从源码结构看,Gateway 的 lark_cli.py 按优先级判定:broker 已配置 ⇒"broker"模式;否则 init 镜像已配置 ⇒"init-container"模式;都未配置则sandbox_runtime_ready=false并给出 “The provisioner has no lark-cli runtime image configured (LARK_CLI_INIT_IMAGE / LARK_CLI_BROKER_IMAGE)” 的提示。这样设置页 UI 能如实显示聊天时lark-cli是否真的存在于沙箱内,避免“状态绿色、聊天时报 command not found”的假就绪(README.md 主文档对此有同样的描述)。

在 docker/docker-compose.yaml 与 docker/docker-compose-dev.yaml 中,provisioner 服务已预留- LARK_CLI_INIT_IMAGE=${LARK_CLI_INIT_IMAGE:-}环境变量(默认空),与 docker/provisioner/README.md 的环境变量表一致:LARK_CLI_INIT_IMAGE默认空(feature off)。

5. 测试与验证

该特性的行为契约由测试固化在 backend/tests/test_provisioner_pvc_volumes.py:

  • test_no_init_container_when_image_unsetLARK_CLI_INIT_IMAGE为空时,即使请求带provision_lark_cli_runtime=True,Pod 中也不出现 init 容器;
  • test_no_init_container_when_flag_disabled:镜像已配置但请求不带标志时同样不注入;
  • test_init_container_and_emptydir_when_enabled:两者齐备时,Pod 得到 init 容器 +emptyDir
  • test_runtime_extra_mount_dropped_when_init_container_enabled:init 容器启用时,指向运行时路径的 extra hostPath 挂载被丢弃;
  • “双镜像双标志”用例断言 broker 胜出(shim init + sidecar),印证第 4 节的优先级。

6. 小结:何时使用 Pattern A

  • 适用场景:Kubernetes 沙箱部署、希望消除安装期外网下载依赖、节点不便于维护 hostPath/PVC 运行时目录的飞书/Lark 集成环境;
  • 启用步骤:构建并发布镜像(tag 编码 lark-cli 版本)→ provisioner 设置LARK_CLI_INIT_IMAGE→ 通过/api/capabilities/api/integrations/lark/status验证sandbox_runtime_ready
  • 不配置时:完全回落到 legacy hostPath / Gateway 下载路径,无行为变化——这是该设计明确的 opt-in 承诺;
  • 后续演进:若目标是让appSecret/OAuth 令牌文件完全不进入沙箱文件系统,仓库提供了 Pattern B(docker/lark-cli-broker),其 broker 模式在两者同时配置时取代 Pattern A。

【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询