跳至内容

Docker 部署

大多数部署场景下,最快的方式是使用 Docker Compose。 本页介绍与之等价的纯 docker build / docker run 流程、运行时镜像基线(镜像内置了哪些 工具以及为什么)、在内网受限环境下可覆盖的构建参数,以及两种基于容器的沙箱后端。

终端窗口
# 在仓库根目录构建镜像
docker build -t aicodereviewer -f deploy/Dockerfile .
# 运行
docker run -d \
--name aicr \
--init \
--env-file example/.env \
-p 8080:8080 \
-v $(pwd)/example/config.yaml:/app/config.yaml:ro \
-v aicr-data:/app/data \
-v aicr-workspaces:/app/workspaces \
-v aicr-logs:/app/logs \
aicodereviewer
宿主侧 容器路径 模式 用途
example/config.yaml /app/config.yaml :ro 主配置 — LLM、triggers、outputs、workspaces
aicr-data /app/data rw 持久化队列数据库、运行历史、SQLite 存储
aicr-workspaces /app/workspaces rw 克隆仓库 / 检出缓存
aicr-logs /app/logs rw 应用日志文件

config.yaml 以只读方式挂载是有意为之:它应当只包含环境变量名,绝不含密钥值 (参见 身份认证与密钥)。密钥本身通过 --env-file example/.env 注入 — 该文件不挂载进容器文件系统,Docker 在宿主侧读取它, 并把变量注入到进程环境中。

容器对外暴露端口 8080(-p 8080:8080),并提供 /healthz 用于健康检查。Compose 文件把 它接到了 healthcheck 块中;如果是纯 docker run,请把你的探针指向 http://localhost:8080/healthz。

镜像有意采用 debian:trixie-slim 作为发行版基线,并从官方 node:lts-trixie-slim 镜像拷贝 Node LTS 用户态(当前为 Node 24),构建与运行两个阶段共享同一 Debian trixie 基线。AICR 仍安装 官方 Perforce APT 包(p4-cli):Perforce 只发布 Ubuntu 代号仓库(已验证最新为 noble), 该构建可直接运行在 trixie 更新版 glibc 上。Perforce 包需要 glibc 和 Debian 系的包布局 — Alpine 风格的基线满足不了这一点。

按用途分组的运行时工具基线:

分组 工具
版本控制 git、git-lfs、subversion、p4
搜索与检视 rg、fd、bat、eza、jq、tree、erd、dust、duf、hexyl、universal-ctags
文本与结构化数据 sd、ugrep、Mike Farah yq、jaq、miller
diff 与日志 delta、difft、lnav、tspin
下载与网络 aria2、xh、doggo
进程、监听与基准 procs、watchexec、hyperfine、fzf
压缩与归档 pigz、zstd、ouch
Kubernetes 与 YAML kubectl、helm、Mike Farah yq;当不需要独立的 kustomize 二进制时,使用 kubectl kustomize 处理 Kustomize overlays
容器客户端 podman、buildah、skopeo,外加一个可选的 Docker 静态 CLI,用于 Docker 兼容 socket 工作流
构建与静态分析 build-essential、cmake、ninja、pkg-config、clang、clang-format、clang-tidy、cppcheck
Python python3、python、pip、venv、Python 头文件、setuptools、wheel
调试与排障 gdb、valgrind、shellcheck、strace、lsof、inotify-tools、curl、wget、dnsutils、iputils-ping、iproute2、tcpdump、netcat-openbsd、openssl
数据与同步 sqlite3、rsync、xxd、bsdextrautils
补丁与归档 diffutils、patch、unzip、zip、xz、tar、gzip、bzip2、zstd、lz4

大多数现代 CLI 工具直接来自 Debian trixie apt 仓库。trixie 未收录的工具 (doggo、jaq、difftastic、ouch、watchexec、erdtree → erd)以及 trixie 只有旧版的工具(dust、xh、procs、tailspin → tspin)在 amd64/arm64 上以 固定版本从上游 GitHub Releases 静态二进制安装;其他架构跳过该层。tokei、qsv、 plocate 有意排除:tokei 自 v13 起上游不再发布二进制,且 trixie 包停留在 2023 年的 12.1.2;qsv 静态二进制约 100 MB,对已内置的 miller 来说过重;plocate 需要容器内 永远不会构建的 updatedb 索引。

