美文网首页
Kubernetes 实战 —— 04. 副本机制和其他控制器:

Kubernetes 实战 —— 04. 副本机制和其他控制器:

作者: 满赋诸机 | 来源:发表于2021-03-21 11:07 被阅读0次

    保持 pod 健康 P84

    只要 pod 调度到某个节点,该节点上的 Kubelet 就会运行 pod 的容器,从此只要该 pod 存在,就会保持运行。如果容器的主进程奔溃, Kubelet 就会自动重启容器;如果应用程序奔溃, Kubelet 就会自动重启应用程序。 P84

    应用程序也可能因为无限循环或死锁等情况而停止响应。为确保应用在这种情况下可以重新启动,必须从外部检查应用程序的运行状况,而不是依赖于应用的内部检测。 P84

    介绍存活探测器 P84

    Kubernetes 可以通过存活探测器 (liveness probe) 检查容器是否还在运行。可以为 pod 中的每个容器单独指定存活探测器。 Kubernetes 将定期执行探测器,如果探测失败,就会自动重启容器。 P84

    注意:Kubernetes 还支持就绪探测器 (readiness probe) ,两者适用于两种不同的场景。 P84

    Kubernetes 有三种探测容器的机制: P84

    • HTTP GET 探测器:对容器的 IP 地址(指定的端口和路径)执行 HTTP GET 请求。如果探测器收到响应,并且响应状态码不代表错误(状态码为 2xx 或 3xx ),则认为探测成功。如果服务器返回错误响应状态码或者没有响应,那么探测就被认为是失败的,容器将被重启。
    • TCP Socket探测器:尝试与容器指定端口建立 TCP 连接。如果连接成功建立,则探测成功。否则,容器将被重启。
    • Exec 探测器:在容器内执行任意命令,并检查命令的退出状态码。如果状态码是 0 ,则探测成功。所有其他状态码都被认为失败,容器将被重启。
    创建基于 HTTP 的存活探测器 P85

    为了让 HTTP GET 探测器探测失败,我们需要修改 kubia 源码,使得其从第五次访问之后开始一直返回 500 状态码 (Internal Server Error) 。 P85

    然后我们可以通过以下描述文件 kubia-liveness-probe.yaml 创建一个包含 HTTP GET 存活探测器的 pod 。 P85

    # 遵循 v1 版本的 Kubernetes API
    apiVersion: v1
    # 资源类型为 Pod
    kind: Pod
    metadata:
      # pod 的名称
      name: kubia-liveness
    spec:
      containers:
        # 创建容器所使用的镜像
        - image: idealism/kubia-unhealthy
          # 容器的名称
          name: kubia
          ports:
            # 应用监听的端口
            - containerPort: 8080
              protocol: TCP
          # 开启一个存活探测器
          livenessProbe:
            # 存活探测器的类型为 HTTP GET
            httpGet:
              # 探测器连接的网络端口
              port: 8080
              # 探测器请求的路径
              path: /
    
    使用存活探测器 P86

    使用 kubectl create -f kubia-liveness-probe.yaml 创建完 pod 后,等待一段时间后,容器将会重启。可以通过 kubectl get pod kubia-liveness 看到容器会重启,并且无限循环下去: 86

    NAME             READY   STATUS    RESTARTS   AGE
    kubia-liveness   1/1     Running   2          4m9s
    

    kubectl logs kubia-liveness --previous: 查看前一个容器的日志,可以了解前一个容器停止的原因。 P86

    kubectl describe pod kubia-liveness: 查看 pod 详情。可以发现在 Containers 和 Events 里面有终止的相关信息。 P86

    ...
    Containers:
      kubia:
        ...
        State:          Running  # 容器目前正常运行
          Started:      Sun, 07 Jun 2020 17:59:35 +0800
        Last State:     Terminated  # 前一个容器由于错误被终止,错误码是 137
          Reason:       Error
          Exit Code:    137
          Started:      Sun, 07 Jun 2020 17:57:44 +0800
          Finished:     Sun, 07 Jun 2020 17:59:27 +0800
        Ready:          True
        Restart Count:  2  # 该容器已被重启 2 次
        Liveness:       http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3
        ...
    Events:
      Type     Reason     Age                  From                   Message
      ----     ------     ----                 ----                   -------
      Normal   Scheduled  <unknown>            default-scheduler      Successfully assigned default/kubia-liveness to minikube-m02
      Warning  Unhealthy  48s (x6 over 2m58s)  kubelet, minikube-m02  Liveness probe failed: HTTP probe failed with statuscode: 500  # 发现容器不健康
      Normal   Killing    48s (x2 over 2m38s)  kubelet, minikube-m02  Container kubia failed liveness probe, will be restarted  # 终止该容器
      ...
    

    错误码 137 是两个数字的总和: 128 + x , x 是终止进程的信号编号。 P86

    • x=9 表示是 SIGKILL 的信号编号,意味着这个进程被强行终止,这个信号不能被捕获或忽略,并且在接收过程中不能执行任何清理在接收到该信号
    • x=15 表示是 SIGTERM 的信号编号,意味着这个进程被终止,先进行询问进程终止,让其清理文件和关闭,可以被捕获和解释或忽略

    底部列出的事件显示了 Kubernetes 发现容器不健康,所以终止并重新创建。 P86

    注意:当容器被强行终止时,会创建一个全新的容器,而不是重启原来的容器。 P86

    配置存活探测器的附加属性 P87

    可以使用 kubectl explain pod.spec.containers.livenessProbe 查看存活探测器能使用的自定义附加参数。

    基于 kubia-liveness-probe.yaml 创建一个新的描述文件 kubia-liveness-probe-initial-delay.yaml ,并添加 pod.spec.containers.livenessProbe.initialDelaySeconds 属性,值为 15 ,表示在第一次探测器等待 15 秒。

    ...
    spec:
      containers:
        # 创建容器所使用的镜像
        - image: idealism/kubia-unhealthy
          ...
          # 开启一个存活探测器
          livenessProbe:
            ...
            # 第一次探测前等待 15 秒
            initialDelaySeconds: 15
    

    这样可以在应用程序准备好之后再进行探测,以免应用程序启动时间过长导致一直探测失败而无限重启。

    创建有效的存活探测器 P88
    • 存活探测器应该检查什么:简易的存活探测器可以仅检查服务器是否响应,但为了更好地进行存活检查,需要将探测器配置为请求特定的 URL 路径(如 /health ),并让应用从内部对内部运行的所有重要组件执行状态检查,以确保它们都没有终止或停止响应。 P88
      • 确保 /health 不需要认证,否则探测会一直失败,导致容器无限重启
      • 检查应用的内部,检查结果不能受任何外部因素的影响。例如数据库连不上时,存活探测器不应该返回失败,如果问题在数据库,那么重启容器不会解决问题。
    • 保持探测器轻量 P89
      • 不应消耗太多计算资源
      • 运行不应花太长时间。默认情况下,探测器执行的频率相对较高,必须在一秒之内执行完毕
    • 无须在探测器中实现重试:探测器的失败阈值是可配置的,并且通常在容器被终止之前探测器必须失败多次 P89
    • 存活探测器小结:存活探测由 pod 上的 Kubelet 执行, Kubernetes 控制面板不会参与。因此节点奔溃时,控制面板会为所有随节点停止运行的 pod 创建替代者,但不会为直接创建的 pod 创建替代者,因为这些 pod 只被节点上的 Kubelet 管理。为了避免这种情况发生,我们应该使用控制器或类似机制管理 pod 。 P89

    了解 Deployment P89

    :本节中提到的 pod 受 Deployment 管理等说法为简化说法,实际上 pod 由受 Deployment 管理创建的 ReplicaSet 进行管理创建。

    Deployment 是一种 Kubernetes 资源,可确保它的 pod 始终保持运行状态。如果 pod 因为任何原因消失(例如节点从集群中消失或由于该 pod 已从节点中逐出),则 Deployment 会注意到缺少了 pod 并创建替代者。 P89

    图 4.1 节点故障时,只有 Deployment 管理的 pod 被重新创建.png

    上图的节点 1 有两个节点, Pod A 是被直接创建的,而 Pod B 由 Deployment 管理。节点异常退出后, Deployment 会创建一个新的 Pod B2 来替换减少的 Pod B ,而 Pod A 由于没有东西负责重建而完全丢失。 P89

    Deployment 的操作 P90

    Deployment 会持续监控正在运行的 pod 列表,并保证匹配标签选择器(03. pod: 运行于 Kubernetes 中的容器 中介绍过标签选择器及使用方式)的 pod 数目与期望相符。 P90

    介绍控制器的协调流程 P91

    Deployment 的工作是确保 pod 数量始终与其标签选择器匹配。 P91

    图 4.2 一个 Deployment 的协调流程.png

    了解 Deployment 的三部分 P91

    • 标签选择器 (label selector) :用于确定 Deployment 作用域中有哪些 pod
    • 副本个数 (replica count) :指定应运行的 pod 数量
    • pod 模版 (pod template) :用于创建新的 pod 副本
    图 4.3 Deployment 的三个关键部分.png

    Deployment 的副本个数、标签选择器和 pod 模版都可以随时修改,但只有副本数目但变更会影响现有的 pod 。 P92

    更改控制器的标签选择器或 pod 模版的效果 P92

    更改标签选择器和 pod 模版对现有的 pod 没有影响。更改标签选择器会使现有的 pod 脱离 Deployment 的范围,因此控制器会停止关注它们。更改模版仅影响由此 Deployment 创建的新 pod 。 P92

    使用 Deployment 的好处 P92

    • 确保 pod 持续运行:在现有 pod 丢失时启动一个新 pod
    • 集群节点发生故障时,为故障节点上运行的受 Deployment 管理的所有 pod 创建替代副本
    • 轻松实现 pod 水平伸缩——手动和自动都可以

    注意: pod 实例永远不会重新安置到另一个节点。 Deployment 会创建一个全新的 pod 实例,它与正在替换的实例无关。 P92

    创建一个 Deployment P92

    我们可以通过以下描述文件 kubia-deployment.yaml 创建一个 Deployment ,它确保符合标签选择器 app=kubia 的 pod 实例始终是三个。

    # 遵循 v1 版本的 Kubernetes API
    apiVersion: apps/v1
    # 资源类型为 Deployment
    kind: Deployment
    metadata:
      # Deployment 的名称
      name: kubia
    spec:
      # 指定与标签选择器匹配的 pod 数目为 3
      replicas: 3
      # 指定 Deployment 操作对象
      selector:
        # 需要匹配以下指定的标签
        matchLabels:
          app: kubia
      # 启动 pod 使用的模版(可以发现模版内容与 kubia-manual.yaml 对应部分一致)
      template:
        metadata:
          # 指定标签为 app=kubia
          labels:
            app: kubia
        spec:
          containers:
            # 容器的名称
            - name: kubia
              # 创建容器所使用的镜像
              image: idealism/kubia
              # 应用监听的端口
              ports:
                - containerPort: 8080
                  protocol: TCP
    

    模版中的 pod 标签必须和 Deployment 的标签选择器匹配, API 服务器会校验 Deployment 的定义,不会接受错误配置。 P93

    若不指定选择器,它会自动根据 pod 模版中的标签自动配置,这样可以让描述文件更简洁。 P93

    使用 Deployment P94

    kubectl create -f kubia-deployment.yaml 会创建一个名为 kubia 的 Deployment ,它会根据 pod 模版启动三个新 pod 。 P94

    kubectl get pods 可以查看当前创建的所有 pod :

    NAME                    READY   STATUS             RESTARTS   AGE
    kubia-9495d9bf5-5dwj7   1/1     Running            0          3m53s
    kubia-9495d9bf5-5j6zr   1/1     Running            0          3m53s
    kubia-9495d9bf5-w98f6   1/1     Running            0          3m53s
    

    查看 Deployment 对已删除的 pod 的响应 P94

    kubectl delete pod kubia-9495d9bf5-5dwj7 会删除一个 pod ,然后再次查看当前所有 pod ,可以发现会有 4 个 pod ,因为删除的 pod 正在终止,并且正在创建一个新的 pod : P94

    NAME                    READY   STATUS              RESTARTS   AGE
    kubia-9495d9bf5-5dwj7   1/1     Terminating         0          24m
    kubia-9495d9bf5-5j6zr   1/1     Running             0          24m
    kubia-9495d9bf5-kxcw5   0/1     ContainerCreating   0          9s
    kubia-9495d9bf5-w98f6   1/1     Running             0          24m
    

    控制器如何创建新的 pod P95

    控制器通过创建一个新的替代 pod 来响应 pod 的删除操作。但它并没有对删除本身作出反应,而是针对由此产生对状态—— pod 数量不足作出反应。 P95

    图 4.4 如果一个 pod 消失, Deployment 将发现 pod 数目就更少并创建一个新的替代 pod.png

    应对节点故障 P96

    接下来我们将关闭一个节点的网络接口来模拟节点故障。 P96

    1. minikube ssh --node='m02': 进入节点内部
    2. sudo ifconfig eth0 down: 关闭该节点的网络接口
    3. kubectl get nodes: 发现节点 minikube-m02 的状态为未就绪 (NotReady)
    4. kubectl get pods: 可能仍然会看到与之前相同的三个 pod ,因为 Kubernetes 在重新调度 pod 之前会等待一段时间(如果节点因临时网络故障或 Kubelet 重启而无法访问)。如果节点在几分钟内无法访问, Deployment 会立即启动一个新的 pod 。

    将 pod 移入/移出 Deployment 的作用域 P97

    Deployment 创建的 pod 并不是绑定到 Deployment 。在任何时刻, Deployment 管理与标签选择器匹配的 pod 。通过更改 pod 的标签,可以将它从 Deployment 的作用域中添加或删除。 P97

    尽管一个 pod 没有绑定到一个 Deployment 拥有的 ReplicaSet ,但该 pod 在 metadata.ownerReferences 中存储它属于哪一个 ReplicaSetP98

    Deployment 管理的 pod 加标签 P98

    kubectl label pod kubia-9495d9bf5-5mmhb type=special: 给 pod 添加其他标签不会影响 Deployment 的管理范围,它只关心该 pod 是否具有标签选择器中引用的所有标签。 P98

    更改已托管的 pod 的标签 P98

    kubectl label pod kubia-9495d9bf5-5mmhb app=foo --overwrite: 更改其中一个 pod 的标签将使其不再与 Deployment 的标签选择器相匹配,并不再由 Deployment 管理,只剩下两个匹配的 pod 。因此, Deployment 会启动一个新的 pod ,将数目恢复为三。 P98

    图 4.5 通过更改标签从 Deployment 的作用域中删除一个 pod.png

    更改 Deployment 的标签选择器 P100

    更改 Deployment 的标签选择器会让所有的 pod 脱离 Deployment 的管理,导致它创建三个新的 pod 。你永远不会修改控制器的标签选择器,但会时不时地更改它的 pod 模版。 P100

    修改 pod 模版 P100

    Deployment 的 pod 模版可以随时修改,可以使用 kubectl edit deployment kubia 编辑 Deployment 。更改后会重新创建一个新的 ReplocaSet ,并使原有的 ReplocaSet 的副本数变为 0 。因此,使用 kubectl get pods 将发现有 6 个 pod ,pod 的前缀是对应的 ReplocaSet 的名称。

    NAME                    READY   STATUS        RESTARTS   AGE
    kubia-9495d9bf5-kxcw5   1/1     Terminating   0          78m
    kubia-9495d9bf5-w98f6   1/1     Terminating   0          102m
    kubia-9495d9bf5-xn67d   1/1     Terminating   0          29m
    kubia-bc974964b-bp4l2   1/1     Running       0          22s
    kubia-bc974964b-r29j2   1/1     Running       0          39s
    kubia-bc974964b-xl677   1/1     Running       0          14s
    

    若通过 kubectl edit replicaset kubia-bc974964b 直接修改 Deployment 拥有的 ReplicaSet 实例。这样效果和直接修改 Deployment 类似,也会创建一个新的 ReplicaSet ,并使原有的 ReplocaSet 的副本数变为 0 。这样修改不会将新的 pod 模版同步回原有的 Deployment ,但删除 Deployment 时仍然会删除所有相关的 ReplocaSet 及其管理的 pod 。

    水平缩放 pod P101

    kubectl scale deployment kubia --replicas=10: 可以修改 Deployment 需要保持的 pod 实例的数量(02. 开始使用 Kubernetes 和 Docker中介绍过使用该命令进行伸缩)。 P101

    也可以通过 kubectl edit deployment kubia 修改 spec.replicas 的数量,从而更改需要保持的 pod 实例的数量。 P102

    删除一个 Deployment

    当通过 kubectl delete deployment kubia 删除 Deployment 时,对应的 ReplicaSet 和 pod 都会被删除。

    而通过 kubectl delete replicaset kubia-bc974964b 删除 ReplicaSet 时,对应的 pod 会被删除,但由于 Deployment 会重新创建一个 Replicaset ,所以又会自动创建对应数量的 pod 。

    图 4.7 使用 --cascade=false 删除 ReplicaSet 使 pod 不受管理.png

    当通过 kubectl delete deployment kubia --cascade=false 删除 Deployment 时,会保留对应的 ReplicaSet 和 pod ,这样ReplicaSet 不再受管理,但是 pod 仍然受 ReplicaSet 管理。当重新创建符合要求的 Deployment 时, ReplicaSet 又会受到管理。

    同样地,通过 kubectl delete replicaset kubia-bc974964b --cascade=false 删除 ReplicaSet 时,也会保留对应的 pod 。这样 pod 不再受管理。当创建符合要求的 ReplicaSet 时,这些 pod 又会受到管理。

    使用 ReplicaSet P104

    :书中原本上一节讲得是 ReplicationController ,但我直接使用 Deployment 进行实践,并依照现在的结果进行了修改。目前推荐使用 Deployment ,并且 ReplicaSet 是受 Deployment 管理的,所以不再详细实践本节内容。

    使用更富有表达力的标签选择器 P106

    基于 kubia-deployment.yaml 创建一个新的描述文件 kubia-deployment-matchexpressions.yaml ,并将 spec.selector.matchLabels 属性替换为 spec.selector.matchExpressionsP107

    ...
    spec:
      ...
      # 指定 Deployment 操作对象
      selector:
        # 需要匹配满足以下要求的标签
        matchExpressions:
          # 标签名为 app 的值在 ["kubia"] 中
          - app: app
            operator: In
            values:
              - kubia
      ...
    

    matchExpressions 运行给选择器添加额外的表达式。每个表达式都必须包含一个 key 、一个 operator ,并且可能还有一个 values 的列表(取决于 operator )。共有四个有效的运算符: P107

    • In: 标签的值必须与其中一个指定的 values 匹配
    • NotIn: 标签的值与任何指定的 values 都不匹配
    • Exists: pod 必须包含一个指定名称的标签(不关心值)。使用此运算符时,不应指定 values 字段
    • DoesNotExist: pod 不得包含指定名称的标签。使用此运算符时,不应指定 values 字段

    如果指定了多个表达式,则所有这些表达式都必须为 true 才能使选择器与 pod 匹配。如果同时指定 matchLabelsmatchExpressions ,则所有标签都必须匹配,且所有表达式都必须为 true 才能使选择器与 pod 匹配。 P107

    使用 DaemonSet 在每个节点上运行一个 pod P107

    DaemonSet 可以让 pod 在集群中的每个节点上运行,并且每个节点正好有一个运行的 pod 实例。 P107

    图 4.8 DaemonSet 在每个节点上只运行一个 pod 副本.png
    使用 DaemonSet 在每个节点上运行一个 pod P108

    DaemonSet 没有副本数的概念,它确保创建足够的 pod ,并在每一个节点上部署一个 pod 。如果节点下线, DaemonSet 不会重新创建 pod ;但新节点添加到集群中,它会立刻部署一个新的 pod 实例到该节点。 P108

    使用 DaemonSet 只在特定的节点上运行 pod P109

    DaemonSet 将 pod 部署到集群的所有节点上,除非通过 pod 模版中的 spec.nodeSelector 属性指定这些 pod 只在部分节点上运行。 P109

    注意:节点可以被设置为不可调度,防止 pod 被部署到节点上。但 DaemonSet 会将 pod 部署到这些节点上,因为无法调度但属性只会被调度器使用,而 DaemonSet 的目的是运行系统服务,即使在不可调度的节点上,系统服务通常也需要运行。 P109

    用一个例子来解释 DaemonSet P109

    假设有一个名为 ssd-monitor 的守护进程,它需要在包含 SSD 的所有节点上运行。包含 SSD 的节点已被添加了 disk=ssd 标签,所以我们需要创建一个 DaemonSet ,它只在拥有上述标签的节点上运行守护进程。 P109

    图 4.9 使用含有节点选择器的 DaemonSet 在特定的节点上部署 pod.png

    创建一个 DaemonSet 描述文件 P110

    为了模拟 ssd-monitor 的监控程序,我们将使用以下 Dockerfile 创建一个每 5 秒中打印 SSD OK 的镜像。

    FROM busybox
    ENTRYPOINT while true; do echo 'SSD OK'; sleep 5; done
    

    为了将 ssd-monitor 部署到符合要求的每个节点上,我们还需要使用以下 ssd-monitor-daemonset.yaml 描述文件进行部署。

    # 遵循 apps/v1 版本的 Kubernetes API
    apiVersion: apps/v1
    # 资源类型为 DaemonSet
    kind: DaemonSet
    metadata:
      # DaemonSet 的名称
      name: ssd-monitor
    spec:
      # 指定 DaemonSet 操作对象
      selector:
        # 需要匹配以下指定的标签
        matchLabels:
          app: ssd-monitor
      # 启动 pod 使用的模版
      template:
        metadata:
          # 指定标签为 app=ssd-monitor
          labels:
            app: ssd-monitor
        spec:
          # 指定选择具有 disk=ssd 标签的节点部署
          nodeSelector:
            disk: ssd
          containers:
            # 容器的名称
            - name: main
              # 创建容器所使用的镜像
              image: idealism/ssd-monitor
    

    实践 P110

    1. kubectl create -f ssd-monitor-daemonset.yaml: 按照指定的描述文件创建一个 DaemonSet
    2. kubectl get daemonsets: 可以发现所有的值都是 0 ,因为目前还没有节点拥有 disk=ssd 标签
    3. kubectl get pods: 可以发现目前还没有 pod
    4. kubectl label node minikube-m03 disk=ssd: 给节点 minikube-m03 打上标签 disk=ssd
    5. kubectl get pods: 可以发现刚刚启动了一个 pod
      NAME                    READY   STATUS              RESTARTS   AGE
      ssd-monitor-bbqbp       0/1     ContainerCreating   0          2s
      
    6. kubectl label node minikube-m03 disk=hdd --overwrite: 将节点 minikube-m03 的标签 disk=ssd 修改为 disk=hdd
    7. kubectl get pods: 可以发现刚刚启动的 pod 正在终止
      NAME                    READY   STATUS        RESTARTS   AGE
      ssd-monitor-bbqbp       1/1     Terminating   0          2m37s
      

    运行执行单个任务的 pod P112

    介绍 Job 资源 P112

    Kubernetes 通过 Job 资源支持运行一种 pod ,该 pod 子啊内部进程成功结束时,不重启容器。一旦任务完成, pod 就被认为处于完成状态。 P112

    在节点发生故障时,该节点上由 Job 管理的 pod 将被重新安排到其他节点。如果进程本身异常退出(进程返回错误退出码时),可以将 Job 配置为重新启动容器。 P112

    图 4.10 由 Job 管理的 pod 会一直被重新安排,知道它们成功完成任务.png
    定义 Job 资源 P113

    为了模拟耗时的任务,我们将使用以下 Dockerfile 创建一个调用 sleep 120 命令的镜像。

    FROM busybox
    ENTRYPOINT echo "$(date) Batch job starting"; sleep 120; echo "$(date) Finished succesfully"
    

    为了管理部署 batch-job ,我们还需要使用以下 batch-job.yaml 描述文件进行部署。

    # 遵循 batch/v1 版本的 Kubernetes API
    apiVersion: batch/v1
    # 资源类型为 Job
    kind: Job
    metadata:
      # Job 的名称
      name: batch-job
    spec:
      # 启动 pod 使用的模版
      template:
        metadata:
          # 指定标签为 app=batch-job
          labels:
            app: batch-job
        spec:
          # Job 不能使用 Always 为默认的重启策略
          restartPolicy: OnFailure
          containers:
            # 容器的名称
            - name: main
              # 创建容器所使用的镜像
              image: idealism/batch-job
    

    设置 Job 的重启策略为 OnFailureNever 可以防止容器在完成任务时重新启动。 P114

    Job 运行一个 pod P114
    1. kubectl create -f batch-job.yaml: 根据描述文件创建指定的 Job
    2. kubectl get jobs: 查看 job ,可以发现刚刚创建的 Job
      NAME        COMPLETIONS   DURATION   AGE
      batch-job   0/1           5s         5s
      
    3. kubectl get pods: 查看 pod ,可以发现 Job 创建的 pod 正在运行
      NAME                    READY   STATUS        RESTARTS   AGE
      batch-job-d59js         1/1     Running       0          10s
      
    4. kubectl get pods: 等两分钟后再查看 pod ,可以发现 Job 创建的 pod 状态已经变为 Completed ,即任务已经完成。 pod 未被删除,所以我们可以查看 pod 的日志
      NAME                    READY   STATUS        RESTARTS   AGE
      batch-job-d59js         0/1     Completed     0          2m56s
      
    5. kubectl logs pod batch-job-d59js: 查看 pod 的日志
      Sun Jun  7 22:36:04 UTC 2020 Batch job starting
      Sun Jun  7 22:38:04 UTC 2020 Finished succesfully
      
    6. kubectl get jobs: 再次查看 job ,可以发现需要运行的 1 个 pod 已经完成
      NAME        COMPLETIONS   DURATION   AGE
      batch-job   1/1           2m45s      6m25s
      
    Job 中运行多个 pod 实例 P114

    Job 配置中设置 spec.completionsspec.parallelism 可以让 Job 创建多个 pod 实例,并允许以并行的方式运行它们。 P114

    基于 batch-job.yaml 创建一个新的描述文件 multi-completion-parallel-batch-job.yaml ,并添加 spec.completionsspec.parallelism 属性,指定需要成功运行完成 5 个 pod ,最多 2 个 pod 并行运行 : P115

    ...
    spec:
      # 必须确保 5 个 pod 运行完成
      completions: 5
      # 最多 2 个 pod 可以并行运行
      parallelism: 2
      ...
    
    1. kubectl create -f multi-completion-parallel-batch-job.yaml: 根据描述文件创建指定的 Job

    2. kubectl get pods: 查看运行的 pod ,可以发现共有两个 pod 正在运行。只要一个 pod 运行完成, Job 将运行下一个 pod ,直至 5 个 pod 都成功完成

      NAME                                        READY   STATUS        RESTARTS   AGE
      multi-completion-parallel-batch-job-fpwv5   1/1     Running       0          37s
      multi-completion-parallel-batch-job-m4cqw   1/1     Running       0          37s
      
    限制 Job pod 完成任务的时间 P116
    • Pod.spec.activeDeadlineSeconds: 可以指定一个 pod 最长存活时间,超时则终止 pod 并标记 Job 失败,可以用来限制 pod 完成任务的时间
    • Job.spec.backoffLimit: 可以配置一个 Job 在被标记为失败前最多尝试的次数,默认为 6 次

    安排 Job 定期运行或在将来运行一次 P116

    创建一个 CronJob P116

    为了每 15 分钟运行一次前面的任务,我们需要创建以下 cronjob.yaml 描述文件:

    # 遵循 batch/v1beta1 版本的 Kubernetes API
    apiVersion: batch/v1beta1
    # 资源类型为 CronJob
    kind: CronJob
    metadata:
      # Job 的名称
      name: batch-job-every-fifteen-minutes
    spec:
      # Cron 表达式表明当前任务在每天每小时的 0, 15, 30, 45 分运行
      schedule: "0,15,30,45 * * * *"
      # 指定最迟必须在预定时间后 15 秒内开始运行,否则就标记为一次失败的 `Job`
      startingDeadlineSeconds: 15
      # 创建 Job 使用的模版(可以发现和 batch-job.yaml 的 spec 部分基本一致)
      jobTemplate:
        spec:
          # 启动 pod 使用的模版
          template:
            metadata:
              # 指定标签为 app=periodic-batch-job
              labels:
                app: periodic-batch-job
            spec:
              # Job 不能使用 Always 为默认的重启策略
              restartPolicy: OnFailure
              containers:
                # 容器的名称
                - name: main
                  # 创建容器所使用的镜像
                  image: idealism/batch-job
    

    kubectl get cronjobs: 可以查看所有的 CronJob

    NAME                              SCHEDULE             SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    batch-job-every-fifteen-minutes   0,15,30,45 * * * *   False     0        <none>          8s
    

    CronJob 总是为计划中配置的每个执行创建一个 Job ,但可能会有以下两种问题:

    • 同时创建两个 Job :保证任务是幂等的
    • 没有创建 Job :保证下一个任务能运行完成错过的任何工作

    相关文章

      网友评论

          本文标题:Kubernetes 实战 —— 04. 副本机制和其他控制器:

          本文链接:https://www.haomeiwen.com/subject/ppencltx.html