①.kubernetes pod

一.Pod是什么

二.Pod管理方式

三.Pod运行应用

四.Pod运行应用对应字段

五.Pod重启策略

六.Pod生命周期流程

七.Init Container

八. Pod Hook

九.Pod检测探针

十.startupProbe

十一.livenessProbe

十二.readinessProbe

十三.Pod资源限制

十四.资源限制单位换算

十五. CPU资源限制实践

十六. 内存资源限制

十七. Pod服务质量Qos

十八. Downward API

==============================================================================================================================

一.Pod是什么

podk8s里能够运行的最小的逻辑端元 一个pod代表集群运行的一个进程!
1个pod里面可以运行单个或者多个容器 他们共享 Network(网络)PID(进程)IPC(进程间通讯)HostName(主机名称)Volume(卷)
Pod中的容器共享IP HostName IPC 他们可以通过localhost 互相发现 他们之间可以通过IPC通讯
Pod中的容器也有访问共享volume的权限 这些volume也会被定义成Pod的一部分被挂载到pod的容器中应用成文件系统
可以把Pod理解成豌豆荚 容器为豆粒

一个pod里运行多个容器 又叫边车(SideCar)模式
边车模式可以很好的保证原有业务不变的情况,通便边车模式添加新的容器来匹配现在的环境,例如日志手机 IAAS平台环境收集

二.Pod管理方式

2.1自助式Pod

kubernetes中,我们部署POD的时候,基本上都是使用控制器管理,如果不使用控制器,也可以直接定义一个Pod资源,那么就是Pod自己去控制自己,这样的Pod称为自主式Pod!

  • 如果Pod被删除,那就是真的被删除,不会重新运行新的Pod
  • 如果Pod所在的节点需要维护,那么节点会先执行驱逐,如果是自主式Pod,驱逐后不会被重建。
  • 如果Pod期望部署多个副本,这个也能实现,但如果想持续维护副本数量,则需要认为参与,过于繁琐。
    1.创建一个自主式Pod
cat nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.16
  ports:
  - containerPort: 80

2.测试删除Pod,验证是否能被彻底删除

kubectl delete pod nginx-pod

3.测试节点故障,当Pod所运行的节点故障,那么改Pod会被删除,不会重新运行起来

kubectl drain node01 --ignore-daemonsets --force #驱逐
kubectl uncordon node01

2.2 控制器Pod

kubernetes通过controller控制器来创建管理Pod实例。Controller可以创建和管理多个Pod,提供副本副本管理、滚动升级和集群级别的自愈呢能力。
Pod的标签能匹配Controller控制器的标签,当运行Pod的节点发生故障时,控制器会把Pod调度到其他节点,Pod被删除,控制器会根据清单上Pod的数量来运行,Controller控制器能控制pod的副本(水平扩展)、滚动升级、故障自愈。

1.创建控制器管理的Pod

cat nginx-dp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.16

2.测试删除Pod,会发现Pod被删除后,立即又启动一个相同的Pod实例。

#查看
[root@k8s-240 pod]# kubectl get pod -o wide
NAME                        READY   STATUS    RESTARTS            AGE   IP               NODE        NOMINATED NODE   READINESS GATES
nginx-dp-776b5f86cc-5t46z   1/1     Running   0                   22s   10.244.232.223   flyfish81   <none>           <none>
nginx-dp-776b5f86cc-kd8s7   1/1     Running   0                   22s   10.244.157.160   flyfish83   <none>           <none>
nginx-dp-776b5f86cc-ngnvw   1/1     Running   0                   22s   10.244.149.155   flyfish82   <none>           <none>
#删除Pod
[root@k8s-240 pod]# kubectl delete pod nginx-dp-776b5f86cc-5t46z 
pod "nginx-dp-776b5f86cc-5t46z" deleted
#验证
[root@k8s-240 pod]# kubectl get pod -o wide
NAME                        READY   STATUS    RESTARTS            AGE   IP               NODE        NOMINATED NODE   READINESS GATES
nginx-dp-776b5f86cc-4xj5b   1/1     Running   0                   7s    10.244.232.224   flyfish81   <none>           <none>
nginx-dp-776b5f86cc-kd8s7   1/1     Running   0                   37s   10.244.157.160   flyfish83   <none>           <none>
nginx-dp-776b5f86cc-ngnvw   1/1     Running   0                   37s   10.244.149.155   flyfish82   <none>           <none>

三.Pod运行应用

3.1 创建应用

cat nginx-pod.yaml
apiVersion: apps/v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx-container
      image: nginx:1.16

3.2 Pod运行阶段

Pod创建后,起始为 Pending 阶段,如果其中至少又一个主要容器正常启动,则进入Running,之后的状态取决于Pod中是否有容器运行失败或被管理员停止运行,从而会进入 Succeeded 或者 Failed 阶段。

  • Pending: Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
  • Running: Pod已经绑定至某个节点,同时Pod中所有的容器都已创建。至少有一个容器在运行,或处于启动、重启状态。
  • Succeeded: Pod中的所有容器都已成功终止,并且不会再重启
  • Failed: Pod中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或被系统终止
  • Unknown: 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

1.可以通过 kubectl describe pod <pod名称> 查看podStatus 对象中的Status,查看当前Pod所处的阶段

[root@k8s-240 pod]# kubectl describe pod nginx-dp-776b5f86cc-4xj5b 
Name:             nginx-dp-776b5f86cc-4xj5b
Namespace:        default
Priority:         0
Service Account:  default
Node:             flyfish81/192.168.1.240
Start Time:       Wed, 24 May 2023 16:39:23 +0800
Status:           Running
#如果某节点死掉或者与集群中其他节点失恋,`Kubernetes`会实施一种策略,将失去节点上运行的`Pod`的`phase`设置为`Failed`

2.在PodStatus对象中还包含了一组Conditions,它主要描述造成当前Status的具体原因。

[root@k8s-240 pod]# kubectl describe pod nginx-dp-776b5f86cc-4xj5b
Conditions:
  Type              Status
  Initialized       True    #pod中所有的init容器都已成功完成;
  Ready             True    #pod可以对外提供服务,并可以加入对应的负载均衡;
  ContainersReady   True    #pod中的所有容器都处于就绪状态;
  PodScheduled      True    #pod已经成功被调度到莫个节点上;

3.3 容器运行阶段

kubernetes会跟踪Pod中每个容器的状态,就像跟踪Pod阶段一样。Pod中运行的容器状态与Pod阶段是存在关联关系的,所以当Pod出现故障时,讲Pod的阶段状态和Pod中的容器状态结合起来查看,更容易定位具体问题。
一旦调度器讲Pod分配给莫格节点,kubelet就通过容器运行时开始为Pod创建容器。容器的状态有三种:Waiting(等待)、Running(运行中)和Terminated(已终止)。容器状态官方站点

可以通过

kubectl describe pod <pod名称> 查看pod种的容器状态

