失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Pod资源管理进阶-Pod对象的生命周期

Pod资源管理进阶-Pod对象的生命周期

时间:2020-06-04 07:14:37

相关推荐

Pod资源管理进阶-Pod对象的生命周期

目录

Pod的生命周期

1、存活性探测行为属性 (Liveness probe)

2、Pod就绪性探测

3、Pod对象的相位

4、Pod的创建过程

5、Pod生命周期中的重要阶段

6、容器的重启策略

7、Pod的终止过程

8、设置Pod对象的安全上下文securityContext

9、资源需求及资源限制

9.1资源需求

9.2资源限制

10、Pod得服务质量类别

1、存活性探测行为属性 (Liveness probe)

使用kubectl describe命令查看配置了存活性探测的Pod对象的详细信息时,其相关容器中会输出类似如下一行的内容:

Liveness: exec [test -e /tmp/healthy] delay=0s timeout=1s period=10s

#success=1 #failure=3

它给出了探测方式及其额外的配置属性delay、timeout、period、success和failure及其各自的相关属性值。用户没有明确定义这些属性字段时,它们会使用各自的默认值,例如上面显示出的设定。这些属性信息可通过“spec.containers.livenessProbe”的如下属性字段来给出。

initialDelaySeconds<integer>

存活性探测延迟时长,即容器启动多久之后再开始第一次探测操作,显示为delay属性;默认为0秒,即容器启动后立刻便开始进行探测。

timeoutSeconds<integer>

存活性探测的超时时长,显示为timeout属性,默认为1s,最小值也为1s

periodSeconds<integer>

存活性探测的频度,显示为period属性,默认为10s,最小值为1s;过高的频率会对Pod对象带来较大的额外开销,而过低的频率又会使得对错误的反应不及时。

successThreshold<integer>

处于失败状态时,探测操作至少连续多少次的成功才被认为是通过检测,显示为#success属性,默认值为1,最小值也为1。

failureThreshold

处于成功状态时,探测操作至少连续多少次的失败才被视为是检测不通过,显示为#failure属性,默认值为3,最小值为1。

现在我们查看一个liveness-exec.yaml实例:

[root@master ~]# git clone /iKubernetes/Kubernetes_Advanced_Practical

Cloning into 'Kubernetes_Advanced_Practical'...

remote: Enumerating objects: 489, done.

remote: Total 489 (delta 0), reused 0 (delta 0), pack-reused 489

Receiving objects: 100% (489/489), 148.75 KiB | 13.00 KiB/s, done.

Resolving deltas: 100% (122/122), done.

[root@master ~]# cd Kubernetes_Advanced_Practical/

[root@master Kubernetes_Advanced_Practical]# ls

chapter10 chapter11 chapter12 chapter13 chapter14 chapter15 chapter2 chapter3 chapter4 chapter5 chapter6 chapter7 chapter8 chapter9 conf_files README.md

[root@master Kubernetes_Advanced_Practical]# cd chapter4

[root@master chapter4]# vim liveness-exec.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

test: liveness-exec

name: liveness-exec

spec:

containers:

- name: liveness-demo

image: busybox

args:

- /bin/sh

- -c

- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 #创建/tmp/healthy;睡眠30s以后,在删除 /tmp/healthy这个文件,在睡眠600s

livenessProbe:

exec:

command:

- test

- -e

- /tmp/healthy #这个文件只要是存在得我就认为是健康得 注意这里我们只指定了exec没指定其他的 其它得都会使用默认值

[root@master chapter4]# kubectl apply -f liveness-exec.yaml

pod/liveness-exec created

[root@master chapter4]# kubectl get pods -o wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

liveness-exec 1/1 Running 0 37s 10.244.2.5 node2 <none> <none>

mypod 1/1 Running 0 41h 10.244.2.4 node2 <none> <none>

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d16h 10.244.2.3 node2 <none> <none>

间隔30s以后查看容器得详细信息

[root@master chapter4]# kubectl describe pods liveness-exec

Name: liveness-exec

Namespace: default

Priority: 0

Node: node2/172.21.16.33

Start Time: Wed, 11 Nov 10:57:17 +0800

Labels: test=liveness-exec

Annotations: <none>

Status: Running

IP: 10.244.2.5

IPs:

IP: 10.244.2.5

Containers:

liveness-demo:

Container ID: docker://bf8f3d77ecadf8f86c50dccc87d1d27e8e215af160cc58dfde631eee088d31e0

Image: busybox

Image ID: docker-pullable://busybox@sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d

Port: <none>

Host Port: <none>

Args:

/bin/sh

-c

touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600

State: Running

Started: Wed, 11 Nov 10:59:14 +0800

Last State: Terminated

Reason: Error

Exit Code: 137

Started: Wed, 11 Nov 10:57:39 +0800

Finished: Wed, 11 Nov 10:59:02 +0800

Ready: True

Restart Count: 1 #这里可以查看到重启了1次

Liveness: exec [test -e /tmp/healthy] delay=0s timeout=1s period=10s #success=1 #failure=3

Environment: <none>

Mounts:

/var/run/secrets/kubernetes.io/serviceaccount from default-token-2jsh9 (ro)

Conditions:

Type Status

Initialized True

Ready True

ContainersReady True

PodScheduled True

Volumes:

default-token-2jsh9:

Type: Secret (a volume populated by a Secret)

SecretName: default-token-2jsh9

Optional: false

QoS Class: BestEffort

Node-Selectors: <none>

Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s

node.kubernetes.io/unreachable:NoExecute op=Exists for 300s

Events:

Type Reason Age From Message

---- ------ ---- ---- -------

Normal Scheduled 2m38s default-scheduler Successfully assigned default/liveness-exec to node2

Normal Pulled 2m16s kubelet Successfully pulled image "busybox" in 21.497183923s

Normal Killing 83s kubelet Container liveness-demo failed liveness probe, will be restarted

Normal Pulling 53s (x2 over 2m37s) kubelet Pulling image "busybox"

Normal Pulled 42s kubelet Successfully pulled image "busybox" in 11.010754251s

Normal Created 41s (x2 over 2m16s) kubelet Created container liveness-demo

Normal Started 41s (x2 over 2m16s) kubelet Started container liveness-demo

Warning Unhealthy 3s (x4 over 103s) kubelet Liveness probe failed:

[root@master chapter4]# kubectl get pods

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 4 7m23s #这里我们可以看到liveness-exec这个pod被重启了4次

mypod 1/1 Running 0 41h

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d16h

查看 liveness-http.yaml实例

[root@master chapter4]# vim liveness-http.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

test: liveness

name: liveness-http

spec:

containers:

- name: liveness-demo

image: nginx:1.14-alpine

ports:

- name: http

containerPort: 80

lifecycle: # 2、上面是我们运行了一个Nginx镜像,我们又借助于lifecycle启动后事件专门创建了一个用于做健康状态检测的URL放在了ng的网页文件路径下

postStart:

exec:

command:

- /bin/sh

- -c

- 'echo Healty > /usr/share/nginx/html/healthz'

livenessProbe: # 3、随着我们健康状态检测 就是像 /usr/share/nginx/html/healthz这个网页发请求,如果能请求成功我们认为是健康得,如果失败我们则认为是不健康得

httpGet: # 1、我们使用 httpGet去向本机得/healthz的URL发送请求,这个文件来自于哪里是我们借助于 lifecycle创建的

path: /healthz

port: http #这里的http是调用上面的ports的name 这两个值必须保持一致

scheme: HTTP

periodSeconds: 2 #每两s中检测一次

failureThreshold: 2 #探测操作至少连续2次的失败才被视为是检测不通过

initialDelaySeconds: 3 #即容器启动3s之后再开始第一次探测操作

[root@master chapter4]# kubectl apply -f liveness-http.yaml

pod/liveness-http created

[root@master chapter4]# kubectl get pods -o wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

liveness-exec 0/1 CrashLoopBackOff 9 26m 10.244.2.5 node2 <none> <none>

liveness-http 1/1 Running 0 58s 10.244.1.5 node1 <none> <none>

mypod 1/1 Running 0 42h 10.244.2.4 node2 <none> <none>

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d17h 10.244.2.3 node2 <none> <none>

[root@master chapter4]# kubectl describe pods liveness-http #查看健康状态检测的详细信息

Name: liveness-http

Namespace: default

Priority: 0

Node: node1/172.21.96.13

Start Time: Wed, 11 Nov 11:22:23 +0800

Labels: test=liveness

Annotations: <none>

Status: Running

IP: 10.244.1.5

IPs:

IP: 10.244.1.5

Containers:

liveness-demo:

Container ID: docker://e099143e80a5d9fbaf8fd01f85e07afdaef85d20c5a43e9cdf6fbc6d3934dae5

Image: nginx:1.14-alpine

Image ID: docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7

Port: 80/TCP

Host Port: 0/TCP

State: Running

Started: Wed, 11 Nov 11:22:34 +0800

Ready: True

Restart Count: 0

Liveness: http-get http://:http/healthz delay=3s timeout=1s period=2s #success=1 #failure=2

Environment: <none>

Mounts:

/var/run/secrets/kubernetes.io/serviceaccount from default-token-2jsh9 (ro)

Conditions:

Type Status

Initialized True

Ready True

ContainersReady True

PodScheduled True

Volumes:

default-token-2jsh9:

Type: Secret (a volume populated by a Secret)

SecretName: default-token-2jsh9

Optional: false

QoS Class: BestEffort

Node-Selectors: <none>

Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s

node.kubernetes.io/unreachable:NoExecute op=Exists for 300s

Events:

Type Reason Age From Message

---- ------ ---- ---- -------

Normal Scheduled 2m14s default-scheduler Successfully assigned default/liveness-http to node1

Normal Pulling 2m14s kubelet Pulling image "nginx:1.14-alpine"

Normal Pulled 2m3s kubelet Successfully pulled image "nginx:1.14-alpine" in 10.768366105s

Normal Created 2m3s kubelet Created container liveness-demo

Normal Started 2m3s kubelet Started container liveness-demo

[root@master chapter4]# kubectl exec -it liveness-http -- /bin/sh #连接到容器里面模拟删除healthz的网页文件查看健康状态检测

/ # ls

bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var

/ # cd /usr/share/nginx/html/

/usr/share/nginx/html # ls

50x.html healthz index.html

/usr/share/nginx/html # rm healthz

[root@master chapter4]# kubectl get pods #可以查看liveness-http的Pod的重启了1次

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 11 31m

liveness-http 1/1 Running 1 6m17s

mypod 1/1 Running 0 42h

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d17h

2、Pod就绪性探测

Pod对象启动后,容器应用通常需要一段时间才能完成其初始化过程,例如加载配置或数据,甚至有些程序需要运行某类的预热过程,若在此阶段完成之前即接入客户端的请求,势必会因为等待太久而影响用户体验。因此,应该避免于Pod对象启动后立即让其处理客户端请求,而是等待容器初始化工作执行完成并转为“就绪”状态,尤其是存在其他提供相同服务的Pod对象的场景更是如此。与存活性探测机制类似,就绪性探测是用来判断容器就绪与否的周期性(默认周期为10秒钟)操作,它用于探测容器是否已经初始化完成并可服务于客户端请求,探测操作返回“success”状态时,即为传递容器已经“就绪”的信号。与存活性探测机制相同,就绪性探测也支持Exec、HTTP GET和TCP Socket三种探测方式,且各自的定义机制也都相同。但与存活性探测触发的操作不同的是,探测失败时,就绪性探测不会杀死或重启容器以保证其健康性,而是通知其尚未就绪,并触发依赖于其就绪状态的操作(例如,从Service对象中移除此Pod对象)以确保不会有客户端请求接入此Pod对象。不过,即便是在运行过程中,Pod就绪性探测依然有其价值所在,例如Pod A依赖到的PodB因网络故障等原因而不可用时,Pod A上的服务应该转为未就绪状态,以免无法向客户端提供完整的响应。将容器定义中的livenessProbe字段名替换为readinessProbe即可定义出就绪性探测的配置,一个简单的示例如下面的配置清单(readiness-exec.yaml)所示,它会在Pod对象创建完成5秒钟后使用test-e/tmp/ready命令来探测容器的就绪性,命令执行成功即为就绪,探测周期为5秒钟:

[root@master chapter4]# vim readiness-exec.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

test: readiness-exec

name: readiness-exec

spec:

containers:

- name: readiness-demo

image: busybox

args: ["/bin/sh", "-c", "while true; do rm -f /tmp/ready; sleep 30; touch /tmp/ready; sleep 300; done"] #模拟就绪检测不成功不成功 30s之后成功了

readinessProbe:

exec:

command: ["test", "-e", "/tmp/ready"] # readinessProbe检测就看这个文件存在与否

initialDelaySeconds: 5 #延迟5s中检测

periodSeconds: 5

[root@master chapter4]# kubectl apply -f readiness-exec.yaml

pod/readiness-exec created

接着,运行“kubectl get-w”命令监视其资源变动信息,由如下命令结果可知,尽管Pod对象处于“Running”状态,但直到就绪探测命令执行 成功后,Pod资源才转为“就绪”:
[root@master chapter4]# kubectl get pods -w #实时去检测容器的状态

NAME READY STATUS RESTARTS AGE

liveness-exec 1/1 Running 49 3h8m

liveness-http 1/1 Running 1 163m

mypod 1/1 Running 0 44h

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d19h

readiness-exec 0/1 Running 0 28s

readiness-exec 1/1 Running 0 39s #看这里

liveness-exec 0/1 CrashLoopBackOff 49 3h9m

模拟把文件删除,查看是否还是就绪的状态

[root@master chapter4]# kubectl get pods -w

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 CrashLoopBackOff 49 3h12m

liveness-http 1/1 Running 1 167m

mypod 1/1 Running 0 44h

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d20h

readiness-exec 1/1 Running 0 4m9s

readiness-exec 0/1 Running 0 4m9s #可以看到左边的为1

我们在人为的创建一个看下效果

^C[root@master chapter4]# kubectl exec readiness-exec -- touch /tmp/ready

[root@master chapter4]# kubectl get pods -w

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 CrashLoopBackOff 49 3h14m

liveness-http 1/1 Running 1 169m

mypod 1/1 Running 0 44h

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d20h

readiness-exec 0/1 Running 0 6m2s

readiness-exec 1/1 Running 0 6m4s

liveness-exec 1/1 Running 50 3h14m #可以看到左边的为1

这里需要特别注意的是,未定义就绪性探测的Pod对象在Pod进入“Running”状态后将立即就绪,在容器需要时间进行初始化的场景 中,在应用真正就绪之前必然无法正常响应客户端请求,因此,生产实践中,必须为关键性Pod资源中的容器定义就绪性探测机制。

3、Pod对象的相位

Pod启动起来以后,Pod对象总是应该处于其生命进程中以下几个相位(phase)之一。 Pending:API Server创建了Pod资源对象并已存入etcd中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。 (一般是资源无法满足调度的需求时会出现pending)Running:Pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成。 Succeeded:Pod中的所有容器都已经成功终止并且不会被重启。 Failed:所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态或已经被系统终止。Unknown:API Server无法正常获取到Pod对象的状态信息,通常 是由于其无法与所在工作节点的kubelet通信所致。

4、Pod的创建过程

Pod是Kubernetes的基础单元,理解它的创建过程对于了解系统运作大有裨益。图4-10描述了一个Pod资源对象的典型创建过程。 1)用户通过kubectl或其他API客户端提交Pod Spec给API Server。 2)API Server尝试着将Pod对象的相关信息存入etcd中,待写入操作执行完成,API Server即会返回确认信息至客户端。 3)API Server开始反映etcd中的状态变化。 4)所有的Kubernetes组件均使用“watch”机制来跟踪检查API Server上的相关的变动。 5)kube-scheduler(调度器)通过其“watcher”觉察到API Server创建了新的Pod对象但尚未绑定至任何工作节点。 6)kube-scheduler为Pod对象挑选一个工作节点并将结果信息更新至API Server。7)调度结果信息由API Server更新至etcd存储系统,而且API Server也开始反映此Pod对象的调度结果。 8)Pod被调度到的目标工作节点上的kubelet尝试在当前节点上调用Docker启动容器,并将容器的结果状态回送至API Server。 9)API Server将Pod状态信息存入etcd系统中。 10)在etcd确认写入操作成功完成后,API Server将确认信息发送至相关的kubelet,事件将通过它被接受。

5、Pod生命周期中的重要阶段

除了创建应用容器(主容器及其辅助容器)之外,用户还可以为Pod对象定义其生命周期中的多种行为,如初始化容器、存活性探测及就绪性探测等。1.初始化容器初始化容器(init container)即应用程序的主容器启动之前要运行的容器,常用于为主容器执行一些预置操作,它们具有两种典型特征。 1)初始化容器必须运行完成直至结束,若某初始化容器运行失 败,那么Kubernetes需要重启它直到成功完成。 2)每个初始化容器都必须按定义的顺序串行运行。

注意: 如果Pod的spec.restartPolicy字段值为“Never”,那么运行失败的初始化容器不会被重启。

有不少场景都需要在应用容器启动之前进行部分初始化操作,例如,等待其他关联组件服务可用、基于环境变量或配置模板为应用程序生成配置文件、从配置中心获取配置等。初始化容器的典型应用需求具 体包含如下几种。 1)用于运行特定的工具程序,出于安全等方面的原因,这些程序不适于包含在主容器镜像中。 2)提供主容器镜像中不具备的工具程序或自定义代码。 3)为容器镜像的构建和部署人员提供了分离、独立工作的途径,使得他们不必协同起来制作单个镜像文件。 4)初始化容器和主容器处于不同的文件系统视图中,因此可以分别安全地使用敏感数据,例如Secrets资源。 5)初始化容器要先于应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至其依赖的条件得到满足。Pod资源的“spec.initContainers”字段以列表的形式定义可用的初始容器,其嵌套可用字段类似于“spec.containers”。下面的资源清单仅是一个 初始化容器的使用示例,可自行创建并观察初始化容器的相关状态

[root@master ~]# vim initialized.yaml

apiVersion: v1

kind: Pod

metadata:

name: myapp-pod

labels:

app: myapp

spec:

containers:

- name: myapp-container

image: ikubernetes/myapp:v1

initContainers:

- name: init-something

image: busybox

command: ['sh', '-c', 'sleep 10']

[root@master ~]# kubectl apply -f initialized.yaml

pod/myapp-pod created

[root@master ~]# kubectl get pods -w

NAME READY STATUS RESTARTS AGE

liveness-exec 0/1 CrashLoopBackOff 59 3h54m

liveness-http 1/1 Running 1 3h29m

myapp-pod 0/1 Init:0/1 0 9s

mypod 1/1 Running 0 45h

ng-dep-5fb7d74687-vfssn 1/1 Running 0 5d20h

readiness-exec 1/1 Running 0 46m

myapp-pod 0/1 Init:0/1 0 29s

myapp-pod 0/1 PodInitializing 0 39s

myapp-pod 1/1 Running

2.生命周期钩子函数 生命周期钩子函数(lifecycle hook)是编程语言(如Angular)中常 用的生命周期管理的组件,它实现了程序运行周期中的关键时刻的可见 性,并赋予用户为此采取某种行动的能力。类似地,容器生命周期钩子 使它能够感知其自身生命周期管理中的事件,并在相应的时刻到来时运 行由用户指定的处理程序代码。Kubernetes为容器提供了两种生命周期钩子。 postStart:于容器创建完成之后立即运行的钩子处理器(handler),不过Kubernetes无法确保它一定会于容器中的 ENTRYPOINT之前运行preStop:于容器终止操作之前立即运行的钩子处理器,它以同步的方式调用,因此在其完成之前会阻塞删除容器的操作的调用

钩子处理器的实现方式有“Exec”和“HTTP”两种,前一种在钩子事 件触发时直接在当前容器中运行由用户定义的命令,后一种则是在当前 容器中向某URL发起HTTP请求。

postStart和preStop处理器定义在容器的spec.lifecycle嵌套字段中,其使用方法如下面的资源清单所示,可自行创建相关的Pod资源对象,并验证其执行结果:

apiVersion: v1

kind: Pod

metadata:

name: lifecycle-demo

spec:

containers:

- name: lifecycle-demo-container

image: ikubernetes/myapp:v1

lifecycle:

postStart:

exec:

command: ["/bin/sh","-c","echo 'lifecycle hooks handler' > /usr/share/nginx/html/test.html"]

3.容器探测

容器探测(container probe)是Pod对象生命周期中的一项重要的日常任务,它是kubelet对容器周期性执行的健康状态诊断,诊断操作由容器的处理器(handler)进行定义。Kubernetes支持三种处理器用于Pod探 测。 ·ExecAction:在容器中执行一个命令,并根据其返回的状态码进行诊断的操作称为Exec探测,状态码为0表示成功,否则即为不健康状 态。·TCPSocketAction:通过与容器的某TCP端口尝试建立连接进行诊断,端口能够成功打开即为正常,否则为不健康状态。 ·HTTPGetAction:通过向容器IP地址的某指定端口的指定path发起HTTP GET请求进行诊断,响应码为2xx或3xx时即为成功,否则为失败。任何一种探测方式都可能存在三种结果:“Success”(成功)、“Failure”(失败)或“Unknown”(未知),只有第一种结果表示 成功通过检测。 ·kubelet可在活动容器上执行两种类型的检测:存活性检测(livenessProbe)和就绪性检测(readinessProbe)。·存活性检测:用于判定容器是否处于“运行”(Running)状态;一 此类检测未通过,kubelet将杀死容器并根据其restartPolicy决定是否将 其重启;未定义存活性检测的容器的默认状为“Success”。就绪性检测:用于判断容器是否准备就绪并可对外提供服务;未通过检测的容器 意味着其尚未准备就绪,端点控制器(如Service对象)会将其IP从所有 匹配到此Pod对象的Service对象的端点列表中移除;检测通过之后,会再次将其IP添加至端点列表中。

6、容器的重启策略

Pod对象容器程因容器发生程序崩溃或容器申请超出限制的资源等原因都可能会导致Pod对象的终止,此时是否应该重建该Pod对象则取决于其重启策略 (restartPolicy)属性的定义。 1)Always:但凡Pod对象终止就将其重启,此为默认设定。 Always时默认的2)OnFailure:仅在Pod对象出现错误时方才将其重启。 正常终止就不重启3)Never:从不重启。需要注意的是,restartPolicy适用于Pod对象中的所有容器,而且它仅用于控制在同一节点上重新启动Pod对象的相关容器。首次需要重启 的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由 kubelet延迟一段时间后进行,且反复的重启操作的延迟时长依次为10 秒、20秒、40秒、80秒、160秒和300秒,300秒是最大延迟时长。事实 上,一旦绑定到一个节点,Pod对象将永远不会被重新绑定到另一个节 点,它要么被重启,要么终止,直到节点发生故障或被删除

7、Pod的终止过程

Pod对象代表了在Kubernetes集群节点上运行的进程,它可能曾用于处理生产数据或向用户提供服务等,于是,当Pod本身不再具有存在的 价值时,如何将其优雅地终止就显得尤为重要了,而用户也需要能够在 正常提交删除操作后可以获知其何时开始终止并最终完成。操作中,当用户提交删除请求之后,系统就会进行强制删除操作的宽限期倒计时, 并将TERM信息发送给Pod对象的每个容器中的主进程。宽限期倒计时结束后,这些进程将收到强制终止的KILL信号,Pod对象随即也将由API Server删除。如果在等待进程终止的过程中,kubelet或容器管理器 发生了重启,那么终止操作会重新获得一个满额的删除宽限期并重新执行删除操作。 如图4-11所示,一个典型的Pod对象终止流程具体如下。 1)用户发送删除Pod对象的命令。 2)API服务器中的Pod对象会随着时间的推移而更新,在宽限期内(默认为30秒),Pod被视为“dead”。 3)将Pod标记为“Terminating”状态。 4)(与第3步同时运行)kubelet在监控到Pod对象转为“Terminating”状态的同时启动Pod关闭过程。 5)(与第3步同时运行)端点控制器监控到Pod对象的关闭行为时将其从所有匹配到此端点的Service资源的端点列表中移除。6)如果当前Pod对象定义了preStop钩子处理器,则在其标记为“terminating”后即会以同步的方式启动执行;如若宽限期结束后, preStop仍未执行结束,则第2步会被重新执行并额外获取一个时长为2秒 的小宽限期。 7)Pod对象中的容器进程收到TERM信号。 8)宽限期结束后,若存在任何一个仍在运行的进程,那么Pod对象即会收到SIGKILL信号。 9)Kubelet请求API Server将此Pod资源的宽限期设置为0从而完成删除操作,它变得对用户不再可见。 默认情况下,所有删除操作的宽限期都是30秒,不过,kubectl delete命令可以使用“--grace-period=<seconds>”选项自定义其时长,若使用0值则表示直接强制删除指定的资源,不过,此时需要同时为命令使 用“--force”选项

8、设置Pod对象的安全上下文securityContext

Pod对象的安全上下文用于设定Pod或容器的权限和访问控制功能,其支持设置的常用属性包括以下几个方面。 基于用户ID(UID)和组ID(GID)控制访问对象(如文件)时的权限。以特权或非特权的方式运行。 通过Linux Capabilities为其提供部分特权。基于Seccomp过滤进程的系统调用。基于SELinux的安全标签。 是否能够进行权限升级。 Pod对象的安全上下文定义在spec.securityContext字段中,而容器的安全上下文则定义在spec.containers[].securityContext字段中,且二者可 嵌套使用的字段还有所不同。下面的配置清单示例为busybox容器定义 了安全上下文,它以uid为1000的非特权用户运行容器,并禁止权限升级:

apiVersion: v1

kind: Pod

metadata:

name: pod-with-securitycontext

spec:

containers:

- name: busybox

image: busybox

command: ["/bin/sh","-c","sleep 86400"]

securityContext:

runAsNonRoot: true

runAsUser: 1000

allowPrivilegeEscalation: false

将上面的配置清单保存于配置文件(如pod-with- securitycontext.yaml文件)中,而后创建于集群中即可验证容器进程的

运行者身份:

[root@master ~]#kubectl apply -f pod-with-securitycontext.yaml [root@master ~]#kubectl exec pod-with-securitycontext -- ps aux PID USER TIME COMMAND 1 1000 0:00 sleep 86
另外,可设置的安全上下文属性还有fsGroup、seLinuxOptions、supplementalGroups、sysctls、capabilities和privileged等,且Pod和容器各 自支持的字段也有所不同。

9、资源需求及资源限制

在Kubernetes上,可由容器或Pod请求或消费的“计算资源”是指CPU和内存(RAM),这也是目前仅有的受支持的两种类型。相比较来 说,CPU属于可压缩(compressible)型资源,即资源额度可按需收 缩,而内存(当前)则是不可压缩型资源,对其执行收缩操作可能会导 致某种程度的问题。 目前来说,资源隔离尚且属于容器级别,CPU和内存资源的配置需要在Pod中的容器上进行,每种资源均可由“requests”属性定义其请求的保可用值,即容器运行可能用不到这些额度的资源,但用到时必须要 确保有如此多的资源可用,而“limits”属性则用于限制资源可用的最大值,即硬限制,如图4-12所示。不过,为了表述方便,人们通常仍然把 资源配置称作Pod资源的请求和限制,只不过它是指Pod内所有容器上某 种类型资源的请求和限制的总和。 在Kubernetes系统上,1个单位的CPU相当于虚拟机上的1颗虚拟CPU(vCPU)或物理机上的一个超线程(Hyperthread,或称为一个逻 辑CPU),它支持分数计量方式,一个核心(1core)相当于1000个微核 心(millicores),因此500m相当于是0.5个核心,即二分之一个核心。内存的计量方式与日常使用方式相同,默认单位是字节,也可以使用 E、P、T、G、M和K作为单位后缀,或Ei、Pi、Ti、Gi、Mi和Ki形式的 单位后缀。

9.1资源需求

下面的示例中,自主式Pod要求为stress容器确保128Mi的内存及五分之一个CPU核心(200m)资源可用,它运行stress-ng镜像启动一个进 程(-m 1)进行内存性能压力测试,满载测试时它也会尽可能多地占用 CPU资源,另外再启动一个专用的CPU压力测试进程(-c 1)。stress-ng是一个多功能系统压力测试具,master/worker模型,Master为主进程, 负责生成和控制子进程,worker是负责执行各类特定测试的子进程,例 如测试CPU的子进程,以及测试RAM的子进程等:

apiVersion: v1kind: Pod

metadata:

name: stress-pod

spec:

containers:

- name: stress

image: ikubernetes/ stress-ng

command: ["/usr/bin/stress-ng", "-m 1", "-c 1", "-metrics-brief"]

resources:

requests:

memory: "128Mi"

cpu: "200m"

上面的配置清单中,其请求使用的CPU资源大小为200m,这意味着一个CPU核心足以确保其以期望的最快方式运行。另外,配置清单中 期望使用的内存大小为128Mi,不过其运行时未必真的会用到这么多。 考虑到内存为非压缩型资源,其超出指定的大小在运行时存在被OOM killer杀死的可能性,于是请求值也应该就是其理想中使用的内存空间上限。 接下来创建并运行此Pod对其资源限制效果进行检查。需要特别说明的是,笔者当前使用的系统环境中,每个节点的可用CPU核心数均为 8,物理内存空间为16GB:
[root@master ~]#kubectl apply -f pod-resources-test.yaml
而后在Pod资源的容器内运行top命令观察其CPU及内存资源的占用状态,如下所示,其中{stress-ng-vm}是执行内存压测的子进程,它默认使用256m的内存空间,{stress-ng-cpu}是执行CPU压测的专用子进程:
[root@master ~]#kubectl exec stress-pod -- top Mem: 2884676K used, 13531796K free, 27700K shrd, 2108K buff, 1701456K cached CPU: 25% usr 0% sys 0% nic 74% idle 0% io 0% irq 0% sirq Load average: 0.57 0.60 0.71 3/435 15 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 9 8 root R 262m 2% 6 13% {stress-ng-vm} /usr/bin/stress-ng 7 1 root R 6888 0% 3 13% {stress-ng-cpu} /usr/bin/stress-ng 1 0 root S 6244 0% 1 0% /usr/bin/stress-ng -c 1 -m 1 --met

top命令的输出结果显示,每个测试进程的CPU占用率为13%(实际为12.5%),{stress-ng-vm}的内存占用量为262m(VSZ),此两项资源 占用量都远超其请求的用量,原因是stress-ng会在可用的范围内尽量多 地占用相关的资源。两个测试线程分布于两个CPU核心以满载的方式运 行,系统共有8个核心,因此其使用率为25%(2/8)。另外,节点上的内存资源充裕,虽然容器的内存用量远超128M,但它依然可运行。一 旦资源紧张时,节点仅保证容器有五分之一个CPU核心可用,对于有着 8个核心的节点来说,它的占用率为2.5%,于是每个进程为1.25%,多占 用的资源会被压缩。内存为非可压缩型资源,

对于压缩型的资源CPU来说,未定义其请求用量以确保其最小的可用资源时,它可能会被其他的Pod资源压缩至极低的水平,甚至会达到 Pod不能够被调度运行的境地。而对于非压缩型资源来说,内存资源在 任何原因导致的紧缺情形下都有可能导致相关的进程被杀死。因此,在 Kubernetes系统上运行关键型业务相关的Pod时必须使用requests属性为 容器定义资源的确保可用量所以此Pod在内存资源紧 张时可能会因OOM被杀死(killed)。

集群中的每个节点都拥有定量的CPU和内存资源,调度Pod时,仅那些被请求资源的余量可容纳当前被调度的Pod的请求量的节点才可作 为目标节点。也就是说,Kubernetes的调度器会根据容器的requests属性 中定义的资源需求量来判定仅哪些节点可接收运行相关的Pod资源,而 对于一个节点的资源来说,每运行一个Pod对象,其requests中定义的请 求量都要被预留,直到被所有Pod对象瓜分完毕为止。

9.2资源限制

