Kubernetes 系统化学习之 资源清单篇(三)

1,962 阅读27分钟

Kubernetes 系统化学习之 基本概念篇(一)
Kubernetes 系统化学习之 POD原理篇(二)
Kubernetes 系统化学习之 资源清单篇(三)
Kubernetes 系统化学习之 服务发现篇(四)
Kubernetes 系统化学习之 持久存储篇(五)
Kubernetes 系统化学习之 集群调度篇(六)
Kubernetes 系统化学习之 集群安全篇(七)

1. Kubernetes 对象资源

Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统。

根据不同的级别,可以将 Kubernetes 中的资源进行多种分类。以下列举的内容都是 Kubernetes 中的 Object,这些对象都可以在 yaml 文件中作为一种 API 类型来配置。

  • 工作负载型资源:Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob
  • 服务发现及负载均衡型资源:Service、Ingress
  • 配置与存储型资源:Volume、CSI
  • 特殊类型的存储卷:ConfigMap、Secret、DownwardAPI
  • 集群级别资源:Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
  • 元数据型资源:HPA、PodTemplate、LimitRange

2. YML 资源文件概览

当创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息,例如名称。当使用 Kubernetes API 创建对象时,或者直接创建或者基于 kubectl,API 请求必须在请求体中包含 JSON 格式的信息。大多数情况下,需要在 .yaml 文件中为 kubectl 提供这些信息。kubectl 在发起 API 请求时,将这些信息转换成 JSON 格式。

大体的 .yaml 文件格式如下所示,其中包含的都是配置 yaml 文件启动服务必须或者建议配置的字段。

apiVersion: v1     # 必选,版本号,例如v1
kind: Pod         # 必选,资源类型,例如 Pod
metadata:         # 必选,元数据
  name: string     # 必选,Pod名称
  namespace: string  # Pod所属的命名空间,默认为"default"
  labels:           # 自定义标签列表
    - name: string                 
spec:  # 必选,Pod中容器的详细定义
  containers:  # 必选,Pod中容器列表
  - name: string   # 必选,容器名称
    image: string  # 必选,容器的镜像名称
    imagePullPolicy: [ Always|Never|IfNotPresent ]  # 获取镜像的策略 
    command: [string]   # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]      # 容器的启动命令参数列表
    workingDir: string  # 容器的工作目录
    volumeMounts:       # 挂载到容器内部的存储卷配置
    - name: string      # 引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string # 存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean # 是否为只读模式
    ports: # 需要暴露的端口库号列表
    - name: string        # 端口的名称
      containerPort: int  # 容器需要监听的端口号
      hostPort: int       # 容器所在主机需要监听的端口号,默认与Container相同
      protocol: string    # 端口协议,支持TCP和UDP,默认TCP
    env:   # 容器运行前需设置的环境变量列表
    - name: string  # 环境变量名称
      value: string # 环境变量的值
    resources: # 资源限制和请求的设置
      limits:  # 资源限制的设置
        cpu: string     # Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string  # 内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests: # 资源请求的设置
        cpu: string    # Cpu请求,容器启动的初始可用数量
        memory: string # 内存请求,容器启动的初始可用数量
    lifecycle: # 生命周期钩子
        postStart: # 容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
        preStop: # 容器终止前执行此钩子,无论结果如何,容器都会终止
    livenessProbe:  # 对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
      exec:         # 对Pod容器内检查方式设置为exec方式
        command: [string]  # exec方式需要制定的命令或脚本
      httpGet:       # 对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     # 对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0   # 容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0      # 对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0       # 对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
  restartPolicy: [Always | Never | OnFailure]  # Pod的重启策略
  nodeName: <string> # 设置NodeName表示将该Pod调度到指定到名称的node节点上
  nodeSelector: obeject # 设置NodeSelector表示将该Pod调度到包含这个label的node上
  imagePullSecrets: # Pull镜像时使用的secret名称,以key:secretkey格式指定
  - name: string
  hostNetwork: false   # 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
  volumes:   # 在该pod上定义共享存储卷列表
  - name: string    # 共享存储卷名称 (volumes类型有很多种)
    emptyDir: {}       # 类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
    hostPath: string   # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
      path: string     # Pod所在宿主机的目录,将被用于同期中mount的目录
    secret:         # 类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
      scretname: string  
      items:     
      - key: string
        path: string
    configMap:         # 类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
      name: string
      items:
      - key: string
        path: string

