用於靜態工作分配的索引作業

特性狀態: Kubernetes v1.24 [stable]

在此示例中,你將執行一個 Kubernetes Job,它使用多個並行工作程序。 每個工作程序都是一個在各自 Pod 中執行的不同容器。 Pod 具有由控制面自動設定的**索引號**,這使得每個 Pod 都能識別要處理的整體任務的哪個部分。

Pod 索引號可以在annotation `batch.kubernetes.io/job-completion-index` 中以十進位制字串表示。為了使容器化任務程序獲取此索引,你可以使用downward API 機制釋出該 annotation 的值。為方便起見,控制平面會自動設定 downward API,以在 `JOB_COMPLETION_INDEX` 環境變數中公開該索引。

以下是本示例中的步驟概述:

  1. 使用索引完成定義 Job 清單。downward API 允許你將 Pod 索引 annotation 作為環境變數或檔案傳遞給容器。
  2. 根據清單啟動一個 `Indexed` Job.

準備工作

你應該已經熟悉 Job 的基本非並行用法。

你需要擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。 建議你在至少有兩個不充當控制平面主機的節點的叢集上執行本教程。 如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 操場之一

你的 Kubernetes 伺服器版本必須是 v1.21 或更高。

要檢查版本,請輸入 kubectl version

選擇一種方法

要從 worker 程式訪問工作項,你有以下幾種選擇

  1. 讀取 `JOB_COMPLETION_INDEX` 環境變數。Job 控制器自動將此變數連結到包含完成索引的 Annotation。
  2. 讀取包含完成索引的檔案。
  3. 假設你無法修改程式,你可以用一個指令碼將其包裝起來,該指令碼使用上述任何方法讀取索引並將其轉換為程式可以用作輸入的內容。

對於此示例,假設你選擇了選項 3,並且你想執行 rev 工具。此程式接受一個檔案作為引數,並反向列印其內容。

rev data.txt

你將使用 `busybox` 容器映象中的 `rev` 工具。

由於這只是一個示例,每個 Pod 只做一點點工作(反轉一個短字串)。在實際工作負載中,你可能會建立一個 Job,例如,該 Job 代表根據場景資料生成 60 秒影片的任務。影片渲染 Job 中的每個工作項將是渲染該影片剪輯的特定幀。索引完成意味著 Job 中的每個 Pod 都知道要渲染和釋出的幀,透過從剪輯的開頭計算幀來確定。

定義一個索引 Job

這是一個使用 `Indexed` 完成模式的 Job 清單示例

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` 環境變數。一個Init 容器將索引對映到一個靜態值,並將其寫入一個檔案,該檔案透過emptyDir 卷與執行 worker 的容器共享。你還可以選擇透過 Downward API 定義自己的環境變數來將索引發布到容器。你還可以選擇從 ConfigMap 載入值列表作為環境變數或檔案

或者,你也可以直接使用 Downward 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.club.tw/examples/application/job/indexed-job.yaml

當你建立此 Job 時,控制平面會建立一系列 Pod,每個 Pod 對應你指定的每個索引。`。spec.parallelism` 的值決定了可以同時執行多少個 Pod,而 `。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 簡碼代替 code 簡碼 (e8b136c3b3)