Docker 和 Kubernetes 有什么区别?从容器打包到集群编排,附配置文件实战
Docker 和 Kubernetes 对比|附配置文件
在云原生技术快速发展的今天,Docker 和 Kubernetes 几乎是每个后端工程师、运维工程师、架构师都绕不开的两个关键词。很多初学者会把它们放在一起比较,甚至认为 Kubernetes 是 Docker 的替代品。但严格来说,二者并不是同一层面的工具:Docker 更偏向于容器的构建、运行和管理,而 Kubernetes 更偏向于容器集群的编排和调度。
本文将从概念、架构、使用场景、核心能力、配置文件示例等多个角度,对 Docker 和 Kubernetes 进行系统对比,并附上常见配置文件示例,帮助你更清晰地理解它们之间的关系和区别。
一、Docker 是什么?
Docker 是一个开源的容器化平台,它可以将应用程序及其运行依赖打包到一个轻量级、可移植的容器中,从而实现“一次构建,到处运行”。
在传统部署方式中,一个应用往往依赖特定版本的操作系统、语言运行时、系统库、环境变量等。如果开发环境、测试环境和生产环境不一致,就很容易出现“在我电脑上明明可以运行”的问题。
Docker 通过镜像和容器解决了这个问题。
Docker 的核心概念
1. 镜像 Image
镜像可以理解为一个只读模板,里面包含应用程序、依赖库、运行环境和启动命令。例如,一个 Java 应用镜像可能包含:
- JDK
- Spring Boot 应用 jar 包
- 配置文件
- 启动脚本
镜像是容器运行的基础。
2. 容器 Container
容器是镜像运行起来之后的实例。镜像类似“类”,容器类似“对象”。
一个镜像可以启动多个容器,每个容器之间相互隔离,但共享宿主机内核。
3. Dockerfile
Dockerfile 是用于构建镜像的配置文件,它描述了镜像如何一步步生成。
4. Docker Compose
Docker Compose 是 Docker 官方提供的多容器编排工具,适合在单机环境下启动多个服务,例如应用服务、MySQL、Redis、Nginx 等。
二、Kubernetes 是什么?
Kubernetes,简称 K8s,是一个开源的容器编排平台,最初由 Google 设计并开源,目前由 CNCF 维护。
如果说 Docker 解决的是“如何把应用打包成容器并运行”的问题,那么 Kubernetes 解决的是“如何在大规模服务器集群中可靠地运行和管理容器”的问题。
Kubernetes 具备以下能力:
- 自动调度容器到合适的节点
- 容器故障后自动重启
- 节点故障后自动迁移
- 服务发现和负载均衡
- 滚动发布和回滚
- 自动扩缩容
- 配置和密钥管理
- 存储编排
- 集群资源管理
在生产环境中,当服务数量、服务器数量、容器数量逐渐增多时,单纯使用 Docker 命令或 Docker Compose 已经难以管理,这时 Kubernetes 的价值就体现出来了。
三、Docker 和 Kubernetes 的关系
Docker 和 Kubernetes 不是简单的竞争关系,而是上下层关系。
可以这样理解:
- Docker:负责容器镜像构建和单机容器运行
- Kubernetes:负责多个节点上的容器调度、编排和管理
在早期 Kubernetes 中,Docker 曾经是最常用的容器运行时。但从 Kubernetes 1.24 开始,Kubernetes 移除了对 dockershim 的内置支持,默认更推荐使用符合 CRI 标准的容器运行时,例如:
- containerd
- CRI-O
需要注意的是,这并不意味着 Docker 镜像不能在 Kubernetes 中运行。Docker 构建出来的镜像仍然符合 OCI 镜像标准,可以被 containerd、CRI-O 等运行时正常拉取和运行。
换句话说:
Docker 仍然常用于本地开发和镜像构建,而 Kubernetes 常用于生产环境中的集群编排。
四、Docker 和 Kubernetes 核心区别对比
下面通过表格对二者进行对比。
| 对比维度 | Docker | Kubernetes |
|---|---|---|
| 定位 | 容器化平台 | 容器编排平台 |
| 主要作用 | 构建、运行、管理容器 | 调度、编排、管理容器集群 |
| 使用场景 | 本地开发、单机部署、小规模服务 | 生产集群、大规模微服务、多节点部署 |
| 管理范围 | 单台主机为主 | 多台主机组成的集群 |
| 配置方式 | Dockerfile、docker-compose.yml | YAML 资源清单 |
| 服务发现 | 需要借助 Compose 网络或额外工具 | 内置 Service 和 DNS |
| 负载均衡 | 基础能力较弱 | 内置服务负载均衡 |
| 自动恢复 | 容器可配置 restart 策略 | Pod 自动重建、节点故障迁移 |
| 扩缩容 | 手动或借助脚本 | 支持手动和自动扩缩容 |
| 滚动发布 | 需要额外脚本或 Compose 支持有限 | 原生支持 Deployment 滚动更新 |
| 学习成本 | 较低 | 较高 |
| 适合团队 | 个人、小团队、开发测试 | 中大型团队、生产环境 |
五、Docker 的典型使用场景
Docker 更适合以下场景:
1. 本地开发环境统一
开发团队可以通过 Docker 构建一致的开发环境。例如后端服务依赖 MySQL、Redis、RabbitMQ 等中间件,团队成员无需分别安装,只需执行:
docker compose up -d
即可启动完整开发环境。
2. 应用镜像构建
在 CI/CD 流水线中,Docker 通常用于构建应用镜像。例如:
docker build -t my-app:1.0.0 .
然后将镜像推送到镜像仓库:
docker push registry.example.com/my-app:1.0.0
3. 单机部署
对于一些小型项目、个人项目、内部工具,单机 Docker 部署已经足够。通过 Docker Compose 可以同时管理 Web 服务、数据库、缓存等组件。
六、Kubernetes 的典型使用场景
Kubernetes 更适合以下场景:
1. 微服务架构
当系统拆分为多个微服务后,每个服务可能有多个副本,并且服务之间需要发现和调用。Kubernetes 提供了 Service、DNS、Ingress 等机制,非常适合管理微服务。
2. 高可用生产环境
Kubernetes 可以在 Pod 异常退出后自动重启,也可以在节点故障时将应用调度到其他可用节点上,从而提高系统可用性。
3. 弹性伸缩
在流量高峰时,可以通过 HPA 根据 CPU、内存或自定义指标自动扩容服务副本数;在低峰时自动缩容,节省资源。
4. 标准化交付
Kubernetes 使用声明式 YAML 描述应用状态,适合 GitOps、DevOps 和自动化发布流程。
七、Docker 配置文件示例
下面以一个简单的 Spring Boot 应用为例,展示 Dockerfile 和 Docker Compose 配置。
假设项目结构如下:
my-app/
├── Dockerfile
├── docker-compose.yml
└── target/
└── my-app.jar
1. Dockerfile 示例
# 使用精简版 JDK 运行环境作为基础镜像
FROM eclipse-temurin:17-jre-alpine
# 设置工作目录
WORKDIR /app
# 复制 jar 包到镜像中
COPY target/my-app.jar app.jar
# 暴露应用端口
EXPOSE 8080
# 设置 JVM 参数,可通过环境变量覆盖
ENV JAVA_OPTS="-Xms256m -Xmx512m"
# 容器启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
这个 Dockerfile 的作用是将 Spring Boot 应用打包成一个可运行镜像。构建命令如下:
docker build -t my-app:1.0.0 .
运行容器:
docker run -d \
--name my-app \
-p 8080:8080 \
my-app:1.0.0
2. docker-compose.yml 示例
如果应用依赖 MySQL 和 Redis,可以使用 Docker Compose 一键启动。
version: "3.9"
services:
app:
image: my-app:1.0.0
container_name: my-app
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
- mysql
- redis
restart: always
mysql:
image: mysql:8.0
container_name: my-mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root123456
MYSQL_DATABASE: app_db
MYSQL_USER: app_user
MYSQL_PASSWORD: app_pass
volumes:
- mysql-data:/var/lib/mysql
restart: always
redis:
image: redis:7-alpine
container_name: my-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: always
volumes:
mysql-data:
redis-data:
启动命令:
docker compose up -d
查看容器:
docker compose ps
停止服务:
docker compose down
Docker Compose 的优点是简单直观,非常适合开发测试和小规模部署。但它主要面向单机环境,在集群调度、高可用、自动扩缩容方面能力有限。
八、Kubernetes 配置文件示例
Kubernetes 使用 YAML 文件描述资源对象。常见资源包括:
- Deployment:管理应用副本和滚动发布
- Service:提供稳定访问入口和负载均衡
- ConfigMap:管理普通配置
- Secret:管理敏感信息
- Ingress:管理 HTTP/HTTPS 入口
- PersistentVolumeClaim:申请持久化存储
下面仍以同一个应用为例。
1. Deployment 配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: registry.example.com/my-app:1.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: MYSQL_HOST
value: "mysql"
- name: REDIS_HOST
value: "redis"
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "1Gi"
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 40
periodSeconds: 15
这个 Deployment 表示希望 Kubernetes 始终保持 3 个 my-app 副本运行。如果某个 Pod 异常退出,Kubernetes 会自动创建新的 Pod 来补足副本数。
2. Service 配置
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 8080
Service 为 Pod 提供稳定访问入口。即使后端 Pod 被重建,Service 的名称和虚拟 IP 也保持稳定。在集群内部,其他服务可以通过以下地址访问:
http://my-app-service
3. ConfigMap 配置
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
data:
application.yml: |
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://mysql:3306/app_db?useSSL=false&serverTimezone=Asia/Shanghai
username: app_user
redis:
host: redis
port: 6379
ConfigMap 适合存放非敏感配置,例如服务端口、数据库地址、缓存地址等。
如果要在 Deployment 中挂载 ConfigMap,可以这样配置:
volumeMounts:
- name: config-volume
mountPath: /app/config
volumes:
- name: config-volume
configMap:
name: my-app-config
4. Secret 配置
敏感信息不建议直接写入 ConfigMap,例如数据库密码、Token、证书等,应该使用 Secret。
apiVersion: v1
kind: Secret
metadata:
name: my-app-secret
type: Opaque
stringData:
MYSQL_PASSWORD: app_pass
JWT_SECRET: my-jwt-secret
在 Deployment 中引用 Secret:
env:
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secret
key: MYSQL_PASSWORD
需要注意,Kubernetes Secret 默认只是 Base64 编码,并不等于强加密。生产环境中还应结合 RBAC、KMS、密钥管理系统等手段提升安全性。
5. Ingress 配置
如果希望从集群外部通过域名访问应用,可以配置 Ingress。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
访问方式:
http://app.example.com
Ingress 通常需要配合 Ingress Controller 使用,例如 Nginx Ingress Controller、Traefik、APISIX Ingress 等。
6. HPA 自动扩缩容配置
Kubernetes 可以根据 CPU 使用率自动调整 Pod 副本数。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
这段配置表示:当 CPU 平均使用率超过 60% 时,Kubernetes 会在 3 到 10 个副本之间自动扩容或缩容。
九、从 Docker Compose 到 Kubernetes 的迁移思路
很多团队一开始会使用 Docker Compose 部署服务,随着业务增长再迁移到 Kubernetes。迁移时可以按照以下思路进行:
1. 拆分服务
Docker Compose 中的每个 service,在 Kubernetes 中通常会拆分成:
- Deployment
- Service
- ConfigMap
- Secret
- PVC
例如 Compose 中的 app 服务,在 Kubernetes 中至少需要一个 Deployment 和一个 Service。
2. 处理配置
Compose 中的 environment 可以迁移到 Kubernetes 的 env、ConfigMap 或 Secret 中。
普通配置放 ConfigMap,敏感配置放 Secret。
3. 处理数据持久化
Compose 中的 volume 需要迁移为 Kubernetes 的 PersistentVolumeClaim。
例如 MySQL 的数据目录不应随 Pod 删除而丢失,需要使用持久化存储。
4. 处理服务访问
Compose 中服务之间可以通过 service name 访问。Kubernetes 中服务之间通过 Service 名称访问,例如:
mysql.default.svc.cluster.local
或者简写为:
mysql
5. 处理外部入口
Compose 常通过端口映射暴露服务,例如:
ports:
- "8080:8080"
Kubernetes 中可以使用:
- NodePort
- LoadBalancer
- Ingress
生产环境中更推荐使用 Ingress 或云厂商 LoadBalancer。
十、Docker 和 Kubernetes 如何选择?
如果你正在做技术选型,可以参考以下建议。
选择 Docker 的情况
如果你的项目满足以下条件,Docker 或 Docker Compose 通常已经足够:
- 项目规模较小
- 服务数量较少
- 只部署在单台服务器上
- 不需要复杂的自动扩缩容
- 团队运维能力有限
- 更重视简单快速上线
例如个人博客、内部管理系统、小型 API 服务、测试环境等,都可以优先使用 Docker Compose。
选择 Kubernetes 的情况
如果你的项目具备以下特点,更适合使用 Kubernetes:
- 服务数量较多
- 采用微服务架构
- 需要多节点部署
- 对高可用要求较高
- 需要滚动发布和快速回滚
- 需要自动扩缩容
- 团队具备一定运维和平台能力
- 计划建设统一的 DevOps 或云原生平台
不过,也要注意 Kubernetes 并不是银弹。它的学习成本、维护成本和排障复杂度都明显高于 Docker。对于小团队来说,如果没有专门人员维护集群,贸然上 Kubernetes 可能会增加不必要的负担。
十一、常见误区
误区一:Kubernetes 替代了 Docker
不准确。Kubernetes 替代的不是 Docker 的全部能力,而是部分单机容器管理能力。Docker 仍然可以用于镜像构建、本地开发、调试和简单部署。
误区二:用了 Kubernetes 就一定高可用
不一定。Kubernetes 提供了高可用的基础能力,但应用本身也需要支持无状态化、健康检查、优雅停机、配置外置、数据库高可用等设计。否则只是把不稳定的应用放进了更复杂的平台。
误区三:Docker Compose 不能用于生产
Docker Compose 并非绝对不能用于生产。对于小规模系统,只要做好数据备份、日志收集、监控告警、重启策略和安全配置,Compose 也可以满足需求。但对于复杂生产环境,Kubernetes 的治理能力更强。
误区四:Kubernetes 配置越复杂越专业
Kubernetes YAML 并不是越复杂越好。高质量的配置应该清晰、可维护、可复用,并且符合实际业务需求。过度抽象和过度配置反而会提高维护成本。
十二、总结
Docker 和 Kubernetes 是云原生体系中非常重要的两个工具,但它们解决的问题不同。
Docker 的核心价值在于容器化:
它让应用和依赖可以被统一打包、快速分发、稳定运行,非常适合本地开发、镜像构建和单机部署。
Kubernetes 的核心价值在于容器编排:
它让大量容器可以在集群中被自动调度、弹性伸缩、故障恢复和统一管理,非常适合生产环境和微服务架构。
简单来说:
Docker 解决“如何把应用装进容器并运行”的问题;
Kubernetes 解决“如何在集群中稳定、高效地管理大量容器”的问题。
在实际项目中,二者往往是配合使用的:开发阶段用 Docker 构建镜像和本地调试,生产阶段将镜像部署到 Kubernetes 集群中,由 Kubernetes 负责服务治理、扩缩容和高可用管理。
如果你是初学者,建议先掌握 Docker 的基础概念和 Docker Compose 的使用,再逐步学习 Kubernetes 的核心资源对象,如 Pod、Deployment、Service、ConfigMap、Secret、Ingress 和 HPA。这样学习路径会更自然,也更容易理解云原生应用的完整交付流程。