3. Pod 资源字段详解

在 kubernetes 中基本所有资源的一级属性都是一样的,主要包含5部分:

  1. apiVersion 版本,由 kubernetes 内部定义,版本号必须可以用 kubectl api-versions 查询到;
  2. kind 类型,由 kubernetes 内部定义,版本号必须可以用 kubectl api-resources 查询到;
  3. metadata 元数据,主要是资源标识和说明,常用的有name、namespace、labels等;
  4. spec 描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述;
  5. status 状态信息,里面的内容不需要定义,由 kubernetes 自动生成。
apiVersion: # 版本信息  
kind: # 资源类别  
metadata: # 资源元数据  
  name: # 元数据对应的名称  
  namespace: # 元数据所属的命名空间  
  lables: # 对资源打上便签供后续使用  
  annotations: # 主要目的是方便用户阅读查找  
spec: # 定义期望状态  
status: # 设置当前状态

关于 Pod 的前置知识学习请参考 Kubernetes 系统化学习之 POD原理篇(二)

1011471-20210725152315314-2007161292.png

创建一个 Pod

vim nginx.yaml

nginx.yaml:

# vim nginx.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
    name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
    containers: # 必选,容器列表
      - name: nginx # 必选,符合 RFC 1035 规范的容器名称
        image: nginx:1.15.12 # 必选,容器所用的镜像的地址
        ports: # 可选,容器需要暴露的端口号列表
          - containerPort: 80 # 端口号
kubectl create -f nginx.yaml

输出结果:

# kubectl create -f nginx.yaml
pod/nginx created

查看 Pod 状态

kubectl get po nginx

输出结果:

# kubectl get po nginx
NAME READY STATUS RESTARTS AGE
nginx 0/1 ContainerCreating 0 20s

使用 kubectl run 创建一个 Pod

kubectl run nginx-run --image=nginx:1.15.12

在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:

  1. containers <[]Object> 容器列表,用于定义容器的详细信息;
  2. nodeName 根据nodeName的值将pod调度到指定的Node节点上;
  3. nodeSelector <map[]> 根据NodeSelector中定义的信息选择将该Pod调度到包含这些label的Node 上;
  4. hostNetwork 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络;
  5. volumes <[]Object> 存储卷,用于定义Pod上面挂在的存储信息;
  6. restartPolicy 重启策略,表示Pod在遇到故障的时候的处理策略;

资源清单中常见字段的解释:

参数名字段类型说明
versionString这里是值的是k8s API的版本, 目前基本上是v1, 可以用kubectl api-versions命令查询
kindString这里指的是yaml文件定义的资源类型和角色, 比如:Pod
metadataObject元数据对象, 固定值就写metadata
metadata.nameString元数据对象的名字, 这里由我们编写,比如命名Pod的名字
metadata.namespaceString元数据对象的命名空间, 由我们自身定义
specObject详细定义对象, 固定值就写spec
spec.containers[]list这里是spec对象的容器列表定义 , 是一个列表
spec.containers[].nameString这里定义容器的名字
spec.containers[].imageString这里定义要用到的镜像名称
spec.containers[].imagePullPolicyString定义镜像拉取策略, 有Always,Never,IfNotPresent三个值(1)Always:意思是每次都尝试重新拉取镜像(2)Never:表示仅使用本地镜像(3)IfNotPresent:如果本地有镜像就使用本地镜像, 没有就拉取在线镜像,上面三个值都没有设置的话, 默认是Always
spec.containers[].command[]List指定容器启动命令, 因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令
spec.containers[].args[]list指定容器启动命令参数, 因为是数组可以指定多个
spec.containers[].workingDirString指定容器的工作目录
spec.containers[].volumeMounts[]list指定容器内部的存储配置
spec.containers[].volumeMounts[].nameString指定可以被容器挂载的存储卷的名称
spec.containers[].volumeMounts[].mountPathString指定可以被容器挂载的存储卷的路径
spec.containers[].volumeMounts[].readOnlyString设置存储卷路径的读写模式, ture或者false,默认为读写模式
spec.containers[].ports[]list指定容器需要用到的端口列表
spec.containers[].ports[].nameString指定端口名称
spec.containers[].ports[].containerPortString指定容器需要监听的端口号
spec.containers[].ports[].hostPortString指定容器所在主机需要监听的端口号, 默认跟上面containerPort相同, 注意设置了hostPort同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同, 这样会冲突)
spec.containers[].ports[].protocolString指定端口协议, 支持tcp和udp , 默认值tcp
spec.containers[].env[]List指定容器运行前需要设置的环境变量列表
spec.containers[].env[].nameString指定环境变量名称
spec.containers[].env[].valueString指定环境变量值
spec.containers[].resourcesObject指定资源限制和资源请求的值(这里开始就是设置容器的资源上限)
spec.containers[].resources.limitsObject指定设置容器的运行时资源的运行上限
spec.containers[].resources.limits.cpuString指定cpu的限制, 单位为core数, 将用于docker run --cpu-shares参数
spec.containers[].resources.limits.memoryString指定MEM内存的限制, 单位为MIB,GiB
spec.containers[].resources.requestsObject指定容器启动和调度时的限制设置
spec.containers[].resources.requets.cpustringCPU请求, 单位为core数,容器启动时初始化可用数量
spec.containers[].resources.requets.memorystring内存请求, 单位为MIB,GiB, 容器启动的初始化可用数量
spec.restartPolicyString定义Pod的重启策略, 可选值为Always,OnFailure,默认为Always,1.Always:Pod 一旦终止运行则无论容器是如何终止的, kubelet服务都将重启它,2,OnFailure: 只有Pod以非零退出码终止时 , kubelet才会重启该容器, 如果容器正常结束(退出码为0),则kubelet将不会重启它, 3.Never:pod终止后,kubelet将退出码报告给Master,不会重启该pod
spec.nodeSelectorobject定义node的label过滤标签, 以key:value格式指定
spec.imagePullSecretsobject定义pull镜像时使用secret名称, 以name:secretkey格式指定
spec.hostNetworkBoolean定义是否使用主机网络模式, 默认为false, 设置true表示使用宿主机网络, 不使用docker网桥, 同时设置了true将无法再同一台宿主机上启动第二个副本
# vim nginx.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
  containers: # 必选,容器列表
    - name: nginx # 必选,符合 RFC 1035 规范的容器名称
      image: nginx:1.15.12 # 必选,容器所用的镜像的地址
      command: # 可选,容器启动执行的命令
        - sleep
        - "10"
      env: # 必选,容器运行前的环境变量列表
        - name: PASSWORD
          value: "123456"
      ports: # 可选,容器需要暴露的端口号列表
        - containerPort: 80 # 端口号
      volumeMounts: # 可选,容器内部的存储配置
        - name: conf
          mountPath: /usr/local/nginx/conf # 被容器挂载的存储卷的路径
      resources: # 可选,容器计算资源
        limit:
          cpu: 100m # 容器最大使用的cpu规格
          memory: 512Mi # 容器最大使用的内存规格

Pod 镜像拉取策略

操作方式说明
Always 总是拉取,当镜像 tag 为 latest 时,且 imagePullPolicy 未配置,默认为 Always
Never不管是否存在都不会拉取
IfNotPresent 镜像不存在时拉取镜像,如果 tag 为非 latest,且 imagePullPolicy 未配置,默认为 IfNotPresent
# vim nginx.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
  containers: # 必选,容器列表
    - name: nginx # 必选,符合 RFC 1035 规范的容器名称
      image: nginx:1.15.12 # 必选,容器所用的镜像的地址
      imagePullPolicy: IfNotPresent # 可选,镜像拉取策略
      ports: # 可选,容器需要暴露的端口号列表
        - containerPort: 80 # 端口号

Pod 重启策略

操作方式说明
Always 默认策略。容器失效时,自动重启该容器
OnFailure 容器以不为 0 的状态码终止,自动重启该容器 
Never无论何种状态,都不会重启
# vim nginx.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
  containers: # 必选,容器列表
    - name: nginx # 必选,符合 RFC 1035 规范的容器名称
      image: nginx:1.15.12 # 必选,容器所用的镜像的地址
      imagePullPolicy: IfNotPresent # 可选,镜像拉取策略
      ports: # 可选,容器需要暴露的端口号列表
        - containerPort: 80 # 端口号
      restartPolicy: Never

Pod 三种探针

