在 kubernetes 的世界里,Pod 是运行应用的载体。 Pod 是由多个容器组成、是 kubernetes 的最小调度单元、Pod 共享底层资源、由 kubernetes 来管理生命周期。

一般情况下,我们并不直接创建 Pod,而是通过 Deployment 来创建 Pod,由 Deployment 来负责创建、更新、维护其所管理的所有 Pods。

这里注意并不直接管理pod, 而是通过管理replicaset来间接管理pod,即:deployment管理replicaset,replicaset管理pod。所以deployment比replicaset的功能更强大。

一、Deployment介绍与工作原理

1.介绍

Deployment是一种更高阶的工作负载资源。其可以视作为对RS的再一次升级。其不仅可以部署应用还可以通过声明的方式升级应用。具体地,Deployment被创建后,其内部先创建相应的RS资源。再利用该RS资源创建相应的Pod

deployment介绍

2.工作流程

工作流程
图片来源书籍: kubernetes in action

客户端将创建 Deployment 的请求发送给 Apiserver
Apiserver 将 Deployment 信息写入 etcd,etcd 将写入结果响应给 Apiserver,Apiserver 将创建结果响应给客户端 (此时未经过 ControllerManager,deployment 的 READY 状态为 0)
ControllerManager 通过 Apiserver 的 watch 接口,获取到新增的 Deployment 资源,Deployment controller 向 Apiserver 发送创建 RS 的请求,Apiserver 将 RS 信息写入 etcd。。。
ControllerManager 通过 Apiserver 的 watch 接口,获取到新增的 ReplicaSet 资源,ReplicaSet controller 向 Apiserver 发送创建 Pod 的请求,Apiserver 将 Pod 信息写入 etcd。。。
Scheduler 通过 Apiserver 的 watch 接口,获取到未调度的 Pod 的通知,根据调度算法选择一个 node 节点,告诉 Apiserver 这个 Pod 应该运行在哪个节点
Apiserver 将这个 Pod 和 node 的绑定信息更新到 etcd,etcd 将写入结果响应给 Apiserver
Kubelet 通过 Apiserver 的 watch 接口,获取到当前节点有创建 Pod 的通知,Kubelet 调用 docker 创建容器,Kubelet 将 Pod 运行状态发送给 Apiserver
Apiserver 将 Pod 状态信息更新到 etcd

二、Deployment的使用

1.创建Deployment

利用 Deployment 也可以创建 Pod,下面来比较一下两种方式创建 Pod 的区别。

方式一:使用kubectl run 创建 Pod

bash
1
kubectl run my-nginx --image=nginx:1.20 -n hello-world

方式二:使用 kubectl create deployment 创建 Pod

bash
1
kubectl create deployment my-nginx-dep --image=nginx:1.20 -n hello-world

如果此时要删除上面创建的 Pod ,对于方式一创建的,很简单,直接执行下面的这行语句即可:

bash
1
kubectl delete pod my-nginx -n hello-world

而要删除方式二创建的 Pod ,我们还能用下面的这行语句吗?

bash
1
kubectl delete pod my-nginx-dep -n hello-world

这么做,是删不掉的。因为每删除一次,k8s又会自动创建一个新的 my-nginx-dep 的 Pod(Deployment自愈能力的体现)。

原因在于方式二是通过 Deployment 的方式创建的 Pod(以部署一个应用的方式)。

如果要删除方式二创建的 Pod,可以通过下面的步骤进行:

bash
1
2
3
4
5
# 第一步,获取deploy(部署)列表信息
kubectl get deploy -n hello-world

# 第二步,通过删除deploy(部署)的方式删除Pod
kubectl delete deploy my-tomcat -n hello-world

2.Deployment的各种能力

2.1 多副本能力

副本:可以理解为对于一个应用而言,将它运行在一个 Pod 上就是起一个副本,将它运行在多个 Pod 上,就是起了多个副本。

下面通过两种方式,来实现多副本的能力。

方式一:命令行方式

bash
1
2
3
4
5
6
7
8
# 通过部署的方式,创建nginx的3个副本
kubectl create deployment nginx-base --image=nginx --replicas=3 -n hello-world

# 查看部署列表信息
kubectl get deploy -n hello-world

