- 人工智能
- AI Agent
- 代码智能体
- 自主智能体
- MCP Clients
- CLI
【免费下载链接】atomcode
Claude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get Started
本篇技术指南以 atomcode 仓库中crates/atomcode-review/rules/dockerfile.md的语言评审清单为核心,系统讲解 AtomCode 只读代码评审 agent 在审查包含 Dockerfile 的变更批次时,会重点检查的三类问题:安全(root 运行、密钥烘焙、未固定镜像标签)、正确性与镜像体积(缓存失效顺序、apt 清理、层合并)、运行时(shell 形式 CMD/ENTRYPOINT 的信号吞噬、EXPOSE/healthcheck/WORKDIR)。读完本文,你将掌握 Dockerfile 评审的完整检查框架,了解这些规则如何被注入到评审任务的系统提示中,并能对照仓库内真实 Dockerfile 实例自查镜像构建配置。
一、规则从何而来:Dockerfile 评审规则在 AtomCode 中的运作机制
crates/atomcode-review是 AtomCode 的只读代码评审特化层(L2),它把中立内核(atomcode-kernel)与能力层(atomcode-capabilities)组装成一个只读评审 agent。与评审语言规则相关的关键机制位于 rules.rs:
- 规则文档编译期内置:
crates/atomcode-review/rules/*.md是语言规则的"单一事实来源",通过include_str!编译进二进制(见 rules.rs 中的RULE_DOCS表)。dockerfile.md即其中的("dockerfile", include_str!("../rules/dockerfile.md"))条目。 - 文件名匹配:评审 agent 从 diff 的
+++ b/<path>行解析变更文件集合,然后用MATCHERS有序表做首匹配。Dockerfile 相关规则覆盖三类文件名形态(见 rules.rs):dockerfile(无扩展名,如Dockerfile)dockerfile.*(如Dockerfile.dev、Dockerfile.prod)*.dockerfile(如service.dockerfile) 匹配时对小写化的文件名做通配匹配,因此大小写变体也能命中。
- 作用域隔离注入:
render_rules_section(rules.rs)把匹配到的规则按文件分组渲染为## Targeted review focus for this batch小节,每组用### Applies to: <文件列表>标明作用域,同一规则文档只渲染一次——保证混合语言批次中 Go 规则不会污染 Dockerfile 评审、SQL 规则不会污染 Go 文件。 - 拼装进评审任务:在
code_review工具的执行路径中(review_tool.rs),评审任务由「带行号的 diff + 语言规则小节 + 影响面计划 + diff 原文」拼接而成:
Review the following changes. Report each issue via the `report_finding` tool ... {rules} ← render_rules_section 的输出(含 dockerfile 规则) {impact_plan} ← render_review_impact_plan 的确定性影响面计划 === DIFF === {annotated} ← 带行号标注的 diffCLI 入口atomcode review同样会注入规则小节,并在 stderr 打印可观测信息:[rules] injected for N changed file(s) (M chars)或[rules] no language rules matched the changed files(见 review.rs)。
理解了注入机制后,下面逐条拆解dockerfile.md的具体检查清单。
二、安全检查:容器根基处的三个高危点
原文档的#### security小节包含三类必须优先处理的安全问题:
1. 以 root 运行(缺少USER)
Running as root (missing
USER)
容器默认以 root 身份运行进程。一旦应用被攻破,攻击者获得的就是容器内最高权限;叠加容器逃逸面,风险进一步放大。评审规则要求在镜像中显式声明USER指令切换到非特权用户。
仓库实证:AtomCode 自己的 daemon 镜像严格遵守了这条规则。看 Dockerfile-Daemon:
RUN useradd -r -s /bin/bash atomcode创建系统用户atomcode后,daemon 二进制安装在/usr/local/bin/atomcode-daemon,最终以该非 root 用户为运行主体。反例则是COPY dist/...与RUN mv ...阶段的构建期 root 操作——这些属于构建时必要的特权步骤,但运行时进程绝不继承 root。评审清单关注的是最终镜像的默认运行用户是否仍是 root。
2. 密钥烘焙进镜像层(ARG/ENV携带凭据、COPY密钥文件)
secrets baked into layers (
ARG/ENVwith credentials,COPYof secret files)
Docker 镜像由多层构成,每一层都是可被docker history检视的不可变文件系统快照。以下三种做法会把机密永久固化进镜像:
ENV API_KEY=sk-xxx或ENV AWS_SECRET_ACCESS_KEY=...:环境变量写入镜像配置元数据,任何人拉取镜像即可docker inspect读出;ARG TOKEN=...且该值被RUN阶段使用:中间层会留下明文;COPY .aws/credentials /root/或COPY id_rsa /root/.ssh/:密钥文件直接成为镜像层内容。
正确替代方案:
- 构建密钥优先用 BuildKit 的
RUN --mount=type=secret,密钥只挂载在构建瞬间、不进层; - 运行期凭据通过
-e/--env-file注入,或使用容器编排的 Secret 机制; ENV只存放非敏感配置,并配合docker inspect自查。
仓库实证:AtomCode 的 compose 部署方案正体现了这一原则——见 docker-compose.yml,API Key 通过environment的${ANTHROPIC_API_KEY:-}/${OPENAI_API_KEY:-}变量注入,或写入宿主机config.toml(见 config-example.toml),而不是烘焙进镜像;config.toml以只读方式挂载(./config.toml:/root/.atomcode/config.toml:ro),避免容器意外改写。
3. 不可信的镜像与脚本源
latest/ unpinned base image tags;curl ... | shof unverified scripts;ADDof remote URLs (preferCOPY)
三类源不可信问题:
- 未固定 tag:
FROM debian:latest或FROM node:20(不带 digest/精确补丁版本)意味着每次重建的基座都可能在漂移——上游删 tag、换内容、修复漏洞后镜像语义悄然改变,构建不可复现。评审规则倾向固定到具体版本(debian:bookworm-slim)乃至 digest 级锁定。 curl ... | sh管道执行:从互联网拉取脚本直接交给 shell,中间没有任何完整性校验,脚本内容随时可能被替换。评审要求先下载、验签/比对哈希、再执行,或使用官方渠道。ADD拉取远程 URL:ADD除了解压本地 tar 还支持远程 URL 抓取,行为隐晦、缺乏校验且引入网络依赖。评审规则明确优先COPY(COPY只做本地文件复制,语义单一、可预测)。
仓库实证:TUI 镜像的依赖安装全部走apt-get官方源(Dockerfile-TUI),基础镜像固定为debian:bookworm-slim(Dockerfile-Daemon),没有curl | sh、没有ADD远程 URL——与规则清单完全一致。唯一的"外部下载"是COPY dist/...本地构建产物,属可信路径。
4. 全量复制丢入无关/密钥文件(缺少.dockerignore)
COPY . .pulling in unwanted/secret files (missing.dockerignore)
COPY . .会把构建上下文(context)中一切文件都拷进镜像,包括:
.git/目录(仓库完整历史、可能含旧密钥);- 本地开发文件:
.env、*.pem、id_rsa、.npmrc、credentials; - 无关产物:
node_modules、target/、dist/、日志文件。
评审规则要求在镜像根目录维护.dockerignore,显式排除node_modules、.git、.env、构建产物等路径,只让必要文件进入构建上下文。这同时减小 context 传输体积、加快构建。
三、正确性与镜像体积:层策略的两大核心问题
原文档的#### correctness / size小节聚焦层的组织方式对构建正确性和最终体积的影响。
1. 缓存失效顺序
Cache invalidation order (
COPYof source before dependency install)
Docker 构建缓存按 Dockerfile 指令顺序逐层判定:某层输入变化,该层及其后所有层全部失效重建。最常见的失效陷阱是先COPY源代码、后安装依赖:
# 错误:任何源码改动都会使下方 apt/pip/npm 依赖层全部失效,每次都重装 COPY . . RUN apt-get update && apt-get install -y ... RUN pip install -r requirements.txt# 正确:先拷贝依赖清单(变化频率低),安装依赖,再拷贝源码(变化频率高) COPY requirements.txt . RUN pip install -r requirements.txt COPY . .评审规则关注的就是依赖安装是否被放在高变化率的源码COPY之后,从而浪费构建缓存。
仓库实证:Dockerfile-Daemon 将apt-get install ca-certificates放在任何业务COPY之前,且镜像基于固定的debian:bookworm-slim,基座与系统包层长期稳定命中缓存;业务二进制(COPY dist/v*/atomcode-daemon-*-linux-*)在最后阶段才复制,配合 buildx 的TARGETARCH参数按平台挑选二进制(Dockerfile-Daemon),一次构建产出 amd64/arm64 双架构镜像。
2. apt 安装未清理、层未合并
apt-get installwithout cleaning lists /--no-install-recommendsMissing cleanup creating bloated layers; manyRUNlines where one chained layer is intended
两条细则解决的都是镜像体积问题:
apt-get install不带--no-install-recommends:apt 默认拉取推荐包,往往引入大量非必需依赖。加上该标志可显著缩小体积。- 不清理 apt 列表:
apt-get update产生的/var/lib/apt/lists/*索引文件会留在层里,应通过rm -rf /var/lib/apt/lists/*清掉(或使用apt-get clean)。清理必须放在同一个 RUN 指令内,否则清理动作本身只是新增一层,之前层里的索引文件依然存在。
关键原理:删除文件并不能让文件从镜像中"消失"。Docker 层是叠加的,下层中被删除的文件仍占据物理空间,只有在下层从未写入过它,体积才会真正减小。所以"安装 → 清理"必须链在同一个
RUN中。
- 多个
RUN不合并:每一条RUN生成一层。零散的RUN apt-get update、RUN apt-get install、RUN rm -rf ...分开写,不仅增加层数(拉取/存储开销),还会让中间层的索引文件残留。应链式合并:
RUN apt-get update && \ apt-get install -y --no-install-recommends \ ca-certificates \ git \ && rm -rf /var/lib/apt/lists/*仓库实证:两个 daemon Dockerfile 与 TUI Dockerfile 全部采用这种链式写法并带--no-install-recommends和rm -rf /var/lib/apt/lists/*(见 Dockerfile-Daemon、Dockerfile-TUI),与规则清单逐条对应。
四、运行时:信号处理、端口声明与工作目录
原文档的#### runtime小节虽然只有一条列举,但包含三个独立检查点。
1. Shell 形式CMD/ENTRYPOINT吞噬信号(用 exec / JSON 数组形式)
Shell-form
CMD/ENTRYPOINTswallowing signals (use exec / JSON-array form)
Dockerfile 中CMD/ENTRYPOINT有两种写法:
- Shell 形式:
CMD atomcode-daemon等价于CMD ["/bin/sh", "-c", "atomcode-daemon"]。实际运行的进程是sh,真正的守护进程变成sh的子进程。docker stop发送的SIGTERM会被sh接住而不转发给子进程,导致容器无法优雅停机,超时后被SIGKILL强杀——这正是评审规则说的"信号被吞掉"。 - Exec / JSON 数组形式:
CMD ["atomcode-daemon"](或ENTRYPOINT ["atomcode-daemon"])让容器 PID 1 直接是目标进程,信号直达,配合 PID 1 的 reaping 行为可正常处理SIGTERM/SIGINT,实现优雅关闭。
仓库实证:三个 Dockerfile 全部使用 JSON 数组形式——Dockerfile-Daemon 的ENTRYPOINT ["atomcode-daemon"]、Dockerfile-TUI 的ENTRYPOINT ["atomcode"],信号可直达守护进程与 TUI 进程。
2. 缺失EXPOSE/ healthcheck
missing
EXPOSE/ healthcheck where relevant
EXPOSE:声明容器监听的端口(不改变实际监听行为,但传递意图、便于编排系统发现)。daemon 监听 13456 端口,Dockerfile-Daemon 中有EXPOSE 13456。- healthcheck:为常驻服务声明健康探针。compose 部署中(docker-compose.yml)用
bash /dev/tcp探活GET /health——注意注释说明:镜像基于 debian slim 没有 curl/wget,所以用 bash 内建能力做 TCP 探活;而基础镜像层面未在 Dockerfile 内写HEALTHCHECK指令,属于"相关场景下建议补充"的可评审点。
3. 未设置WORKDIR
WORKDIRnot set
缺少WORKDIR时,容器默认工作目录是/,后续RUN/CMD的相对路径都基于根目录,易产生路径歧义与权限问题。评审规则要求显式设置WORKDIR。
仓库实证:Dockerfile-Daemon 先设WORKDIR /home/atomcode(配合刚创建的非 root 用户),最终又设WORKDIR /workspace作为挂载项目代码的固定目录(compose 中./projects:/workspace即映射此处,见 docker-compose.yml)。
五、实战自查清单:按 diff 行号逐项核对
综合以上规则,评审 agent 面对 Dockerfile 变更时会按以下顺序检查(每项均可锚定到具体 diff 行):
| 类别 | 检查项 | 判定要点 | 仓库参考实例 |
|---|---|---|---|
| 安全 | USER指令 | 最终运行用户是否为 root | Dockerfile-Daemon 创建atomcode用户 |
| 安全 | 密钥烘焙 | ARG/ENV/COPY是否带入凭据 | docker-compose.yml 运行期注入 |
| 安全 | 镜像/脚本源 | 是否latest、curl \| sh、ADD远程 URL | 固定debian:bookworm-slim、全COPY |
| 安全 | .dockerignore | COPY . .是否缺少排除规则 | — |
| 正确性/体积 | 缓存顺序 | 依赖安装是否在源码COPY之后 | Dockerfile-Daemon 先装系统包 |
| 正确性/体积 | apt 清理 | 是否--no-install-recommends+ 链式rm -rf | Dockerfile-TUI |
| 正确性/体积 | 层合并 | 多个RUN是否可链成一层 | 同上链式写法 |
| 运行时 | 信号处理 | CMD/ENTRYPOINT是否 JSON 数组形式 | Dockerfile-Daemon |
| 运行时 | 端口/探针 | 常驻服务是否EXPOSE/healthcheck | EXPOSE 13456+ compose healthcheck |
| 运行时 | 工作目录 | 是否显式WORKDIR | Dockerfile-Daemon |
六、规则的定制与开关:--rules-dir与--no-rules
Dockerfile 评审规则不是写死的,AtomCode 提供两条 CLI 定制通道(定义见 review.rs):
--rules-dir <dir>:用指定目录下的<name>.md覆盖同名内置规则(如<dir>/dockerfile.md)。load_rule_doc的优先级是:--rules-dir/<name>.md存在且非空 → 覆盖内置;否则回退到编译进二进制的默认文档(见 rules.rs)。这意味着你可以针对团队内部规范扩展 Dockerfile 检查项(例如强制固定 digest、强制多阶段构建),无需重新编译。对应测试rules_dir_overrides_builtin验证了这一覆盖行为(rules.rs)。--no-rules:完全禁用内置语言规则注入,用于需要干净提示词的 prompt A/B 实验(见 review.rs 中if !args.no_rules分支)。
此外还有--append-system-prompt/--append-system-prompt-file可以追加团队级评审指令而不替换内置 reviewer 指令(review.rs),适合把"Dockerfile 必须使用多阶段构建"之类的仓库规范挂在内置规则之后。
七、规则注入后的落地:结构化 findings 输出
规则小节进入评审任务后,评审 agent 依据内置 reviewer persona(persona.rs)逐项调查 diff,并通过report_finding工具输出结构化发现。每条 finding 携带file_path、line_start、line_end、priority(P0–P3)、confidence(0.0–1.0)、suggestion等字段。对照本节规则,典型的 Dockerfile findings 形态是:
- P0/P1(安全):
docker run进程以 root 运行(无USER);ENV/COPY烘焙密钥;从不可信 URLcurl ... | sh。 - P2(正确性/体积):依赖安装在源码
COPY之后导致缓存失效;apt-get install缺--no-install-recommends或未链式清理。 - P3(运行时):shell 形式
CMD吞信号建议改 JSON 数组;常驻服务缺 healthcheck 建议补充。
这些 findings 在单评审路径下由report.findings()收集,在depth: deep模式则按维度扇出多个只读评审者再合并去重(见 review_tool.rs 的 fanout 路径),最终呈现在atomcode review的评审报告中。
结语
dockerfile.md用三条简短清单覆盖了 Dockerfile 评审最核心的检查面:安全层的用户与密钥与来源可信、体积层的缓存与层组织、运行时层的信号与声明完备性。在 AtomCode 中,这份清单通过文件名匹配注入评审任务、按文件作用域隔离、可被--rules-dir热替换,并最终沉淀为带行号、带优先级的结构化 findings。仓库内docker/目录下三个真实 Dockerfile 恰好是这套规则的正面样例——固定基础镜像、链式 apt 清理、JSON 数组 ENTRYPOINT、非 root 用户与显式 WORKDIR 一应俱全,可作为团队镜像规范的对照范本。
- 人工智能
- AI Agent
- 代码智能体
- 自主智能体
- MCP Clients
- CLI
【免费下载链接】atomcode
Claude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get Started
相关推荐
BuildKit Dockerfile 检查规则 JSONArgsRecommended 详解:让 ENTRYPOINT/CMD 正确接收 OS 信号
BuildKit Dockerfile 检查规则 JSONArgsRecommended 详解:让 ENTRYPOINT/CMD 正确接收 OS 信号 本文基于
构建工具云原生后端atomcode-review 语言规则引擎:45 条内置评审规则的匹配、分组注入与 --rules-dir 运行时定制
atomcode review 语言规则引擎:45 条内置评审规则的匹配、分组注入与 rules dir 运行时定制 本文以 crates/atomcode r
人工智能AI Agent代码智能体自主智能体MCP ClientsCLIDockerfile安全审计必备:Hadolint规则DL3000-DL3061全解析
Dockerfile安全审计必备:Hadolint规则DL3000 DL3061全解析 Hadolint是一款基于Haskell开发的Dockerfile静态分
开发工具代码质量
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考