种类说明
startupProbe Kubernetes1.16新加的探测方式,用于判断容器内的应用程序是否已经启动。如果配置了startupProbe,就会先禁用其他探测,直到它成功为止。如果探测失败,Kubelet会杀死容器,之后根据重启策略进行处理,如果探测成功,或没有配置startupProbe,则状态为成功,之后就不再探测
livenessProbe 用于探测容器是否在运行,如果探测失败,kubelet会“杀死”容器并根据重启策略进行相应的处理。如果未指定该探针,将默认为Success
readinessProbe一般用于探测容器内的程序是否健康,即判断容器是否为就绪(Ready)状态。如果是,则可以处理请求,反之EndpointsController将从所有的Service的Endpoints中删除此容器所在Pod的IP地址。如果未指定,将默认为Success

Pod 探针的实现方式

实现方式 说明
 ExecAction在容器内执行一个指定的命令,如果命令返回值为0,则认为容器健康 
 TCPSocketAction 通过TCP连接检查容器指定的端口,如果端口开放,则认为容器健康
 HTTPGetAction 对指定的URL进行Get请求,如果状态码在200~400之间,则认为容器健康
# vim nginx.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
  containers: # 必选,容器列表
    - name: nginx # 必选,符合 RFC 1035 规范的容器名称
      image: nginx:1.15.12 # 必选,容器所用的镜像的地址
      imagePullPolicy: IfNotPresent
      command: # 可选,容器启动执行的命令
        - sh
        - -c
        - sleep 10; nginx -g "daemon off;"
      readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。
        httpGet: # 接口检测方式
          path: /index.html # 检查路径
          port: 80
          scheme: HTTP # HTTP or HTTPS
        initialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间
        timeoutSeconds: 2 # 超时时间
        periodSeconds: 5 # 检测间隔
        successThreshold: 1 # 检查成功为 2 次表示就绪
        failureThreshold: 2 # 检测失败 1 次表示未就绪
      livenessProbe: # 可选,健康检查
        tcpSocket: # 端口检测方式
          port: 80
        initialDelaySeconds: 10 # 初始化时间
        timeoutSeconds: 2 # 超时时间
        periodSeconds: 5 # 检测间隔
        successThreshold: 1 # 检查成功为 2 次表示就绪
        failureThreshold: 2 # 检测失败 1 次表示未就绪
      ports: # 可选,容器需要暴露的端口号列表
        - containerPort: 80 # 端口号
      restartPolicy: Never

Pod 的 preStop 和 postStart

# vim nginx.yaml
apiVersion: v1 # 必选,API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
  containers: # 必选,容器列表
    - name: nginx # 必选,符合 RFC 1035 规范的容器名称
      image: nginx:1.15.12 # 必选,容器所用的镜像的地址
      imagePullPolicy: IfNotPresent
      lifecycle:
      postStart: # 容器创建完成后执行的指令, 可以是 exec httpGet TCPSocket
        exec:
          command:
            - sh
            - -c
            - 'mkdir /data/'
      preStop:
        exec:
          command:
            - sh
            - -c
            - sleep 10
      ports: # 可选,容器需要暴露的端口号列表

4. Pod 的生命周期

Pod 的生命周期才是 Kubernetest 资源清单中的重中之重!

Kubernetes 中的基本组件 kube-controller-manager 就是用来控制 Pod 的状态和生命周期的,在了解各种 controller 之前我们有必要先了解下 Pod 本身和其生命周期。想要深入理解 Pod 的实现原理,最好最快的办法就是从 Pod 的生命周期入手,通过理解 Pod 创建、重启和删除的原理我们最终就能够系统地掌握 Pod 的生命周期与核心原理。

src=http___qny.zhengxingtao.com_media_images_Pod.png&refer=http___qny.zhengxingtao.webp 将 Pod 对象从创建至终的这段时间范围称为 Pod 的生命周期,它主要包含下面的过程:

  • Pod 创建过程
  • 运行初始化容器(init container)过程
  • 运行主容器(main container)
  • 容器启动后钩子(post start)、容器终止前钩子(pre stop)
  • 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
  • Pod 终止过程

Init C(Init 容器)

Pod 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器。 Init 容器与普通的容器非常像 , 除了如下两点:

  • Init 容器总是运行到成功完成为止;
  • 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成。

如果 Pod 的 Init 容器失败, Kubernetes 会不断地重启 Pod,直到 Init 容器成功为止,然而,如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动

