# Індексоване завдання (Job) для паралельної обробки з фіксованим призначенням роботи

LLMS index: [llms.txt](/llms.txt)

---

<div class="feature-state-notice feature-stable">
      <span class="feature-state-name">СТАН ФУНКЦІОНАЛУ:</span>
      <code>Kubernetes v1.24 [stable]</code>
    </div>
  



<!-- overview -->

У цьому прикладі ви запустите Job Kubernetes, яке використовує кілька паралельних робочих процесів. Кожен робочий процес — це різний контейнер, що працює у власному Podʼі. Podʼи мають _індексний номер_, який автоматично встановлює панель управління, що дозволяє кожному Podʼу визначити, над якою частиною загального завдання працювати.

Індекс Podʼа доступний в <a class='glossary-tooltip' title='Ключ-значення, які використовуються для додавання довільних невизначених метаданих до обʼєктів.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/concepts/overview/working-with-objects/annotations' target='_blank' aria-label='анотації'>анотації</a> `batch.kubernetes.io/job-completion-index` у вигляді рядка, який представляє його десяткове значення. Щоб контейнеризований процес завдання отримав цей індекс, можна опублікувати значення анотації за допомогою механізму [downward API](/docs/concepts/workloads/pods/downward-api/). Для зручності панель управління автоматично встановлює downward API для експонування індексу в змінну середовища `JOB_COMPLETION_INDEX`.

Нижче наведено огляд кроків у цьому прикладі:

1. **Визначте маніфест завдання з використанням індексованого завершення**. Downward API дозволяє передавати індекс Podʼа як змінну середовища або файл до контейнера.
2. **Запустіть `Indexed` завдання на основі цього маніфесту**.

## Перш ніж ви розпочнете

Ви маєте бути знайомі з базовим, не-паралельним використанням [Job](/docs/concepts/workloads/controllers/job/).

<p>Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою <a href="https://minikube.sigs.k8s.io/docs/tutorials/multi_node/">minikube</a> або використовувати одну з цих пісочниць:</p>
<ul>
<li><a href="https://labs.iximiuz.com/playgrounds?category=kubernetes&filter=all">iximiuz Labs</a></li>
<li><a href="https://killercoda.com/playgrounds/scenario/kubernetes">Killercoda</a></li>
<li><a href="https://kodekloud.com/public-playgrounds">KodeKloud</a></li>
</ul>
 
 
 Версія вашого Kubernetes сервера має бути не старішою ніж v1.21.
  <p>Для перевірки версії введіть  <code>kubectl version</code>.</p>


<!-- steps -->

## Оберіть підхід {#choose-an-approach}

Щоб отримати доступ до робочого елемента з програми робочого процесу, у вас є кілька варіантів:

1. Прочитайте змінну середовища `JOB_COMPLETION_INDEX`. Job <a class='glossary-tooltip' title='Контролер — цикл управління, що спостерігає за загальним станом кластера через apiserver і вносить зміни в намаганні наблизити поточний стан до бажаного.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/concepts/architecture/controller/' target='_blank' aria-label='контролер'>контролер</a> автоматично повʼязує цю змінну з анотацією, що містить індекс завершення.
2. Прочитайте файл, який містить індекс завершення.
3. Припускаючи, що ви не можете змінити програму, ви можете обгорнути її сценарієм, який читає індекс за допомогою будь-якого з методів вище і перетворює його в щось, що програма може використовувати як вхід.

