---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.6
alternate:
  - https://sourcecraft.dev/portal/docs/en/sourcecraft/operations/self-hosted-worker-kubernetes.md
  - https://sourcecraft.dev/portal/docs/ru/sourcecraft/operations/self-hosted-worker-kubernetes.md
---
> **Documentation Index:** Fetch the complete configuration index at https://sourcecraft.dev/portal/docs/ru/llms.txt

# Настроить выполнение заданий CI/CD SourceCraft в кластере Kubernetes

В [пользовательском воркере](https://sourcecraft.dev/portal/docs/ru/sourcecraft/concepts/workers.md#self-hosted-workers) `self-hosted-processor` поддерживается режим, в котором [задания](https://sourcecraft.dev/portal/docs/ru/sourcecraft/concepts/ci-cd.md#tasks) CI/CD выполняются в [кластере Kubernetes](https://yandex.cloud/ru/docs/glossary/containerization#kubernetes). Каждое задание выполняется в отдельном [поде](https://kubernetes.io/docs/concepts/workloads/pods/). Поды создаются воркером заранее и поддерживаются в пуле. Когда появляется новое задание, воркер выбирает доступный под из пула и передает задание агенту, который запущен в поде. После выполнения задания под автоматически удаляется.

{% note info %}

Поддержка Kubernetes-режима доступна начиная с версии воркера `0.14.1`.

{% endnote %}

## Обзор {#overview}

Воркер может быть запущен:
* _вне кластера Kubernetes_, например на компьютере пользователя. В таком случае в параметры воркера передается `kubeconfig` для работы с кластером Kubernetes. Для передачи задания агенту используется проброс порта `port forward`.

  Конфигурация `kubeconfig` должна содержать единственный контекст, и этот контекст должен быть выбран текущим.

* _внутри кластера Kubernetes_. Для передачи задания агенту используется IP-адрес пода `podIP`.

  [Пространство имен](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/), в котором запущен воркер, должно отличаться от пространства имен, выделенного под пул подов.

Работа воркера состоит из следующих этапов: 
* [Старт](#worker-start)
* [Обслуживание пула подов](#pool-maintenance)
* [Выполнение задания](#task-execution)

### Старт воркера {#worker-start}

При старте воркер в пространстве имен Kubernetes, выделенном под пул подов, удаляет и создает заново секрет `agent-secrets`. Секрет содержит конфигурацию агента и сертификат удостоверяющего центра (`certificate authority`, `CA`), необходимые для запуска агента. Сертификат удостоверяющего центра используется для авторизации запросов воркера к агенту по протоколу mTLS.

### Обслуживание пула подов {#pool-maintenance}

Воркер периодически запускает процедуру обслуживания пула подов:
* Внутренние состояния подов синхронизируются с состояниями в кластере Kubernetes.
* Обрабатываются переходы подов между состояниями. 
* Создаются новые поды.
* Неизвестные поды удаляются, в том числе поды, оставшиеся от предыдущего запуска воркера, или поды, созданные другим воркером.

  {% note warning %}

  Не запускайте несколько экземпляров воркера с пулом подов в одном пространстве имен. Воркеры будут удалять поды друг друга.

  {% endnote %}

В пуле поддерживается количество доступных подов, равное минимальному размеру пула, заданному в конфигурации воркера. Общее количество подов в пуле не может превышать максимальный размер пула, также заданный в конфигурации воркера.

### Выполнение задания {#task-execution}

После получения задания воркер ищет в пуле доступный под и передает задание агенту, который запущен в этом поде.

Процесс отправки задания агенту отличается в зависимости от того, где размещен воркер:

{% list tabs %}

- Воркер вне кластера

  Воркер пробрасывает порт агента на свой локальный порт (`port forward`), отправляет задание агенту через локальный порт и закрывает соединение, использованное для проброса порта.

- Воркер в кластере

  Воркер отправляет задание на порт агента по IP-адресу пода. 

  {% note warning %}

  Разрешите взаимодействие воркера с подом в пространстве имен пула — такое взаимодействие может быть ограничено сетевыми политиками или другими инструментами.

  {% endnote %}

{% endlist %}

При передаче задания агенту воркер авторизует свой запрос с помощью клиентского сертификата и ключа. Агент проверяет авторизацию с помощью сертификата удостоверяющего центра. Соединение воркера и агента защищено по протоколу mTLS.

Далее агент выполняет задание самостоятельно. После завершения выполнения задания воркер удаляет под.

## Процесс настройки {#setup}

Чтобы настроить выполнение заданий CI/CD в кластере Kubernetes:
1. [Подготовьте кластер Kubernetes](#prepare-cluster)
1. [Создайте конфигурационный файл воркера](#config-file)
1. [Создайте шаблон пода](#pod-template)
1. [Запустите воркер](#start-worker)

### Подготовьте кластер Kubernetes {#prepare-cluster}

{% note tip %}

Для выполнения заданий CI/CD SourceCraft вы можете использовать [кластер Yandex Managed Service for Kubernetes](https://yandex.cloud/ru/docs/managed-kubernetes/quickstart).

{% endnote %}

1. [Установите](https://kubernetes.io/ru/docs/tasks/tools/#kubectl) `kubectl` и подключитесь к кластеру Kubernetes.
1. Создайте пространство имен для пула подов воркера:

    ```bash
    kubectl create namespace pods-namespace
    ```

1. Создайте файл `role.yaml` с описанием роли пользователя, от имени которого воркер будет взаимодействовать с кластером Kubernetes. Пользователь должен иметь права на управление секретами и подами в пространстве имен пула подов. Если воркер запущен вне кластера Kubernetes, дополнительно требуются права на проброс портов.

    {% list tabs %}

    - Воркер вне кластера

      ```yaml
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: processor-role
      rules:
        - apiGroups: [""]
          resources: ["secrets", "pods"]
          verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
        - apiGroups: [""]
          resources: ["pods/portforward"]
          verbs: ["create"]
      ```

    - Воркер в кластере

      ```yaml
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: processor-role
      rules:
        - apiGroups: [""]
          resources: ["secrets", "pods"]
          verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
      ```

    {% endlist %}

1. Примените манифест для пространства имен, созданного ранее:

    ```bash
    kubectl apply -f role.yaml -n pods-namespace
    ```

### Создайте конфигурационный файл воркера {#config-file}

Создайте файл `config.yaml` со следующей конфигурацией:

```yaml
kubernetes:
  kubeconfig_path: /path/to/.kube/config
  namespace: <пространство_имен_пула>
  pod_template_path: /path/to/pod-template.yaml
  agent:
    port: 8693
    ca_cert_path: /path/to/ca.crt
    client_cert_path: /path/to/client.crt
    client_key_path: /path/to/client.key
  pool_max_size: 10
  pool_min_size: 3
  pool_maintenance_period: 10s
  secret_updating_timeout: 20s
  pods_listing_timeout: 10s
  pod_creation_timeout: 1m
  pod_startup_timeout: 2m
  pod_deletion_timeout: 30s
  endpoint_resolving_timeout: 10s

endpoint:
  host: ci.sourcecraft.tech
  port: 443
  ssl_no_verify: false

executor_type: kubernetes

logger_type: json
logger_level: info

tags: ["my-tag", "+my-required-tag"]

auth:
  pat: <персональный_токен>
```

Где:
* `kubernetes` — раздел с параметрами, специфичными для режима Kubernetes:
    * `kubeconfig_path` — путь до файла `kubeconfig`. Также можно задать через переменную окружения `KUBECONFIG`. Если параметр не задан, используется внутрикластерная конфигурация.
    * `namespace` — пространство имен, выделенное под пул подов. Обязательный параметр.
    * `pod_template` — [шаблон пода](#pod-template) в формате YAML. Также можно задать через переменную окружения `KUBERNETES_POD_TEMPLATE`. Должен быть задан либо `pod_template`, либо `pod_template_path`. Указывать одновременно оба параметра нельзя.
    * `pod_template_path` — путь до файла с шаблоном пода. Должен быть задан либо `pod_template`, либо `pod_template_path`. Указывать одновременно оба параметра нельзя.
    * `agent` — подраздел с параметрами для взаимодействия с агентом:
        * `port` — порт агента. Значение по умолчанию — `8693`. Порт должен отличаться от всех других портов пода. Попадает в конфигурацию агента.
        * `ca_cert` — сертификат удостоверяющего центра. Также можно задать через переменную окружения `KUBERNETES_AGENT_CA_CERT`. Должен быть задан либо `ca_cert`, либо `ca_cert_path`. Указывать оба параметра одновременно нельзя. Попадает в конфигурацию агента.
        * `ca_cert_path` — путь до файла с сертификатом удостоверяющего центра. Должен быть задан либо `ca_cert`, либо `ca_cert_path`. Указывать одновременно оба параметра нельзя. Попадает в конфигурацию агента.
        * `client_cert` — клиентский сертификат. Также можно задать через переменную окружения `KUBERNETES_AGENT_CLIENT_CERT`. Должен быть задан либо `client_cert`, либо `client_cert_path`. Указывать одновременно оба параметра нельзя.
        * `client_cert_path` — путь до файла с клиентским сертификатом. Должен быть задан либо `client_cert`, либо `client_cert_path`. Указывать одновременно оба параметра нельзя.
        * `client_key` — клиентский ключ. Также можно задать через переменную окружения `KUBERNETES_AGENT_CLIENT_KEY`. Должен быть задан либо `client_key`, либо `client_key_path`. Указывать одновременно оба параметра нельзя.
        * `client_key_path` — путь до файла с клиентским ключом. Должен быть задан либо `client_key`, либо `client_key_path`. Указывать одновременно оба параметра нельзя.
    * `pool_max_size` — максимальный размер пула подов. Обязательный параметр. Должен быть не меньше значения `pool_min_size`.
    * `pool_min_size` — минимальный размер пула подов. Обязательный параметр. Должен быть больше `0`.
    * `pool_maintenance_period` — периодичность обслуживания пула подов. Значение по умолчанию — `10s`.
    * `secret_updating_timeout` — таймаут обновления секрета. Значение по умолчанию — `20s`.
    * `pods_listing_timeout` — таймаут запроса для получения списка подов. Значение по умолчанию — `10s`.
    * `pod_creation_timeout` — таймаут запроса создания пода. Значение по умолчанию — `1m`.
    * `pod_startup_timeout` — таймаут ожидания запуска пода. Значение по умолчанию — `2m`. Включает время ожидания запуска пода со всеми его контейнерами.
    * `pod_deletion_timeout` — таймаут запроса удаления пода. Значение по умолчанию — `30s`.
    * `endpoint_resolving_timeout` — таймаут разрешения конечной точки. Значение по умолчанию — `10s`. Включает время ожидания проброса порта агента.
* `endpoint` — раздел с параметрами для взаимодействия с сервисом SourceCraft. Раздел полностью попадает в конфигурацию агента:
    * `host` — хост сервиса SourceCraft. Обязательный параметр.
    * `port` — порт сервиса SourceCraft. Обязательный параметр.
    * `ssl_no_verify` — флаг отключения проверки серверного сертификата сервиса SourceCraft. Значение по умолчанию — `false`.
* `executor_type` — тип воркера. Для режима Kubernetes должно быть указано значение `kubernetes`.
* `logger_type` — формат логирования. Допустимые значения: `json` или `console`.
* `logger_level` — уровень логирования. Допустимые значения: `debug`, `info`, `warn`, `error`. Необязательный параметр.
* `tags` — список [меток воркера](https://sourcecraft.dev/portal/docs/ru/sourcecraft/ci-cd-ref/self-hosted-tags.md). Необязательный параметр.
* `auth` — раздел с параметрами аутентификации воркера в сервисе SourceCraft:
    * `pat` — [персональный токен доступа](https://sourcecraft.dev/portal/docs/ru/sourcecraft/security/pat.md) (PAT). Также можно задать через переменную окружения `PAT_CREDENTIALS`. Обязательный параметр.

### Создайте шаблон пода {#pod-template}

Шаблон пода задает конфигурацию, по которой воркер создает поды в пространстве имен пула. 

{% note warning %}

В шаблоне обязательно должен быть контейнер с именем `cicd-worker`. В этом контейнере запускается агент, который выполняет задание. Ресурсы для контейнера `cicd-worker` выбирайте с учетом предполагаемой нагрузки при выполнении заданий.

{% endnote %}

Создайте файл `pod-template.yaml` с шаблоном пода, например:

```yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-template
spec:
  containers:
    - name: cicd-worker
      image: cr.yandex/sourcecraft/ci/self-hosted-processor:latest
      resources:
        requests:
          cpu: 250m
          memory: 256Mi
        limits:
          cpu: "1"
          memory: 1Gi
```

При создании пода воркер автоматически дополняет шаблон следующими параметрами:
* В контейнер `cicd-worker` добавляются переменные окружения из секрета `agent-secrets`, контейнерный порт `agent-port` для порта агента и проба запуска.
* Имя пода меняется на `cicd-worker-<уникальный_идентификатор>`.
* Пространство имен меняется на пространство имен пула подов.
* Запрещается перезапуск пода.

{% cut "Пример дополненной конфигурации" %}

```yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: cicd-worker-<уникальный_идентификатор>
  namespace: <пространство_имен_пула>
spec:
  containers:
    - name: cicd-worker
      image: cr.yandex/sourcecraft/ci/self-hosted-processor:latest
      resources:
        requests:
          cpu: 250m
          memory: 256Mi
        limits:
          cpu: "1"
          memory: 1Gi
      envFrom:
        - secretRef:
            name: agent-secrets
      ports:
        - name: agent-port
          containerPort: 8693
          protocol: TCP
      startupProbe:
        exec:
          command: ["nc", "-z", "localhost", "8693"]
        initialDelaySeconds: 5
        periodSeconds: 5
        failureThreshold: 10
  restartPolicy: Never
```

{% endcut %}

#### Docker-образ агента {#agent-image}

В качестве Docker-образа агента рекомендуется использовать базовый образ контейнера воркера `cr.yandex/sourcecraft/ci/self-hosted-processor:latest`. Если для выполнения заданий требуется собственный образ, при его создании учитывайте следующие требования:
* Воркер должен запускаться без указания пути к файлу конфигурации в командной строке — конфигурация передается через переменную окружения `PROCESSOR_CONFIG`:

  ```Dockerfile
  ENTRYPOINT ["/self-hosted-processor", "run"]
  ```

* В образе должна быть создана директория `/home/sourcecraft-ci-runner`. Пользователь, от имени которого работает контейнер, должен иметь полный доступ к этой директории.
* В образе должны быть установлены и доступны для запуска следующие исполняемые файлы: `bash`, `sh`, `git`, `git-lfs`, `docker`, `nc`.

#### Использование Docker в задании {#docker-in-task}

Если для выполнения заданий нужен Docker, добавьте в шаблон пода контейнер с `Docker-in-Docker`.

{% cut "Пример шаблона пода с Docker-in-Docker" %}

```yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-template
spec:
  containers:
    - name: cicd-worker
      image: cr.yandex/sourcecraft/ci/self-hosted-processor:latest
      resources:
        requests:
          cpu: 250m
          memory: 256Mi
        limits:
          cpu: "1"
          memory: 1Gi
      env:
        - name: DOCKER_HOST
          value: "tcp://localhost:2376"
        - name: DOCKER_TLS_VERIFY
          value: "1"
        - name: DOCKER_CERT_PATH
          value: "/.docker-certs/client"
      volumeMounts:
        - name: docker-certs
          mountPath: /.docker-certs
    - name: dind
      image: docker:dind
      securityContext:
        privileged: true
      startupProbe:
        exec:
          command: ["docker", "info"]
        initialDelaySeconds: 5
        periodSeconds: 5
        failureThreshold: 30
      env:
        - name: DOCKER_TLS_CERTDIR
          value: "/.docker-certs"
      resources:
        requests:
          cpu: 500m
          memory: 512Mi
        limits:
          cpu: "2"
          memory: 2Gi
      volumeMounts:
        - name: docker-certs
          mountPath: /.docker-certs
  volumes:
    - name: docker-certs
      emptyDir: {}
```

{% endcut %}

Ресурсы для контейнера с `Docker-in-Docker` выбирайте с учетом предполагаемой нагрузки. Проба запуска для контейнера с `Docker-in-Docker` обязательна — она позволяет избежать ошибок выполнения заданий из-за неготовности `Docker-in-Docker` к работе при высокой нагрузке.

Также можно использовать более безопасный образ `docker:dind-rootless`. В этом случае на узлы кластера Kubernetes необходимо установить дополнительный компонент [sysbox](https://github.com/nestybox/sysbox).

### Запустите воркер {#start-worker}

{% list tabs %}

- В вашем окружении

  1. [Подготовьте](https://sourcecraft.dev/portal/docs/ru/sourcecraft/operations/self-hosted-worker.md#prepare-environment) окружение.
  1. Запустите воркер с конфигурацией, созданной ранее, одним из способов:

      * Передать путь до файла конфигурации в командной строке:

        ```bash
        self-hosted-processor run --config-path <путь_к_config.yaml>
        ```

      * Передать содержимое конфигурации через переменную окружения `PROCESSOR_CONFIG`:

        ```bash
        PROCESSOR_CONFIG="<содержимое_конфигурации>" self-hosted-processor run
        ```

      {% note warning %}

      Без передачи конфигурации воркер не запустится. Одновременно использовать оба способа передачи конфигурации нельзя — в этом случае воркер также не запустится.

      {% endnote %}

- В контейнере

  В реестре доступен базовый Docker-образ контейнера воркера `cr.yandex/sourcecraft/ci/self-hosted-processor:latest`, а также теги конкретных версий.

  В этом образе воркер запускается без указания пути к файлу конфигурации:

  ```Dockerfile
  ENTRYPOINT ["/self-hosted-processor", "run"]
  ```

  Поэтому при запуске контейнера передайте конфигурацию через переменную окружения `PROCESSOR_CONFIG`:

  ```bash
  docker run --rm -e "PROCESSOR_CONFIG=<содержимое_конфигурации>" cr.yandex/sourcecraft/ci/self-hosted-processor:latest
  ```

{% endlist %}

Пример манифеста для запуска воркера внутри кластера Kubernetes приведен в подразделе [Запуск воркера внутри кластера Kubernetes](#example-in-cluster).

## Примеры конфигураций {#examples}

### Запуск воркера вне кластера Kubernetes {#example-out-of-cluster}

Файл конфигурации `config.yaml`:

```yaml
kubernetes:
  kubeconfig_path: /path/to/.kube/config
  namespace: pods-namespace
  pod_template_path: /path/to/pod-template.yaml
  agent:
    port: 8693
    ca_cert_path: /path/to/ca.crt
    client_cert_path: /path/to/client.crt
    client_key_path: /path/to/client.key
  pool_max_size: 10
  pool_min_size: 3

endpoint:
  host: ci.sourcecraft.tech
  port: 443

executor_type: kubernetes

logger_type: json

tags: ["my-tag", "+my-required-tag"]

auth:
  pat: <персональный_токен>
```

Команда запуска:

```shell
self-hosted-processor run --config-path /path/to/config.yaml
```

### Запуск воркера внутри кластера Kubernetes {#example-in-cluster}

Манифест с сервисным аккаунтом, ролью, секретом и развертыванием воркера:

```yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: processor-sa
  namespace: processor-namespace

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: processor-role
  namespace: pods-namespace
rules:
  - apiGroups: [""]
    resources: ["secrets", "pods"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: processor-role-binding
  namespace: pods-namespace
subjects:
  - kind: ServiceAccount
    name: processor-sa
    namespace: processor-namespace
roleRef:
  kind: Role
  name: processor-role
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: v1
kind: Secret
metadata:
  name: processor-secrets
  namespace: processor-namespace
type: Opaque
stringData:
  PROCESSOR_CONFIG: |
    ---
    kubernetes:
      namespace: pods-namespace
      agent:
        port: 8693
      pool_max_size: 10
      pool_min_size: 3

    endpoint:
      host: ci.sourcecraft.tech
      port: 443

    executor_type: kubernetes

    logger_type: json

    tags: ["my-tag", "+my-required-tag"]

  KUBERNETES_POD_TEMPLATE: |
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-template
    spec:
      containers:
        - name: cicd-worker
          image: cr.yandex/sourcecraft/ci/self-hosted-processor:latest
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: "1"
              memory: 1Gi
          env:
            - name: DOCKER_HOST
              value: "tcp://localhost:2376"
            - name: DOCKER_TLS_VERIFY
              value: "1"
            - name: DOCKER_CERT_PATH
              value: "/.docker-certs/client"
          volumeMounts:
            - name: docker-certs
              mountPath: /.docker-certs
        - name: dind
          image: docker:dind
          securityContext:
            privileged: true
          startupProbe:
            exec:
              command: ["docker", "info"]
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 30
          env:
            - name: DOCKER_TLS_CERTDIR
              value: "/.docker-certs"
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: "2"
              memory: 2Gi
          volumeMounts:
            - name: docker-certs
              mountPath: /.docker-certs
      volumes:
        - name: docker-certs
          emptyDir: {}

  KUBERNETES_AGENT_CA_CERT: |
    -----BEGIN CERTIFICATE-----
    certificate content
    -----END CERTIFICATE-----

  KUBERNETES_AGENT_CLIENT_CERT: |
    -----BEGIN CERTIFICATE-----
    certificate content
    -----END CERTIFICATE-----

  KUBERNETES_AGENT_CLIENT_KEY: |
    -----BEGIN PRIVATE KEY-----
    key content
    -----END PRIVATE KEY-----

  PAT_CREDENTIALS: <персональный_токен>

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubernetes-processor
  namespace: processor-namespace
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kubernetes-processor
  template:
    metadata:
      labels:
        app: kubernetes-processor
    spec:
      serviceAccountName: processor-sa
      containers:
        - name: kubernetes-processor
          image: cr.yandex/sourcecraft/ci/self-hosted-processor:latest
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: "1"
              memory: 1Gi
          envFrom:
            - secretRef:
                name: processor-secrets
```

### Полезные ссылки {#see-also}

* [Настроить пользовательский (self-hosted) воркер для SourceCraft](https://sourcecraft.dev/portal/docs/ru/sourcecraft/operations/self-hosted-worker.md)
* [Метки пользовательских (self-hosted) воркеров в SourceCraft](https://sourcecraft.dev/portal/docs/ru/sourcecraft/ci-cd-ref/self-hosted-tags.md)
* [Настроить CI/CD в репозитории SourceCraft](https://sourcecraft.dev/portal/docs/ru/sourcecraft/operations/ci-cd.md)
* [Справочник CI/CD](https://sourcecraft.dev/portal/docs/ru/sourcecraft/ci-cd-ref/index.md)
* [Непрерывная интеграция и непрерывное развертывание в SourceCraft](https://sourcecraft.dev/portal/docs/ru/sourcecraft/concepts/ci-cd.md)
