Pod 基础 + 各类控制器实战

4 阅读33分钟

Pod与Pod控制器(K8s核心实战详解)

一、Pod 介绍

Pod是k8s集群进行调度的最小单元,k8s会将Pod调度到集群中的节点上运行,一个Pod中可以存在一个或多个容器,这些容器共享Pod中的存储、网络等资源,所以我们可以把Pod看做一个抽象的逻辑主机,来为容器提供一个运行的环境。

二、静态 Pod

在k8s中,静态Pod也称之为无控制器管理的自主式Pod,这种Pod不由k8s的控制平面(如kube-apiserver、kube-scheduler、kube-controller-manager)进行管理, 而是由对应节点上的kubelet进程负责管理,这意味着它们不受k8s的自动调度、健康检查或重启策略的控制, 因此通常不建议在生产环境中广泛使用静态Pod。 ​

案例:创建一个Nginx的静态Pod

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain pod

cat static-web.yaml

apiVersion: v1
kind: Pod
metadata:
  name: static-web
spec:
  containers:
    - name: web
      image: nginx:1.18.0
# 创建Pod
kubectl create -f static-web.yaml
​
# 查看Pod信息
kubectl get pod
​
# 删除Pod
kubectl delete pod static-web

三、Pod 资源清单

在k8s中基本所有资源的一级属性都是一样的,主要分为五部分:

  • apiVersion //资源版本,由k8s内部定义,版本号可以通过资源对应文档查询
  • kind //资源类型,由k8s内部定义,类型可以通过资源对应文档查询
  • metadata //元数据,主要是指定资源标识与说明,常用的有name、namespace、labels等
  • spec //定义资源详细配置信息,这是资源对象中最重要的一部分
  • status //资源状态信息,里边的内容不需要定义,由资源自动生成

Pod配置参考地址:kubernetes.io/zh-cn/docs/…

以下是比较详细的资源清单介绍

KIND:     Pod  #资源类型
VERSION:  v1   #资源版本

FIELDS:        #资源可配置的属性,如下
apiVersion: v1      #必选的一级属性,版本号,例如v1
kind: Pod           #必选的一级属性,资源类型,例如Pod
metadata:           #必选的一级属性,元数据
    name:           #资源名称
    namespace: test #资源所属的名称空间,例如dev,默认为default名称空间
    labels:         #自定义标签列表
     - name:        #标签名称
spec:               #必选的一级属性
 containers:        #Pod中容器列表
 - name:            #容器名称
   image:           #容器镜像名称
   imagePullPolicy: #镜像的拉取策略
   command:         #容器的启动命令列表,如不指定,使用打包时使用的启动命令
   args:            #容器的启动命令参数列表
   workingDir:      #容器的工作目录
   volumeMounts:    #挂载到容器内部的存储卷配置
   - name:          #引用pod定义的共享存储卷的名称
     mountPath:     #存储卷在容器内mount的绝对路径,应少于512字节
     readOnly:      #是否为只读模式
   ports:           #需要暴露的端口号列表
   - name:          #端口的名称
     containerPort: #容器需要监听的端口号
     hostPort:      #容器所在的主机需要监听的端口号,默认与Container相同
     protocol:      #端口协议,支持TCP/UDP,默认为TCP
   env:             #容器运行前需要设置的环境变量列表
   - name:          #环境变量名称
     value:         #环境变量的值
   resources:       #资源限制和请求的设置     
     limits:        #资源最大限制的设置
        CPU:        #CPU资源限制,单位为core数,将用于docker run --cpu-shares参数
        memory:     #内存资源限制,单位可以为Mib/Gib,将用于docker run --memory参数
     requests:      #资源最小请求的设置
        CPU:        #CPU请求,容器启动的初始可用数量
        memory:     #内存请求,容器启动的初始可用数量
   lifecycle:       #生命周期钩子
     postStart:     #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
     preStop:       #容器终止前执行此钩子,无论结果如何,容器都会终止
   livenessProbe:   #对Pod内个容器健康检查设置,当探测容器无响应后将自动重启该容器
   tcpSocket:       #对Pod内容器健康检查方式
   initialDelaySeconds:     #容器启动完成后,首次探测时间,单位为秒
   timeoutSeconds:          #对容器健康检查探测等待相应的超时时间,单位秒,默认1秒
   periodSeconds:           #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
 restartPolicy:     #Pod的重启策略
 nodeName:          #设置pod调度到指定的node节点上
 nodeSelector:      #设置Pod调度到指定的label的node节点上
 imagePullSecrets:  #拉取镜像时,使用secret名称,以key:secretkey格式指定
 hostNetwork:       #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
 volumes:           #在该Pod上定义共享存储卷列表
 - name:            #共享存储卷名称
   emptyDir:        #类型为emptyDir的存储卷
   hostPath:        #类型为hostPath的存储卷
     path:          #Pod所在宿主机的目录
   secret:          #类型为secret的存储卷,挂载secret对象到容器内部
   configMap:       #类型为configMap的存储卷,挂载configMap对象到容器内部

四、Pod 控制器

参考地址:kubernetes.io/zh-cn/docs/…

在k8s中,Pod控制器(Controller)用于管理和控制Pod的生命周期、副本数和状态。Pod控制器的主要作用包括以下几个方面:

  • 副本管理:Pod控制器可以定义和管理Pod的副本数,确保指定数量的Pod副本在集群中运行。
  • 自愈性和健康检查:Pod控制器通过监视Pod的健康状态来实现自愈性。如果Pod出现故障或终止,控制器会自动重启或创建新的Pod,以确保应用程序的高可用性和可靠性。
  • 扩展性:使用Pod控制器,可以通过调整副本数来扩展应用程序。通过增加副本数,可以实现应对高负载的能力,并在负载减少时自动缩减副本数,从而实现资源的有效利用。
  • 版本管理:Pod控制器还负责应用程序的滚动更新和版本回退。
  • Pod调度规则:通过Pod控制器,可以确保Pod被调度到指定的节点上,以满足特殊的部署策略。

1. ReplicaSet 控制器

ReplicaSet(RS)控制器具备副本管理、自愈性和健康检查、扩展性、Pod调度规则等功能。

案例:通过RS控制器创建3个Nginx Pod

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain rs

# cat rs-nginx.yml

apiVersion: apps/v1     
kind: ReplicaSet        
metadata:               
    name: rs-nginx
    namespace: test     

spec:                   
    replicas: 3                 #创建pod的副本数量,默认为1
    selector:                   #标签选择器,通过标签指定RS管理哪些pod
      matchLabels:              #标签类型(key-value)
        app: rs-nginx           #匹配pod的标签(表示RS管理带有此标签的Pod)

    template:                   #pod的配置模板,通过模板创建Pod
      metadata:                 #定义模板元数据信息
        labels:                 #定义标签
          app: rs-nginx         #标签名称(与selector中的标签保持一致)
          
      spec:                     #定义容器的详细配置
        containers:             #定义容器列表
        - name: nginx           #定义容器名称
          image: nginx:1.18.0   #定义容器镜像
# 创建pod
kubectl create -f rs-nginx.yml
​
# 查看pod信息
kubectl get po -n test
​
# 查看pod控制器信息
kubectl get rs -o wide -n test
​
DESIRED     //期望的pod副本数量
CURRENT     //当前的pod副本数量
READY       //已经准备好提供服务的副本数量# 查看Pod详细信息
kubectl describe pod -n test
案例:通过RS控制器实现Pod数量的扩缩容功能
# 方式1:通过vim编辑配置文件来调整Pod的副本数,然后通过apply更新资源对象配置
# 方式2:通过命令行直接修改 kubectl scale rs rs-nginx -n test --replicas=4
# 方式3:通过edit(实时修改)更新资源对象的配置(资源配置文件不会跟着发生变化)
​
kubectl edit rs rs-nginx -n test
...
spec:
  replicas: 6     #修改pod的副本数# 查看pod信息
kubectl get pod -n test
删除RS方式
# 命令删除方式
kubectl delete rs rs-nginx -n test# 查看rs信息
kubectl get rs -n test# 配置文件删除方式
kubectl delete -f rs-nginx.yml

2. Deployment 控制器

Deployment(deploy)控制器是在RS控制器的基础上进行进一步扩展和增强的一种控制器,提供了更高级的功能和更便捷的应用程序管理方式。Deployment控制器的主要功能包括:

  • 具备RS所有功能:通过控制RS来实现对Pod的副本管理、自愈性和健康检查、扩展性、Pod调度规则等功能。
  • 滚动更新:Deployment控制器支持应用程序的滚动更新, 确保应用程序在更新过程中的平滑过渡,避免服务中断。
  • 版本管理:Deployment控制器可以管理应用程序的不同版本,可以轻松地进行版本切换和回滚。
案例:通过 Deployment 控制器创建3个Nginx Pod

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain deploy

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 3                 #创建pod的副本数量,默认为1
    selector:                   #标签选择器
      matchLabels:              #标签类型(key-value)
        app: deploy-nginx       #匹配pod的标签(表示deploy管理带有此标签的Pod)

    template:                   #pod的配置模板,通过模板创建pod
      metadata:                 #定义模板元数据信息
        labels:                 #定义标签
          app: deploy-nginx     #标签名称(与select中的标签保持一致)

      spec:
        containers:
        - name: nginx
          image: nginx:1.17.0
# 创建deploy
kubectl create -f deploy-nginx.yml
​
# 查看deploy信息
kubectl get deploy -n test
kubectl get deploy -n test -o wide
​
UP-TO-DATE      //最新版本的pod数量
AVAILABLE       //当前可用的pod数量# 查看rs信息,deploy通过控制rs管理pod,所以rs控制器也会被创建出来(rs的名称在deploy基础上随机生成)
kubectl get rs -n test 
​
# 查看pod信息(pod名称是在rs基础上随机添加生成)
kubectl get po -n test
​
# 查看Pod标签
kubectl get pod -n test --show-labels

五、Pod 生命周期

Pod 的生命周期分为几个阶段,主要用来让用户理解Pod的当前状态和问题所在:

  • Pending:Pod 已经被系统接受,但是它需要完成一些准备工作才能运行。这些工作包括分配到指定节点上,下载容器镜像等。简单来说,这个阶段就是 Pod 的"准备"阶段。
  • Running:Pod 已经被分配到节点上,同时Pod中的所有容器都已经创建。至少有一个容器在运行、或处于启动、重启状态,这个阶段可以被看作是 Pod 的"运行"阶段。
  • Succeeded:Pod 的所有容器都已经成功完成了它们的任务并且都成功地终止了,并且不会再重启。这意味着,Pod 已经完成了它的生命周期并且不再需要。这个阶段看作是 Pod 的"完成"阶段。
  • Failed:Pod 中的所有容器都已经停止,但是至少有一个容器是因为失败而停止的。这意味着 Pod 在尝试完成它的任务时遇到了一些问题。这个阶段可以被看作是 Pod 的"失败"阶段。
  • Unknown:系统不能确定 Pod 的状态。通常是因为与Pod所在的主机通讯失败导致。这个阶段可以被看作是 Pod 的"未知"阶段。
  • CrashLoopBackOff:这个状态通常意味着Pod 中的一个或多个容器在启动后立即崩溃,系统在重新启动它,但是连续多次尝试都失败了。

六、Pod 镜像拉取策略

imagePullPolicy 属性用于设置镜像拉取策略,k8s支持三种拉取策略:

  • Always //总是从远程仓库拉取镜像
  • IfNotPresent //本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
  • Never //只使用本地镜像,从不去远程仓库拉取,本地如果没有就报错

默认值说明:如果镜像 tag 为具体版本号,默认策略是 IfNotPresent ,如果镜像标签为 latest,默认策略是Always

案例1:指定镜像拉取策略为 Never

# cat deploy-nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.20.0           #指定一个本地不存在的镜像版本
          imagePullPolicy: Never        #设置镜像拉取策略
# 更新pod配置
kubectl apply -f deploy-nginx.yml
​
# 查看pod信息
kubectl get pod -n test# 查看pod详细信息
kubectl describe pod -n test

案例2:指定镜像拉取策略为 IfNotPresent

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.20.0
          imagePullPolicy: IfNotPresent     #设置镜像拉取策略
# 更新pod配置
kubectl apply -f deploy_nginx.yml
​
# 查看pod信息
kubectl get pod -n test# 查看pod详细信息
kubectl describe pod -n test

七、Pod 端口设置

ports 属性用于配置容器需要暴露的端口列表,支持的属性:

  • containerPort //容器要监听的端口(不定义,采用默认端口)
  • name //端口名称,如果指定,必须保证名称在该pod中是唯一的(可以省略)
  • protocol //端口协议,支持TCP、UDP,默认为TCP

案例:创建Pod并指定容器暴露80端口

资源文档查询方法:kubectl explain pod.spec.containers.ports

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.20.0       
          imagePullPolicy: IfNotPresent
          ports:                            #定义容器端口
          - containerPort: 80               #端口(必须为列表类型)
            protocol: TCP                   #端口协议
# 更新pod配置
kubectl apply -f deploy-nginx.yml
​
# 查看pod信息
kubectl get pod -n test# 查看pod详细信息
kubectl describe pod  -n test
...
​
    Port:           80/TCP
​
# 访问pod中的容器需要访问pod的IP加容器端口
curl 10.244.2.30:80

八、Pod 资源配额

resources 属性用于限制Pod中的容器对系统的资源的使用量,避免容器出现问题大量吞噬系统资源,k8s目前提供了对内存CPU的资源限制,当我们对Pod中的容器配置资源限额以后,如果容器超出资源使用量,k8s则会认为该容器出现故障,则重新启动该容器。

resources 支持的属性:

  • limits //限制容器资源上限,当容器超出该使用量时,容器会被终止,并进行重启。
  • requests //限制容器需要的最小资源,如果环境资源不够,容器将无法启动,如果不定义,默认与 limits 相等。

案例:设置容器的内存与CPU资源限额

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain pod.spec.containers.resources

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.20.0       
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
          resources:            #定义资源限额
            limits:             #资源上限
              cpu: "1"          #表示一核心CPU资源
              memory: "128M"    #内存单位可以使用G、M等形式
            requests:           #资源下限
              cpu: "0.5"        #表示0.5核心CPU资源
              memory: "64M"     #所需最低内存资源(如果不足64M,容器无法启动)
# 更新pod配置
kubectl apply -f deploy-nginx.yml

# 查看pod信息
kubectl get pod -n test

# 查看pod详细信息
kubectl describe pod -n test
...
    Limits:
      cpu:     500m
      memory:  128Mi
    Requests:
      cpu:        250m
      memory:     64Mi

九、Pod 多容器创建方式

案例:将nginx与tomcat放在同一个Pod中运行

# cat vim deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: test

spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-nginx

  template:
    metadata:
      labels:
        app: deploy-nginx

    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        imagePullPolicy: IfNotPresent
        ports:
        - name: web-nginx
          containerPort: 80
          protocol: "TCP"
        resources:
            limits: 
              cpu: "500m"
              memory: "128Mi"
            requests:
              cpu: "250m"
              memory: "64Mi"

      # 通过-name再定义一个容器的配置
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        imagePullPolicy: IfNotPresent
        ports:
        - name: web-tomcat
          containerPort: 8080
          protocol: "TCP"
        resources:
            limits:
              cpu: "500m"
              memory: "128Mi"
            requests:
              cpu: "250m"
              memory: "64Mi"
# 更新Pod配置
kubectl apply -f deploy-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test

十、进入Pod中容器 & 执行命令

1. 进入容器

格式:kubectl exec -it -n 命名空间 pod名称 -c 容器名称 -- /bin/bash

提示:-c 为可选项,如果是1个pod中只有1个容器,则不用指定,如果是1个pod中有多个容器,不指定默认为第1个容器。

# 进入nginx容器
kubectl exec -it -n test deploy-nginx-579696c576-jfqz6 -c nginx -- /bin/bash
​
# 进入tomcat容器
kubectl exec -it -n test deploy-nginx-579696c576-jfqz6 -c tomcat -- /bin/bash

2. 执行命令

格式: kubectl exec -n 名称空间 pod名 -c 容器名 -- 命令

提示:没有 -it 选项

# 对nginx容器执行命令
kubectl exec -n test deploy-nginx-579696c576-jfqz6 -c nginx -- ls /opt
​
# 对tomcat容器执行命令
kubectl exec -n test deploy-nginx-579696c576-jfqz6  -c tomcat -- ls /opt

十一、Pod 环境变量

env 属性是用于设置容器环境变量的列表,环境变量的定义要根据容器具体需求定义,本章节只讲解如何定义环境变量,env支持的属性:

  • name //定义环境变量名称
  • value //定义变量值

案例:为MySQL添加环境变量设置root密码

资源文档查询方法:kubectl explain pod.spec.containers.env

# cat vim mysql.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-mysql
    namespace: test

spec:
    replicas: 1
    selector: 
      matchLabels:
        app: deploy-mysql

    template:
      metadata:
        labels:
          app: deploy-mysql

      spec:
        containers:
        - name: mysql
          image: mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 3306
            protocol: TCP
          env:                             #定义环境变量
          - name: "MYSQL_ROOT_PASSWORD"    #变量名称(必须为列表类型)
            value: "123456"                #变量值
# 更新Pod配置
kubectl create -f mysql.yml
​
# 查看Pod信息
kubectl get pod -n test# 查看Pod详细信息
kubectl describe pod  -n test# 删除Pod
kubectl delete -f mysql.yml

十二、Pod 调度策略

在默认情况下,一个Pod被调度到哪个Node节点运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的,但是在实际工作中,我们想要控制某些Pod调度到指定的Node节点,就需要用到Pod调度,k8s提供了四种调度方式:

  • 自动调度 //由Scheduler对Pod进行调度,不受人工干预。
  • 定向调度 //人为的将Pod调度到指定的节点。
  • 亲和性调度 //人为的将Pod调度到指定的节点。
  • 反亲和性调度 //人为的将Pod调度到指定的节点。

1. Pod定向调度

定向调度是通过在pod上声明 nodeName 或者 node Selector 将pod调度到指定的节点上

  • nodeName //根据节点名称, 可以强制将Pod调度到指定的节点上。
  • node Selector //根据节点的标签,可以强制将Pod调度到指定的节点上。

定向调度属于强制调度,即使指定的Node节点不存在,也会向该节点进行调度,只不过pod运行失败而已。

案例1:通过 NodeName 调度到 worker01节点

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方式:kubectl explain pod.spec.nodeName

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:                           
      matchLabels:                      
        app: deploy-nginx               
    template:                           
      metadata:
        labels:
          app: deploy-nginx             

      spec:
        nodeName: worker01              #定义调度策略,并指定集群节点名称
        containers:
        - name: nginx
          image: nginx:1.20.0 
          imagePullPolicy: IfNotPresent
          ports: 
          - containerPort: 80
            protocol: TCP 
# 更新pod配置
kubectl apply -f deploy-nginx.yml
​
# 查看pod信息
kubectl get pod -o wide -n test 
案例2:通过 node Selector 调度到带有node=worker02标签的节点
# worker02节点打标签
kubectl label node worker02 node=worker02
​
# 查看节点标签
kubectl get node worker02 --show-labels | grep worker02

创建Pod并通过 NodeSelector 进行调度:

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        nodeSelector:          #定义nodeSelector
          node: worker02       #指定节点标签
        containers:
        - name: nginx
          image: nginx:1.20.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
# 更新pod配置
kubectl apply -f deploy-nginx.yml
​
# 查看pod信息
kubectl get pod -o wide -n test 

2. 污点和容忍

污点(Taint) 通过在节点上添加污点属性,来避免 Pod 被分配到不合适的节点上。 容忍(Toleration) 通过在 Pod 上添加容忍属性,允许Pod被调度到带有污点的节点上。

污点属性说明:
  • PreferNoSchedule //尽量避免调度(软限制),除非没有其他节点可调度。
  • NoSchedule //拒绝调度(硬限制),但不会影响当前节点已经存在的pod。
  • NoExecute //拒绝调度,同时驱逐已经存在的pod。
污点案例1:设置污点 PreferNoSchedule

参考地址:kubernetes.io/zh-cn/docs/… 命令查询方法:kubectl taint --help

设置污点格式:kubectl taint node 节点名称 key=value:污点属性 更新污点格式:kubectl taint node 节点名称 key=value:新污点属性 删除污点格式:kubectl taint node 节点名称 key=value:污点-

# 设置污点PreferNoSchedule
kubectl taint node worker01 node=worker01:PreferNoSchedule
​
# 通过Pod详细查看污点
kubectl describe node worker01 | grep -i taint
...
Taints:     node=worker01:PreferNoSchedule

为了演示污点效果,将worker02节点关机:

# kubectl get nodes
...
worker02   NotReady  

将前边案例创建的Pod先删除掉:

kubectl delete -f deploy-nginx.yml

把配置文件中定向调度属性删除,再进行创建:

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        nodeSelector:          #删除(或者注释掉)
          node: worker02       #删除(或者注释掉)
        containers:
        - name: nginx
          image: nginx:1.20.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
# 创建pod
kubectl apply -f deploy-nginx.yml
​
# 查看pod信息
kubectl get pod -o wide -n test# 验证Pod如果已经被调度到worker01节点后,删除Pod
kubectl delete -f deploy-nginx.yml
污点案例2:设置污点 NoScheduler
# 更新node=worker01污点为NoSchedule
kubectl taint node worker01 node=worker01:NoSchedule
​
# 查看污点信息
kubectl describe node worker01 | grep -i taint
...
Taints:             node=worker01:NoSchedule
# 创建Pod
kubectl create -f deploy-nginx.yml
​
# 查看Pod信息
kubectl get pod -o wide -n test# 验证Pod如果无法被调度到worker01节点后,删除Pod
kubectl delete -f deploy-nginx.yml

提示:使用kubeadm搭建的集群,默认就会给 Master 节点添加一个污点NodeSchedule,默认的Pod不会被调度到Master节点。

kubectl describe node master01 | grep -i taint
kubectl describe node master02 | grep -i taint
kubectl describe node master03 | grep -i taint
容忍案例:添加容忍调度到worker01节点

资源文档查询方法:kubectl explain pod.spec.tolerations

# cat vim deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        tolerations:            #添加容忍
        - key: "node"           #污点的key(必须引起来)
          value: "worker01"     #key的值
          effect: NoSchedule    #容器的污点
          
        containers:
        - name: nginx
          image: nginx:1.17.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
# 创建pod
kubectl create -f deploy-nginx.yml
​
# 查看pod信息
kubectl get pod -o wide -n test# 验证Pod如果已经被调度到worker01节点后,删除Pod
kubectl delete -f deploy-nginx.yml
​
# 删除污点
kubectl taint node worker01 worker01:NoSchedule-

十三、Pod 容器探测

容器探测类似于对容器进行健康检查,用来探测容器中的程序是否可以正常工作,如果探测到容器出现故障,k8s会尝试重启容器,如果重启失败,k8s不会将流量分配给该容器,不承担业务流量。

k8s提供了两种探针来实现对容器的探测,可通 kubectl explain pod.spec.containers 查看:

  • liveness Probe //存活探针,检测容器是否为正常运行状态,如果不是,容器将会被重启。
  • readiness Probe //就绪探针,检测容器当前是否能接收请求,如果不能,k8s不会分配流量,也不会被重启。

以上两种探针目前均支持多种探测方式:

  • exec //通过在容器内执行命令,并根据返回的状态码来判断容器是否存活。
  • tcpSocket //通过检查容器的特定端口是否可以成功连接来判断容器是否存活。
  • httpGet //通过向容器发送HTTP请求,根据返回的状态码,判断容器是否存活。
  • initialDelaySeconds //容器启动后等待多少秒执行第一次探测,默认为立即开始执行。
  • timeoutSeconds //探测超时时间,默认1秒,最小可设置1秒。
  • failureThreshold //连续探测失败多少次才被认定失败,默认3次为失败,最小可设置1。
  • periodSeconds //执行探测频率,默认是10秒,最小可设置1秒。
  • successThreshold //连续探测成功多少次才被认定为成功,默认1次。

案例1:liveness Probe + exec 探测

参考地址:kubernetes.io/zh-cn/docs/…

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector: 
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
          livenessProbe:                            #定义探针
            exec:                                   #定义探测方式
              command: [/bin/ls,/etc/hello.txt]     #探测一个不存在的文件
# 创建Pod
kubectl create -f deploy-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test# 查看Pod详细信息
kubectl describe pod -n test# 删除Pod
kubectl delete -f deploy-nginx.yml

探测存在的文件:

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector: 
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0 
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
          livenessProbe:
            exec:
              command: [/bin/ls,/etc/passwd]    #探测一个存在的文件
# 创建Pod
kubectl create -f deploy-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test# 查看Pod详细信息
kubectl describe pod -n test# 删除Pod
kubectl delete -f deploy-nginx.yml

案例2:readiness Probe + tcpSocket 探测

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
          readinessProbe:           #定义探针
            tcpSocket:              #定义探测方式
              port: 8080            #探测一个不存在的端口
            initialDelaySeconds: 3  #容器启动后等待3秒执行探测
            periodSeconds: 3        #执行探测频率为3秒
# 创建pod
kubectl create -f deploy-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test# 查看Pod详细信息
kubectl describe pod -n test# 删除Pod
kubectl delete -f deploy-nginx.yml

探测存在的端口:

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    replicas: 1
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
          livenessProbe:
            tcpSocket:
              port: 80          #探测一个存在的端口
            initialDelaySeconds: 3  #容器启动后等待3秒执行探测
            periodSeconds: 3        #执行探测频率为3秒
# 创建pod
kubectl create -f deploy-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test# 查看Pod详细信息
kubectl describe pod -n test# 删除Pod
kubectl delete -f deploy-nginx.yml

案例3:readiness Probe + httpGet 探测

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test

spec:
#  replicas: 3
  selector:
    matchLabels:
      app: deploy-nginx

  template:
    metadata:
      labels:
        app: deploy-nginx

    spec:
      containers:
      - name: nginx
        image: nginx:1.20.2
        ports:
        - name: http-nginx
          containerPort: 80
          protocol: TCP
        imagePullPolicy: IfNotPresent
        resources:
          limits: 
            cpu: "1"
            memory: "200M"
          requests:
            cpu: "0.5"
            memory: "128M"
        readinessProbe:             #就绪探针
          httpGet:                  #发送HTTP请求
            path: /index.html       #请求的页面
            port: 80                #端口
          initialDelaySeconds: 3    #容器启动后等待3秒执行探测
          periodSeconds: 3          #执行探测频率为3秒

十四、Pod 重启策略

参考地址:kubernetes.io/zh-cn/docs/…

当Pod中的容器一旦出现了问题,K8s就会对容器所在的Pod进行重启,重启操作是由Pod的重启策略决定,Pod的重启策略有三种,可通过 kubectl explain pod.spec.restartPolicy 查看:

  • Always //容器异常时,自动重启该容器,默认策略
  • OnFailure //容器终止运行,且退出码不为0时重启(异常终止)
  • Never //无论容器状态如何,都不重启该容器

重启操作延时:首次立即重启,随后为 10s、20s、40s、80s、160s、300s,最长延时为 300s,以后重启延时均为 300s,直至重启成功。

十五、Pod 更新策略

Deployment 控制器支持两种 Pod 更新的策略,通过 strategy 属性进行配置,可通过 kubectl explain deploy.spec.strategy 查看:

  • Recreate(重建更新) //首先停止所有旧的Pod副本,然后再创建新的Pod副本,直到新的Pod副本完全就绪。
  • RollingUpdat(滚动更新) //逐步替换旧的Pod副本,以确保在更新过程中服务的持续可用性,也是默认策略。

案例1:Recreate 重建更新

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    strategy:           #更新策略
      type: Recreate    #策略类型
    replicas: 3         #创建Pod数量
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0       
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
# 创建pod
kubectl create -f deploy-nginx.yml
​
# 另外开一个终端查看pod的信息,-w(Watch)选项可以持续监视资源的变化
kubectl get pod -w -n test 

更新镜像版本:

# 更新镜像版本
kubectl edit deploy deploy-nginx -n test
...
    spec:
      containers:
      - image: nginx:1.20.0    #指定新版本

观察pod的重建过程:

  • 第一步:将Running的pod先终止(Terminating)
  • 第二步:接下来创建新Pod,新Pod刚开始处于等待状态(Pending)
  • 第三步:创建容器(ContainerCreating)
  • 第四步:新的容器被创建且以成功运行(Running )
# 查看Pod信息
kubectl get pod -n test# 查看deploy信息
kubectl get deploy -o wide -n test# 删除Pod
kubectl delete -f deploy-nginx.yml

案例2:RollingUpdate 滚动更新

可以通过以下属性控制Pod的更新数量:

  • maxUnavailable //用来指定在升级过程中最多可停止的pod数量,默认为25%
  • maxSurge //用来指定在升级过程中最多可新建的pod数量,默认为25%
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1
    maxSurge: 1

完整配置:

# cat deploy-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: deploy-nginx
    namespace: test

spec:
    strategy:           
      rollingUpdate:            #滚动更新
        maxUnavailable: 1       #最多停止的Pod数量为1个
        maxSurge: 1             #最多新建的Pod数量为1个
    replicas: 3
    selector:
      matchLabels:
        app: deploy-nginx

    template:
      metadata:
        labels:
          app: deploy-nginx

      spec:
        containers:
        - name: nginx
          image: nginx:1.18.0       
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80
            protocol: TCP
# 创建pod
kubectl create -f deploy-nginx.yml
​
# 另外一个终端动态查看pod信息
kubectl get pod -w -n test

更新镜像版本:

# 更新镜像版本
kubectl edit deploy deploy-nginx -n test
    spec:
      containers:
      - image: nginx:1.20.0
# 查看Pod信息
kubectl get pod -n test# 查看deploy信息
kubectl get deploy -o wide -n test# 查看RS信息,当pod滚动更新后,rs也会随之跟着更新,原有rs中的pod会被删除,但是原有的rs并不会删除,用于做版本回退
kubectl get rs -o wide -n test

十六、Pod 版本回退

Deploy支持滚动升级过程中的暂停、继续、回退等功能,具体功能如下:

命令格式:kubectl rollout <command> [选项]

  • status //显示当前升级状态
  • history //显示升级历史记录
  • pause //暂停升级过程
  • resume //继续升级过程
  • restart //重启升级过程
  • undo //版本回退(可以通过--to-revision切换到指定版本)

案例:多次更新镜像版本并回退

# 升级镜像版本
kubectl edit deploy deploy-nginx -n test
    spec:
      containers:
      - image: nginx:1.20.1

# 升级镜像版本
kubectl edit deploy deploy-nginx -n test
    spec:
      containers:
      - image: nginx:1.21.0
# 通过 kubectl rollout status 显示当前升级的状态
kubectl rollout status deploy deploy-nginx -n test# 查看deploy当前使用的版本
kubectl get deploy -o wide -n test# 查看当前所有版本(通过rs可以查看)
kubectl get rs -o wide -n test# 通过 kubectl rollout history 查看升级历史记录
kubectl rollout history deploy deploy-nginx -n test# 通过 kubectl rollout history --revision=版本编号,查看具体版本详细信息
kubectl rollout history --revision=2 deploy deploy-nginx -n test# 通过 kubectl rollout undo --to-revision=版本编号,可直接回退到1版本,如果省略这个选项,就是回退到上个版本
kubectl rollout undo --to-revision=1 deploy deploy-nginx -n test# 查看当前使用的版本
kubectl get deploy -o wide -n test# 查看升级历史记录
kubectl rollout history deploy deploy-nginx -n test

十七、DaemonSet 控制器

DaemonSet(DS)控制器在功能方面与Deployment控制器几乎一样,支持滚动更新、版本回退等, 但DaemonSet适合部署系统级别的服务,如日志收集、节点监控、节点代理、网络插件等,以下是DaemonSet的特点及应用场景:

提示:DaemonSet不通过控制RS管理Pod。

  • 每个节点只有一个副本:DaemonSet确保每个节点上都运行一个Pod副本(如:日志收集、节点监控、节点代理等),当新的节点加入集群时,DaemonSet会自动创建并调度Pod到这个新节点上。相反,如果节点从集群中被移除,这个节点上的Pod将被垃圾回收。
  • 支持Pod的故障自动恢复:如果DaemonSet控制的Pod发生故障,它会自动重启Pod,如果Pod被删除,他会在节点重建新的Pod,以保证服务的可用性。
  • 滚动更新:DaemonSet支持滚动更新,这使得你可以对运行在所有节点上的Pod进行版本更新操作,而不会影响到整个服务的可用性。
  • 特定节点运行:也可以通过在DaemonSet的Pod模板中设置nodeSelector来让DaemonSet仅在满足某种条件的节点上运行。

案例1:创建Nginx Pod保证每个节点运行

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain ds

# cat ds-nginx.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-nginx
  namespace: test

spec:
  selector:
    matchLabels:
      name: ds-nginx

  template:
    metadata:
      labels:
        name: ds-nginx

    spec:
#      tolerations:             #如果节点有污点且需要调度,需要通过添加容忍来调度
#      - key:                   #污点key
#        value:                 #污点的值
#        effect: NoSchedule     #污点类型
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
# 创建Pod
kubectl create -f ds-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test -o wide
​
# 查看ds信息
kubectl get ds -n test# 删除Pod
kubectl delete -f ds-nginx.yml

案例2:指定仅在master01、master02节点运行

为master01、master02节点打标签:

# master01、master02节点打标签
kubectl label node master01 master02 k8s=master
​
# 查看节点标签
kubectl get node master01 master02 --show-labels | grep master

检查节点是否存在污点:

kubectl describe node master01 master02 | grep -i taint
Taints:             master:NoSchedule
Taints:             master:NoSchedule

创建Pod:

# cat ds-nginx.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-nginx
  namespace: test

spec:
  selector:
    matchLabels:
      name: ds-nginx

  template:
    metadata:
      labels:
        name: ds-nginx

    spec:
      nodeSelector:          #定义nodeSelector
        k8s: master          #指定节点标签
      tolerations:           #如果节点有污点,需要通过添加容忍来调度
      - key: master          #污点key
        value:               #污点的值
        effect: NoSchedule   #污点类型
      containers:
      - name: nginx
        image: nginx:1.18.0
        ports:
        - containerPort: 80
# 创建Pod
kubectl create -f ds-nginx.yml
​
# 查看Pod信息
kubectl get pod -n test -o wide
​
# 查看ds信息
kubectl get ds -n test# 删除Pod
kubectl delete -f ds-nginx.yml

十八、HPA 控制器

HPA(Horizontal Pod Autoscaler)控制器, 可帮助Deployment 或者StatefulSet 根据CPU利用率自动调整Pod副本数量,它获取每个Pod的CPU指标,然后和HPA中定义的CPU指标进行对比,同时计算出需要增加或者删除的具体数量,最后实现pod的数量的自动(非手动)调整。以下是HPA控制器的主要特点:

  • 自动扩缩容:HPA可以根据实际的工作负载自动调整Pod的副本数,以实现Pod的水平扩缩。这对于那些工作负载波动较大的应用非常有用。
  • CPU利用率:HPA可以基于CPU利用率来自动调整Pod的副本数。当Pod的平均CPU利用率超过预定的目标时,HPA会增加Pod的副本数;反之,则减少副本数。
  • 稳定性:HPA会根据规定的最小和最大副本数进行扩缩,不会导致副本数无休止的增加或者减少,这有助于保持系统的稳定性。
  • 与Metrics Server协同工作:HPA依赖于Metrics Server(资源监控组件),通过Metrics Server获取到实时的监控数据,来决定是否需要增加或减少Pod的副本数。

