转载与翻译声明
本文译自 Philipp Hauer 的文章 Discussing Docker. Pros and Cons.
- 原文标题:Discussing Docker. Pros and Cons.
- 原文作者:Philipp Hauer(Head of Engineering @ commercetools,@philipp_hauer)
- 原文出处:phauer.com
- 发布时间:2015-10-25;最后修订:2019-01-20
- 翻译说明:原文版权归 Philipp Hauer 所有。正文部分为完整中文翻译,文中配图在原文里,此处以文字说明位置;仅供学习交流,如原作者有异议将立即删除。
原文正文(第一节)之后都是本文新增的部分,不代表原作者观点:第二节逐条对照它当年的担忧在今天是否成立,第三节讲这十年底层技术栈被换掉了什么,第四节是一份 2026 年的现代容器技术栈实操清单(多阶段构建、distroless、BuildKit、供应链签名与准入控制……),第五节讲 Docker 在 2026 年的新战场——给 AI Agent 当边界。
十年过去,原文的结论大多已经过时,但它论证的结构一条都没过时,这恰恰是它值得重读的原因。
目录
- 一、原文正文
- 二、2026 现状:逐条对照
- 三、2026 现状:骨架被换掉了
- 四、今天实际怎么做:2026 年的容器技术栈
- 五、2026 现状:Docker 的新战场是 AI Agent
- 六、哪些没变
- 七、可以带走的东西
- 附:原文与参考资料
一、原文正文
Docker 让我们能轻松地为应用创建可复现的环境。我们把环境搭建自动化,消灭了手工易错的操作。这样我们降低了部署过程的风险、提升了它的可靠性。但也有一些挑战,以及一些使用 Docker 会很困难的领域。这篇文章讨论 Docker 的若干优点,也指出一些缺点。
1.1 优点
对开发团队的好处
完全掌控应用的执行环境。 这包括必要的基础设施:JRE、应用服务器、VM 参数,以及应用运行所需的其他环境变量。基础设施可以由开发团队自己轻松、独立地修改,因为他们不必等运维团队去改环境。
(原文配图:一个 Docker 镜像包含应用运行所需的一切,数据库等外部资源除外。)
降低风险。 测试跑的就是最终会在生产服务器上运行的那个镜像。这提升了测试的可靠性。而且发布变得没那么吓人,因为我们在生产上跑的,和在测试、以及构建流水线其他阶段(预发系统、验收测试、容量测试等等)跑的是同一个镜像。
(原文配图:镜像一旦构建完成,就会被用在(持续)交付流水线的所有阶段。这提升了交付的可靠性。)
对运维团队的好处
维护应用环境的开销更小。 环境的创建是自动化的,因此需要的手工操作更少。这降低了风险、提升了可靠性。
在一堆服务器上手工维持一致的环境既容易出错、也可能是噩梦。 用 Docker 创建多个环境实例很容易,因为只要在服务器上执行镜像就行。这样给集群加节点、做水平扩展都很轻松。
更新已有应用和环境很容易。 用传统方式搭建环境(比如安装脚本)时,一旦环境已经存在就会出问题。在脚本里考虑更新路径可能是一项非常复杂的任务(比如检查文件是否存在、清理不再使用的文件)。用 Docker,我们就不必考虑已有环境(数据库除外)。我们只要停掉正在运行的容器、启动更新后的新容器。因为我们总是从空环境开始,搭建过程因此被简化了。
基础设施即代码
用 Docker(以及 Chef、Puppet 这类工具)搭建环境时,我们能享受「基础设施即代码」的好处。基础设施不再是手工创建的,而是一个自动化过程的产物。我们显式地描述自己的基础设施。就 Docker 而言,Dockerfile 就是描述我们环境的那份文档。这带来如下好处:
- 我们可以把 Dockerfile 纳入版本控制、追踪环境的变化。这样我们始终知道哪个应用版本对应哪个环境版本。
- 我们得到一份可靠的基础设施文档。我们始终知道应用运行需要什么、环境里当前装了什么。
- 而且这份文档永远是最新的,因为要改环境就必须改它。
- 因此,搭建新环境很容易,因为我们知道自己需要装什么。
与其他自动化工具的比较
用 Chef 或 Puppet 这类工具,你也能获得 Docker 的很多优点(可复现的环境、基础设施文档、新节点搭建容易)。但当我们使用(Docker 这样的)虚拟化方案时,还能额外得到:
- 当我们要实施持续交付时,需要为交付流水线的每个阶段(提交阶段、验收测试、容量测试、预发、生产)搭建多个环境实例。为此使用物理机是不现实的。
- 应用及其所需环境的安装变得容易,因为我们总是从空 VM 开始(实际上 Docker 并不启动真正的 VM,见下)。旧的 VM 可以完全删掉,重新搭一个新的。
轻量级虚拟化
正因为上面这些原因,Chef 或 Puppet 常常和虚拟化配合使用:先启动一台虚拟机,再用 Chef 或 Puppet 在 VM 里搭建环境。而用 Docker 替代真正的 VM,我们能得到:
- 轻量级虚拟化。 启动一个 Docker 容器比启动 VM 快得多,因为不需要引导客户机操作系统。这减少了开销。多个容器共享宿主操作系统的内核,但拥有各自的文件系统、用户、网络和进程。从宿主操作系统的视角看,运行一个 Docker 容器不过是启动了另一个进程。这在显著加快容器启动速度的同时,依然提供了不错的隔离性。
1.2 缺点与挑战
在(过分地?)赞美了 Docker 之后,让我们来考虑使用 Docker 时的缺点和挑战:
- 多了一层,导致复杂度上升。 这不仅影响部署,也影响开发和构建。
- 此外,管理大量容器本身就是挑战,尤其是要把容器集群化的时候。像 Google Kubernetes 和 Apache Mesos 这样的工具可以帮上忙。
- 容器共享同一个内核,因此隔离性不如真正的 VM。内核里的一个 bug 会影响每一个容器。
- Docker 基于 Linux Containers(LXC),这是一项 Linux 技术。因此我们无法在其他系统上运行 Docker,容器也永远是 Linux 系统。不过 Boot2Docker 借助 VirtualBox 让 Docker 能在 Windows 和 Mac OS X 上使用:Docker 客户端跑在宿主 OS 上,通过 VirtualBox 里的 Docker daemon 通信。遗憾的是,这没那么舒服,日常使用比起原生运行 Docker 更笨重、更麻烦。
- 引入 Docker 可能是一项费力且耗时的任务。 我们必须评估它是否值得这份投入和随之而来的额外复杂度。在我过去的一个项目里,管理层拒绝 Docker 的理由是:生产、预发、实验一共 3 个节点,不足以证明这份投入是合理的……然而,当你拥有一个节点集群(做水平扩展时)、或者使用持续交付时,你就需要一种复现环境的手段,而 Docker 在这件事上非常出色。此外,持续交付能缩短上市时间(因为部署和环境搭建都自动化了,新功能能更快到达生产环境),这可以用来说服管理层。
- 我还体会到,在监管严格的领域(比如银行业),人们对 Docker 也有顾虑:
- 运行容器需要 root 权限。 对某些公司来说这是问题——在那些公司里,负责在生产服务器上运行和更新应用的人,不能拥有 root 权限。
- Docker 的使用是否符合某些必须满足的安全标准(比如 PCI),并不明确。
- 有些公司有一条可疑的规定:机器上只能安装来自官方/可信来源的软件。举例来说,Red Hat Enterprise Linux 6 里不包含 Docker,因此必须从 docker.com 安装,而那是「不可信来源」。
原文的相关阅读:用 Maven 构建 Docker 镜像
二、2026 现状:逐条对照
原文修订于 2019-01,那时 Docker Engine 还是 18.x;今天是 2026-09,最新是 Docker Engine 29.8.1。逐条看它当年担心的事:
| 2015 年的担忧 | 2026 年的实况 |
|---|---|
| Docker 是 Linux 技术,非 Linux 只能靠笨重的 Boot2Docker | 基本解决。Mac 走 Virtualization.framework、Windows 走 WSL2,Docker Desktop 开箱即用;还有 Podman Desktop、Colima、Rancher Desktop、Lima 一堆替代品 |
| 跑容器需要 root,生产上不给 | 部分解决:Rootless Docker(20.10 GA)和 userns-remap 都可用。但默认仍是 rootful,rootless 在网络和端口上有额外限制,多数生产环境还是以 root 运行 |
| 共享内核,隔离性不如真 VM | 物理事实没变,但周边补强了:默认 seccomp/AppArmor、capabilities 收敛;要强隔离可上 gVisor / Kata Containers / Firecracker。更戏剧性的是 Docker 自己在 2026 年给出的答案,见第四节 |
| 是否符合 PCI 等安全标准存疑 | 议题已经翻篇。OCI 标准化 + NIST SP 800-190《应用容器安全指南》(2017)+ 云厂商全面采用。今天的合规问题不是「能不能用容器」,而是「镜像从哪来、有没有签名和 SBOM」 |
| 基于 LXC | 早就换了:LXC → libcontainer → runc。OCI 在 2015 年成立,定下了镜像规范和运行时规范 |
| 集群难管,需要 K8s 或 Mesos | K8s 赢了(最新 1.37.1);Mesos 已于 2021 年退役进入 Apache Attic |
三、2026 现状:骨架被换掉了
这是最大的认知变化:今天说「Docker」,指的通常已经不是那个运行时了。
- containerd 被拆出来并捐给 CNCF(2017,2019 年毕业),成为今天绝大多数生产集群的实际底层。
- Kubernetes 1.20 弃用 dockershim,1.24(2022)正式移除。 也就是说,今天跑在 K8s 上的容器,多半根本没用 Docker 的运行时,用的是 containerd 或 CRI-O。
- Moby 项目拆分(2017):Docker 被拆成开源上游(Moby)和商业产品两条线。
- Docker Enterprise 于 2019 年卖给了 Mirantis。
- Swarm 在 1.12(2016)的 Swarm mode 之后就基本休眠了。
- 构建方式变化最大:多阶段构建(17.05,2017)——这是原文完全没提、但极大改变了镜像瘦身实践的一件事;BuildKit 在 23.0(2023)成为默认,带来并行构建、cache mount、
--secret、SSH 转发、docker init;buildx 支持多架构;Compose 进入 V2 和 Compose Spec。 - 商业模式变了:Docker Desktop 从 2022 年 1 月起对大公司收费(>250 人或 >1000 万美元营收),直接催生了 Podman / Colima / Rancher Desktop 这一波替代;Docker Hub 也开始拉取限流。
- 供应链安全成为主线:Sigstore/cosign 签名、Notation、SBOM、provenance attestation、Docker Scout。这是原文「只准装可信来源软件」那条担忧的转世——只是现在担心的是镜像里到底有什么。(2024 年初 runc 的 CVE-2024-21626「Leaky Vessels」也提醒了大家:容器运行时本身也是攻击面。)
一句话:今天说 Docker,通常指的是镜像格式 + Dockerfile 语法 + docker CLI 的手感。运行时是 runc/containerd,编排是 K8s,仓库可能是 Harbor/GHCR/ECR。Docker 公司 ≠ Docker 技术。
四、今天实际怎么做:2026 年的容器技术栈
前面两节是「变了什么」。这一节回答一个更实际的问题:如果今天从零开始搭一套容器化的交付链路,具体会用到什么。 这是原文完全没有覆盖的部分——它写于 2015 年,那时多阶段构建还不存在。
4.1 写 Dockerfile:多阶段构建是标配
原文通篇没提镜像怎么构建,因为当年只有单阶段。多阶段构建(17.05,2017)是这十年对日常实践影响最大的一个变化:
# ---- 构建阶段:工具链只活在这里 ----
FROM golang:1.27 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 go build -trimpath -o /out/app ./cmd/app
# ---- 运行阶段:没有 shell、没有包管理器 ----
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
要点:
- 多阶段:编译器和依赖不进最终镜像。同一个应用的镜像可以从约 1GB 降到 10MB 量级。
- 基础镜像的选择谱系:
alpine(小,但 musl 和 glibc 的兼容坑不少)→distroless(Google 维护,没有 shell 和包管理器,攻击面极小)→scratch(空镜像,连 CA 证书都要自己拷)。 - BuildKit(23.0 起默认):
--mount=type=cache缓存 Go 模块和编译产物;--mount=type=secret传密钥且不留在镜像层里(这是当年最容易出事的地方);--ssh转发 agent 做私有仓库拉取。 .dockerignore常常是最大的构建加速杠杆——把.git、node_modules、测试数据挡在外面。- 多架构:
docker buildx build --platform linux/amd64,linux/arm64(Apple Silicon 之后这变成了刚需)。 docker init会给你的项目自动生成 Dockerfile、compose 文件和.dockerignore,作为起点够用。
4.2 运行时与隔离:别再默认 rootful
今天的运行时栈是分层的:docker CLI → containerd → runc(OCI 运行时)。每一层都是可替换的。
默认加固,这几条应该是起点而不是进阶:
- 非 root 用户:
USER nonroot,配合 rootless Docker 或 userns-remap(把容器内的 root 映射成宿主机上的非特权用户)。 - capabilities 收敛:
--cap-drop=ALL,再按需--cap-add。 - 只读根文件系统:
--read-only,需要写的地方挂 tmpfs 或卷。 - seccomp / AppArmor / SELinux:Docker 现在有默认 profile,但很多生产环境用的是自己收紧的版本。
要强隔离时的选项:
| 方案 | 做法 | 代价 |
|---|---|---|
| gVisor | 用户态内核,拦截并重新实现系统调用 | 兼容性好但性能有损,syscall 密集的场景明显 |
| Kata Containers | 每个 Pod 一个轻量 VM,OCI 兼容 | 启动更慢、内存开销更大 |
| Firecracker | AWS 的 microVM,Lambda 底层 | 需要自己管 VM 生命周期 |
这一节和原文第 3 条缺点(共享内核)的关系:十年前的标准回答是「隔离性够用了,性能更重要」。今天多了一个更诚实的版本——隔离强度是威胁模型的函数。面对你写的、行为确定的程序,namespace 够用;面对会主动探测边界的行动者,就不够。Docker 自己在 2026 年给出的答案就是 microVM,见下一节。
4.3 编排:K8s 赢了,但别急着上
Kubernetes 已是事实标准(最新 1.37),但今天的共识和 2015 年一样值得重复:「3 个节点值得上 K8s 吗」和当年「3 个节点值得上 Docker 吗」是同一个问题。
- 小规模:单机 Docker Compose 往往就够了。再往外一点有 K3s(轻量 K8s 发行版)、Nomad。
- 标准做法:Helm / Kustomize 管清单,ArgoCD / Flux 做 GitOps(集群状态由 git 仓库声明并自动收敛)。GitOps 是这些年最大的实践变化——它把原文「基础设施即代码」那条推到了部署阶段。
- 网络与策略:Cilium(基于 eBPF 的数据面)成为主流,Gateway API 正在取代 Ingress。
- Service mesh 在降温:不是不需要,而是很多能力下沉到了 eBPF 和 K8s 本身,Istio 的 sidecar 模式正在被 sidecarless(Ambient 模式)替代。
4.4 供应链安全:这是 2026 年新增的最重要一层
原文那条「有些公司规定只能装官方/可信来源的软件,而 docker.com 是『不可信来源』」——这个问题今天有了完整的工程答案,而且形式完全变了。
今天的问题不是「从哪下载的」,而是「这个镜像的每一层是谁构建的、里面有什么、有没有被改过」。对应的工具链:
| 环节 | 工具 |
|---|---|
| 生成 SBOM(软件物料清单) | Syft(SPDX / CycloneDX 格式) |
| 漏洞扫描 | Trivy、Grype、Docker Scout |
| 签名 | cosign(Sigstore,支持 keyless 签名)、Notation(CNCF Notary Project) |
| 来源证明 | SLSA provenance、in-toto attestation |
| 准入控制 | Kyverno / OPA Gatekeeper——在集群入口强制「镜像必须已签名且扫描通过」才允许调度 |
2024 年初 runc 的 CVE-2024-21626(「Leaky Vessels」) 是个提醒:容器运行时本身也是攻击面。这条链路上没有任何一环是「装完就不用管」的。
4.5 开发体验
- Dev Containers:把开发环境也写进版本控制(
devcontainer.json)。这才是原文「基础设施即代码」最彻底的形态——连你同事的编辑器配置都开始可复现了。 - 本地运行时:Docker Desktop、Mac 上的 OrbStack、Podman Desktop、Colima、Rancher Desktop。选择比当年多了太多。
- Compose Watch:改代码自动同步进容器并重启,不再每次 rebuild。
- 远程/混合开发:Tilt、Skaffold、Telepresence、Garden 把「本地开发 + 集群调试」接起来;现在还有云端开发沙箱。
4.6 还没成气候,但值得盯
- Wasm:Spin / SpinKube、wasmCloud。冷启动毫秒级,沙箱模型比容器更严格(默认没有文件系统、没有网络,能力全靠显式授予)。
- microVM 的复兴:Firecracker、Cloud Hypervisor。这条线在 2026 年被 Docker 自己推了一把,原因见下一节。
- 容器和虚拟机那条线在变模糊:容器做隔离,microVM 拿性能,两者的边界正在往中间靠。
4.7 如果今天从零开始
把上面收成一份清单:
- Dockerfile 用多阶段 + BuildKit + distroless,
.dockerignore写全 - 本地 用 Docker Desktop / OrbStack,团队环境用 Dev Containers 固化
- 镜像 用 cosign 签名、Syft 出 SBOM、Trivy 扫漏洞,全部进 CI
- 集群 3 个节点以内先别上 K8s;要上的话 Helm + ArgoCD 起步
- 运行时 非 root + cap-drop + 只读根文件系统,作为默认而非例外
- 准入 用 Kyverno 强制「未签名不允许部署」
五、2026 现状:Docker 的新战场是 AI Agent
这一节是原文完全无法预见的,但读起来会让人起鸡皮疙瘩——因为它恰好是原文第 3 条缺点的正面回应。
2026 年 9 月,Docker 总裁 Mark Cavage 在 WeAreDevelopers 的主题演讲里,把公司的重心明确压在了 AI coding agent 的沙箱上。Docker 官方博客的原话是:
容器打包应用。沙箱容纳 agent。
容器打包应用,它共享宿主内核,用 namespace 和 cgroup 给一个固定的工作负载提供自己的文件系统、网络和进程视图。对「跑起来、干完活、只碰交给它的东西」的软件来说,这是对的工具。
然而 agent 是一个概率性的行动者。它自己决定下一步做什么,然后去做——对着你的文件系统、网络、凭证和云账号。它会装一个需要 root 的包,会开一个没人规划过的端口,被挡住就换个方法。容器不是为此设计的:边界就是那个行动者正在探测的同一个内核。
于是 Docker 的答案是 microVM:
- Docker Sandboxes:每个 agent 拿到自己独立的 microVM 和自己的内核,与开发者宿主环境隔离。开发者可以选择 agent、模型和工具,然后定义这个沙箱对文件、网络和密钥的访问权限——而这些策略在 agent 的控制范围之外。Docker 的说法很直白:正因为边界在下面,所以可以放心给 agent root 权限,让它放开了跑。
- Docker Sandbox Kits:把 agent、它的工具、以及「它能碰什么」的规则,打包成一个带版本、可分享的产物。2026 年 9 月 24 日发布的 Kit 规范 v3 里,Kit 已经就是一个普通的 OCI 镜像了(没有自定义 media type、没有 sidecar 文件),清单里用一条 annotation
vnd.docker.sandbox.kit.descriptor承载声明。规范以 Apache 2.0 开源在docker/sandbox-kit-spec,并且 Docker 已承诺将其提交给 CNCF 做中立治理。 - Docker Cloud Sandboxes:同样的 microVM 隔离,从笔记本延伸到 Docker 托管的云算力,按量付费,
sbx工作流一条命令把活儿搬上云。 - 免费的独立 CLI,可用。
Docker 给这件事提炼的口号,值得单独抄下来:
Dockerfile 让软件可复现,Kit 让权限可复现。 (Dockerfiles made software reproducible. Kits make authority reproducible.)
这两件事其实是同一个论证的闭环。 原文十一年前说:Dockerfile 就是环境的文档,而且它永远是最新的,因为不改它就改不了环境。今天这句话被原样搬到了权限上——当年的问题是「我知道环境里装了什么吗」,今天的问题是「我知道 agent 能碰什么吗」。同一个论证结构,换了个宾语。
还有一个反转挺有意思。原文第 3 条缺点说「共享内核,隔离性不如真 VM」,十年前 Docker 阵营的标准回答是「隔离性够用了,性能更重要」。2026 年 Docker 自己给出的答案是:用 microVM。
这不是 Docker 认错了,而是威胁模型变了:面对一个你自己写的、行为确定的程序,namespace 够用;面对一个会主动探测边界、被挡住就换个方法的行动者,就不够了。隔离强度从来不是绝对的技术指标,它是威胁模型的函数。
六、哪些没变
1. 复杂度那条,反而变本加厉。 原文说「多了一层」。今天是一层套一层:容器 → 编排 → service mesh → GitOps → 内部开发者平台。当年「3 个节点值得上 Docker 吗」的辩论,今天原样搬到了「3 个节点值得上 K8s 吗」——同一个争论,只是往上挪了一级。
2. 组织与合规的摩擦还在,只是议题换了。 从「能不能用容器」换成「镜像治理、仓库策略、许可证成本」。原文用整整一段讲「怎么说服管理层」,那一节今天依然有实际价值。
3. 原文最有价值的两段——管理层的「不值得」论、强监管领域的阻力——恰恰是唯一没过时的部分。 技术结论全都过时了,论证结构一条都没过时。
七、可以带走的东西
1. 判断一个技术观点是否过时,要看它的约束条件变没变,而不是看它的结论。 这篇文章的结论类论断(「Go 没有泛型」式的那种)几乎全过时了,但它的论证方式——「3 个节点够不够支撑这份复杂度」「持续交付缩短上市时间,所以值」——今天换个技术栈照样成立。
2. 技术选型的说服永远是算经济账,不是比谁先进。 原文说服管理层的抓手不是「Docker 很酷」,而是「持续交付缩短 time-to-market」。这条在 2026 年做 AI Agent 沙箱、做平台工程、上 K8s 时,一样适用。
3.「永远从空环境开始」是一个可迁移的洞察。 原文用它论证更新为什么简单;十年后同样的论证被搬到了权限上(Kit 让权限可复现)。当你想让某样东西可审计、可 diff、可回滚时,先想办法让它从零重建,而不是打补丁。
4. 隔离强度是威胁模型的函数,不是技术排名。 同一个技术,面对确定的程序和面对概率性的行动者,需要的边界强度完全不同。这条在 2026 年做 agent 系统时比在 2015 年做微服务时更值钱。
附:原文与参考资料
原文
- Philipp Hauer, Discussing Docker. Pros and Cons. — 发布于 2015-10-25,修订于 2019-01-20 https://phauer.com/2015/discussing-docker-pros-and-cons/
本文新增部分的依据(截至 2026-09)
- Docker Engine 版本:29.8.1(2026-09-15),见 endoflife.date/docker-engine
- Kubernetes 版本:1.37.1(2026-09-23),见 endoflife.date/kubernetes
- Docker Sandboxes / Sandbox Kit 规范 v3 / Cloud Sandboxes:Docker 官方博客,2026-09-24
- 相关标准:OCI Image Spec / Runtime Spec、NIST SP 800-190《Application Container Security Guide》(2017)