Kubernetes 深入Pod
Pod声明周期和重启策略
Pod在整个生命周期过程中被系统定义为各种状态
状态值 | 描 述 |
---|---|
Pending | API Server已经创建该Pod,但Pod内还有一个或多个容器的镜像没有创建成功,包括正在下载的镜像的过程 |
Running | Pod内所有容器均已创建,且至少有一个容器处于运行状态、正在启动或正在重启状态 |
Succeeded | Pod内所有容器均已成功执行退出,且不会再重启 |
Failed | Pod内所有容器均已退出,但至少有一个容器退出为失败状态 |
Unknown | 由于某种原因无法获取该Pod的状态,可能由于网络通信不畅导致 |
Pod重启策略
Pod重启策略RestartPolicy
应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时,kubelet将根据RestartPolicy的设置来进行相应的操作。
Pod的重启策略包括Always、OnFailure和Never,默认值为Always
- Always:当容器失效时,由kubelet自动重启该容器
- OnFailure:当容器终止运行切退出代码不为0时,由kubelet自动重启该容器
- Never:不论容器运行状态如何,kubelet都不会重启该容器
kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算,例如1、2、4、8倍等,最长延时5min,并且在成功重启后的10min后重置该时间
Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下:
- RC和DaemonSet: 必须设置为Always,需要保证该容器持续运行
- Job: OnFailure或Never,确保容器执行完成后不再重启。
- Kubelet: 在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查
Pod 健康检查
对Pod的健康状态检查可以通过两类探针来检查:LivenessProbe
和ReadinessProbe
1.LivenessProbe探针
用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含你LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是 "Success"
2.ReadinessProbe探针
用于判断容器是否完成(Ready状态),可以接收请求。如果ReadinessProbe探针检测到失败,则Pod的状态将被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在的Pod的Endpoint
探针配置参数说明
探针参数 | 说明 |
---|---|
initialDelaySeconds | 启动活动或准备就绪探测之前容器启动后的秒数 |
periodSeconds | 执行探测的频率(以秒为单位)。默认为10秒。最小值为1 |
timeoutSeconds | 探测超时的秒数。默认为1秒。最小值为1 |
successThreshold | 失败后探测成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。 |
failureThreshold | Pod启动并且探测器失败时,Kubernetes会failureThreshold在放弃之前尝试一次。在活动探测的情况下放弃意味着重新启动Pod。如果准备好探测,Pod将被标记为未准备好。默认为3.最小值为1 |
Http探针配置
Http Get | 说明 |
---|---|
host | 要连接的主机名,默认为pod IP。您可能希望在httpHeaders中设置“主机” |
scheme | 用于连接主机(HTTP或HTTPS)的方案。默认为HTTP |
path | HTTP服务器上的访问路径 |
httpHeaders | 要在请求中设置的自定义标头。HTTP允许重复标头 |
port | 容器上要访问的端口的名称或编号。数字必须在1到65535的范围内 |
对于HTTP探测,kubelet将HTTP请求发送到指定的路径和端口以执行检查。kubelet将探测器发送到pod的IP地址,除非地址被可选host字段覆盖httpGet。如果 scheme字段设置为HTTPS,则kubelet会发送跳过证书验证的HTTPS请求。在大多数情况下,您不希望设置该host字段。这是您设置它的一个场景。假设Container侦听127.0.0.1并且Pod的hostNetwork字段为true。然后host,在httpGet,应设置为127.0.0.1。如果你的pod依赖虚拟主机,这可能是更常见的情况,你不应该使用host,而是设置Host标头httpHeaders
kubelet定期执行LivenessProbe探针来诊断容器的健康状况。LivenessProbe有以下三种方式
(1) ExecAction
在容器内执行一个命令,如果该命令的返回码为0,则表示容器健康
案例
通过执行"cat /tmp/health" 命令来判断一个容器运行是否正常。而该pod运行之后,在创建/tmp/health文件的10s之后将删除该文件,而LivenessProbe健康检查的初始探测时间(initialDelaySeconds)为15s,探测结果将是Fail,将导致kubelet杀掉该容器并重启它
[root@master test]# cat abcdocker_pod.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: abcdocker-pod
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: abcdocker-nginx-docker
image: daocloud.io/library/nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
command: ["/bin/sh", "-c", "echo ok >/tmp/health; sleep 60;rm -rf /tmp/health; sleep 600"]
livenessProbe:
exec:
command:
- cat
- /tmp/health
initialDelaySeconds: 15
timeoutSeconds: 1
=======================分割线======================
initialDelaySeconds #执行第一次探测之前等待15秒
periodSeconds #每5秒执行一次活跃度探测
结果演示
kubelet将cat /tmp/healthy在Container中执行命令。如果命令成功,则返回0,并且kubelet认为Container是活动且健康的。如果该命令返回非零值,则kubelet会终止Container并重新启动它。
当Container启动时,它会执行以下命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600" 对于Container的生命的前30秒,有一个/tmp/healthy文件。因此,在前30秒内,该命令cat /tmp/healthy返回成功代码。30秒后,cat /tmp/healthy返回失败代码。kubelet会将容器杀死并重新创建
(2) TCPSocketAction
通过容器的IP地址和端口号执行TCP检查,如果能联立TCP连接,则表示容器健康
TCP检查的配置与HTTP检查非常相似。在容器启动10秒后,kubelet将发送第一个就绪探测器。这将尝试连接到容器端口80上的容器。如果探测成功,则该pod将标记为就绪。kubelet将每10秒继续运行此检查。如果重启探测失败将会新建容器并重新启动
[root@master test]# cat abcdocker_pod.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: abcdocker-pod
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: abcdocker-nginx-docker
image: daocloud.io/library/nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 1
#参数解释请往上翻阅
测试 因为使用tomcat镜像,默认端口8080,所以80一直无法探测成功
(3) HTTPGetAction
通过容器的IP地址、端口号及路径调用HTTP Get方法,如果影响的状态码大于等于200且小于400,则认为容器状态健康。
为了执行探测,kubelet向在Container中运行的服务器发送HTTP GET请求并侦听端口80.如果服务器abcdicjer路径的处理程序返回成功代码,则kubelet认为Container是活动且健康的。如果处理程序返回失败代码,则kubelet会终止Container并重新启动它。
任何大于或等于200且小于400的代码表示成功。任何其他代码表示失败
[root@master test]# cat abcdocker_pod.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: abcdocker-pod
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: abcdocker-nginx-docker
image: daocloud.io/library/nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /abcdocker/
port: 80
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 1
因为请求的abcdocker路径不存在,所以容器报错404并进行重启
Pod 调度
在Kubernetes系统中,Pod在大部分场景下都只是容器的载体而已,通常需要Deployment、DaemonSet、RC、Job等对象来完成一组Pod的调度和自动控制功能
1.Deployment/RC:全自动调度
Deployment或RC的主要功能之一就是自动部署一个容器应用的多个副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量
下面是创建一个Deployment配置的例子,使用这个配置文件创建一个ReplicaSet,ReplicasSet (与Replication Controller同名)会创建3个nginx应用的pod
[root@master test]# cat abcdocker_pod.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: abcdocker-pod
spec:
replicas: 3
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: abcdocker-nginx-docker
image: daocloud.io/library/nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
从调度策略来说,这三个nginx Pod由系统全自动完成调度,它们各自最终运行在哪个节点上,完全由master的schedulet经过一系列的算法得出,用户无法干预调度过程和结果。
除了使用系统自动调度算法完成一组Pod的部署,Kubernetes也提供了丰富的调度策略,用户只需要在Pod的定义中使用NodeSelector
NodeAffinity
PodAffinity
Pod
驱逐等更加细粒的调度策略设置,就能完成对Pod的精准调度。
2.NodeSelector:定向调度
Kubernetes Master上的Scheduler服务(kube-scheduler进程) 负责实现Pod的调度,这个调度过程通过一系列复杂的算法,最终为每个Pod计算出一个最佳的目标节点,这一过程是自动完成的,通常我们无法指定Pod最终会被调度在哪个节点上,在实际强开中,也可以需要将pod调度到指定的一些Node上,可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配,来达到目的。
(1) 首先通过kubectl label命令给目标Node打赏一些标签
kubectl label nodes [node-name] <label-key>=<label-value>
这里我们使用node节点打上一个abcdocker=aaa的标签
[root@master test]# kubectl label nodes node abcdocker=aaa
上述命令操作也可以通过修改资源定义文件的方式,并执行kubectl replace -f xxx.yaml命令来完成
(2)需要在Pod中定义nodeSelector的配置,我们以Nginx为例
[root@master test]# cat abcdocker_pod.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: abcdocker-pod
spec:
replicas: 3
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: abcdocker-nginx-docker
image: daocloud.io/library/nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
nodeSelector:
abcdocker: aaa
###nodeSelector是配置绑定node
abcdocker:aaa 是我们之前创建的标签
如果我们给多个Node都定义了相同的标签(例如:abcdocker=aaa),则scheduler将会根据调度算法从这组Node中挑选一个可用的Node进行pod调度