01_introduction/1.3_why.md
在回答 “为什么用 Docker” 之前,笔者想先问一个问题:你有没有经历过这些场景?
在 Docker 出现之前,软件开发和运维面临着诸多棘手的问题。我们先来看看以下三个典型的痛点场景。
周五下午 5:00
├── 开发者:代码写完了,本地测试通过,提交!🎉
├── 周一早上 9:00
│ └── 测试:"这个功能在测试环境跑不起来"
└── 开发者:"不可能,在我电脑上明明能跑啊……"
笔者统计过,这个问题通常由以下原因导致:
新同事入职
├── Day 1:领电脑,配环境
├── Day 2:继续配环境,遇到问题
├── Day 3:换种方法配环境
├── Day 4:问老同事怎么配的,他也忘了
└── Day 5:终于能跑起来了!但不知道为什么……
运维:"我们需要把服务迁移到新服务器"
开发:"旧服务器上的配置文档在哪?"
运维:"当时是一个已经离职的同事配的……"
所有人:😱
Docker 的出现为上述问题提供了完美的解决方案。它通过 “一次构建,到处运行” 的核心理念,从根本上改变了软件交付的方式。
flowchart LR
dev["开发团队"] -->|创建| img["Docker 镜像"]
img -->|测试团队验证| test["测试团队"]
test -- "有问题
反馈修改和更新" --> dev
test -- "没问题
发布" --> prod["生产环境"]
除了解决上述痛点,Docker 还拥有诸多显著的技术优势,包括环境一致性、秒级启动、高效的资源利用等。
Docker 镜像包含了应用运行所需的 一切:代码、运行时、系统工具、库、配置。这意味着:
## 新同事入职第一天
$ git clone https://github.com/company/project.git
$ docker compose up
## 完整的开发环境就准备好了
...
传统虚拟机启动需要几分钟 (引导操作系统),而 Docker 容器启动通常只需要 几秒甚至几百毫秒。
笔者实测数据:
| 启动内容 | 虚拟机 | Docker 容器 |
|---|---|---|
| 空系统 | ~60 秒 | ~0.5 秒 |
| MySQL | ~90 秒 | ~3 秒 |
| 完整 Web 应用 | ~120 秒 | ~5 秒 |
这个差异对以下场景尤为重要:
Docker 容器共享宿主机内核,无需为每个应用运行完整的操作系统。以一台 64GB 内存的物理服务器为例:
flowchart TD
subgraph VM ["传统虚拟机方案 ❌"]
direction TB
Server1["物理服务器 (64GB 内存)"]
subgraph VMs ["可用应用内存: 约 18GB"]
direction LR
VM1["VM 1: 应用 1
(含 2GB OS)"]
VM2["VM 2: 应用 2
(含 2GB OS)"]
VM3["VM 3: 应用 3
(含 2GB OS)"]
end
Server1 --- VMs
end
subgraph Docker ["Docker 方案 ✅"]
direction TB
Server2["物理服务器 (64GB 内存)
含约 4GB OS及引擎配置"]
subgraph Containers ["可用应用内存: 约 60GB"]
direction LR
C1["容器 1: 应用 1
(按需分配)"]
C2["容器 2: 应用 2
(按需分配)"]
C3["容器 3: 应用 3
(按需分配)"]
end
Server2 --- Containers
end
Docker 完美契合 DevOps 的工作流程:
flowchart LR
A["代码提交
(Git push)"] --> B["自动构建镜像
(docker build)"]
B --> C["自动测试
(容器内运行测试)"]
C --> D["自动部署
(容器滚动更新)"]
使用 Dockerfile 定义镜像构建过程,使得:
Docker 可以在几乎任何平台上运行:
同一个镜像,在任何地方运行结果都一致。 这让应用迁移变得前所未有的简单。
现代微服务架构几乎都依赖容器技术。Docker 让你可以:
flowchart TD
subgraph Microservices ["微服务架构示例"]
direction TB
subgraph AppLayer ["应用层"]
direction LR
Frontend["前端容器
(Node.js)"]
API["API 容器
(Python)"]
Worker["Worker 容器
(Go)"]
end
Redis["Redis 容器"]
DB["PostgreSQL 容器"]
Frontend --> API
API --> Redis
API --> DB
Worker --> Redis
Worker --> DB
end
笔者认为,技术选型要客观。Docker 并非银弹,以下场景可能不太适合:
关于容器与虚拟机的详细特性对比,请参阅 1.2.3 Docker vs 虚拟机 中的对比表。总结来说: