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 https://github.com/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 2020 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 2020 10:59:14 +0800
    Last State:     Terminated       
      Reason:       Error
      Exit Code:    137
      Started:      Wed, 11 Nov 2020 10:57:39 +0800
      Finished:     Wed, 11 Nov 2020 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 2020 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 2020 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 )之一。
 
  • PendingAPI Server创建了Pod资源对象并已存入etcd中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。 (一般是资源无法满足调度的需求时会出现pending)
  • RunningPod已经被调度至某节点,并且所有容器都已经被kubelet创建完成。
  • SucceededPod中的所有容器都已经成功终止并且不会被重启。
  • Failed:所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态或已经被系统终止。
  • UnknownAPI Server无法正常获取到Pod对象的状态信息,通常 是由于其无法与所在工作节点的kubelet通信所致。

4、Pod的创建过程

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

 

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

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

 注意: 如果Podspec.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请求进行诊断,响应码为2xx3xx时即为成功,否则为失败。
任何一种探测方式都可能存在三种结果: “Success” (成功)、 “Failure” (失败)或 “Unknown” (未知),只有第一种结果表示 成功通过检测。
  • ·kubelet可在活动容器上执行两种类型的检测:存活性检测(livenessProbe)和就绪性检测(readinessProbe)。·
  • 存活性检测:用于判定容器是否处于运行Running)状态;一 此类检测未通过,kubelet将杀死容器并根据其restartPolicy决定是否将 其重启;未定义存活性检测的容器的默认状为“Success”
  • 就绪性检测:用于判断容器是否准备就绪并可对外提供服务;未通过检测的容器 意味着其尚未准备就绪,端点控制器(如Service对象)会将其IP从所有 匹配到此Pod对象的Service对象的端点列表中移除;检测通过之后,会再次将其IP添加至端点列表中。

 

6、容器的重启策略

Pod对象容器程因容器发生程序崩溃或容器申请超出限制的资源等原因都可能会导致Pod对象的终止,此时是否应该重建该Pod 对象则取决于其重启策略 restartPolicy )属性的定义。
 
  •  1Always:但凡Pod对象终止就将其重启,此为默认设定。   Always时默认的
  • 2OnFailure:仅在Pod对象出现错误时方才将其重启。   正常终止就不重启
  • 3Never:从不重启。
需要注意的是, 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对象的命令。
  • 2API服务器中的Pod对象会随着时间的推移而更新,在宽限期内(默认为30秒),Pod被视为“dead”
  • 3)将Pod标记为“Terminating”状态。
  • 4)(与第3步同时运行)kubelet在监控到Pod对象转为“Terminating”状态的同时启动Pod关闭过程。
  • 5)(与第3步同时运行)端点控制器监控到Pod对象的关闭行为时将其从所有匹配到此端点的Service资源的端点列表中移除。
  • 6)如果当前Pod对象定义了preStop钩子处理器,则在其标记为“terminating”后即会以同步的方式启动执行;如若宽限期结束后, preStop仍未执行结束,则第2步会被重新执行并额外获取一个时长为2的小宽限期。
  • 7Pod对象中的容器进程收到TERM信号。
  • 8)宽限期结束后,若存在任何一个仍在运行的进程,那么Pod对象即会收到SIGKILL信号。
  • 9Kubelet请求API Server将此Pod资源的宽限期设置为0从而完成删除操作,它变得对用户不再可见。
    默认情况下,所有删除操作的宽限期都是 30 秒,不过, kubectl delete 命令可以使用 “--grace-period=<seconds>” 选项自定义其时长,若使 0 值则表示直接强制删除指定的资源,不过,此时需要同时为命令使 “--force” 选项
 
 

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

Pod 对象的安全上下文用于设定 Pod 或容器的权限和访问控制功能,其支持设置的常用属性包括以下几个方面。
  • 基于用户IDUID)和组IDGID)控制访问对象(如文件)时的权限。
  • 以特权或非特权的方式运行。
  • 通过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}的内存占用量为262mVSZ),此两项资源 占用量都远超其请求的用量,原因是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对象会被杀死并重启(重启策略为AlwaysOnFailure时),或者是容器进程的子进程被其父进程所重启。

下面的配置清单文件( 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 2018 12:42:50 +0800
Finished: Wed, 02 May 2018 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属性,以及每个容器都为内存资源设置了具有相同值的requestslimits属性的Pod资源会自动归属于此类别,这类Pod资源具有最高优先级。
  • ·Burstable:至少有一个容器设置了CPU或内存资源的requests属性,但不满足Guaranteed类别要求的Pod资源将自动归属于此类别,它们 具有中等优先级。
  • ·BestEffort:未为任何一个容器设置requestslimits属性的Pod资源将自动归属于此类别,它们的优先级为最低级别。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值