[root@k8s-240 pod]# kubectl describe pod nginx-dp-776b5f86cc-4xj5b 
Containers:
  nginx-container:
    Container ID:   containerd://7410087425f295554a14e42f5cc2927c3f738005dc3381dc0e8536f24b6a4fa9
    Image:          nginx:1.16
    Image ID:       docker.io/library/nginx@sha256:d20aa6d1cae56fd17cd458f4807e0de462caf2336f0b70b5eeb69fcaaf30dd9c
    Port:           <none>
    Host Port:      <none>
    State:          Running  #当前状态除了Running,还有Waiting Terminated
      Started:      Wed, 24 May 2023 16:39:26 +0800
    Ready:          True     #容器是否已经就绪
    Restart Count:  0        #容器重启的次数
    Environment:    <none>

四. Pod运行容器对应字段

4.1 容器镜像拉取策略

imagePullPolicy 容器的镜像拉取策略

  • IfNotPresent: 本地有镜像则使用本地镜像,本地不存在则拉取镜像。
  • Always: 每次都会尝试拉取新镜像
  • Never: 永不拉取镜像!如果镜像已经存在本地,kubelet会尝试启动容器,否则会启动失败。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.16
        imagePullPolicy: Always #指定镜像的拉取策略 每次pod启动都拉取最新版

没有设置imagePullPolicy字段,容器镜像的标签是latest,imagePullPolicy会自动设置为Always.如果你省略了imagePullPolicy字段,并且没有指定容器镜像的标签,imagePullPolicy会自动设置为Always.如果省略了imagePullPolicy字段,并且tag为非 latest, imagePullPolicy就会自动设置为IfNotPresent.

4.2 容器拉取私有仓库镜像

ImagePullSecrets拉取私有仓库中的镜像
1.创建一个Pod资源,拉取一个私有仓库镜像,在不添加ImagePullSectets时,验证是否正常拉取镜像

apiVersion: v1
kind: Pod
metadata:
  name: pod-image-secret
spec:
  containers:
  - name: pod-image-secret
    image: registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest
    imagePullPolicy: Always

2.检查Pod状态,发信啊Pod状态为ErrImagePull,通过describe描述,发现需要docker login 后才能拉取镜像

[root@k8s-240 pod]# kubectl apply -f imagepull.yaml 
pod/pod-image-secret created
[root@k8s-240 pod]# kubectl get pod
NAME                        READY   STATUS         RESTARTS      AGE
pod-image-secret            0/1     ErrImagePull   0             2s
[root@k8s-240 pod]# kubectl describe pod pod-image-secret
Events:
  Type     Reason     Age                 From               Message
  ----     ------     ----                ----               -------
  Normal   Scheduled  2m6s                default-scheduler  Successfully assigned default/pod-image-secret to flyfish83
  Normal   Pulling    36s (x4 over 2m6s)  kubelet            Pulling image "registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest"
  Warning  Failed     35s (x4 over 2m5s)  kubelet            Failed to pull image "registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest": rpc error: code = Unknown desc = failed to pull and unpack image "registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest": failed to resolve reference "registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
  Warning  Failed     35s (x4 over 2m5s)  kubelet            Error: ErrImagePull
  Warning  Failed     23s (x6 over 2m5s)  kubelet            Error: ImagePullBackOff
  Normal   BackOff    8s (x7 over 2m5s)   kubelet            Back-off pulling image "registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest"

3.创建一个名为aliyun的secret资源,然后配置对应仓库的用户名称及密码

[root@k8s-240 pod]# kubect create secret docker-registry aliyun --docker-username=552408925@qg.com -docker-password=123456 --docker-server registry.cn-huhehaote.aliyuncs .com

4.修改Pod资源清单,添加ImagePullSecrets传入对应的Secrets资源名称

apiVersion: v1
kind: Pod
metadata:
  name: pod-image-secret
spec:
  imagePullSecrets:  #增加imagePullSecrets字段,传入对应资源的名称
  - name: aliyun

  containers:
  - name: pod-image-secret
    image: registry.cn-huhehaote.aliyuncs.com/oldxu3957/nginxdemo:latest
    imagePullPolicy: Always

4.3 容器环境变量自定义

使用 env 控制容器环境变量
1.准备一个mysql镜像,然后通过env传入对应的登录密码,同事创建一个默认的k8s数据库

apiVersion: v1
kind: Pod
metadata:
  name: pod-mysql-env
spec:
  containers:
  - name: mysql
    image: mysql:5.7.37
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "oldxu3957"
    - name: MYSQL_DATABASE
      value: "k8s"

2.查看mysql-pod容器详情

[root@k8s-240 pod]# kubectl get pod -o wide
NAME               READY   STATUS             RESTARTS      AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod-mysql-env      1/1     Running            0             94s   10.244.149.156   flyfish82   <none>           <none>

3.通过本机的 mysql client 尝试连接服务,验证密码是否传入成功数据库是否建立

[root@k8s-240 pod]# mysql -h 10.244.149.156 -uroot -p
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| k8s                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

4.4 容器启动命令与参数

  • command: 为容器指定启动命令,会覆盖容器启动的默认命令,不指定则默认容器的启动命令
  • args: 为命令提供选项或参数
    1.准备一个nginx镜像演示command与args的作用
container:
  - images; nginx
    name: nginx
  command:
    - /bin/bash  #参数
    - -C
    - "echo $(msg);sleep 600:"
  env:
    - name : msg
      value: "Hello 0ldxu"

4.5 容器自定义端口

ports 用于暴露pod对外访问的端口,如不指定,则无法通过 PodIP + PodPort 访问该应用

  • containerPort: 填写Pod对外暴露的端口(0~65535)
  • name: 为端口指定一个名称,当服务存在多个端口,可以通过名称区分
  • protocol: 指定端口对应的协议,有tcp udp sctp 默认不写为tcp
    示例文件
apiVersion: v1
kind: Pod
metadata:
  name: redis-port
spec:
  containers:
    - name: redis-port
      image: redis
      ports:
        - name: port
          containerPort: 6379
          protocol: TCP

五.Pod重启策略

Podspec 中包含一个 restartPolicy 字段,用来设置 Pod 中所有容器的重启策略,取值有ALways0nFailureNever。默认值是ATways

  • ALways: 当容器出现异常退出时,kubelet 会尝试重启该容器已恢复正常状态; (默认策略)
  • Never: 当容器退出时,kubelet 永远不会尝试重启该容器 (适合Job类一次性任务)
  • 0nFailure: 当容器异常退出 (且退出状态码非0时) ,kubelet会尝试重启容器 (适合Job类一次性任务)
    注意: 通过 kubelet 重新启动的容器,后续如果还出现异常退出,则会以指数增加延迟 (10s,20s,40s...) 来进行容器的重新创建和启动,其最长延迟为 5 分钟。一旦容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启计时器进行重置为初始状态

5.1 Always

1.编写Pod的yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: pod-always
spec:
  restartPolicy: Always
  containers:
  - name: pod-always
    image: nginx
    ports:
    - containerPort: 80

2.检查Pod的运行状态,可以看到Pod正常运行,RESTARTS(重启次数)字段为0

[root@k8s-240 pod]# kubectl get pod 
NAME         READY   STATUS    RESTARTS   AGE
pod-always   1/1     Running   0          17m