1. metrics-server 资源监控

Metrics Server是Kubernetes的一个核心监控组件,它用于收集和存储每个节点和Pod的资源使用情况,如CPU和内存等。以下是Metrics Server的主要作用:

  • 提供资源使用情况的数据:Metrics Server会周期性地从每个节点和Pod收集CPU和内存使用情况,并存储在内存中。
  • 支持自动扩缩:Metrics Server的数据是HPA做自动扩缩容决策的重要依据。HPA根据Metrics Server提供的数据来决定是否需要增加或减少Pod的副本数。
  • 支持kubectl top命令:kubectl top命令用于显示Node或Pod的CPU和内存使用情况。这个命令需要Metrics Server的支持才能工作。

请注意,Metrics Server并不提供长期的指标存储和数据可视化,只提供实时的资源使用情况。如果需要长期存储和数据可视化,或者需要收集更多种类的指标(如网络流量、磁盘使用等),需要使用其他的监控系统,如Prometheus等。

部署Metrics Server
# 下载Metrics Server资源文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

在文件中添加 --kubelet-insecure-tls 参数,忽略证书检测:

# vim components.yaml
...
      - args:
        - --kubelet-insecure-tls     #忽略证书检测

生成Metrics Server证书签名请求文件:

cat > metrics-csr.json <<EOF
{
  "CN": "aggregator",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
EOF

使用现有的CA证书及其私钥签署:

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes metrics-csr.json | cfssljson -bare metrics

分发证书到其他master节点:

# 本机
cp metrics*.pem /etc/kubernetes/ssl/
​
# 其他master节点
for master in k8s-master02 k8s-master03
do 
    scp metrics*.pem $master:/etc/kubernetes/ssl
done

将Metrics Server证书注册到 API Server 中,三台master节点修改kube-apiserver.conf文件:

  --runtime-config=api/all=true \
  --requestheader-allowed-names=aggregator \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --requestheader-extra-headers-prefix=X-Remote-Extra- \
  --requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \
  --proxy-client-cert-file=/etc/kubernetes/ssl/metrics.pem \
  --proxy-client-key-file=/etc/kubernetes/ssl/metrics-key.pem"
  
# 参数说明:
runtime-config=api/all=true     //启用所有API版本和资源,这样可以使用所有API功能。
requestheader-allowed-names     //允许"aggregator"用户发送请求,该用户在证书中已定义。
requestheader-group-headers     //用户所在的组信息将通过X-Remote-Group请求头告诉API。
requestheader-username-headers  //用户名将通过X-Remote-User这个请求头告诉API。
requestheader-extra-headers-prefix=X-Remote-Extra-  //请求头中需要检查的前缀名。

三台节点重启API server服务:

systemctl daemon-reload
systemctl restart kube-apiserver
# 创建Metrics Server
kubectl create -f components.yaml
​
# 查看Metrics Server信息
kubectl get pod -n kube-system# 通过kubectl top命令查看监控数据
kubectl top node
kubectl top pod -n kube-system

2. 案例:HPA自动扩缩容

参考地址:kubernetes.io/zh-cn/docs/… 资源文档查询方法:kubectl explain hpa

# cat hpa-nginx.yml

apiVersion: autoscaling/v1              #自动扩缩容版本
kind: HorizontalPodAutoscaler
metadata:
    name: hpa-nginx
    namespace: test

spec:
  minReplicas: 1                        #最小的pod数量
  maxReplicas: 10                       #最大的pod数量
  targetCPUUtilizationPercentage: 10    #cpu使用指标,表示10%(生产环境建议定义在60-80)
  scaleTargetRef:                       #指定要控制的deploy信息
    apiVersion: apps/v1                 #deploy版本
    kind: Deployment                    #deploy类型
    name: deploy-nginx                  #deploy名称
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  namespace: test

spec:
  selector:
    matchLabels:
      app: deploy-nginx

  template:
    metadata:
      labels:
        app: deploy-nginx

    spec:
      containers:
      - name: nginx
        image: nginx:1.18.0
        resources:            #资源限额
          limits:             #资源上限
            cpu: 100m         #cpu 1核心的10%的资源(生产环境建议600m-800m)
# 创建Pod
kubectl create -f hpa-nginx.yml
​
# 查看Pod信息
kubectl get pod test# 查看deploy,hpa信息
kubectl get deploy,hpa -n test
测试HPA扩缩容
# 另开终端动态查看pod信息
kubectl get po -n test -w
​
# 通过压力测试工具访问Pod地址进行压力测试
yum -y install httpd-tools
ab -n 300000 -c 100 http://10.244.30.104/index.html
​
# 选项介绍
 -n  请求的总数量
 -c  并发数量
备注:autoscaling/v2版本配置

在HPA的autoscaling/v2版本中,废弃targetCPUUtilizationPercentage属性,通过下边方式定义CPU利用率:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
    name: hpa-nginx
    namespace: test

spec:
  scaleTargetRef:                       #指定要控制的deploy信息
    apiVersion: apps/v1                 #deploy版本
    kind: Deployment                    #deploy类型
    name: deploy-nginx                  #deploy名称
  minReplicas: 1                        #最小的pod数量
  maxReplicas: 10                       #最大的pod数量
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 10