容器的资源需求仅能达到为其保证可用的最少资源量的目的,它并不会限制容器的可用资源上限,因此对因应用程序自身存在Bug等多种 原因而导致的系统资源被长时间占用的情况则无计可施,这就需要通过 limits属性为容器定义资源的最大可用量。资源分配时,可压缩型资源 CPU的控制阀可自由调节,容器进程无法获得超出其CPU配额的可用时 间。不过,如果进程申请分配超出其limits属性定义的硬限制的内存资 源时,它将被OOM killer杀死,不过,随后可能会被其控制进程所重 启,例如,容器进程的Pod对象会被杀死并重启(重启策略为Always或 OnFailure时),或者是容器进程的子进程被其父进程所重启。

下面的配置清单文件(memleak-pod.yaml)中定义了如何使用saadali/simmemleak镜像运行一个Pod对象,它模拟内存泄漏操作不断地 申请使用内存资源,直到超出limits属性中memory字段设定的值而导 致“OOMKillled”为

piVersion: v1kind: Pod

metadata:

name: memleak-pod

labels:

app: memleak

spec:

containers:

- name: simmemleak

image: saadali/simmemleak

resources:

requests:

memory: "64Mi"

cpu: "1"

limits:

memory: "64Mi"

cpu: "1"

下面测试其运行效果,首先将配置清单中定义的资源复用下面的命令创建于集群中:
[root@master ~]#kubectl apply -f memleak-pod.yaml pod/memleak created
Pod资源的默认重启策略为Always,于是在memleak因内存资源达到硬限制而被终止后会立即重启,因此用户很难观察到其因OOM而被 杀死的相关信息。不过,多次重复地因为内存资源耗尽而重启会触发 Kubernetes系统的重启延迟机制,即每次重启的时间间隔会不断地拉长。于是,用户看到的Pod资源的相关状态通常 为“CrashLoopBackOff”:
[root@master ~]#kubectl get pods -l app=memleak NAME READY STATUS RESTARTS AGE memleak-pod 0/1 CrashLoopBackOff 1 24s
Pod资源首次的重启将在crash后立即完成,若随后再次crash,那么其重启操作会延迟10秒进行,随后的延迟时长会逐渐增加,依次为20 秒、40秒、80秒、160秒和300秒,随后的延迟将固定在5分钟的时长之 上而不再增加,直到其不再crash或者delete为止。describe命令可以显示 其状态相关的详细信息,其部分内容如下所示:

[root@master ~]#kubectl describe pods memleak-pod

Name: memleak-pod

…… Last State: Terminated Reason: OOMKilled Exit Code: 137 Started: Wed, 02 May 12:42:50 +0800 Finished: Wed, 02 May 12:42:50 +0800 Ready: False Restart Count: 3 ……

如上述命令结果所显示的,OOMKilled表示容器因内存耗尽而被终止,因此,为limits属性中的memory设置一个合理值至关重要。与 requests不同的是,limits并不会影响Pod的调度结果,也就是说,一个节 点上的所有Pod对象的limits数量之和可以大于节点所拥有的资源量,即 支持资源的过载使用(overcommitted)。不过,这么一来一旦资源耗尽,尤其是内存资源耗尽,则必然会有容器因OOMKilled而终止。 另外需要说明的是,Kubernetes仅会确保Pod能够获得它们请求(requests)的CPU时间额度,它们能否获得额外(throttled)的CPU时 间,则取决于其他正在运行的作业对CPU资源的占用情况。例如,对于总数为1000m的CPU资源来说,容器A请求使用200m,容器B请求使用500m,在不超出它们各自的最大限额的前提下,余下的300m在双方都需要时会以2:5(200m:500m)的方式进行配置。

10、Pod得服务质量类别

根据Pod对象的requests和limits属性,Kubernetes将Pod对象归类到BestEffort、Burstable和Guaranteed三个服务质量(Quality of Service, QoS)类别下,具体说明如下。 ·Guaranteed:每个容器都为CPU资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源设置了具有相同值的requests和limits属性的Pod资源会自动归属于此类别,这类Pod资源具有最高优先级。·Burstable:至少有一个容器设置了CPU或内存资源的requests属性,但不满足Guaranteed类别要求的Pod资源将自动归属于此类别,它们 具有中等优先级。 ·BestEffort:未为任何一个容器设置requests或limits属性的Pod资源将自动归属于此类别,它们的优先级为最低级别。

如果觉得《Pod资源管理进阶-Pod对象的生命周期》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。
相关阅读
pod生命周期详解

pod生命周期详解

2023-04-14

Pod生命周期

Pod生命周期

2023-08-16

67 Pod生命周期

67 Pod生命周期

2022-06-04

Pod详解-生命周期-概述

Pod详解-生命周期-概述

2019-06-10