因为init容器具有应用程序容器分离的单独镜像, 所以它们的启动相关代码具有如下优势:

  1. 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的;
  2. 它们可以包含实用工具和定制化代码来安装,但是不能出现在应用程序镜像中,例如,创建镜像没有必要 FROM 另一个镜像,只需要在安装过程中使用类似 sed ,awk, python 或 dig 这样的工具;
  3. 应用程序镜像可以分离出创建和部署角色, 二没有必要联合他们构建一个单独的镜像;
  4. init 容器使用 linux namespace,所以相对应用程序容器来说具有不同的文件系统视图,因此,他们能够具有访问 secret 的权限,二应用程序容器则不能;
  5. 他们必须在应用程序容器启动之前运行完成,二应用程序容器是并行运行的。所以 init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,知道满足了一种先决条件;

Pod 的状态(相位)

状态说明
Pending(挂起) Pod 已被 Kubernetes 系统接收,但仍有一个或多个容器未被创建,可以通过kubectl describe 查看处于 Pending 状态的原因 
Running(运行中) Pod 已经被绑定到一个节点上,并且所有的容器都已经被创建,而且至少有一个
 是运行状态,或者是正在启动或者重启,可以通过 kubectl logs 查看 Pod 的日志 
Succeeded(成功) 所有容器执行成功并终止,并且不会再次重启,可以通过 kubectl logs 查看 Pod 日志 
Failed(失败) 所有容器都已终止,并且至少有一个容器以失败的方式终止,也就是说这个容器要么以非零状态退出,要么被系统终止,可以通过 logs 和 describe 查看 Pod 日志和状态 
Unknown(未知) 通常是由于通信问题造成的无法获得 Pod 的状态

Pod 的创建过程

  1. 用户通过 kubectl 或其他 api 客户端提交需要创建的 pod 信息给 apiServer;
  2. apiServer 开始生成 pod 对象的信息,并将信息存入 etcd,然后返回确认信息至客户端;
  3. apiServer 开始反映 etcd 中的 pod 对象的变化,其它组件使用 watch 机制来跟踪检查 apiServer 上的变动;
  4. scheduler 发现有新的 pod 对象要创建,开始为 Pod 分配主机并将结果信息更新至 apiServer;
  5. node 节点上的 kubelet 发现有 pod 调度过来,尝试调用 docker 启动容器,并将结果回送至 apiServer;
  6. apiServer 将接收到的 pod 状态信息存入 etcd 中。

Pod 的终止过程

  1. 用户向 apiServer 发送删除 pod 对象的命令;
  2. apiServcer 中的 pod 对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod 被视为 dead;
  3. 将 pod 标记为 terminating 状态;
  4. kubelet 在监控到 pod 对象转为 terminating 状态的同时启动 pod 关闭过程;
  5. 端点控制器监控到 pod 对象的关闭行为时将其从所有匹配到此端点的 service 资源的端点列表中移除;
  6. 如果当前 pod 对象定义了 preStop 钩子处理器,则在其标记为 terminating 后即会以同步的方式启动执行;
  7. pod 对象中的容器进程收到停止信号;
  8. 宽限期结束后,若 pod 中还存在仍在运行的进程,那么 pod 对象会收到立即终止的信号;
  9. kubelet 请求 apiServer 将此 pod 资源的宽限期设置为 0 从而完成删除操作,此时 pod 对于用户已不可见。

5. Pod 的控制器使用

我们很少会直接在 kubernetes 中创建单个 Pod。因为 Pod 的生命周期是短暂的,用后即焚的实体。当 Pod 被创建后,都会被 Kubernetes 调度到集群的 Node 上。直到 Pod 的进程终止、被删掉、因为缺少资源而被驱逐、或者 Node 故障之前这个 Pod 都会一直保持在那个 Node 上。

我们需要知道 Pod 本身是不会自愈修复的。如果 Pod 运行的 Node 故障或者是调度器本身故障,这个 Pod 就会被删除。同样的,如果 Pod 所在 Node 因为缺少资源或者 Pod 处于维护状态,那么 Pod 也就会被自动驱逐掉。Kubernetes 使用更高级的称为 Controller 的抽象层,来管理 Pod 实例。虽然可以直接使用 Pod,但是 在 Kubernetes 中通常是使用 Controller 来管理 Pod 的。Controller 可以创建和管理多个 Pod,提供副本管理、滚动升级和集群级别的自愈能力