У цьому прикладі уявіть, що ви вибрали третій варіант, і ви хочете запустити [rev](https://man7.org/linux/man-pages/man1/rev.1.html) утиліту. Ця програма приймає файл як аргумент і виводить зміст у зворотньому порядку.

```shell
rev data.txt
```

Ви будете використовувати інструмент `rev` з контейнерного образу [`busybox`](https://hub.docker.com/_/busybox).

Оскільки це лише приклад, кожен Pod робить лише невеликий шматок роботи (реверсування короткого рядка). У реальному навантаженні ви, наприклад, можете створити Job, що представляє задачу рендерингу 60 секунд відео на основі даних про сцену. Кожен робочий елемент в завданні відеорендерингу буде створювати певний кадр цього відеокліпу. Індексоване завершення означатиме, що кожен Pod у Job знає, який кадр рендерити та опублікувати, рахуючи кадри від початку кліпу.

## Визначте Indexed Job {#define-indexed-job}

Ось приклад маніфесту Job, який використовує режим завершення `Indexed`:


















<div class="highlight code-sample">
    <div class="copy-code-icon">
    <a href="https://raw.githubusercontent.com/kubernetes/website/main/content/uk/examples/application/job/indexed-job.yaml" download="application/job/indexed-job.yaml"><code>application/job/indexed-job.yaml</code>
    </a><img src="/images/copycode.svg" class="icon-copycode" onclick="copyCode('application-job-indexed-job-yaml')" title="Копіювати application/job/indexed-job.yaml до буферу обміну"></img></div>
    <div class="includecode" id="application-job-indexed-job-yaml"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">batch/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Job</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;indexed-job&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">completions</span><span class="p">:</span><span class="w"> </span><span class="m">5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">parallelism</span><span class="p">:</span><span class="w"> </span><span class="m">3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">completionMode</span><span class="p">:</span><span class="w"> </span><span class="l">Indexed</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">restartPolicy</span><span class="p">:</span><span class="w"> </span><span class="l">Never</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">initContainers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;input&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;docker.io/library/bash&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">command</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="s2">&#34;bash&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="s2">&#34;-c&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">          items=(foo bar baz qux xyz)
</span></span></span><span class="line"><span class="cl"><span class="sd">          echo ${items[$JOB_COMPLETION_INDEX]} &gt; /input/data.txt</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">volumeMounts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">containers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;worker&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;docker.io/library/busybox&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">command</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="s2">&#34;rev&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="s2">&#34;/input/data.txt&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">volumeMounts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">emptyDir</span><span class="p">:</span><span class="w"> </span>{}<span class="w">
</span></span></span></code></pre></div></div>
</div>

У вищенаведеному прикладі ви використовуєте вбудовану змінну середовища `JOB_COMPLETION_INDEX`, яку встановлює контролер завдань для всіх контейнерів. [Контейнер ініціалізації](/docs/concepts/workloads/pods/init-containers/) відображає індекс на статичне значення та записує його в файл, який спільно використовується з контейнером, що виконує робочий процес через [том emptyDir](/docs/concepts/storage/volumes/#emptydir). Додатково ви можете [визначити свою власну змінну середовища через downward API](/docs/tasks/inject-data-application/environment-variable-expose-pod-information/) для публікації індексу в контейнерах. Ви також можете вибрати завантаження списку значень з [ConfigMap як змінної середовища або файлу](/docs/tasks/configure-pod-container/configure-pod-configmap/).

У іншому варіанті ви можете безпосередньо [використовувати downward API для передачі значення анотації як файлу тому](/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#store-pod-fields), як показано у наступному прикладі:


















<div class="highlight code-sample">
    <div class="copy-code-icon">
    <a href="https://raw.githubusercontent.com/kubernetes/website/main/content/uk/examples/application/job/indexed-job-vol.yaml" download="application/job/indexed-job-vol.yaml"><code>application/job/indexed-job-vol.yaml</code>
    </a><img src="/images/copycode.svg" class="icon-copycode" onclick="copyCode('application-job-indexed-job-vol-yaml')" title="Копіювати application/job/indexed-job-vol.yaml до буферу обміну"></img></div>
    <div class="includecode" id="application-job-indexed-job-vol-yaml"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">batch/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Job</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;indexed-job&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">completions</span><span class="p">:</span><span class="w"> </span><span class="m">5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">parallelism</span><span class="p">:</span><span class="w"> </span><span class="m">3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">completionMode</span><span class="p">:</span><span class="w"> </span><span class="l">Indexed</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">restartPolicy</span><span class="p">:</span><span class="w"> </span><span class="l">Never</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">containers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;worker&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;docker.io/library/busybox&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">command</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="s2">&#34;rev&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="s2">&#34;/input/data.txt&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">volumeMounts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">input</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">downwardAPI</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">items</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;data.txt&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">fieldRef</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">fieldPath</span><span class="p">:</span><span class="w"> </span><span class="l">metadata.annotations[&#39;batch.kubernetes.io/job-completion-index&#39;]</span></span></span></code></pre></div></div>
</div>

## Запуск Job {#run-the-job}

Тепер запустіть Job:

```shell
# Це використовує перший підхід (покладаючись на $JOB_COMPLETION_INDEX)
kubectl apply -f https://kubernetes.io/examples/application/job/indexed-job.yaml
```

При створенні цього Завдання панель управління створює серію Podʼів, по одному для кожного вказаного індексу. Значення `.spec.parallelism` визначає, скільки може працювати одночасно, в той час, як `.spec.completions` визначає, скільки Podʼів створює Job в цілому.

Оскільки `.spec.parallelism` менше, ніж `.spec.completions`, панель управління чекає, поки деякі з перших Podʼів завершаться, перш ніж запустити ще.

Ви можете зачекати, поки Завдання завершиться успішно, з тайм-аутом:

```shell
# Перевірка умови назви нечутлива до регістру
kubectl wait --for=condition=complete --timeout=300s job/indexed-job
```

Тепер опишіть Завдання та переконайтеся, що воно виконалося успішно.

```shell
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 (тимчасова тека, яка поділяє життя Podʼа)
    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ʼів:

```shell
kubectl logs indexed-job-fdhq5 # Змініть це, щоб відповідати імені Podʼа з цього Завдання
```

Вивід схожий на:

```none
xuq
```