Debian 包提供的是 fdfind 和 batcat。镜像添加了兼容性符号链接 (fd、bat),这样 agent 的提示词就能一致地引用这些名字。容器还直接内置了 p4,因此部署 不再依赖 bind-mount 宿主侧的 Perforce 二进制。

以下参数均为可选。当你的网络无法访问上游镜像源,或想锁定到不同版本时,用 docker build --build-arg ... 覆盖它们。

构建参数 默认值 用途
BASE_IMAGE debian:trixie-slim 构建与运行时阶段的发行版基线
NODE_IMAGE node:lts-trixie-slim 作为 Node 用户态来源的官方 Node LTS 镜像(当前为 Node 24)。当宿主已经通过全局镜像源重写 registry 拉取时,可省略/保持默认
APT_MIRROR (空) Debian apt 主档案镜像根,例如 http://mirrors.ustc.edu.cn/debian;security 条目自动追加 -security 后缀
PERFORCE_APT_DISTRO noble Perforce APT 仓库的 Ubuntu 代号(Perforce 只发布 Ubuntu 源,noble 构建可在 trixie 上运行)
NPM_REGISTRY https://registry.npmjs.org npm/pnpm registry
NPM_STRICT_SSL true 使用 HTTP 镜像时设为 false
PIP_INDEX_URL https://pypi.org/simple pip simple index URL
KUBERNETES_APT_REPO_BASE https://pkgs.k8s.io/core:/stable: kubectl APT 仓库基址(必须以 core:/stable: 结尾)
KUBERNETES_APT_REPO_VERSION v1.36 kubectl 对应的 Kubernetes 小版本仓库
HELM_APT_REPO https://packages.buildkite.com/helm-linux/helm-debian/any/ Helm Debian 包仓库
HELM_APT_KEY_URL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey Helm 仓库签名密钥
YQ_VERSION v4.53.2 Mike Farah yq 发布版本
YQ_DOWNLOAD_BASE https://github.com/mikefarah/yq/releases/download yq release 下载基址
GH_RELEASE_PREFIX (空) 作用于固定版本静态 CLI 工具(dust、xh、doggo、jaq、difftastic、ouch、procs、watchexec、tailspin、erdtree)GitHub release 下载的 URL 前缀;github.com 不可达时设置为 ghproxy 风格前缀或内部缓存根

以下是 deploy.sh 的环境变量(不是 Dockerfile ARG),仅在嵌套容器沙箱下载可选 Docker 静态 CLI 时使用:

变量 默认值 用途
DOCKER_DOWNLOAD_MIRROR https://download.docker.com/linux/static/stable/x86_64 deploy.sh 下载可选 Docker 静态 CLI 时使用的镜像源