# 删除本次部署(即同时删除3个Pod)
kubectl delete deploy nginx-base -n hello-world

方式二:yaml文件方式

(1)写一个 yaml 文件,例如 nginx-base.yaml

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1 # 版本号
kind: Deployment # 资源类型
metadata:
labels:
app: nginx-base # 标签名称
name: nginx-base # 本次部署的名字
namespace: hello-world # 命名空间
spec:
replicas: 3 # 副本数量
selector:
matchLabels:
app: nginx-base
template:
metadata:
labels:
app: nginx-base
spec:
containers:
- image: nginx:1.20 # 容器的镜像名称
name: nginx # 容器名

(2)执行 nginx-base.yaml 文件

bash
1
kubectl apply -f nginx-base.yaml

2.2 扩缩容能力

扩容:遇到流量高峰,需要增加副本数量,降低当前负载

缩容:流量高峰过去,不需要这么多副本,减少数量

方式一:命令行方式

bash
1
2
3
4
5
# 将nginx-base的副本数量扩容到5个
kubectl scale --replicas=5 deployment/nginx-base -n hello-world

# 将nginx-base的副本数量缩减到2个
kubectl scale --replicas=2 deployment/nginx-base -n hello-world

方式二:修改yaml方式

打开对应的 yaml 文件,修改副本发数量,然后保存退出即可。

(1)打开文件

bash
1
2
3
kubectl get deploy

kubectl edit deployment nginx-base

(2)编辑文件

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1 # 版本号
kind: Deployment # 资源类型
metadata:
labels:
app: nginx-base # 标签名称
name: nginx-base # 本次部署的名字
namespace: hello-world # 命名空间
spec:
replicas: 2 # 副本数量
selector:
matchLabels:
app: nginx-base
template:
metadata:
labels:
app: nginx-base
spec:
containers:
- image: nginx:1.20 # 容器的镜像名称
name: nginx # 容器名

(3)保存退出

2.3 自愈及故障转移能力

自愈能力:假设某个 Pod 发生故障,不能正常对外提供服务,此时 k8s 会自动杀死该 Pod ,然后再将该 Pod 重新启动。

转移能力:假设某个 Pod 所在的结点 node-01 发生了宕机,整个服务器坏掉,不能正常使用,当 k8s 经过一小段时间(可能是5分钟)检测后,发现该服务器确实不能提供服务了,那么 k8s 会自动在其它结点上重新创建 node-01 结点里面的所有 Pod ,以达到正常对外提供服务的目的。

2.4 滚动更新能力

k8s 在更新集群应用时,对于每个结点上的 Pod ,会先启动一个新的 Pod ,然后再停掉对应的老的 Pod,如此循环,直至实现每个结点上的 Pod 的更新,才算完成本次集群应用的更新。

方式一:命令行方式

bash
1
2
3
kubectl set image deployment/nginx-base nginx=nginx:1.16.1 --record -n hello-world

kubectl rollout status deployment/nginx-base -n hello-world

方式二:修改yaml方式

打开对应的 yaml 文件,修改副本发数量,然后保存退出即可。

(1)打开文件

bash
1
2
3
kubectl get deploy

kubectl edit deployment nginx-base

(2)编辑文件

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1 # 版本号
kind: Deployment # 资源类型
metadata:
labels:
app: nginx-base # 标签名称
name: nginx-base # 本次部署的名字
namespace: hello-world # 命名空间
spec:
replicas: 2 # 副本数量
selector:
matchLabels:
app: nginx-base
template:
metadata:
labels:
app: nginx-base
spec:
containers:
- image: nginx:1.16.1 # 容器的镜像名称
name: nginx # 容器名

(3)保存退出

2.5 版本回退能力

如果对当前这次部署不满意,无法正常提供服务,k8s可以回滚到之前的历史版本。

bash
1
2
3
4
5
6
7
8
9
10
11
#历史记录
kubectl rollout history deployment/nginx-base -n hello-world

#查看某个历史详情
kubectl rollout history deployment/nginx-base --revision=2

#回滚到上次版本
kubectl rollout undo deployment/nginx-base -n hello-world

#回滚到指定版本
kubectl rollout undo deployment/nginx-base --to-revision=2 -n hello-world