3.正常停止容器应用,可以看到容器被重启了一次,然后Pod又恢复正常状态了。

[root@k8s-240 pod]# kubectl exec -it pod-always  -- /bin/bash -c 'nginx -s quit'
2023/05/25 08:07:31 [notice] 33#33: signal process started
[root@k8s-240 pod]# kubectl get pod
NAME         READY   STATUS    RESTARTS     AGE
pod-always   1/1     Running   1 (4s ago)   28m

4.非正常停止容器应用,发现容器又被重启了一下,然后Pod又恢复正常状态了,并且重启次数再次增加1次;

[root@k8s-240 pod]# kubectl exec -it pod-always  -- /bin/bash -c 'kill 1'
[root@k8s-240 pod]# kubectl get pod
NAME         READY   STATUS    RESTARTS      AGE
pod-always   1/1     Running   2 (55s ago)   53m

重启侧罗Always,在创建单个Pod的情况下,不管Pod中的容器是否正常停止,最终都会恢复。

5.2 Never

1.编写Pod的yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: pod-never
spec:
  restartPolicy: Never
  containers:
  - name: pod-never
    image: nginx
    ports:
    - containerPort: 80

2.检查Pod的运行状态,可以看到Pod正常运行,RESTARTS(重启次数)字段为0.

[root@k8s-240 pod]# kubectl exec -it pod-never  -- /bin/bash -c 'nginx -s quit'
2023/05/25 08:50:35 [notice] 33#33: signal process started
[root@k8s-240 pod]# kubectl get pod
NAME         READY   STATUS      RESTARTS      AGE
pod-always   1/1     Running     2 (18m ago)   71m
pod-never    0/1     Completed   0             29s

5.3 OnFailure

1.编写Pod的yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: pod-onfailure
spec:
  restartPolicy: OnFailure
  containers:
  - name: pod-onfailure
    image: nginx
    ports:
    - containerPort: 80

2.检查Pod的运行状态,可以看到Pod正常运行,RESTARTS(重启次数)字段为0.

[root@k8s-240 pod]# kubectl get pod 
NAME            READY   STATUS    RESTARTS   AGE
pod-onfailure   1/1     Running   0          19s
[root@k8s-240 pod]# kubectl exec -it pod-onfailure -- /bin/bash -c 'kill 1'
error: cannot exec into a container in a completed pod; current phase is Succeeded
[root@k8s-240 pod]# kubectl get pod 
NAME            READY   STATUS      RESTARTS   AGE
pod-onfailure   0/1     Completed   0          61s                      #没有成功

6.Pod生命周期

6.1 什么是Pod生命周期

Pod对象从创建开始至终止退出之间的时间称其为生命周期

6.2 生命周期流程

下图展示了一个Pod的完整生命周期过程,其中包含Init Container、Pod Hook、健康检查 三个主要部分,接下来我们就来分别介绍影响Pod生命周期的部分

6.3 生命周期总结

当一个Pod对象被创建时,其生命周期的运行步骤如下:
1. 创建pause基础容器:在启动任何其他容器之前,首先创建一个pause容器。该容器用于初始化Pod的环境,并提供共享的名称空间给后续加入的容器使用。
2. 运行初始化容器:按照定义顺序依次运行用户定义的初始化容器。这些初始化容器以串行方式运行,用于完成Pod环境的初始化。如果任何一个初始化容器运行失败,将导致Pod创建失败。根据restartPolicy的策略进行处理,默认为重启。
3. 启动程序容器:在所有初始化容器成功完成后,启动主要的程序容器。如果Pod中有多个容器,它们将并行启动,并各自维护自己的生命周期。同时,主容器上定义的Poststart钩子函数会在容器启动时运行。如果该步骤失败,相关容器将被重启。
4. 运行健康状态监测:在容器启动后,执行容器启动健康状态的监测(startupProbe)。如果检测失败,根据restartPolicy中定义的策略进行处理。如果没有定义策略,默认状态为成功(Success)。
5. 运行存活状态和就绪状态监测:容器在启动成功后,定期进行存活状态监测(Liveness)和就绪状态监测(Readiness)。如果存活状态监测失败,将导致容器重启;而就绪状态监测失败将使容器从负载均衡中被移除。
6. 终止Pod:在终止Pod时,先运行preStop钩子函数。在经过宽限期(terminationGracePeriodSeconds)后,终止容器。宽限期默认为30秒。
以上是Pod对象生命周期的运行步骤。

7.Init Container

7.1 基本概念

Init Container是用来做初始化工作的容器。可以有一个或多个,如果多个按照定义的顺序依次执行,只有所有的执行完后,主容器才启动由于一个Pod里的存储卷是共享的,所以 Init Container 里产生的数据可以被主容器使用到,但它仅仅是在Pod启动时,在主容器启动前执行,做初始化工作,如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。如果 Pod 对应的restartPolicy 值为 Never,Kubernetes 不会重新启动 Pod。

7.2 应用场景

1、app容器依赖MySQL的数据交互,所以可以启动一个初始化容器检查MySOL服务是否正常,如果正常则启动主容器;
2、在启动主容器之前,使用初始化容器对系统内核参数进行调优.然后共享给主容器使用;
3、获取集群成员节点地址,为主容器生成对应配置信息,这样主容器启动后,可以通过配置信息加入集群环境;

7.3 场景实践

1.编写yaml,使用初始化容器对MySQL端口进行检查,如果存活则运行Pod,否则一直重启尝试

apiVersion: v1
kind: Pod
metadata:
  name: init-check-mysql
spec:
  initcontainers:
    - name: check-mysql
      image: oldxu3957/tools
      command: ["sh", "-c", "nc -z 10.0.0.206 3306"]
      securityContext:
        privileged: true          #以特权模式运行容器,否则无法修改内核参数
  Containers:                     #主容器
    - name: app-mysql
      image: nginx
      ports:
        - containerPort: 80

2.当MySQL服务没有启动完毕,则改Pod会出现初始化失败,然后触发重启

[root@master ~]# kubectl get pod init-systctl-nginx
NAME          READYSTATUS      RESTARTS                      AGE
init-check-mysql 0/1         Init:CrashLoopBack0ff(5s ago)   43s

3.安装MySQL服务,确保3306对外监听

yum install mariadb-server
systemctl start mariadb

4.检查Pod,发现已经检查到MySQL运行,所以会启动主容器

[root@master ~] kubectl get pod init-systctl-nginx
NAME                READY   STATUS   RESTARTS   AGE
init-check-mysql    1/1]   Running    0         103s

场景实践二 优化内核参数
1.编写yaml,使用初始化容器对内核参数进行优化

[root@master pod-init]# cat init-sysctl-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: init-sysctl-nginx
spec:
  initContainers: #初始化容器,必须运行完就结束,否则后续无法正常运行主容器
  - name: set-sysctl
    image: alpine:3.13
    command: ["sh","-c","sysctl -wnet.core.somaxconn=32769; sysctl -wnet.ipv4.ip_local_port_range='1024 65000"]
    securityContext:
      privileged: true# 以特权模式运行容器否则无法修改内核参数
  containers:   #主容器
  - name: app-sysctl
    image: nginx
    ports:
    - containerPort: 80

2.运行Pod,检查Pod的内核参数,发现已经优化了(建议使用镜像查看此前的内核参数)

[root@master ~]# kubectl get pod
NAME                  READY    STATUS     RESTARTS     AGE
init-sysctl-nginx      0/1     Init:0/1     0           4S
[root@master ~]# ubectl exec -it init-systctl-nginx-c "app-sysctl" -- /bin/bash -c "cat/proc/sys/net/core/somaxconn"
32769

八.Pod Hook

容器生命周期钩子(Container Lifecycle Hooks)监听容器生命周期的特定实践,并在事件发生时执行已注册的回调函数。
kubernetes支持 poststart和prestop事件。当一个容器启动后,kubernetes将立即发送poststart事件;在容器被终结之前,kubernetes将发送一个prestop事件。容器可以为每个事件指定一个处理程序。

8.1 两种钩子

postStart: 容器创建后立即执行,由于是异步执行,它无法保证一定在容器之前运行。如果失败,容器会被杀死,并根据RestartPolicy决定是否重启。
preStop: 容器终止前执行。用于:释放占用的资源,清理注册过的信息,优雅的关闭进程。在其完成之前会阻塞删除容器的操作,默认等待时间为30s,可以通过terminationGracePeriodSecpnds宽限时间。

8.2 钩子示例

postStart示例:

#通过postStart设定端口重定向,将请求本机的8080调度到本机的80端口
lifecycle:
  postStart:
    exec:
      command:
        - "/bin/bash"
        - "-c"
        - "iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-ports 80"

preStop

# runner主要用来编译打包提高CI效率。启动后悔注册到gitlab上,后续不需要可以删除Pod,然后清理注册信息
#通过preStop清理runner注册信息
lifecycle:
  preStop:
    exec:
      command:
        - /bin/bash
        - -c
        - /usr/bin/gitlab-runner unregister -n $RUNNER_NAME

8.3 场景实践

postStart 命令在容器的 /usr/share/nginx/html/index.html自定义一段内容 preStop负载优雅的终止nginx服务。
terminationGracePeriodSecpnds: 宽限期,如果超过宽限期pod还没终止,则会由SIGKILL强制关闭信号介入。

apiVersion: v1
kind: Pod
metadata:
  name: Tifecycle-nginx
spec:
  containers:
    - name: Tifecycle-demo-container
      image: nginx
      lifecycle:
        postStart:
          exec:
            command:
              - "/bin/sh"
              - "-c"
              - "echo 'Hello from the postStart handler' > /usr/share/nginx/html/index.html"
        preStop:
          exec:
            command:
              - "/bin/sh"
              - "-c"
              - "nginx -s stop"

场景实践二
postStart命令负责将默认页面,拷贝至/usr/local/tomcat/webapps preStop负责给容器发送 SIGERM信号,从而优雅的终止tomcat服务。
terminationGracePeriodSecpnds: 宽限期,如果超过宽限期pod还没终止,则会有SIGKILL强制关闭信号介入。

apiVersion: v1
kind: Pod
metadata:
  name: Tifecycle-tomcat-hook
  labels:
    web: tomcat
spec:
  terminationGracePeriodSeconds: 120
  containers:
    - name: tomcat
      image: tomcat
      ports:
        - containerPort: 8080
      lifecycle:
        postStart:
          exec:
            command:
              - "/bin/bash"
              - "-c"
              - "cp -rf /usr/local/tomcat/webapps.dist/* /usr/local/tomcat/webapps"
        preStop:
          exec:
            command:
              - "/bin/bash"
              - "-c"
              - "sleep 10; /usr/local/tomcat/bin/shutdown.sh"

九.Pod检测探针

9.1 为何需要探针

当容器进程运行时如果出现了异常退出,Kubernetes则会认为容器发生故障,会尝试进行重启解决该问题。但有不少情况是发生了故障,但进程并没有退出。比如访问Web服务器时出现了500的内错误,可能是系统超载,也可能是资源死锁,但nginx进程并没有异常退出,在这种情况下重启容器可能是最佳的方法。那如何来实现这个检测呢;
Kubernetes 使用探针 (probe) 的方式来保障容器正常运行,实现零宕机;它通过 kubelet 定期对容器进行健康检查 (exec、tcp.http) ,当探针检测到容器状态异常时,会通过重启策略来进行重启或重建完成修复。修复后继续进行探针检测,已确保容器稳定运行。

9.2 探针探测类型

针对运行中的容器,kubelet 可以选择以下三种探针来探测容器的状态

  • startupProbe 启动探针
    用于检测容器中的应用是否已经正常启动。如果使用了启动探针,则所有其他探针都会被禁用,需要等待启动探针检测成功之后才可以执行。如果启动探针探测失败,则 kubelet 会将容器杀死,而容器依其重启策略 进行重启。如果容器没有提供启动探测,则默认状态为Success。
  • LivenessProbe 存活探针
    用于检测容器是否存活,如果存活探测检测失败,kubeLet会杀死容器,然后根据容器重启策略,决定是否重启该容器。如果容器不提供存活探针,则默认状态为Success。
  • readinessProbe 就绪探针
    指容器是否准备好接收网络请求,如果就绪探测失败,则将容器设定为未就绪状态,然后将其从负载均衡列表中移除,这样就不会有请求会调度到该Pod上;如果容器不提供就绪态探针,则默认状态为Success.

9.3 探针检查机制

使用探针来检查容器有如下集中方式

  • exec : 在容器内执行指定命令。如果命令退出时返回码为 则认为诊断成功。
  • httpGet: 对指定的IP、端口,执行HTTP请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的。
  • tcpSocket: 对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。
    每次探测都将获得以下三种结果之一
  • Success (成功) : 容器通过了诊断Success
  • Failure (失败) :容器未通过诊断,可能会触发重启操作
  • Unknown (未知) : 诊断失败,因此不会采取任何行动.

9.4 探针配置格式

apiVersion: v1
kind: Pod
metadata :
  name : probe
spec :
  containers:
  - name :
    image:
    livenessProbe:
      exec:
      httpGet:
      tcpSocket:
      initialDelaySeconds:
      timeoutseconds:
      PeriodSeconds:
      successThreshold:
      failureThreshold:

十.startupProbe

10.1 exec

apiVersion: v1
kind: Pod
metadata:
  name: pod-startup-exec
spec:
  containers:
  - name: pod-startup-exec
    image: oldxu3957/demoapp:v1.8
    ports:
    - containerPort: 80
    startupProbe:
      exec:
        command:
        - "/bin/sh"
        - "-c"
        - "ps aux | grep demo.py"
      initialDelaySeconds: 10            #容器启动多久后开始探测,默认0
      periodSeconds: 10                  #探测频率,10s探测一次
      timeoutSeconds: 10                 #探测超时时间     
      successThreshold: 1                #成功多少次则为成功,默认1次
      failureThreshold: 3                #失败多少次则为失败,默认3次

PS 第一次探测失败多久会重启

initialDelaySeconds + (periodSeconds +timeoutSeconds) * faiureThreshold