需要注意的是,重启 Pod 中的容器跟重启 Pod 不是一回事。Pod 只提供容器的运行环境并保持容器的运行状态,重启容器不会造成 Pod 重启。

Kubernetes 使用了一个更高级的称为 控制器 的抽象,由它处理相对可丢弃的 Pod 实例的管理工作。因此,虽然可以直接使用 Pod,但在 Kubernetes 中,更为常见的是使用控制器管理 Pod。

  • Deployment
  • StatefulSet
  • DaemonSet

Deployment 资源清单

为了更好地解决服务编排的问题,k8s 在 V1.2 版本开始,引入了 deployment 控制器,值得一提的是,这种控制器并不直接管理 pod,而是通过管理 replicaset 来间接管理 pod,即:deployment 管理 replicaset,replicaset 管理 pod。所以 deployment 比 replicaset 的功能更强大。

2164474-20210716210057908-1704850787.png

apiVersion: apps/v1  # 版本号
kind: Deployment  # 类型
metadata:    # 元数据
  name:    # rs名称
  namespace:   # 所属命名空间
  labels:   # 标签
    controller: deploy
spec:   # 详情描述
  replicas:  # 副本数量
  revisionHistoryLimit: # 保留历史版本,默认是10
  paused: # 暂停部署,默认是false
  progressDeadlineSeconds: # 部署超时时间(s),默认是600
  strategy: # 策略
    type: RollingUpdates  # 滚动更新策略
    rollingUpdate:  # 滚动更新
      maxSurge: # 最大额外可以存在的副本数,可以为百分比,也可以为整数
      maxUnavaliable: # 最大不可用状态的pod的最大值,可以为百分比,也可以为整数
  selector:  # 选择器,通过它指定该控制器管理哪些pod
    matchLabels:   # Labels匹配规则
       app: nginx-pod
    matchExpressions:   # Expression匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template:  # 模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
        labels:
          app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

Deployment 主要功能

