使用靜態工作分配進行平行處理的索引化任務

功能狀態: Kubernetes v1.24 [stable]

在此範例中,您將執行一個 Kubernetes 任務,該任務使用多個平行工作程序。每個工作程序都是在其自己的 Pod 中執行的不同容器。Pod 具有索引編號,控制平面會自動設定該編號,這允許每個 Pod 識別要處理的整體任務的哪個部分。

Pod 索引在 註解 batch.kubernetes.io/job-completion-index 中以字串形式表示其十進位值。為了讓容器化任務程序取得此索引,您可以使用向下 API 機制發佈註解的值。為了方便起見,控制平面會自動設定向下 API 以在 JOB_COMPLETION_INDEX 環境變數中公開索引。

以下是此範例中步驟的概述

  1. 使用索引完成定義任務資訊清單。向下 API 允許您將 Pod 索引註解作為環境變數或檔案傳遞到容器。
  2. 根據該資訊清單啟動 Indexed 任務.

開始之前

您應該已經熟悉 任務 的基本、非平行使用方式。

您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少兩個非作為控制平面主機的節點的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用以下 Kubernetes Playground 之一

您的 Kubernetes 伺服器必須為 v1.21 或更新版本。若要檢查版本,請輸入 kubectl version

選擇一種方法

若要從工作程序存取工作項目,您有幾個選項

  1. 讀取 JOB_COMPLETION_INDEX 環境變數。任務 控制器 會自動將此變數連結到包含完成索引的註解。
  2. 讀取包含完成索引的檔案。
  3. 假設您無法修改程式,您可以使用腳本包裝它,該腳本使用上述任何方法讀取索引,並將其轉換為程式可以使用的輸入。

在此範例中,假設您選擇了選項 3,並且想要執行 rev 工具。這個程式接受檔案作為參數,並列印其反轉的內容。

rev data.txt

您將使用來自 busybox 容器映像檔的 rev 工具。

因為這只是一個範例,每個 Pod 只執行一小部分工作(反轉一個短字串)。在實際的工作負載中,您可能會建立一個 Job,代表根據場景資料產生 60 秒影片的任務。影片渲染 Job 中的每個工作項目都是渲染該影片片段的特定影格。索引完成表示 Job 中的每個 Pod 都知道要渲染和發布哪個影格,方法是從片段的開頭開始計數影格。

定義索引 Job

這是一個範例 Job 資訊清單,使用 Indexed 完成模式

apiVersion: batch/v1
kind: Job
metadata:
  name: 'indexed-job'
spec:
  completions: 5
  parallelism: 3
  completionMode: Indexed
  template:
    spec:
      restartPolicy: Never
      initContainers:
      - name: 'input'
        image: 'docker.io/library/bash'
        command:
        - "bash"
        - "-c"
        - |
          items=(foo bar baz qux xyz)
          echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt          
        volumeMounts:
        - mountPath: /input
          name: input
      containers:
      - name: 'worker'
        image: 'docker.io/library/busybox'
        command:
        - "rev"
        - "/input/data.txt"
        volumeMounts:
        - mountPath: /input
          name: input
      volumes:
      - name: input
        emptyDir: {}

在上面的範例中,您使用 Job 控制器為所有容器設定的內建 JOB_COMPLETION_INDEX 環境變數。 初始化容器 將索引對應到靜態值,並將其寫入檔案,該檔案透過 emptyDir 卷 與執行工作程式的容器共用。 或者,您可以透過向下 API 定義自己的環境變數,以將索引發布到容器。 您也可以選擇從 ConfigMap 作為環境變數或檔案載入值清單。

或者,您可以直接使用向下 API 將註解值作為卷檔案傳遞,如下列範例所示

apiVersion: batch/v1
kind: Job
metadata:
  name: 'indexed-job'
spec:
  completions: 5
  parallelism: 3
  completionMode: Indexed
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: 'worker'
        image: 'docker.io/library/busybox'
        command:
        - "rev"
        - "/input/data.txt"
        volumeMounts:
        - mountPath: /input
          name: input
      volumes:
      - name: input
        downwardAPI:
          items:
          - path: "data.txt"
            fieldRef:
              fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']

執行 Job

現在執行 Job

# This uses the first approach (relying on $JOB_COMPLETION_INDEX)
kubectl apply -f https://kubernetes.dev.org.tw/examples/application/job/indexed-job.yaml

當您建立此 Job 時,控制平面會為您指定的每個索引建立一系列 Pod。 .spec.parallelism 的值決定可以同時執行的數量,而 .spec.completions 決定 Job 總共建立多少個 Pod。

因為 .spec.parallelism 小於 .spec.completions,所以控制平面會等待前幾個 Pod 完成後,再啟動更多 Pod。

您可以等待 Job 成功,並設定逾時

# The check for condition name is case insensitive
kubectl wait --for=condition=complete --timeout=300s job/indexed-job

現在,描述 Job 並檢查它是否成功。

kubectl describe jobs/indexed-job

輸出類似於

Name:              indexed-job
Namespace:         default
Selector:          controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
Labels:            controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
                   job-name=indexed-job
Annotations:       <none>
Parallelism:       3
Completions:       5
Start Time:        Thu, 11 Mar 2021 15:47:34 +0000
Pods Statuses:     2 Running / 3 Succeeded / 0 Failed
Completed Indexes: 0-2
Pod Template:
  Labels:  controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
           job-name=indexed-job
  Init Containers:
   input:
    Image:      docker.io/library/bash
    Port:       <none>
    Host Port:  <none>
    Command:
      bash
      -c
      items=(foo bar baz qux xyz)
      echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt

    Environment:  <none>
    Mounts:
      /input from input (rw)
  Containers:
   worker:
    Image:      docker.io/library/busybox
    Port:       <none>
    Host Port:  <none>
    Command:
      rev
      /input/data.txt
    Environment:  <none>
    Mounts:
      /input from input (rw)
  Volumes:
   input:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
    SizeLimit:  <unset>
Events:
  Type    Reason            Age   From            Message
  ----    ------            ----  ----            -------
  Normal  SuccessfulCreate  4s    job-controller  Created pod: indexed-job-njkjj
  Normal  SuccessfulCreate  4s    job-controller  Created pod: indexed-job-9kd4h
  Normal  SuccessfulCreate  4s    job-controller  Created pod: indexed-job-qjwsz
  Normal  SuccessfulCreate  1s    job-controller  Created pod: indexed-job-fdhq5
  Normal  SuccessfulCreate  1s    job-controller  Created pod: indexed-job-ncslj

在此範例中,您使用每個索引的自訂值執行 Job。 您可以檢查其中一個 Pod 的輸出

kubectl logs indexed-job-fdhq5 # Change this to match the name of a Pod from that Job

輸出類似於

xuq
上次修改時間:2023 年 8 月 24 日下午 6:38 PST:使用 code_sample shortcode 而非 code shortcode (e8b136c3b3)