第8章:K8s 核心概念(上)- 工作负载
我们的 K8s 集群已经就绪,就像一个建好的港口。现在,我们需要学习如何把我们的"集装箱"(容器)运送到这个港口,并让港口按照我们的意愿来管理它们。
在 K8s 的世界里,我们不直接操作单个容器。相反,我们通过操作更高级别的 "工作负载 (Workload)" 资源来管理应用的生命周期。本章,我们将学习两个最核心的工作负载资源:Pod 和 Deployment。
8.1 Pod:K8s 的原子调度单元
在 Docker 中,最基本的管理单元是容器。但在 K8s 中,情况有所不同。
Pod 是 Kubernetes 中创建和管理的、最小的可部署计算单元。
把它想象成一个"豆荚"。一个豆荚(Pod)里,可以包含一个或多个紧密相关的豆子(容器)。
-
一个 Pod 里有什么?
- 一个或多个容器 :这些容器共享同一个网络空间(它们可以用
localhost
互相访问)和存储卷(数据卷)。 - 网络资源:每个 Pod 都会被分配一个集群内唯一的 IP 地址。
- 存储资源:可以为 Pod 挂载存储卷。
- 一个或多个容器 :这些容器共享同一个网络空间(它们可以用
-
为什么需要 Pod? 为什么不直接管理容器呢?因为有些应用场景,需要多个容器"像一个单元一样"被部署和管理。最经典的例子是"边车模式 (Sidecar)":一个主应用容器,旁边跟着一个专门负责日志收集或网络代理的辅助容器。这两个容器生命周期高度一致,需要被一起调度、一起扩缩容。Pod 完美地解决了这个问题。
-
黄金法则 : 虽然一个 Pod 可以有多个容器,但在绝大多数情况下(99%) ,我们的实践是"一个 Pod,一个容器"。除非你有非常明确的理由,否则请坚持这个原则,它能让你的应用架构更清晰。
所以,你可以暂时简单地理解为:Pod 就是对 Docker 容器的一层封装。
8.2 ReplicaSet & Deployment:应用的扩缩容与滚动更新
我们很少会直接创建一个孤零零的 Pod。为什么?因为如果这个 Pod 所在的 Node 节点宕机了,这个 Pod 也就消失了,K8s 不会自动重建它。这显然不满足我们对高可用的要求。
我们需要一个更高级别的"老板"来照看我们的 Pod。
-
ReplicaSet (副本集)
- 职责 :它的唯一职责,就是确保在任何时候,都有指定数量的、一模一样的 Pod 副本在运行。
- 工作方式:你告诉 ReplicaSet:"我需要3个A应用的Pod副本"。它就会创建3个。如果有一个Pod死掉了,ReplicaSet 会立刻发现,并马上创建一个新的来替代它,始终维持总数为3。
-
Deployment
-
职责 :这是我们在生产环境中最常用 的工作负载资源。它是一个更高级别的控制器,它管理 ReplicaSet ,并为我们提供了更强大的功能,特别是声明式的应用更新(滚动更新)和回滚。
-
工作方式:
- 你创建一个 Deployment,在里面定义你应用的期望状态(比如,使用
my-app:1.0
镜像,需要3个副本)。 - Deployment 会创建一个 ReplicaSet。
- ReplicaSet 再去创建3个 Pod。
- 这个关系链是 Deployment -> ReplicaSet -> Pods。
- 你创建一个 Deployment,在里面定义你应用的期望状态(比如,使用
-
为什么需要 Deployment? 想象一下你要发布新版本
my-app:1.1
。你只需要修改 Deployment 的定义,把镜像版本从1.0
改成1.1
。Deployment 就会智能地为你执行一次滚动更新 (Rolling Update):它会创建一个新的、使用新版本镜像的 ReplicaSet,然后一个一个地用新 Pod 替换旧 Pod,直到全部替换完成。整个过程服务不中断,非常平滑。
-
8.3 [实战] 将我们的 Web 应用部署到 K8s
理论讲完了,让我们把之前在 Docker 篇创建的 my-app
应用,部署到我们的 Minikube 集群中。
第一步:准备 YAML 文件
与 K8s 交互,就是与 YAML 文件打交道。在你的 my-app
项目根目录下,创建一个名为 deployment.yaml
的文件。
yaml
# 指定 API 版本
apiVersion: apps/v1
# 指定资源类型为 Deployment
kind: Deployment
# 元数据,描述这个 Deployment
metadata:
name: my-app-deployment
# 规格,定义期望状态
spec:
# 期望的 Pod 副本数量
replicas: 2
# 选择器,告诉 Deployment 要管理哪些 Pod
selector:
matchLabels:
app: my-app
# Pod 的模板,定义了要创建的 Pod 长什么样
template:
metadata:
# Pod 自身的标签,必须和上面的 selector 匹配
labels:
app: my-app
spec:
# 定义 Pod 中的容器
containers:
- name: my-app-container
# 使用哪个镜像
# 注意:这里需要使用你推送到 Docker Hub 的镜像地址
# 并且 minikube 可能需要特殊设置才能访问本地镜像
image: <your-dockerhub-username>/my-app:1.1
# 容器监听的端口
ports:
- containerPort: 8080
重要提示:关于镜像 Minikube 运行在一个独立的 Docker 环境中,它默认是无法访问你主机本地 Docker 里的镜像的。你有两个选择:
- 推荐 :将你构建好的镜像
push
到 Docker Hub,然后在 YAML 文件里使用完整的 Docker Hub 镜像地址,如docker.io/<your-username>/my-app:1.1
。 - 开发技巧 :执行
eval $(minikube docker-env)
(macOS/Linux) 或minikube docker-env | Invoke-Expression
(PowerShell)。这个命令会将你的命令行环境指向 Minikube 内的 Docker daemon。这样,你再执行docker build
,镜像就会被直接构建到 Minikube 内部,可以直接使用。
第二步:应用你的配置
使用 kubectl apply
命令,将你的"期望状态"提交给 K8s 集群。
bash
kubectl apply -f deployment.yaml
apply
: K8s 的核心命令之一,表示"让集群的状态与这个文件描述的一致"。-f
: 指定配置文件的路径。
执行后,如果成功,会提示 deployment.apps/my-app-deployment created
。
第三步:检查部署状态
bash
# 查看 Deployment 的状态
kubectl get deployment my-app-deployment
# 查看 ReplicaSet
kubectl get rs
# 查看 Pods,你应该能看到两个 my-app-deployment-xxx 的 Pod 正在运行
kubectl get pods
你还可以用 describe
命令查看更详细的信息,这在排错时非常有用: kubectl describe deployment my-app-deployment
kubectl describe pod <pod_name>
8.4 [实战] 体验"永不宕机"的滚动更新
现在,来体验一下 K8s 最令人兴奋的功能。
体验自愈能力 手动删除一个 Pod,模拟故障:
bash
# 找到一个 Pod 的名字,比如 my-app-deployment-xxxx
kubectl delete pod <pod_name>
删除后,你立刻再次执行 kubectl get pods
,你会发现 K8s 几乎在瞬间就创建了一个新的 Pod 来替代被删除的那个,replicas
始终保持为2。这就是 ReplicaSet 的功劳。
体验滚动更新
-
修改代码并构建新镜像:
- 修改
app.js
,比如返回 "Hello, Kubernetes!"。 - 构建一个新版本的镜像
my-app:1.2
,并推送到 Docker Hub (或者构建到 Minikube 内部)。
- 修改
-
更新 Deployment: 有两种方式:
-
方法一(推荐) :直接修改
deployment.yaml
文件,将image
的 tag 改为1.2
,然后再次执行kubectl apply -f deployment.yaml
。K8s 会智能地计算出差异并只更新变化的部分。 -
方法二(命令式) :
bashkubectl set image deployment/my-app-deployment my-app-container=<your-dockerhub-username>/my-app:1.2
-
-
观察更新过程 : 执行更新后,立刻打开另一个终端,执行
kubectl get pods -w
(-w
表示 watch,实时监控变化)。你会看到 K8s 正在:- 创建一个新的 Pod (版本1.2)
- 等新 Pod 启动成功后,删除一个旧的 Pod (版本1.1)
- 再创建一个新 Pod,再删除一个旧 Pod...
- 直到所有 Pod 都更新为版本1.2。
整个过程服务不中断。这就是滚动更新的魅力!
体验回滚 如果发现新版本有 Bug 怎么办?一键回滚!
bash
# 查看发布历史
kubectl rollout history deployment/my-app-deployment
# 回滚到上一个版本
kubectl rollout undo deployment/my-app-deployment
K8s 会用同样平滑的方式,将应用回滚到之前的稳定版本。
8.5 本章小结
你已经掌握了在 K8s 中部署无状态应用的核心技能。
- 本章回顾 :
- 我们理解了 Pod 是 K8s 中最小的部署单元,通常坚持"一个 Pod 一个容器"的原则。
- 我们学习了通过 Deployment 来管理应用的副本数量、自愈和滚动更新。
- 我们掌握了通过编写 YAML 文件来向 K8s 声明我们的应用部署意图。
- 我们使用
kubectl apply
将应用部署到了 K8s,并用get
,describe
,delete
等命令进行了交互。 - 我们亲身体验了 K8s 强大的自愈能力 、滚动更新 和一键回滚功能。
目前,我们的应用虽然已经在 K8s 中运行起来了,但外界还无法访问它。在下一章,我们将学习 K8s 的网络核心------Service,来为我们的应用打开通往世界的大门。