一个简易的 Deployment 的例子(nginx-deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
     app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1

创建 deployment

[root@master ~]# kubectl create -f nginx-deployment.yaml 
deployment.apps/nginx-deployment created
[root@master ~]# kubectl get deploy -n dev -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-deployment   3/3     3            3           16s   nginx        nginx:1.17.1   app=nginx-pod
[root@master ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
nginx-deployment-5d89bdfbf9   3         3         3       2m13s
[root@master ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
nginx-deployment-5d89bdfbf9-k8j9n   1/1     Running   0          2m42s
nginx-deployment-5d89bdfbf9-vw87k   1/1     Running   0          2m42s
nginx-deployment-5d89bdfbf9-x7nsm   1/1     Running   0          2m42s

伸缩扩容

[root@master ~]# kubectl scale deploy nginx-deployment --replicas=5 -n dev
deployment.apps/nginx-deployment scaled
[root@master ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
nginx-deployment-5d89bdfbf9-bhcns   1/1     Running   0          83s
nginx-deployment-5d89bdfbf9-cfls7   1/1     Running   0          83s
nginx-deployment-5d89bdfbf9-k8j9n   1/1     Running   0          8m54s
nginx-deployment-5d89bdfbf9-vw87k   1/1     Running   0          8m54s
nginx-deployment-5d89bdfbf9-x7nsm   1/1     Running   0          8m54s

镜像更新

更新方式配置名称更新说明
重建更新Recreate在创建出新的pod之前会先杀掉所有已存在的pod
滚动更新(默认)RollingUpdate杀死一部分,就启动一部分,在更新过程中,存在两个版本pod
strategy:指定新的pod替换旧的pod的策略,支持两个属性:
  type:指定策略类型,支持两种策略
    Recreate:在创建出新的pod之前会先杀掉所有已存在的pod
    RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本pod
  rollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性
    maxUnavailable:用来指定在升级过程中不可用pod的最大数量,默认为25%
    maxSurge:用来指定在升级过程中可以超过期望的pod的最大数量,默认为25%
[root@master ~]# vim nginx-deployment.yaml 
[root@master ~]# kubectl apply -f nginx-deployment.yaml 
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps/nginx-deployment configured
#记录以前的pod
[root@master ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
nginx-deployment-5d89bdfbf9-526wf   1/1     Running   0          61s
nginx-deployment-5d89bdfbf9-b5x5v   1/1     Running   0          64s
nginx-deployment-5d89bdfbf9-kc7hb   1/1     Running   0          59s
#更新镜像
[root@master ~]# kubectl set image deploy nginx-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/nginx-deployment image updated
#查看pod状态
[root@master ~]# kubectl get pod -n dev
NAME                             READY   STATUS              RESTARTS   AGE
nginx-deployment-5d89bdfbf9-526wf   0/1     Terminating         0          2m2s
nginx-deployment-5d89bdfbf9-b5x5v   1/1     Running             0          2m5s
nginx-deployment-5d89bdfbf9-kc7hb   0/1     Terminating         0          2m
nginx-deployment-675d469f8b-7vw6x   1/1     Running             0          3s
nginx-deployment-675d469f8b-rzq82   0/1     ContainerCreating   0          2s
nginx-deployment-675d469f8b-zk4fs   1/1     Running             0          5s
[root@master ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
nginx-deployment-675d469f8b-7vw6x   1/1     Running   0          38s
nginx-deployment-675d469f8b-rzq82   1/1     Running   0          37s
nginx-deployment-675d469f8b-zk4fs   1/1     Running   0          40s

滚动更新的过程如图:

2164474-20210719201104989-783532322.png

版本回退

deployment 支持版本升级过程中的暂停,继续功能以及版本回退等诸多功能,下面具体来看

kubectl rollout:版本升级相关功能,支持下面的选项:

  • status:显示当前升级状态
  • history:显示升级历史记录
  • pause:暂停版本升级过程
  • resume:继续已经暂停的版本升级过程
  • restart:重启版本升级过程
  • undo:回滚到上一级版本(可以使用--to-revision回滚到指定版本)
#查看升级状态
[root@master ~]# kubectl rollout status deploy nginx-deployment -n dev
deployment "nginx-deployment" successfully rolled out

#查看升级历史(注意:如果只显示版本号说明一开始使用yaml创建文件的时候没有加上--record命令)
[root@master ~]# kubectl rollout history deploy nginx-deployment -n dev
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         kubectl create --filename=nginx-deployment.yaml --record=true
2         kubectl create --filename=nginx-deployment.yaml --record=true

#版本回滚
#这里使用--to-revision=1回滚到1版本,如果省略这个选项,则会回退到上个版本
[root@master ~]# kubectl rollout undo deploy nginx-deployment --to-revision=1 -n dev
deployment.apps/nginx-deployment rolled back

#查看是否回滚成功,发现5序号开头的rs被启动了
[root@master ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
nginx-deployment-5d89bdfbf9   3         3         3       31m
nginx-deployment-675d469f8b   0         0         0       22m

金丝雀发布

deployment 支持更新过程中的控制,如"暂停(pause)"或"继续(resume)"更新操作。

比如有一批新的pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新的pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。

#更新deployment版本,并配置暂停deployment
[root@master ~]# kubectl set image deploy nginx-deployment nginx=nginx:1.17.2 -n dev && kubectl rollout pause deploy nginx-deployment -n dev
deployment.apps/nginx-deployment image updated
deployment.apps/nginx-deployment paused

#查看rs,发现老版本rs没有减少,新版本rs增加一个
[root@master ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
nginx-deployment-5d89bdfbf9   3         3         3       44m
nginx-deployment-675d469f8b   1         1         1       35m

#在窗口2中查看deploy状态,发现deploy正在等待更新且已经有1个更新好了
[root@master ~]# kubectl rollout status deploy nginx-deployment -n dev
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...


#在窗口1中继续deploy的更新
[root@master ~]# kubectl rollout resume deploy nginx-deployment -n dev
deployment.apps/nginx-deployment resumed

#查看窗口2的状态
Waiting for deployment spec update to be observed...
Waiting for deployment spec update to be observed...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

#在窗口1查看rs更新结果,发现老版本均停止,新版本已经创建好
[root@master ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
nginx-deployment-5d89bdfbf9   0         0         0       49m
nginx-deployment-675d469f8b   3         3         3       40m

Kubernetes 系统化学习之 基本概念篇(一)
Kubernetes 系统化学习之 POD原理篇(二)
Kubernetes 系统化学习之 资源清单篇(三)
Kubernetes 系统化学习之 服务发现篇(四)
Kubernetes 系统化学习之 持久存储篇(五)
Kubernetes 系统化学习之 集群调度篇(六)
Kubernetes 系统化学习之 集群安全篇(七)