PS 程序启动完成后: 此时不需要计入initiaLDelaySeconds.

(periodSeconds + timeoutSeconds) * failureThreshold

10.2 httpGet

apiVersion: v1
kind: Pod
metadata:
  name: pod-startup-http
spec:
  containers:
  - name: pod-startup-http
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    startupProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 10   #容器启动多久后开始探测,默认0
      periodSeconds: 10         #探测频率,10s探测一次
      timeoutSeconds: 10        #探测超时时长
      successThreshold: 1       #成功多少次则为成功,默认1次
      failureThreshold: 3       #失败多少次则为失败默认3次

10.3 tcpSocket

apiVersion: v1
kind: Pod
metadata:
  name: pod-startup-tcp
spec:
  containers:
  - name: pod-startup-tcp
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    startupProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10           #启动多久开始探测
      periodSeconds: 10                 #探测频率 10s一次
      timeoutSeconds: 10                #探测超时时长
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

十一. livenessProbe

11.1 exec

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-exec
spec:
  containers:
  - name: pod-liveness-exec
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    livenessProbe:
      exec:
        command:
        - "/bin/sh"
        - "-c"
        - '["$(curl -s 127.0.0.1/livez)" = "OK"]'
      initialDelaySeconds: 10           #容器启动后多久开始探测,默认0
      periodSeconds: 10                 #探测时间间隔 10s探测一次
      timeoutSeconds: 10                #探测的超时时间
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

2、为了测试存活状态监测效果,可以手动将/Livez接口的响应内容修改为任意值。

[root@master ~]# kubectl exec -it pod-liveness-exec- curl -s -X POST -d 'livez=error' http://127.0.0.1/livez

3、会发现容器等待60s之后,会触发重启操作

[root@master ~]# kubectl describe pod pod-liveness-exec
...
Warning   Unhealthy 31s (x3 over 51s) kubelet Liveness probe failed:
Normal    Killing   31s               kubelet Container pod-liveness-exec failed livenessprobe, will be restarted

11.2 httpGet

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-http
spec:
  containers:
  - name: pod-liveness-http
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: '/livez'
        port: 80
        scheme: HTTP
      initialDelaySeconds: 10           #容器启动后多久开始探测,默认0
      periodSeconds: 10                 #探测时间间隔 10s探测一次
      timeoutSeconds: 10                #探测的超时时间
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

2、镜像中定义的默认响应是以200状态码响应,存活状态会成功完成为了测试存活状态监测效果,可以手动将/Livez接口的响应内容修改为任意值。

[root@master ~]# kubectl exec -it pod-liveness-http-- curl -s -X POST -d 'livez=error' 127.0.0.1/ivez

3、等待3个监测周期,容器会因健康监测失败而被重启,重启后/ivez响应内容会被重置为ok,后续存活状态监测不会出现错误

[root@master ~]# kubectl describe pod pod-liveness-http
Warning Unhealthy 30s (x6 over 7m30s) kubeletLiveness probe failed: HTTP probe failedwith statuscode: 506
Normal Killing30s (x2 over 7m10s) kubeletContainer pod-liveness-http failed livenessprobe, will be restarted

11.3 tcpSocket

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcp
spec:
  containers:
  - name: pod-liveness-tcp
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10           #容器启动后多久开始探测,默认0
      periodSeconds: 10                 #探测时间间隔 10s探测一次
      timeoutSeconds: 10                #探测的超时时间
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

十二.readinessProbe

指容器是否准备好接收网络请求,如果就绪探测失败,则将容器设定为未就绪状态,然后将其从负载均衡列表中移除,这样就不会有请求会调度到该Pod上;如果容器不提供就绪态探针,则默认状态为Success。
有些程序启动后需要加载配置或数据,甚至有些程序需要运行预热的过程,需要一定的时间。所以需要避免Pod启动成功后立即让其处理客户端请求,而应该让其初始化完成后转为就绪状态,在对外提供服务。此类应用就需要使用readinessProbe探针。

12.1 exec

apiVersion: v1
kind: Pod
metadata:
  name: pod-readiness-exec
  labels:
    app: readiness
spec:
  containers:
  - name: pod-readiness-exec
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    readinessProbe:
      exec:
        command:
        - "/bin/sh"
        - "-c"
        - '[ "$(curl -s 127.0.0.1/readyz)" = "OK" ]'
      initialDelaySeconds: 10           #容器启动后多久开始探测,默认0
      periodSeconds: 10                 #探测时间间隔 10s探测一次
      timeoutSeconds: 10                #探测的超时时间
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

12.2 httpGet

apiVersion: v1
kind: Pod
metadata:
  name: pod-readiness-http
  labels:
    app: readiness
spec:
  containers:
  - name: pod-readiness-http
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    readinessProbe:
      httpGet:
        path: '/readyz'
        port: 80
        scheme: HTTP
      initialDelaySeconds: 10           #容器启动后多久开始探测,默认0
      periodSeconds: 10                 #探测时间间隔 10s探测一次
      timeoutSeconds: 10                #探测的超时时间
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

2.为了测试就绪状态监测效果,将/readyz修改为非0K

[root@master ~]# kubectl exec -it pod-readiness-http -- curl -s -X POST -d 'readyz=error' http://127.0.0.1/readyz

3.由于pod未就绪,所以会将该节点从Service负载均衡中准为未就绪状态 (需要事先创建好负载均衡,否则难以观察效果)

[root@master ~]# kubectl get pod pod-readiness-http
NAME                 READY   STATUS   RESTARTS  AGE
pod-readiness-http    0/1    Running     0      6m
[root@master ~]# kubectl describe endpoints pod-readiness-exec
Name:   pod-readiness-exec
Subsets:
   Addresses:          <none>
   NotReadyAddresses: 192.168.3.38

12.3 tcpSocket

apiVersion: v1
kind: Pod
metadata:
  name: pod-readiness-tcp
  labels:
    app: readiness
spec:
  containers:
  - name: pod-readiness-tcp
    image: oldxu3957/demoapp:v1.0
    ports:
    - containerPort: 80
    readinessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10           #容器启动后多久开始探测,默认0
      periodSeconds: 10                 #探测时间间隔 10s探测一次
      timeoutSeconds: 10                #探测的超时时间
      successThreshold: 1               #成功多少次为成功 默认1次
      failureThreshold: 3               #失败多少次为失败 默认3次

十三.Pod资源限制

13.1 什么是资源限制

在kubernetes集群中,某Pod发生异常,不断的使用系统资源。会对kubernetes中所有Pod稳定性产生影响,所以需对运行的Pod进行资源限制。

13.2 如何实现资源限制

kubernetes 通过 requests 和 limits 字段阿里实现对pod的资源进行限制

  • requests:启动Pod时申请分配的资源大小;(Pod在调度的时候requests比较重要)
  • limits: 限制Pod运行时最大可用的资源大小;(Pod在运行时limits比较重要)
spec.containers[].resources .request.cpu
spec.containers[].resources.request.memory
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory

13.3 资源限制的目的与意义