APT_MIRROR 指向 Debian 主档案根(例如 http://mirrors.ustc.edu.cn/debian); deploy/Dockerfile 会把 security 条目派生为同一镜像根加 -security 后缀 (http://mirrors.ustc.edu.cn/debian-security),并在第一次 apt-get update 之前 同时重写 deb822 格式的 debian.sources 和旧式 sources.list,因此一个 HTTP 镜像值 即可工作,无需提前引导 CA。Debian 所有 release 架构共用一个档案根 — 没有 Ubuntu ubuntu-ports 那样的架构分流。

对于腾讯云镜像,Kubernetes 路径为 kubernetes_new(通过 KUBERNETES_APT_REPO_BASE 设置)。 未验证有专门的 mirrors.tencent.com/helm/、mirrors.tencent.com/yq/ 或 GitHub release 端点 — 如果要完全在内网构建,请把 Helm/yq 参数指向一个保留相同仓库布局的内部缓存,并设置 GH_RELEASE_PREFIX 为镜像前缀(或依赖 deploy.sh 的构建期代理自动探测)来覆盖从 GitHub Releases 下载的固定版本静态 CLI 工具。

如果你的构建宿主通过使用私有根 CA 的企业代理或本地镜像访问外部 HTTPS,请在构建前把所需的 .crt 文件拷贝到 deploy/extra-ca/:

终端窗口
cp /etc/ssl/certs/my-corporate-root.crt deploy/extra-ca/
docker build -t aicodereviewer -f deploy/Dockerfile .

deploy/Dockerfile 会在拉取任何外部密钥、npm 包或 release 制品之前,把 deploy/extra-ca/ 拷贝到 /usr/local/share/ca-certificates/ 并执行 update-ca-certificates,这样后续构建就信任 你的私有根证书。

如果部署宿主在 TCP 3128 上暴露了 HTTP 代理,deploy.sh 会自动探测到,并把它用于宿主侧下载 以及 podman build / docker build 的拉取。显式的 HTTP_PROXY / HTTPS_PROXY / NO_PROXY 环境变量始终优先于自动探测;如果代理只监听回环地址(127.0.0.1:3128),构建会自动切换到 host networking,以便 Dockerfile 的 RUN 步骤仍能访问它。

AICR 可以把每个 agent 运行隔离在独立的容器中。当服务本身运行在 Docker 内时,有两种容器后端相关。

docker_socket 遵循与 docker 相同的容器运行规则,但用于标识通过 Unix socket 访问 Docker 守护进程的 运行。当服务本身运行在一个挂载了 /var/run/docker.sock 的容器内时,配置它:

agent:
sandbox:
kind: docker_socket
engine: docker
image: ghcr.io/owent/aicr-agent:latest

无需额外的 Docker Engine API 客户端 — AICR 调用 docker CLI,并依赖服务容器能访问到宿主 socket。

Socket 即特权访问

挂载 /var/run/docker.sock 等于把宿主 Docker 守护进程的完整、root 等效控制权交给了容器。仅在你 完全可控的宿主上这样做。威胁模型见 运维与安全。

嵌套容器沙箱(AICR 运行在容器内)

Section titled “嵌套容器沙箱(AICR 运行在容器内)”

当 AICR 本身运行在容器内,且你希望沙箱为 agent 隔离派生子容器时,在 deploy.sh 中启用嵌套容器 沙箱:

终端窗口
AICR_ENABLE_CONTAINER_SANDBOX=true bash deploy/deploy.sh

这会告诉 deploy.sh:

  1. 当需要 Docker 兼容 socket 客户端时,把 Docker 静态二进制下载到构建上下文中。
  2. 把宿主用户级 Podman socket 挂载进 AICR 容器。
  3. 为原生 podman CLI 设置 CONTAINER_HOST,为 Docker CLI 设置 DOCKER_HOST,使两者都路由到 宿主 Podman 服务。
  4. 添加 --userns=keep-id --group-add keep-groups,使容器用户能访问该 socket。

当嵌套容器沙箱未启用时,deploy.sh 仍会创建一个空的 deploy/docker-static 占位文件,以保证 干净的同步不会让 Dockerfile 的可选 COPY 步骤失败。运行时镜像会移除这个空占位文件,而不是安装一个 0 字节的 docker 可执行文件。

启用宿主用户级 Podman socket(rootless):

终端窗口
systemctl --user enable --now podman.socket

然后,当通过宿主 Podman socket 审查容器化工作负载时,优先使用原生 Podman:

agent:
sandbox:
kind: podman
engine: podman

对于 Docker 兼容工作流,设置 sandbox.kind: docker,让容器内的 Docker CLI 通过 DOCKER_HOST 与 Podman 通信:

agent:
sandbox:
kind: docker
engine: auto

完整的 Podman rootless 配置、运行时保证、SELinux 注意事项,以及 --storage-driver=overlay 故障恢复要点,请见 Podman 页面。

agent.timeout_seconds 是对一次 agent 运行的硬性上限。触发时,沙箱会杀死整个进程树 — agent 二进制及其 worker 子进程 — 而不仅仅是直接子进程,因此一次运行无法通过遗留孤儿 worker 来超支预算。

如果审查看起来卡住,或在多次重试间变得越来越慢,原因通常是逃过了进程树清理的遗留 agent 进程 (这正是 --init 重要的原因)。重启 AICR 容器 — 运行时会在重启时回收任何遗留的 agent 进程。