共计 3760 个字符,预计需要花费 10 分钟才能阅读完成。
文章目录[显示]
你用 Docker 跑了几个容器,觉得自己已经站在云原生的门口了。然后有人告诉你:" 试试 Kubernetes 吧。" 于是你打开官方文档,看到 Pod、Service、Deployment、ReplicaSet、Ingress……默默关上了浏览器。
别慌。今天这篇文章,就是帮你把那扇门真正推开。
先搞清楚一个问题:Docker 不够用吗?
Docker 解决了 " 在我机器上能跑 " 的经典难题。一个容器打包好,扔到哪里都能运行,这很好。
但当你的应用从 1 个容器变成 10 个、50 个时,问题来了:
- 某个容器挂了,谁来自动重启?
- 流量暴增时,谁来自动扩容?
- 10 个容器之间的网络通信怎么管理?
- 滚动更新怎么做到不停机?
Docker Compose 能解决部分问题,但它本质上还是个 " 单机编排 " 工具。你需要的是一个 集群级别的调度系统——这就是 Kubernetes(简称 K8s)登场的理由。
Kubernetes 核心概念:只需记住三个
K8s 的概念多到让人头皮发麻,但对于入门而言,你只需要先吃透三个。
Pod:最小调度单元
Pod 不是容器,而是 " 一组容器的包装 "。大多数情况下,一个 Pod 里只跑一个容器,你可以简单理解为 Pod ≈ 一个运行中的容器实例。
为什么不直接管理容器?因为 K8s 需要在 Pod 层面附加额外信息:IP 地址、存储卷、重启策略等。Pod 是 K8s 的原子单位,就像进程之于操作系统。
Deployment:声明式管理
Deployment 告诉 K8s:" 我希望始终有 3 个 Pod 在运行。" 然后 K8s 会帮你维持这个状态——挂了一个就自动拉起一个,需要更新就滚动替换。
这就是所谓的 声明式 思维:你不用说 " 先停掉旧的,再启动新的 ",你只需要说 " 我要的最终状态是什么 ",K8s 自己想办法达到。
Service:稳定的访问入口
Pod 的 IP 是临时的,每次重启都可能变化。Service 提供一个 固定的虚拟 IP 和 DNS 名称,把请求自动转发到后面的 Pod 上。
你可以把 Service 理解为一个内置的负载均衡器:前端应用访问 http://backend-service:8080,不用关心背后到底有几个 Pod、IP 是什么。
从 Docker Compose 到 K8s:一个实际的迁移示例
假设你有一个经典的 Web 应用,Docker Compose 文件长这样:
# docker-compose.yml
version: '3'
services:
web:
image: my-web-app:1.0
ports:
- "8080:8080"
environment:
- DB_HOST=db
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:
两个服务:一个 Web 应用,一个 MySQL 数据库。现在我们把它搬到 K8s 上。
第一步:Web 应用的 Deployment + Service
# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: my-web-app:1.0
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: db-service
---
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: NodePort
selector:
app: web
ports:
- port: 8080
targetPort: 8080
nodePort: 30080
关键对比: Compose 里写 ports: "8080:8080",K8s 里拆成了 containerPort、targetPort 和 nodePort 三层。replicas: 3 意味着直接起了 3 个实例——这在 Compose 里需要额外配置。
第二步:数据库的 Deployment + Service
# db-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: db
spec:
replicas: 1
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: secret
- name: MYSQL_DATABASE
value: myapp
---
apiVersion: v1
kind: Service
metadata:
name: db-service
spec:
selector:
app: db
ports:
- port: 3306
targetPort: 3306
Web 应用里环境变量 DB_HOST=db-service,对应的就是这个 Service 的名称。K8s 内置 DNS 会自动将 db-service 解析到数据库 Pod 的地址。
(生产环境数据库建议用 StatefulSet 而非 Deployment,但入门阶段先这样跑起来,别给自己太大压力。)
用 Minikube 在本地跑起来
说了这么多 YAML,该动手了。Minikube 是 K8s 官方的本地开发工具,能在你的笔记本上模拟一个单节点集群。
安装 Minikube
macOS 用户一行命令搞定:
brew install minikube
Linux 用户:
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
启动集群并部署
# 启动集群(首次启动需要几分钟,去倒杯水)minikube start
# 部署数据库
kubectl apply -f db-deployment.yaml
# 部署 Web 应用
kubectl apply -f web-deployment.yaml
# 查看 Pod 状态
kubectl get pods
# 查看 Service
kubectl get services
顺利的话,你会看到类似这样的输出:
NAME READY STATUS RESTARTS AGE
db-5d4f7b8c9-x2k8m 1/1 Running 0 45s
web-7f8a6b5d4-abc12 1/1 Running 0 30s
web-7f8a6b5d4-def34 1/1 Running 0 30s
web-7f8a6b5d4-ghi56 1/1 Running 0 30s
3 个 Web Pod,1 个数据库 Pod,全部 Running。
访问应用
minikube service web-service --url
这条命令会返回一个本地可访问的 URL。打开浏览器,你的应用已经在 K8s 上跑起来了。
体验自愈能力
现在来点刺激的——手动删掉一个 Pod:
kubectl delete pod web-7f8a6b5d4-abc12
然后立刻执行 kubectl get pods,你会发现 K8s 在几秒内自动创建了一个新 Pod 来维持 3 副本的状态。这就是 Deployment 的声明式管理在起作用。
Docker Compose 能做到吗?不能。容器挂了就是挂了,得你自己去重启。
Compose 到 K8s 的核心思维转变
| 维度 | Docker Compose | Kubernetes |
|---|---|---|
| 运行范围 | 单机 | 集群 |
| 扩缩容 | 手动 | 声明 replicas 自动维持 |
| 自愈 | 无 | Pod 崩溃自动重建 |
| 服务发现 | 容器名直连 | Service + 内置 DNS |
| 更新策略 | 停机替换 | 滚动更新,零停机 |
| 配置管理 | .env 文件 | ConfigMap / Secret |
最核心的转变是:从 " 命令式 " 到 " 声明式 "。你不再告诉系统 " 做什么 ",而是告诉它 " 我要什么样的结果 "。
下一步该学什么
跑通了今天的例子,你已经完成了从单机 Docker 到集群编排的第一步。接下来建议按这个顺序深入:
第一,ConfigMap 和 Secret。 把数据库密码写在 YAML 里显然不安全,Secret 专门解决这个问题。
第二,Ingress。 目前我们用 NodePort 暴露服务,生产环境需要 Ingress 来做域名路由和 HTTPS 终止。
第三,持久化存储。 数据库的数据不能跟着 Pod 一起消失,PersistentVolume 和 PersistentVolumeClaim 是必修课。
第四,Helm。 当你的 YAML 文件多到需要 " 管理 YAML 的工具 " 时,Helm 就该上场了。它是 K8s 的包管理器,相当于 apt 之于 Ubuntu。
Kubernetes 的学习曲线确实陡峭,但好消息是:你不需要一次学完。先把今天的 Deployment、Service、Pod 玩熟,足够覆盖大部分开发环境的需求。
毕竟,登珠峰也是从大本营开始的——而你现在,已经扎好了营地。