CPU: 为集群中运行的容器配置CPU请求和限制,可以有效利用集群上可用的CPU资源。

  • 设置Pod CPU请求 设定在较低的数值,可以使Pod更有机会被调度。

  • 设置CPU limit大于CPU request,可以完成如下两件事:

     * 当Pod碰到一些突发负载时,它可以合理利用可用的CPU资源
     * 当Pod在突发流量期间,可使用的CPU被限制为合理的数值,从而可以避免影响其他Pod的正常运行
    

Memory: 为集群中运行的容器配置内存请求和限制,可以有效利用集群节点上可用的内存资源。

  • 通过将POD的内存请求设定在脚底的数值,可以使Pod更有机会被调度。

  • 通过让内存限制大于内存请求,可以完成如下两件事:

    • 当Pod碰到一些突发负载时,可以更好的利用其主机上的可用内存。
    • 当Pod在突发负载期间可使用的内存被限制为合理的数值,从而可以避免影响其他的Pod的运行。

十四.资源限制单位换算

14.1 CPU限制单位

1核CPU等于1000毫核,当定义容器为0.5时,所能用到的CPU资源时1核心CPU的一半,对于 CPU 资源单位,表达式 .1 等价于表达式100m,可以看作 1 millicpu.

1 核心 = 100 millicpu(1 Core = 1000m)
0.5 核 = 50日 millicpu(0.5 Core = 500m)

举例:当我们有1个物理CPU,16核心,如果某个Pod最多使用一半的核心数,则表达式可以写入如下两种:

  • limits.cpu: 8
  • Timits.cpu: 8000m 计算公式: (160*.5=8000m)

注意: Kubernetes不允许设置精度小于 1m 的CPU资源。因此当CPU 单位小于1时,只能使用毫核来表示。
例如: 期望使用1个CPU的0.5%,应该写 5m 而不是 .5

14.2 内存限制单位

内存的基本单位是字节数(Bytes),也可以加上国际单位,十进制的E、P、T、G、M,K、m,或二进制的 Ei、Pi、Ti、Gi、Mi、Ki.

1MB = 1000 KB = 100000 Bytes
1Mi = 1024 KB = 1048576 bytes

十五.CPU资源限制实践

metrics-server

15.1 设置容器的CPU请求和限制

1.创建一个具有一个容器的Pod。容器将请求0.5个CPU,最多限制使用1个CPU

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo
spec:
  containers:
  - name: cpu-demo-ctr
    image: vish/stress
    args:              #容器启动命令,容器尝试使用2核CPU
    - "-cpus"
    - "2"
    resources:
      requests:        #显示启动Pod时最多申请0.5核的CPU
        cpu: "500m"
      limits:          #限制运行中的Pod最多使用1核CPU
        cpu: "1000m"

2.查看Pod详细信息,输出显示Pod中的一个容器的CPU请求为500 milli CPU,并且 CPU限制为1个CPU.

[root@master ~]# kubectl get pod cpu-demo -o yaml
    resources:
      Limits:
        cpu:"1"
      requests:
        cpu: 500m

3.检查资源限制情况,容器配置为尝试使用2个CPU,但是容器只被允许最大使用1个CPU,所以容器的CPU用量受到限制。

[root@master ~]# kubectl apply -f https://linux.oldxu .net/metrics-server.yaml
[root@master ~]# kubectl top pod cpu-demo
NAME        CPU(cores)         MEMORY(bytes)
cpu-demo     913m                 0Mi

15.2 设置超过节点的CPU请求

1.创建一个 Pod,设置该Pod中容器的请求为100核,这个值会大于集群中的任何一个节点。

apiVersion: V1
kind: Pod
metadata:
  name: cpu-demo-2
spec:
  containers:  
  - name: cpu-demo-ctr-2
    image: vish/stress
    args:
    - -cpus
    - "2"
    resources:
      requests:
        cpu: "100"
      limits:
        cpu:"100"

2.查看该Pod的状态,输出显示Pod状态为 pending.也就是说 Pod未被调度到任何节点上运行。

[root@master pod-request]# kubectl get pod
NAME           READY        STATUS      RESTARTS     AGE
cpu-demo-2     0/1         Pending        0          3s

3.查看该Pod的详细信息及事件,输出显示由于节点上的CPU资源不足,无法调度容器

[rootmaster ~]# kubectl describe pod cpu-demo-2
Events:
   Type     Reason     Age     From     Message

-----------------------------------------------
Warning FailedScheduling 49s (x2 over 116s)default-scheduler /3 nodes are available: 1node(s) had taint {node-role .kubernetes .io/master:}, that the pod didn't tolerate, 2 Insufficient cpu.

4.删除Pod

[root@master ~]# kubectl delete pod cpu-demo-2
pod "cpu-demo-2" deleted

15.3 如果不指定CPU的limits

如果没有为容器指定 CPU 限制,那么容器在可以使用的 CPU 资源是没有上限。因而可以使用所在节点上所有的可用 CPU 资源,这样可能会造成某一个Pod占用了大量的CPU时间,可能会影响其他的Pod正常运行从而造成业务的不稳定性。
这个也不用担心,在Kubernetes中,可以通过 LimitRange 自动为容器设定,所使用的CPU资源和内存资源最大最小值。

十六. 内存资源限制实践

16.1 设置容器的内存请求和限制

1.创建一个拥有一个容器的Pod。容器将会请求100MiB内存,并且内存会被限制在200MiB 以内

apiVersion: v1
kind: Pod
metadata:
  name: memory- demo
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    command: ["stress"]
    args: ["--vm","1","--vm-bytes","150M","--vm-hang”,"1”] # 告知容器尝试分配 150 MB 内存
    resources:
      requests:
        memory: "100Mi'
      limits:
        memory: "200Mi"

2.检查Pod,结果显示该Pod中容器的内存请求为 100MiB,内存限制为 200MiB

[root@master ~]# kubectl get pod memory-demo -o yaml
    resources :
      limits:
        memory: 200Mi
      requests:
        memory: 100Mi

3.获取该Pod的指标数据: 输出结果显示Pod正在只用的内存为150MiB.这大于Pod请求的100MiB,但又在Pod限制的200MiB之内。

[root@master ~]# kubectl top pod memory-demo
NAME            CPU(cores)       MEMORY(bytes)
mmemory-demo    46m              150Mi

4.删除pod

[root@master ~]# kubectl delete pod memory-demo
pod "memory-demo" deleted

16.2 运行超过容器内存限制的应用

当节点拥有足够的可用内存时,容器可以使用其请求的内存。但是,容器不允许使用超过其限制的内存。如果容器分配的内存超过其限制,该容器会成为被终止的候选容器。如果容器继续消耗超出其限制的内存,则终止容器。如果终止的容器可以被重启,则 kubelet 会重新启动它。
1.创建一个 Pod,其拥有一个容器,该容器的内存请求为 100MiB,内存限制为 200MiB,尝试分配超出其限制的内存。

