管理Pod(rc,rs,deployment)
1.概述
可以把容器想像成豆荚里的豆子,把一个或多个关系紧密的豆子包在一起就是豆荚(一个Pod)。在k8s中我们不会直接操作容器,而是把容器包装成Pod再进行管理.
2.管理Pod
1
2
3
|
a. 使用Replication Controller 来部署、升级Pod
b. Replica
Set
– 下一代Replication Controller
c. Deployment – 更加方便的管理Pod和Replica
Set
|
例子1: 提出疑惑
1
2
3
4
5
6
7
8
9
10
|
先举个例子,假设我们有一个Pod在提供线上服务,现在有如下几个场景,大家想想如何应对:
1.
节日活动,网站访问量突增
2.
遭到攻击,网站访问量突增
3.
运行Pod的节点发生故障
第
1
种情况,活动前预先多启动几个Pod,活动结束后再结束掉多余的,虽然要启动和结束的Pod有点多,但也能有条不紊按计划进行
第
2
种情况,正在睡觉突然手机响了说网站反应特慢卡得要死,赶紧爬起来边扩容边查找攻击模式、封IP等等……
第
3
种情况,正在休假突然手机又响了说网站上不去,赶紧打开电脑查看原因,启动新的Pod
|
解决办法:引入rc
1
2
3
|
Pod需要手动管理,好累……能否在Pod发生问题时自动恢复呢,我们先来看下Replication Controller(以下简称RC)
先说RC是什么。RC保证在同一时间能够运行指定数量的Pod副本,保证Pod总是可用。如果实际Pod数量比指定的多就结束掉多余的,如果实际数量比指定的少就启动缺少的。<br>当Pod失败、被删除或被终结时RC会自动创建新的Pod来保证副本数量。所以即使只有一个Pod也应该使用RC来进行管理。
|
1
2
3
4
5
6
7
|
这个文件定义了RC的属性,我们先关注如下字段:
spec.replicas:副本数量
3
spec.selector:RC通过spec.selector来筛选要控制的Pod
spec.template:这里写Pod的定义(但不需要apiVersion和kind)
spec.template.metadata.labels:Pod的label,可以看到这个label与spec.selector相同
这个文件的意思是定义了一个RC对象,它的名字是hello
-
rc(metadata.name:hello
-
rc),保证有
3
个Pod运行(spec.replicas:
3
),<br>Pod的镜像是index.tenxcloud.com
/
tailnode
/
hello:v1.
0
(spec.template.spec.containers.image: index.tenxcloud.com
/
tailnode
/
hello:v1.
0
)<br>关键在于spec.selector与spec.template.metadata.labels,这两个字段必须相同,否则下一步创建RC会失败。<br>(也可以不写spec.selector,这样默认与spec.template.metadata.labels相同)
|
现在通过kubectl来创建RC:
解决办法:引入rs,官方推荐使用RS代替RC
1
2
3
|
1.RC
只支持基于等式的selector(env
=
dev或environment!
=
qa)但Replica
Set
还支持新的基于集合的selector(version
in
(v1.
0
, v2.
0
)或env notin (dev, qa)),<br>这对复杂的运维管理带来很大方便
2.
使用Deployment升级Pod只需要定义Pod的最终状态,k8s会为你执行必要的操作,虽然能够使用命令kubectl rolling
-
update完成升级,<br>但它是在客户端与服务端多次交互控制RC完成的,所以REST API中并没有rolling
-
update的接口,这为定制自己的管理系统带来了一些麻烦。
3.Deployment
拥有更加灵活强大的升级、回滚功能
|
Replica Set目前与RC的区别只是支持的selector不同,后续肯定会加入更多功能。Deployment使用了Replica Set,是更高一层的概念。除非需要自定义升级功能或根本不需要升级Pod,所以推荐使用Deployment而不直接使用Replica Set。
3.Pod创建流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
step.
1
kubectl 向 k8s api server 发起一个create pod 请求(即我们使用Kubectl敲一个create pod命令) 。
step.
2
k8s api server接收到pod创建请求后,不会去直接创建pod;而是生成一个包含创建信息的yaml。
step.
3
apiserver 将刚才的yaml信息写入etcd数据库。到此为止仅仅是在etcd中添加了一条记录, 还没有任何的实质性进展。
step.
4
scheduler 查看 k8s api ,类似于通知机制。
首先判断:pod.spec.Node
=
=
null?
若为null,表示这个Pod请求是新来的,需要创建;因此先进行调度计算,找到最“闲”的node。
然后将信息在etcd数据库中更新分配结果:pod.spec.Node
=
nodeA (设置一个具体的节点)
ps:同样上述操作的各种信息也要写到etcd数据库中中。
step.
5
kubelet 通过监测etcd数据库(即不停地看etcd中的记录),发现 k8s api server 中有了个新的Node;
如果这条记录中的Node与自己的编号相同(即这个Pod由scheduler分配给自己了);
则调用node中的docker api,创建container。
|
4.ReplicaSet创建流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
step.
1
kubectl 发起 create replicaSet 请求
step.
2
k8s api server 接受 replicaSet 创建请求,创建yaml。
step.
3
k8s api server将yaml的信息写入etcd数据库。
step.
4
Controller
-
Manager中的ReplicaSetController,在etcd数据库中读到了新的replicaSet 信息后,
向k8s api server发起请求,创建
3
个Pod(个数可以自己指定)。
step.
5
scheduler 在etcd中读到相应信息
若
3pod
.spec.Node
=
=
null
则执行调度计算,找到最“闲”的若干个Node(如果有一个Node真的太闲,可能
3
个Pod都会被起在这个Node上面)
pod1.spec.Node
=
nodeA (更新记录)
pod2.spec.Node
=
nodeB
pod3.spec.Node
=
nodeA (Node都是随机分配的)
将这些信息写回etcd数据库中。
step.
6
nodeA 的 kubelet 读etcd时读到apiserver的信息,调用docker api;创建属于自己的pod1
/
pod3的container
step.
7
nodeB kubelet 读到 k8s api server的信息,调用docker api,创建pod2的container。
|
4.生命周期,重启策略,镜像拉取
pod声明周期(状态):pending , running, succeeded, failed, unknown
1
2
3
4
5
|
挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非
0
状态退出或者被系统终止。
未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。
|
pod重启策略: 当某个容器异常退出或者健康检查失败, kubelet将根据RestartPolicy的设置来进行相应的操作, 重启策略有Always , OnFailure, Never
1
2
3
|
Always: 当容器失效时, 由kubelet自动重启该容器
OnFailure: 当容器终止运行且退出码不为
0
时, 由kubelet自动重启该容器
Never: 不论容器运行状态如何, kubelet都不会重启该容器
|
kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算, 例如1丶2丶4丶8倍等, 最长延时5min, 并且在重启后的10min后重置该时间
pod的重启策略与控制方式息息相关
RC和DeamonSet必须设置为Always,需要保证该容器持续运行
Job: OnFailure或Never, 确保容器执行完成后不再重启
镜像拉取策略
1
2
3
|
Always: 表示每次都尝试重新拉取镜像
IfNotPresent: 表示如果本地有镜像, 则使用本地的镜像, 本地不存在时拉取镜像
Never: 表示仅使用本地镜像
|
示例
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx spec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: restartPolicy: Always containers: - name: nginx image: nginx:1.12 imagePullPolicy: IfNotPresent ports: - containerPort: 80