Docker 和 Kubernetes(K8s)是最常被混淆的两个概念:很多人以为它们是同类产品,实际上它们解决的是完全不同层级的问题。Docker 是"容器运行时"(run a container),Kubernetes 是"容器编排平台"(manage thousands of containers)。本文用清晰的对比和选型决策,帮你理解两者的关系。
一、定位差异:一件事的两个层级
| 维度 | Docker | Kubernetes |
|---|---|---|
| 核心层级 | 容器运行时 + 镜像构建 | 容器编排 / 调度平台 |
| 解决的核心问题 | “如何把应用打包成容器并在单机上运行” | “如何在集群中管理成百上千个容器” |
| 类比 | 单个集装箱及其内容 | 港口调度系统(管理无数集装箱的装卸、调度、路由) |
| 主要操作对象 | 镜像(Image)、容器(Container) | Pod、Deployment、Service、Ingress |
| 功能范围 | 构建、运行、网络、存储(单机) | 调度、扩缩容、自愈、服务发现、负载均衡(集群) |
| 学习曲线 | 平缓(1-2 天上手) | 陡峭(2-4 周入门) |
| 运维复杂度 | 低 | 高 |
协作关系
Kubernetes Cluster
├── Master Node(控制平面)
│ └── API Server / Scheduler / Controller Manager / etcd
└── Worker Node(计算节点)
└── kubelet → 调用 → Docker / containerd(容器运行时)
↑
Docker 在这里:实际启动/停止容器
关键点:Kubernetes 本身不"运行"容器,它通过 kubelet 调用 Docker(或 containerd / CRI-O)来实际运行容器。Docker 是 K8s 的底层依赖之一。
二、Docker 提供的核心能力
# 构建镜像
docker build -t my-app .
# 运行容器
docker run -d -p 3000:3000 my-app
# 容器间通信(单机)
docker network create my-net
docker run --name db --network my-net postgres
docker run --name api --network my-net my-api
Docker 的局限(单机体感):
- 只能管理一台机器上的容器
- 容器故障不会自动重启
- 流量大了不能自动扩容
- 没有内置的服务发现和负载均衡
三、Kubernetes 提供的核心能力
# deployment.yaml:声明式部署 3 个副本
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-api
spec:
replicas: 3
selector:
matchLabels:
app: my-api
template:
metadata:
labels:
app: my-api
spec:
containers:
- name: api
image: my-app:v1.0
ports:
- containerPort: 3000
K8s 解决的核心问题:
| 场景 | Docker 单机 | K8s |
|---|---|---|
| 容器挂了 | 手动重启 | 自动重启(Self-healing) |
| 流量突增 | 手动启动新容器 | HPA 自动扩缩容 |
| 滚动更新 | 手动停旧启新 | 零停机滚动更新 |
| 服务发现 | 手动配 IP | 内置 DNS 服务发现 |
| 负载均衡 | 手动配 Nginx | 内置 Service + Ingress |
| 配置管理 | 环境变量 | ConfigMap / Secret |
| 存储挂载 | Volume | PersistentVolume / StorageClass |
| 多机部署 | 不支持 | 跨节点调度 |
四、中间层:Docker Compose
Docker Compose 是 Docker 官方的单机多容器编排工具,适合开发和测试环境:
# docker-compose.yml
version: '3'
services:
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: secret
api:
build: .
ports:
- "3000:3000"
depends_on:
- db
environment:
DATABASE_URL: postgres://postgres:secret@db:5432/mydb
volumes:
postgres_data:
# 一键启动整个应用栈
docker-compose up -d
# 停止
docker-compose down
Docker Compose 的定位:
- ✅ 本地开发环境
- ✅ CI/CD 测试流水线
- ✅ 小型项目(< 5 个服务)的单机部署
- ❌ 生产级多机集群(这时需要 K8s)
五、选型决策树
你需要运行容器?
├── 是 → 只有一台服务器?
│ ├── 是 → 服务数量?
│ │ ├── 1-3 个服务 → Docker Compose ✅
│ │ └── 4+ 个服务 → Docker Compose 勉强可用 ✅
│ └── 否(多台服务器/集群)→ 需要 K8s ✅
└── 否 → 你不需要 Docker 也不需要 K8s
Kubernetes 必需场景(必须上 K8s):
├── 多服务器容器调度
├── 自动扩缩容(HPA)
├── 生产级滚动更新(零停机)
├── 复杂的微服务拓扑(10+ 服务互调)
└── 多云/混合云部署
场景矩阵
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 本地开发 | Docker Compose | 简单,一键启动全栈 |
| 单服务生产部署 | Docker + systemd | 最简单,运维成本低 |
| 小型 SaaS(3-5 服务) | Docker Compose + 1-2 台服务器 | 够用,维护简单 |
| 中型产品(5-20 服务) | Kubernetes(托管) | AWS EKS / GKE / 阿里云 ACK |
| 大型微服务(20+ 服务) | Kubernetes + Service Mesh(Istio) | 服务治理、流量管控 |
| Serverless | 无需 Docker/K8s | 直接用 Vercel / Lambda / Cloud Run |
六、托管 K8s vs 自建 K8s
| 方案 | 成本 | 运维负担 | 适用 |
|---|---|---|---|
| 自建 K8s | 低(只有服务器费用) | 极高 | 大规模、有专职 DevOps 团队 |
| AWS EKS | 中 ($73/月集群管理费 + EC2) | 低 | AWS 用户 |
| GKE | 中 ($73/月 + GCP 费用) | 低 | GCP 用户 |
| 阿里云 ACK | 中 (~¥400/月 + ECS) | 低 | 国内部署 |
| Vercel / Railway / Render | 高(按量) | 无 | 不想碰 K8s 的小团队 |
常见问题(FAQ)
Kubernetes 正在淘汰 Docker 吗?
不是淘汰 Docker 作为容器运行时,而是 K8s 在 1.24 版本移除了对 Docker Engine 的直接支持,改用 containerd 作为默认容器运行时。containerd 是 Docker 的核心运行时组件,Docker 本身也基于 containerd。
对开发者的影响:开发机上仍然用 Docker Desktop 构建镜像、运行容器。K8s 集群内部默默用 containerd 替代 Docker Engine,这是 K8s 内部实现细节,对使用者几乎透明。
公司内部已经用 Docker 了,需要立刻迁移到 K8s 吗?
不需要。Docker 容器可以在任何地方运行。只有当以下情况才需要引入 K8s:
- 单台服务器资源不够,需要多机部署
- 容器数量多到手动管理困难
- 业务对高可用和自动扩容有硬性要求
有了 K8s 还需要 Docker 吗?
仍然需要。Docker(或 BuildKit / Podman)负责构建镜像。K8s 不构建镜像,它只运行和管理镜像。两者是上下游关系,不是替代关系。
相关阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。