[root@master ~]# cat memory-request-limit-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: memory- demo-2
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    command: ["stress"]# 容器会尝试分配 250 MiB 内存,这远高于 100 MiB 的限制。
    args: ["--vm","1","--vm-bytes","250M","-- vm-hang","1” ] # 模拟1个进程产生250M内存
    resources:
      requests:
        memory:"100Mi"
      limits:
        memory: "200Mi"

2.查看Pod,此时,容器可能正在运行或被杀死。重复前面的命令,直到容器被杀掉:

[root@master ~]# kubectl get pod
NAME           READY    STATUS     RESTARTS    AGE
memory-demo-2   0/1      00MKilled   0         13s

3.查看容器更详细的信息,其输出结果为,内存溢出 (00M) ,容器已被杀掉:

[root@master ~]# kubectl get pod memory-demo-2 -o yaml
      lastState: 
        terminated:
          containerID:docker://43d2278dacdac6cea191c6c04f2147025128ce45c961ab0c2d366840dobc5e40
          exitCode: 1
          finishedAt: "2022-04-11T15:45:17Z
          reason: 00MKilTed
          startedAt: "2022-04-11T15:45:17Z"

4.删除Pod

[root@master ~]# kubectl delete pod memory-demo-2
pod "memory-demo-2" deleted

16.3 超过节点的内存分配

Pod 的调度基于请求。只有当节点拥有足够满足 Pod 内存请求的内存时,才会将 Pod 调度至节点上运行。
1.创建一个 Pod,其拥有一个请求 1000GiB 内存的容器,这应该超过了集群中任何一台节点所拥有的内存。

[root@master pod-request]# cat memory-request-limit-3.yaml
apiVersion: V1
kind: Pod
metadata:
  name: memory- demo-3
spec:
  containers:
  - name: memory-demo-3-ctr
    image: polinux/stress
    command: ["stress"]
    args: ["--vm","1","--vm-bytes","25M","--vm-hang","1”] # 告知容器尝试分配 25 MiB 内存
    resources:
      requests:
        memory: "100Gi"
      limits:
        memory:"200Gi"

2.查看 Pod 状态,发现处于 PENDING 状态。 这意味着,该 Pod 没有被调度至任何节点上运行

[root@master ~]# kubectl get pod
NAME            READY    STATUS     RESTARTS   AGE
memory-demo-3    0/1      Pending     0        46s

3.查看Pod详情,输出结果显示,由于节点内存不足,该容器无法被调度:

[root@master ~]# kubectl describe pod memory-demo-3
Events:
   Type           Reason        Age     From
   Message
------------------------------------------------
WarningFailedScheduling 78s default-scheduler0/3 nodes are available: 1 node(s) had taint inoderole.kubernetes .io/master: ], that the pod didn'ttolerate,2 Insufficient memory.
iang

4.删除Pod

[root@master ~]# kubectl delete pod memory-demo-3
pod "memory-demo-3" deleted

16.4 如果没有指定内存限制

如果没有为容器指定内存限制,容器可无限制地使用其所在节点的所有可用内存,进而可能导致该节点调用 00M KiLLer。 此外,如果发生 00MKi飞,没有配置资源限制的容器将被杀掉的可行性更大。
不用担心,在Kubernetes中,可以通过[LimitRange]自动为其容器设定,所使用的内存资源最大最小值。

十七. Pod服务质量QoS

17.1 设么是QoS

QoS (Quality of Service) ,可译为 "服务质量等级",或者译作"服务质量保证",是作用在 Pod 上的一个配置,当 Kubernetes 创建一个 Pod 时,它就会给这个 Pod 分配一个 QoS 等级。
在Kubernetes的环境中,Kubernetes允许节点的Pod过载使用资源这意味着节点无法同时满足所有Pod以过载的方式运行。因此在内存资源紧缺的情况下,Kubernetes需要借助Pod对象的服务质量和优先级等完成判定,进而挑选对应的Pod杀死。Kubernetes根据pod的Requests和Limits属性,把Pod对象归类为三类 BestEffort、BurStable、Guaranteed

17.2 QoS类别

  • Guaranteed: Pod对象为每个容器都设置了CPU资源需求和资源限制,且两者的值相同;还同时为每个容器设置了内存需求与内存限制,并且两者的值相同。这类Pod对象具有最高级别服务质量。
  • Burstable: 至少有一个容器设置了CPU或内存资源Requests属性,但不满足Guaranteed,这类Pod具有中级服务质量。
  • BestEffort:没有为任何容器设置Requests和Limits属性,这类Pod对象服务质量是最低级别。
    当 Kubernetes 集群内存资源紧缺,优先杀死BestEffort类别的容器,因为系统不为该类资源提供任何服务保证,但此类资源最大的好处就是能够尽可能的使用资源
    如果系统中没有BestEffort类别的容器,接下来就轮到Burstable类别的容器,如果有多个Burstable类别的容器,就看谁的内存资源占用多,就优先干掉谁。比如A容器申请1G内存资源,实际使用了95%,而B容器申请了2G内存资源,实际使用了80%,但任然会优先干掉A容器,虽然A容器的用量少,但与自身的Requests值相比,它的占比要大于B容器.
    对于Guaranteed类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者00M时没有其他更低优先级的Pod对象存在,才会干掉Guaranteed类容器。

17.3 创建Guaranteed的Pod

对于 QoS 类为 Guaranteed 的 Pod:

  • Pod 中的每个容器都必须指定内存请求和内存限制,且Pod中每个容器内存请求必须等于内存限制。
  • Pod 中的每个容器都必须指定CPU请求和CPU限制,且Pod中每个容器CPU请求必须等于CPU限制。
    1.创建一个Pod,容器设置了内存请求和内存限制,值都是200MiB。容器设置了CPU请求和CPU限制,值都是70 milLiCPU
[root@master ~]# cat pod-gos-guaranteed.yaml
apiVersion: V1
kind: Pod
metadata:
  name: pod-qos-guarantee
spec:
  containers:
  - name: qos-demo
    image: nginx
    resources: 
      requests:
        cpu:"700m"
        memory: "200Mi"
      limits:
        cpu: "700m"
        memory: "200Mi"

2.查看Pod详情

spec:
  containers:
    Limits:
      cpu:  700m
      memory: 200Mi 
    Requests:
      cpu: 700m 
      memory: 200Mi
status:
  qosClass: Guaranteed

17.4 创建Burstable的Pod

如果满足下面条件,将会指定 Pod 的 QoS 类为 Burstable。

  • Pod 不符合 Guaranteed QoS 类的标准。
  • Pod 中至少一个容器指定了,内存或 CPU 的请求或限制
    1.创建一个Pod,容器设置了内存请求 100 MiB,以及内存限制 200MiB。
[root@master ~]# cat pod-qos-burstable.yaml
apiVersion: V1
kind: Pod
metadata:
  name: pod-gos-burstable
spec:
  containers:
  - name: qos-demo
    image: nginx
    resources:
      requests:
        memory: "100Mi"
      limits:
        memory: "200Mi"

2.查看Pod详情

spec :
  containers:
    Limits:
      memory: 200Mi
    Requests:
      memory : 100Mi
status:
   qosClass: Burstable

17.5 创建BestEffort的Pod

对于 QoS 类为 BestEffort 的 Pod,Pod 中的容器必须没有设置内存和 CPU 限制或请求。
1.创建一个Pod,容器没有设置内存和 CPU 限制或请求

[root@master tmp]# cat pod-qos-besteffort.yaml
apiVersion: 1
kind: Pod
metadata:
  name: pod-qos-besteffort
spec:
  containers:
  - name: qos-demo
    image: nginx

2.查看 Pod 详情

spec:
  containers:
     ...
    resources: {}
   ...
status:
  qosClass: BestEffort

17.6 创建多容器Pod

1.创建一个Pod,一个容器指定了内存请求 200 MiB。 另外一个容器没有指定任何请求和限制。此 Pod 满足 Burstable QoS 类的标准但它不满足 Guaranteed QoS 类标准,因为它的一个容器设有内存请求。

[root@master ~]# cat pod-qos-mutil.yaml
apiVersion: V1
kind: Pod
metadata:
  name: pod-qos-mutil
spec:
  containers:
  - name: gos-demo
    image: nginx
    resources :
      requests:
        memory: "100Mi"

  - name: qos-demo2
    image: redis

2.查看Pod

spec :
  containers:
    name: qos-demo
    resources :
      Requests:
        memory: 100Mi
......
    name: qos-demo2
    resources: {}
    ....
status:
  qosClass:Burstable

十八. Downward API

18.1 什么是DownwardAPI

DownwardAPI可以让容器获取Pod的相关元数据信息,比如Pod名称Pod的IP,Pod的资源限制等,获取后通过env、volume的方式将相关的环境信息注入到容器中,从而让容器通过这些信息,来设定容器的运行特性。

  • 例如: Nginx进程根据节点的CPU核心数量自动设定要启动的worker进程数。
  • 例如: JVM虚拟根据Pod的内存资源限制,来设定对应容器的堆内存大小。
  • 例如: 获取Pod名称,以Pod名称注册到某个服务,当Pod结束后调用prestop清理对应名称的注册信息。

18.2 可注入的元数据信息

使用 pod.spec.containers.env.valueFrom.fieldRef 可以注入的字段有:

  • metadata.name: Pod对象的名称
  • metadata.namespace: Pod对象隶属的名称空间
  • metadata.uid: Pod对象的UID
  • metadata.Labels[']: 获取Label指定KEY对应的值
  • metadata.annotations[']: 获取Annotations对应KEY的值
  • status.podIP: Pod对象的IP地址
  • status.hostIP: 节点IP
  • status.nodeName: 节点名称
  • spec.serviceAccountName: Pod对象使用的ServiceAccount资源名称
    使用
    pod.spec.containers.env.valueFrom .resourceFieldRef 可以注入的字段有:
  • requests.cpu
  • requests.memory
  • limits.cpu
  • limits.memory

18.3环境变量方式注入元数据

1.创建Pod容器,将Pod相关环境变量注入到容器中,比如 (pod名称命名空间、标签、以及cpu、内存的请求和限制)

apiVersion: v1
kind: Pod
metadata:
  name: pod-downward
  labels:
    app: pod-app
spec:
  containers:
  - name: pod-downward
    image: nginx
    command: ["/bin/sh", "-c", "env"]
    resources:
      requests:
        cpu: "200m"
        memory: "32Mi"
      limits:
        cpu: "200m"
        memory: "64Mi"
    env:
    - name: THIS_POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: THIS_POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: THIS_POD_APP_LABEL
      valueFrom:
        fieldRef:
          fieldPath: metadata.labels['app']
    - name: THIS_CPU_LIMITS
      valueFrom:
        resourceFieldRef:
          resource: limits.cpu
    - name: THIS_MEMORY_REQUEST
      valueFrom:
        resourceFieldRef:
          resource: requests.memory
          #divisor: 1Mi         #默认显示为字节,通过divisor调整显示单位为兆

2.通过控制台日志获取注入的环境变量

[root@master tmp]# kubectl Togs pod-downward |grep ^THIS

THIS_CPU_LIMITS=1    # 200毫核,不足1核,则进行取整。
THIS_POD_APP_LABEL=pod-app
THIS_POD_NAME=pod-downward
THIS_MEMORY_REQUEST=32  # 单位为兆,默认字节
THIS_POD_NAMESPACE=default

18.4 存储卷方式注入元数据

apiVersion: v1
kind: Pod
metadata:
  name: pod-downward-volumes
  labels:
    app: pod-app
    zone: beijing
    role: backend
spec:
  containers:
  - name: pod-downward
    image: nginx
    resources:
      requests:
        cpu: "200m"
        memory: "32Mi"
      limits:
        cpu: "200m"
        memory: "54Mi"
    volumeMounts:         #将环境变量挂载到/etc/podinfo目录中,每注入一条元数据都会产生一个文件
    - name: podinfo
      mountPath: /etc/podinfo
  volumes:
  - name: podinfo
    downwardAPI:
      items:
      - path: podname
        fieldRef:
          fieldPath: metadata.name

      - path: podlabels
        fieldRef:
          fieldPath: metadata.labels

      - path: podnamespace
        fieldRef:
          fieldPath: metadata.namespace

      - path: mem_limits
        resourceFieldRef:
          containerName: pod-downward
          resource: limits.memory
          #divisor: 1Mi      #默认显示为字节,通过divisor调整显示单位为兆
      - path: mem_requests
        resourceFieldRef:
          containerName: pod-downward
          resource: requests.memory
          #divisor: 1Mi      #默认显示为字节,通过divisor调整显示单位为兆

18.4 为注册服务注入Pod名称

使用DownwardAPI实现注册与卸载

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-mysql-register
spec:
  replicas: 10
  selector:
    matchLabels:
      app: tools
  template:
    metadata:
      labels:
        app: tools
    spec:
      containers:
      - name: register
        image: oldxu3957/tools:latest
        imagePullPolicy: IfNotPresent
        command:
        - "/bin/bash"
        - "-c"
        - |
         mysql -h 10.8.0.286 -u oldxu -p123 -e "create database ${POD_NAME//-/_}"
         sleep 9999999
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        lifecycle:
          preStop:
            exec:
              command:
              - "/bin/bash"
              - "-c"
              - "mysql -h 10.8.0.286 -u oldxu -p123 -e 'drop database ${POD_NAME//-/_}'"

18.5 为tomcat注入堆内存限制

默认Tomcat应用会使用Pod所在的物理节点内存,初始堆内存为1/64,最大堆内存为1/4.

[root@master tmp]# cat 11-pod-lifecycle-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-tomcat
spec:
  containers:
  - name: tomcat-web
    image: tomcat:9.0.63
    ports:
    - containerPort: 8080
    env:
    - name: JAVA_OPTS
      value: -server -Xms${JVM_XMS} -Xmx${JVM_XMX} -XX:+UseConcMarkSweepGC
    # downward API
    - name: JVM_XMS
      valueFrom:
        resourceFieldRef:
          resource: requests.memory
    - mame: JVM_XMX
      valueFrom:
        resourceFieldRef:
           resource: limits.memory
    resources:
      requests:
        memory: "250Mi"
      limits:
        memory: "500Mi"
posted @ 2021-07-20 08:54  老夫聊发少年狂88  阅读(311)  评论(0)    收藏  举报