Kubernetes executor

Tier: Free, Premium, Ultimate Offering: GitLab.com, 자체 관리

Kubernetes executor를 사용하여 빌드를 위해 Kubernetes 클러스터를 사용할 수 있습니다. 이 실행기는 Kubernetes 클러스터 API를 호출하고 각 GitLab CI 작업에 대해 Pod를 생성합니다.

Kubernetes executor는 빌드를 다음과 같은 여러 단계로 나눕니다:

  1. 준비: Kubernetes 클러스터에 Pod 생성. 이는 빌드에 필요한 컨테이너와 서비스를 생성합니다.
  2. 빌드 이전: 이전 단계에서 클론하고 캐시를 복원하고 아티팩트를 다운로드합니다. 이 단계는 Pod의 일부로 특수 컨테이너에서 실행됩니다.
  3. 빌드: 사용자 빌드입니다.
  4. 빌드 이후: 캐시를 생성하고 GitLab에 아티팩트를 업로드합니다. 이 단계도 Pod의 특수한 컨테이너를 사용합니다.

runner가 Kubernetes pod를 생성하는 방법

다음 다이어그램은 GitLab 인스턴스와 Kubernetes 클러스터에 호스팅된 runner 간의 상호 작용을 보여줍니다. runner는 클러스터 상에서 Pod를 생성하기 위해 Kubernetes API를 호출합니다.

service.gitlab-ci.yml 또는 config.toml 파일에서 정의된 경우, Pod에는 다음과 같은 컨테이너가 포함됩니다:

  • build로 정의된 build 컨테이너.
  • helper로 정의된 도우미 컨테이너.
  • svc-X로 정의된 서비스 컨테이너, 여기서 X[0-9]+입니다.

서비스와 컨테이너는 Kubernetes Pod 내에서 실행되며 동일한 localhost 주소를 공유합니다. 다음 제한이 적용됩니다:

  • GitLab Runner 12.8 및 Kubernetes 1.7 이상에서는 서비스가 DNS 이름을 통해 접근 가능합니다. 이전 버전을 사용하는 경우 localhost를 사용해야 합니다.
  • 동일한 포트를 사용하는 여러 서비스를 사용할 수 없습니다. 예를 들어, 동시에 두 개의 mysql 서비스를 가질 수 없습니다.
sequenceDiagram participant G as GitLab 인스턴스 participant R as Kubernetes 클러스터에 호스팅된 Runner participant Kube as Kubernetes API participant P as POD R->>+G: CI 작업 가져오기 loop G-->R: ; end Note over R,G: POST /api/v4/jobs/request G->>+R: CI 작업 데이터 R-->>-Kube: CI 작업을 실행할 POD 생성 Note over R,Kube: Kube API에 POST P->>+P: 작업 실행 Note over P: CI 빌드 작업 = 준비 + 빌드 이전 + 빌드 + 빌드 이후 P->>+G: 작업 로그

다이어그램의 상호 작용은 모든 Kubernetes 클러스터에 대해 유효합니다. 예를 들어, 주요 공개 클라우드 제공 업체 또는 자체 관리 Kubernetes 설치에 호스팅된 솔루션 등이 있습니다.

Kubernetes API에 연결

다음 옵션을 사용하여 Kubernetes API에 연결하세요. 제공된 사용자 계정은 지정된 네임스페이스의 Pod를 생성, 나열 및 연결할 수 있는 권한이 있어야 합니다.

옵션 설명
host 선택적인 Kubernetes apiserver 호스트 URL (지정되지 않은 경우 자동 검색 시도).
cert_file 선택적인 Kubernetes apiserver 사용자 인증 인증서.
key_file 선택적인 Kubernetes apiserver 사용자 인증 개인 키.
ca_file 선택적인 Kubernetes apiserver ca 인증서.

GitLab Runner를 Kubernetes 클러스터에서 실행 중인 경우, 모든 이러한 필드를 생략하여 GitLab Runner가 Kubernetes API를 자동으로 탐지하도록해야합니다.

클러스터 외부에서 GitLab Runner를 실행하는 경우 각 설정을 설정하고 GitLab Runner가 클러스터 상의 Kubernetes API에 액세스 할 수 있도록해야합니다.

Kubernetes API 호출을위한 bearer 토큰 설정

Pod를 만들기위한 API 호출을위한 bearer 토큰을 설정하려면 KUBERNETES_BEARER_TOKEN 변수를 사용하십시오. 이렇게하면 프로젝트 소유자가 프로젝트 비밀 변수를 사용하여 bearer 토큰을 지정할 수 있습니다.

bearer 토큰을 지정할 때 Host 구성 설정을 설정해야합니다.

variables:
  KUBERNETES_BEARER_TOKEN: 다른 네임 스페이스에서 얻은 beartertoken

runner API 권한 구성

코어 API 그룹의 권한을 구성하려면 GitLab Runner Helm 차트의 values.yml 파일을 업데이트하십시오.

다음 중 하나를 선택할 수 있습니다.

  • rbac.createtrue로 설정합니다.
  • 다음 권한과 함께 서비스 계정 rbac.serviceAccountName: <service_account_name>values.yml 파일에 지정합니다.

리소스 동사 (옵션 기능 플래그)
events list, watch (FF_PRINT_POD_EVENTS=true)
namespaces create, delete
pods attach (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), create, delete, exec, get, watch (FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/log get (FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false, FF_WAIT_FOR_POD_TO_BE_REACHABLE=true), list (FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
secrets create, delete, get, update
serviceAccounts get
services create, get
## 구성 설정

`config.toml` 파일에서 Kubernetes 실행기를 구성하는 다음 설정을 사용하십시오.

### CPU 요청과 제한

| 설정 | 설명 |
|---------|-------------|
| `cpu_limit` | 빌드 컨테이너에 할당된 CPU |
| `cpu_limit_overwrite_max_allowed` | 빌드 컨테이너의 CPU 할당에 쓰여질 수 있는 최대량. 비어 있으면 CPU 제한 덮어쓰기 기능이 비활성화됩니다. |
| `cpu_request` | 빌드 컨테이너용 요청된 CPU 할당 |
| `cpu_request_overwrite_max_allowed` | 빌드 컨테이너의 CPU 요청에 쓰여질 수 있는 최대량. 비어 있으면 CPU 요청 덮어쓰기 기능이 비활성화됩니다. |
| `helper_cpu_limit` | 빌드 도우미 컨테이너에 할당된 CPU |
| `helper_cpu_limit_overwrite_max_allowed` | 도우미 컨테이너의 CPU 할당에 쓰여질 수 있는 최대량. 비어 있으면 CPU 제한 덮어쓰기 기능이 비활성화됩니다. |
| `helper_cpu_request` | 빌드 도우미 컨테이너에 요청된 CPU 할당 |
| `helper_cpu_request_overwrite_max_allowed` | 도우미 컨테이너의 CPU 요청에 쓰여질 수 있는 최대량. 비어 있으면 CPU 요청 덮어쓰기 기능이 비활성화됩니다. |
| `service_cpu_limit` | 빌드 서비스 컨테이너에 할당된 CPU |
| `service_cpu_limit_overwrite_max_allowed` | 서비스 컨테이너의 CPU 할당에 쓰여질 수 있는 최대량. 비어 있으면 CPU 제한 덮어쓰기 기능이 비활성화됩니다. |
| `service_cpu_request` | 빌드 서비스 컨테이너용 요청된 CPU 할당 |
| `service_cpu_request_overwrite_max_allowed` | 서비스 컨테이너의 CPU 요청에 쓰여질 수 있는 최대량. 비어 있으면 CPU 요청 덮어쓰기 기능이 비활성화됩니다. |

### 메모리 요청과 제한

| 설정 | 설명 |
|---------|-------------|
| `memory_limit` | 빌드 컨테이너에 할당된 메모리 양 |
| `memory_limit_overwrite_max_allowed` | 빌드 컨테이너의 메모리 할당에 쓰여질 수 있는 최대량. 비어 있으면 메모리 제한 덮어쓰기 기능이 비활성화됩니다. |
| `memory_request` | 빌드 컨테이너가 요청한 메모리 양 |
| `memory_request_overwrite_max_allowed` | 빌드 컨테이너의 메모리 요청에 쓰여질 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능이 비활성화됩니다. |
| `helper_memory_limit` | 빌드 도우미 컨테이너에 할당된 메모리 양 |
| `helper_memory_limit_overwrite_max_allowed` | 도우미 컨테이너의 메모리 할당에 쓰여질 수 있는 최대량. 비어 있으면 메모리 제한 덮어쓰기 기능이 비활성화됩니다. |
| `helper_memory_request` | 빌드 도우미 컨테이너가 요청한 메모리 양 |
| `helper_memory_request_overwrite_max_allowed` | 도우미 컨테이너의 메모리 요청에 쓰여질 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능이 비활성화됩니다. |
| `service_memory_limit` | 빌드 서비스 컨테이너에 할당된 메모리 양 |
| `service_memory_limit_overwrite_max_allowed` | 서비스 컨테이너의 메모리 할당에 쓰여질 수 있는 최대량. 비어 있으면 메모리 제한 덮어쓰기 기능이 비활성화됩니다. |
| `service_memory_request` | 빌드 서비스 컨테이너가 요청한 메모리 양 |
| `service_memory_request_overwrite_max_allowed` | 서비스 컨테이너의 메모리 요청에 쓰여질 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능이 비활성화됩니다. |

### 저장소 요청과 제한

| 설정 | 설명 |
|---------|-------------|
| `ephemeral_storage_limit` | 빌드 컨테이너의 순간적인 저장소 한도 |
| `ephemeral_storage_limit_overwrite_max_allowed` | 빌드 컨테이너의 순간적인 저장소 한도를 덮어쓸 수 있는 최대량. 비어 있으면 순간적인 저장소 한도 덮어쓰기 기능이 비활성화됩니다. |
| `ephemeral_storage_request` | 빌드 컨테이너에 주어진 순간적인 저장소 요청 |
| `ephemeral_storage_request_overwrite_max_allowed` | 빌드 컨테이너의 순간적인 저장소 요청을 덮어쓸 수 있는 최대량. 비어 있으면 순간적인 저장소 요청 덮어쓰기 기능이 비활성화됩니다. |
| `helper_ephemeral_storage_limit` | 도우미 컨테이너에 주어진 순간적인 저장소 한도 |
| `helper_ephemeral_storage_limit_overwrite_max_allowed` | 도우미 컨테이너의 순간적인 저장소 한도를 덮어쓸 수 있는 최대량. 비어 있으면 순간적인 저장소 한도 덮어쓰기 기능이 비활성화됩니다. |
| `helper_ephemeral_storage_request` | 도우미 컨테이너에 주어진 순간적인 저장소 요청 |
| `helper_ephemeral_storage_request_overwrite_max_allowed` | 도우미 컨테이너의 순간적인 저장소 요청을 덮어쓸 수 있는 최대량. 비어 있으면 순간적인 저장소 요청 덮어쓰기 기능이 비활성화됩니다. |
| `service_ephemeral_storage_limit` | 서비스 컨테이너에 주어진 순간적인 저장소 한도 |
| `service_ephemeral_storage_limit_overwrite_max_allowed` | 서비스 컨테이너의 순간적인 저장소 한도를 덮어쓸 수 있는 최대량. 비어 있으면 순간적인 저장소 한도 덮어쓰기 기능이 비활성화됩니다. |
| `service_ephemeral_storage_request` | 서비스 컨테이너에 주어진 순간적인 저장소 요청 |
| `service_ephemeral_storage_request_overwrite_max_allowed` | 서비스 컨테이너의 순간적인 저장소 요청을 덮어쓸 수 있는 최대량. 비어 있으면 순간적인 저장소 요청 덮어쓰기 기능이 비활성화됩니다. |

### 기타 `config.toml` 설정

| 설정 | 설명 |
|---------|-------------|
| `affinity` | 빌드를 실행할 노드를 결정하는 친밀도 규칙을 지정합니다. [친밀도 사용](#define-a-list-of-node-affinities)에 대해 자세히 알아보세요. |
| `allow_privilege_escalation` | 모든 컨테이너를 `allowPrivilegeEscalation` 플래그로 실행합니다. 비어 있으면 컨테이너의 `SecurityContext``allowPrivilegeEscalation` 플래그를 정의하지 않고 Kubernetes가 기본 [권한 상승](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) 동작을 사용합니다. |
| `allowed_images` | `.gitlab-ci.yml`에서 지정할 수 있는 와일드카드 이미지 목록. 누락된 경우 모든 이미지가 허용됩니다(equivalent to `["*/*:*"]`). [세부 정보 보기](#restrict-docker-images-and-services). |
| `allowed_pull_policies` | `.gitlab-ci.yml` 파일 또는 `config.toml` 파일에서 지정할 수 있는 pull 정책 목록. |
| `allowed_services` | `.gitlab-ci.yml`에서 지정할 수 있는 와일드카드 서비스 목록. 누락된 경우 모든 이미지가 허용됩니다(equivalent to `["*/*:*"]`). [세부 정보 보기](#restrict-docker-images-and-services). |
| `automount_service_account_token` | 빌드 파드 내의 서비스 계정 토큰을 자동으로 마운트할지 여부를 제어합니다. |
| `bearer_token` | 빌드 파드를 시작하는 데 사용되는 기본 베어러 토큰. |
| `bearer_token_overwrite_allowed` | 빌드 파드를 생성하는 데 사용될 수 있는 베어러 토큰을 프로젝트에서 지정할 수 있는지 여부를 나타내는 부울 값. |
| `build_container_security_context` | 빌드 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. [보안 컨텍스트 자세히 보기](#set-a-security-policy-for-the-pod). |
| `cap_add` | 작업 파드 컨테이너에 추가해야 하는 Linux 기능을 지정합니다. Kubernetes 실행기에서 기능 구성 자세히 보기. |
| `cap_drop` | 작업 파드 컨테이너에서 제거해야 하는 Linux 기능을 지정합니다. Kubernetes 실행기에서 기능 구성 자세히 보기. |
| `cleanup_grace_period_seconds` | 작업이 완료된 후 파드가 정상적으로 종료되기까지 걸리는 시간(단위: 초). 이 기간이 지나면 프로세스가 강제로 종료됩니다. `terminationGracePeriodSeconds`가 지정되어 있는 경우 무시됩니다. |
| `dns_policy` | 파드를 구성할 때 사용할 DNS 정책을 지정합니다: `none`, `default`, `cluster-first`, `cluster-first-with-host-net`. 지정되지 않은 경우 Kubernetes 기본값(`cluster-first`)이 사용됩니다. |
| `dns_config` | 파드를 구성할 때 사용할 DNS 구성을 지정합니다. [파드의 DNS 구성 사용 자세히 보기](#configure-pod-dns-settings). |
| `helper_container_security_context` | 도우미 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. [보안 컨텍스트 자세히 보기](#set-a-security-policy-for-the-pod). |
| `helper_image` | (고급) 저장소를 복제하고 아티팩트를 업로드하는 데 사용되는 기본 도우미 이미지([자세히 보기](../../configuration/advanced-configuration.md#helper-image)). |
| `helper_image_flavor` | 도우미 이미지 플레이버(`alpine`, `alpine3.16`, `alpine3.17`, `alpine3.18`, `alpine3.19`, 또는 `ubuntu`)를 설정합니다. 기본값은 `alpine`입니다. `alpine`을 사용하는 것은 `alpine3.18`과 같습니다. |
| `host_aliases` | 모든 컨테이너에 추가될 추가 호스트 이름 별칭의 목록. [추가 호스트 별칭 사용 자세히 보기](#add-extra-host-aliases). |
| `image_pull_secrets` | 개인 레지스트리에서 Docker 이미지를 인증하기 위해 사용되는 Kubernetes `docker-registry` 시크릿 이름을 포함하는 항목의 배열. |
| `init_permissions_container_security_context` | init-permissions 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. [보안 컨텍스트 자세히 보기](#set-a-security-policy-for-the-pod). |
| `namespace` | Kubernetes 파드를 실행할 네임스페이스. |
| `namespace_per_job` | 작업을 별도의 네임스페이스에 격리합니다. 활성화된 경우 `namespace``namespace_overwrite_allowed`가 무시됩니다. |
| `namespace_overwrite_allowed` | 네임스페이스 덮어쓰기 환경 변수의 내용을 확인하는 정규 표현식. 비어 있으면 네임스페이스 덮어쓰기 기능이 비활성화됩니다. |
| `node_selector` | `string=string`(`환경 변수의 경우 string:string`) 형식의 `key=value` 쌍으로 된 테이블. 이를 설정하면 모든 `key=value` 쌍이 일치하는 Kubernetes 노드에 파드를 생성하는 것을 제한합니다. [노드 셀렉터 사용 자세히 보기](#specify-the-node-to-execute-builds). |
| `node_tolerations` | `string=string:string` 형식으로 된 `"key=value"="Effect"` 쌍으로 된 테이블. 이를 설정하면 허용된 테인트에 모든 또는 일부에 대한 팟을 스케줄링할 수 있습니다. 환경 변수 구성을 통해 하나의 허용만 제공할 수 있습니다. `key`, `value`, `effect`는 Kubernetes 팟 허용 구성의 해당 필드 이름과 일치합니다. |
| `pod_annotations` | `string=string` 형식으로 된 `key=value` 쌍으로 된 테이블. 이는 실행기가 만든 각 빌드 파드에 추가될 주석 목록입니다. 이 값은 환경 변수 포활 확장을 위해 환경 변수를 포함할 수 있습니다. 빌드마다 파드 주석을 덮어쓸 수 있습니다. |
| `pod_annotations_overwrite_allowed` | 파드 주석 덮어쓰기 환경 변수의 내용을 확인하는 정규 표현식. 비어 있으면 파드 주석 덮어쓰기 기능이 비활성화됩니다. |
| `pod_labels` | `string=string` 형식으로 된 `key=value` 쌍으로 된 테이블. 이는 실행기가 만든 각 빌드 파드에 추가될 레이블 목록입니다. 이 값은 환경 변수 포활 확장을 위해 환경 변수를 포함할 수 있습니다. 빌드마다 파드 레이블을 덮어쓸 수 있습니다. |
| `pod_labels_overwrite_allowed` | 파드 레이블 덮어쓰기 환경 변수의 내용을 확인하는 정규 표현식. 비어 있으면 파드 레이블 덮어쓰기 기능이 비활성화됩니다. |
| `pod_security_context` | 구성 파일을 통해

### 구성 예제

다음 샘플은 쿠버네티스 executor를 위한 `config.toml` 파일의 예제 구성을 보여줍니다.

```toml
concurrent = 4

[[runners]]
  name = "myRunner"
  url = "https://gitlab.com/ci"
  token = "......"
  executor = "kubernetes"
  [runners.kubernetes]
    host = "https://45.67.34.123:4892"
    cert_file = "/etc/ssl/kubernetes/api.crt"
    key_file = "/etc/ssl/kubernetes/api.key"
    ca_file = "/etc/ssl/kubernetes/ca.crt"
    namespace = "gitlab"
    namespace_overwrite_allowed = "ci-.*"
    bearer_token_overwrite_allowed = true
    privileged = true
    cpu_limit = "1"
    memory_limit = "1Gi"
    service_cpu_limit = "1"
    service_memory_limit = "1Gi"
    helper_cpu_limit = "500m"
    helper_memory_limit = "100Mi"
    poll_interval = 5
    poll_timeout = 3600
    dns_policy = "cluster-first"
    priority_class_name = "priority-1"
    logs_base_dir = "/tmp"
    scripts_base_dir = "/tmp"
    [runners.kubernetes.node_selector]
      gitlab = "true"
    [runners.kubernetes.node_tolerations]
      "node-role.kubernetes.io/master" = "NoSchedule"
      "custom.toleration=value" = "NoSchedule"
      "empty.value=" = "PreferNoSchedule"
      "onlyKey" = ""

executor 서비스 계정 구성

executor 서비스 계정을 구성하려면 KUBERNETES_SERVICE_ACCOUNT 환경 변수를 설정하거나 --kubernetes-service-account 플래그를 사용할 수 있습니다.

Pods 및 containers

작업이 실행되는 방식을 제어하기 위해 pods 및 containers를 구성할 수 있습니다.

작업 pods를 위한 기본 주석

다음 주석은 기본적으로 작업을 실행하는 Pod에 추가됩니다:

Key Description
job.runner.gitlab.com/id GitLab 인스턴스 전체에서 고유한 작업 ID입니다.
job.runner.gitlab.com/url 작업 세부 정보에 대한 URL입니다.
job.runner.gitlab.com/sha 프로젝트가 빌드된 커밋 리비전입니다.
job.runner.gitlab.com/before_sha 브랜치 또는 태그에 존재하는 이전 최신 커밋입니다.
job.runner.gitlab.com/ref 프로젝트가 빌드된 브랜치 또는 태그 이름입니다.
job.runner.gitlab.com/name 작업명입니다.
project.runner.gitlab.com/id 작업의 프로젝트 ID입니다.

기본 주석을 덮어쓰려면 GitLab Runner 구성의 pod_annotations를 사용합니다. 또한 .gitlab-ci.yml` 파일에서 각 CI/CD 작업의 주석을 덮어쓸 수도 있습니다.

Pod 라이프사이클

pod의 라이프사이클은 다음과 같이 영향을 받을 수 있습니다:

  • TOML 구성 파일의 pod_termination_grace_period_seconds 속성 설정. Pod에서 실행 중인 프로세스는 TERM 신호가 전송된 후 지정된 기간 동안 실행될 수 있습니다. 이 기간 이후에도 Pod이 성공적으로 종료되지 않으면 kill 신호가 전송됩니다.
  • FF_USE_POD_ACTIVE_DEADLINE_SECONDS feature flag 활성화. 활성화되면 작업이 시간 초과되면 CI/CD 작업을 실행 중인 pod이 실패로 표시되고 모든 관련된 컨테이너가 종료됩니다. 먼저 GitLab에서 작업 시간을 초과하려면 activeDeadlineSeconds구성된 시간 초과 + 1초로 설정됩니다.

참고: FF_USE_POD_ACTIVE_DEADLINE_SECONDS 기능 플래그와 pod_termination_grace_period_seconds이 0이 아닌 값으로 설정된 경우, 작업이 시간 초과되었을 때 CI 작업 pod이 즉시 종료되지 않습니다. pod terminationGracePeriods는 pod이 만료될 때만 종료되도록 보장합니다.

Pod tolerations 덮어쓰기

Kubernetes pod tolerations를 덮어쓰려면:

  1. config.toml 또는 Helm values.yaml 파일에서 CI 변수 이름의 값을 검증하는 정규 표현식으로 node_tolerations_overwrite_allowed를 정의하여 CI 작업 pod tolerations 덮어쓰기를 활성화합니다.

    runners:
     ...
     config: |
       [[runners]]
         [runners.kubernetes]
           node_tolerations_overwrite_allowed = ".*"
    
  2. .gitlab-ci.yml 파일에서 하나 이상의 CI 변수를 정의하여 CI 작업 pod tolerations를 덮어쓸 수 있습니다.

    variables:
      KUBERNETES_NODE_TOLERATIONS_1: 'node-role.kubernetes.io/master:NoSchedule'
      KUBERNETES_NODE_TOLERATIONS_2: 'custom.toleration=value:NoSchedule'
      KUBERNETES_NODE_TOLERATIONS_3: 'empty.value=:PreferNoSchedule'
      KUBERNETES_NODE_TOLERATIONS_4: 'onlyKey'
      KUBERNETES_NODE_TOLERATIONS_5: '' # 모든 taint 받아들이기
    

Pod labels 덮어쓰기

각 CI/CD 작업에 대해 Kubernetes pod labels를 덮어쓰려면:

  1. .config.yaml 파일에서 정규 표현식으로 pod_labels_overwrite_allowed를 정의합니다.
  2. .gitlab-ci.yml 파일에서 KUBERNETES_POD_LABELS_* 변수를 key=value의 값으로 설정하여 pod labels를 덮어씁니다. 여러 값을 적용할 수 있습니다:

     variables:
       KUBERNETES_POD_LABELS_1: "Key1=Val1"
       KUBERNETES_POD_LABELS_2: "Key2=Val2"
       KUBERNETES_POD_LABELS_3: "Key3=Val3"
    

파드 주석 덮어쓰기

각 CI/CD 작업에 대한 Kubernetes 파드 주석을 덮어쓰려면:

  1. .config.yaml 파일에서 pod_annotations_overwrite_allowed에 대한 정규 표현식을 정의합니다.
  2. .gitlab-ci.yml 파일에서 KUBERNETES_POD_ANNOTATIONS_* 변수를 설정하고 값으로 key=value를 사용합니다. 파드 주석이 key=value로 덮어쓰여집니다. 여러 주석을 지정할 수 있습니다:

    variables:
     KUBERNETES_POD_ANNOTATIONS_1: "Key1=Val1"
     KUBERNETES_POD_ANNOTATIONS_2: "Key2=Val2"
     KUBERNETES_POD_ANNOTATIONS_3: "Key3=Val3"
    

아래 예에서 pod_annotationspod_annotations_overwrite_allowed가 설정됩니다. 이 구성은 config.toml에 구성된 pod_annotations 중 하나를 덮어쓸 수 있게 합니다.

[[runners]]
  # 일반적인 구성
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine"
    pod_annotations_overwrite_allowed = ".*"
    [runners.kubernetes.pod_annotations]
      "Key1" = "Val1"
      "Key2" = "Val2"
      "Key3" = "Val3"
      "Key4" = "Val4"

생성된 파드 사양 덮어쓰기

상태: 베타
  • 소개: GitLab Runner 15.10에서 소개되었습니다.

이 기능은 베타 상태입니다. 프로덕션 클러스터에서 사용하기 전에 테스트 Kubernetes 클러스터에서 이 기능을 사용하는 것을 강력히 권장합니다. 이 기능을 사용하려면 FF_USE_ADVANCED_POD_SPEC_CONFIGURATION 피처 플래그를 활성화해야 합니다.

이 기능이 일반적으로 사용 가능하게 되기 전에 개선을 위한 피드백을 추가하려면 이 이슈를 사용하세요.

런너 매니저에서 생성된 PodSpec을 수정하려면 config.toml 파일의 pod_spec 설정을 사용합니다.

pod_spec 설정은 다음을 수행합니다:

  • 생성된 파드 사양에 대한 필드를 덮어씁니다 및 완성시킵니다.
  • GitLab Runner에서 [runners.kubernetes] 아래에 설정된 구성 값을 덮어씁니다.

여러 pod_spec 설정을 구성할 수 있습니다.

설정 설명
name 사용자 정의 pod_spec에 지정된 이름
patch_path 최종 PodSpec 개체에 적용되기 전에 변경을 정의하는 파일의 경로입니다. 파일은 JSON 또는 YAML 파일이어야 합니다.
patch 최종 PodSpec 개체에 적용해야 하는 변경을 설명하는 JSON 또는 YAML 형식 문자열
patch_type 러너가 GitLab Runner에서 생성된 PodSpec에 지정된 변경을 적용하기 위해 사용하는 전략입니다. 허용되는 값은 merge, json, strategic입니다.

patch_pathpatch를 동시에 pod_spec 구성에 설정할 수 없습니다. 그렇지 않으면 오류가 발생합니다.

config.toml에서 여러 pod_spec 설정의 예:

[[runners]]
  [runners.kubernetes]
    [[runners.kubernetes.pod_spec]]
      name = "hostname"
      patch = '''
        hostname: "custom-pod-hostname"
      '''
      patch_type = "merge"
    [[runners.kubernetes.pod_spec]]
      name = "subdomain"
      patch = '''
        subdomain: "subdomain"
      '''
      patch_type = "strategic"
    [[runners.kubernetes.pod_spec]]
      name = "terminationGracePeriodSeconds"
      patch = '''
        [{"op": "replace", "path": "/terminationGracePeriodSeconds", "value": 60}]
      '''
      patch_type = "json"

병합 패치 전략

merge 패치 전략은 기존 PodSpec키-값 대체를 적용합니다. 이 전략을 사용하면 config.tomlpod_spec 구성이 최종 PodSpec 개체에서 값을 덮어쓰기 때문에 이 패치 전략은 신중히 사용해야 합니다.

merge 패치 전략을 사용한 pod_spec 구성의 예:

concurrent = 1
check_interval = 1
log_level = "debug"
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = ""
  url = "https://gitlab.example.com"
  id = 0
  token = "__REDACTED__"
  token_obtained_at = 0001-01-01T00:00:00Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "kubernetes"
  shell = "bash"
  environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"]
  [runners.kubernetes]
    image = "alpine"
    ...
    [[runners.kubernetes.pod_spec]]
      name = "build envvars"
      patch = '''
        containers:
        - env:
          - name: env1
            value: "value1"
          - name: env2
            value: "value2"
          name: build
      '''
      patch_type = "merge"

이 구성으로 최종 PodSpec에는 두 개의 환경 변수 env1env2를 가진 build라는 하나의 컨테이너만 있습니다. 위 예시는 다음과 같이 관련 CI 작업이 실패하는 것으로 나타납니다:

  • helper 컨테이너 사양이 제거됩니다.
  • build 컨테이너 사양에서 GitLab Runner가 설정한 필요한 구성이 모두 잃어버립니다.

이러한 경우 작업이 실패하지 않도록 하려면 이 예시의 pod_spec에는 GitLab Runner에 의해 생성된 속성이 포함되어야 합니다.

JSON 패치 전략

json 패치 전략은 JSON Patch 명세를 사용하여 PodSpec 개체 및 배열을 업데이트하는 데 제어를 제공합니다. 이 전략은 array 속성에는 사용할 수 없습니다.

json 패치 전략을 사용한 pod_spec 구성의 예시입니다. 이 구성에서 새로운 key: value pair가 기존 nodeSelector에 추가됩니다. 기존 값은 덮어쓰지 않습니다.

concurrent = 1
check_interval = 1
log_level = "debug"
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = ""
  url = "https://gitlab.example.com"
  id = 0
  token = "__REDACTED__"
  token_obtained_at = 0001-01-01T00:00:00Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "kubernetes"
  shell = "bash"
  environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"]
  [runners.kubernetes]
    image = "alpine"
    ...
    [[runners.kubernetes.pod_spec]]
      name = "val1 node"
      patch = '''
        { "op": "add", "path": "/nodeSelector", "value": { key1: "val1" } }
      '''
      patch_type = "json"

전략적 패치 전략

전략적 패치 전략은 PodSpec 개체의 각 필드에 적용된 기존 patchStrategy를 사용합니다.

strategic 패치 전략을 사용한 pod_spec 구성의 예시입니다. 이 구성에서 빌드 컨테이너resource request가 설정됩니다.

concurrent = 1
check_interval = 1
log_level = "debug"
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = ""
  url = "https://gitlab.example.com"
  id = 0
  token = "__REDACTED__"
  token_obtained_at = 0001-01-01T00:00:00Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "kubernetes"
  shell = "bash"
  environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"]
  [runners.kubernetes]
    image = "alpine"
    ...
    [[runners.kubernetes.pod_spec]]
      name = "cpu request 500m"
      patch = '''
        containers:
        - name: build
          resources:
            requests:
              cpu: "500m"
      '''
      patch_type = "strategic"

이 구성으로 인해 빌드 컨테이너resource request가 설정됩니다.

모범 사례

  • 프로덕션 환경에 배포되기 전에 테스트 환경에서 추가된 pod_spec를 테스트하세요.
  • pod_spec 구성이 GitLab Runner가 생성한 명세에 부정적인 영향을 미치지 않도록 확인하세요.
  • 복잡한 pod 사양 업데이트에 대해 merge 패치 전략을 사용하지 마세요.
  • 가능한 경우 구성을 사용할 때 config.toml을 사용하세요. 예를 들어, 다음 구성은 첫 번째 환경 변수를 GitLab Runner가 설정한 것으로 대체하여 기존 목록에 설정된 환경 변수를 추가하는 대신 사용자 정의 pod_spec에 설정합니다.
concurrent = 1
check_interval = 1
log_level = "debug"
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = ""
  url = "https://gitlab.example.com"
  id = 0
  token = "__REDACTED__"
  token_obtained_at = 0001-01-01T00:00:00Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "kubernetes"
  shell = "bash"
  environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"]
  [runners.kubernetes]
    image = "alpine"
    ...
    [[runners.kubernetes.pod_spec]]
      name = "build envvars"
      patch = '''
        containers:
        - env:
          - name: env1
            value: "value1"
          name: build
      '''
      patch_type = "strategic"

각 빌드 작업을 위한 PVC 생성을 위한 Pod Spec 수정

각 빌드 작업에 대한 PersistentVolumeClaim를 만들려면 Pod Spec functionality를 활성화하는 방법을 확인하세요.

Kubernetes는 Pod 수명과 연결된 변동성 PersistentVolumeClaim를 만들 수 있습니다. 이는 각 PVC가 새 Volume을 요청할 수 있는 경우에 작동합니다. 즉, 볼륨도 Pod의 수명에 맞게 됩니다.

변동성 할당이 활성화된 후, 다음과 같이 config.toml을 수정하여 변동성 PVC를 만들 수 있습니다:

[[runners.kubernetes.pod_spec]]
  name = "ephemeral-pvc"
  patch = '''
    containers:
    - name: build
      volumeMounts:
      - name: builds
        mountPath: /builds
    - name: helper
      volumeMounts:
      - name: builds
        mountPath: /builds
    volumes:
    - name: builds
      ephemeral:
        volumeClaimTemplate:
          spec:
            storageClassName: <The Storage Class that will dynamically provision a Volume>
            accessModes: [ ReadWriteOnce ]
            resources:
              requests:
                storage: 1Gi
  '''

Pod의 보안 정책 설정

빌드 Pod에 대한 보안 정책을 설정하려면 보안 컨텍스트config.toml에 구성하세요.

다음 옵션을 사용하세요:

옵션 유형 필수여부 설명
fs_group int 아니요 팟의 모든 컨테이너에 적용되는 특별 보충 그룹입니다.
run_as_group int 아니요 컨테이너 프로세스의 진입점을 실행할 GID입니다.
run_as_non_root boolean 아니요 컨테이너가 루트가 아닌 사용자로 실행해야 함을 나타냅니다.
run_as_user int 아니요 컨테이너 프로세스의 진입점을 실행할 UID입니다.
supplemental_groups int list 아니요 컨테이너의 기본 GID에 추가로 적용되는 그룹 목록입니다.
selinux_type string 아니요 팟의 모든 컨테이너에 적용되는 SELinux 유형 라벨입니다.

config.toml에 있는 Pod 보안 컨텍스트의 예시:

concurrent = %(concurrent)s
check_interval = 30
  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"
    [runners.kubernetes]
      helper_image = "gitlab-registry.example.com/helper:latest"
      [runners.kubernetes.pod_security_context]
        run_as_non_root = true
        run_as_user = 59417
        run_as_group = 59417
        fs_group = 59417

이전 러너 파드 제거

가끔씩 이전 러너 파드가 제대로 지워지지 않을 수 있습니다. 이는 러너 매니저가 잘못 종료되었을 때 발생할 수 있습니다.

이 상황을 처리하기 위해 이전 파드를 정리하는 GitLab Runner Pod Cleanup 애플리케이션을 사용할 수 있습니다. 자세한 내용은 다음을 참조하세요:

  • GitLab Runner Pod Cleanup 프로젝트 README.
  • GitLab Runner Pod Cleanup 문서.

컨테이너에 보안 정책 설정

config.toml 실행기의 컨테이너 보안 콘텍스트를 구성하여 빌드, 헬퍼 또는 서비스 파드의 컨테이너 보안 정책을 설정합니다.

다음 옵션을 사용합니다:

옵션 유형 필수 설명
run_as_group int 아니요 컨테이너 프로세스의 진입점을 실행하는 GID입니다.
run_as_non_root boolean 아니요 컨테이너가 반드시 루트가 아닌 사용자로 실행해야 함을 나타냅니다.
run_as_user int 아니요 컨테이너 프로세스의 진입점을 실행하는 UID입니다.
capabilities.add string list 아니요 컨테이너를 실행할 때 추가할 기능(캐퍼빌리티)입니다.
capabilities.drop string list 아니요 컨테이너를 실행할 때 삭제할 기능(캐퍼빌리티)입니다.
selinux_type string 아니요 컨테이너 프로세스와 연관된 SELinux 타입 라벨입니다.

다음은 config.toml에서 보안 콘텍스트 구성의 예시입니다:

  • 파드 보안 콘텍스트 설정
  • 빌드 및 헬퍼 컨테이너에 대해 run_as_userrun_as_group 재정의
  • 모든 서비스 컨테이너가 파드 보안 콘텍스트로부터 run_as_userrun_as_group를 상속받음을 지정
concurrent = 4
check_interval = 30
  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"
    [runners.kubernetes]
      helper_image = "gitlab-registry.example.com/helper:latest"
      [runners.kubernetes.pod_security_context]
        run_as_non_root = true
        run_as_user = 59417
        run_as_group = 59417
        fs_group = 59417
      [runners.kubernetes.init_permissions_container_security_context]
        run_as_user = 1000
        run_as_group = 1000
      [runners.kubernetes.build_container_security_context]
        run_as_user = 65534
        run_as_group = 65534
        [runners.kubernetes.build_container_security_context.capabilities]
          add = ["NET_ADMIN"]
      [runners.kubernetes.helper_container_security_context]
        run_as_user = 1000
        run_as_group = 1000
      [runners.kubernetes.service_container_security_context]
        run_as_user = 1000
        run_as_group = 1000

Pull 정책 설정

config.toml 파일의 pull_policy 매개변수를 사용하여 단일 또는 다중 pull 정책을 지정합니다. 이 정책은 이미지를 가져오고 업데이트하는 방식을 제어하며, 빌드 이미지, 헬퍼 이미지 및 서비스에 적용됩니다.

어떤 정책을 사용할 지 결정하려면 Kubernetes pull 정책에 대한 문서를 참조하세요.

단일 pull 정책의 경우:

[runners.kubernetes]
  pull_policy = "never"

다중 pull 정책의 경우:

[runners.kubernetes]
  # 여러 pull 정책 사용
  pull_policy = ["always", "if-not-present"]

여러 정책을 정의할 경우 이미지가 성공적으로 얻어질 때까지 각 정책이 시도됩니다. 예를 들어 [ always, if-not-present ]를 사용하면 always 정책이 일시적인 레지스트리 문제로 인해 실패하면 if-not-present 정책이 사용됩니다.

실패한 pull을 다시 시도하려면:

[runners.kubernetes]
  pull_policy = ["always", "always"]

GitLab의 네이밍 규칙은 Kubernetes와 다릅니다.

Runner pull 정책 Kubernetes pull 정책 설명
blank blank Kubernetes에서 지정한 기본 정책을 사용합니다.
if-not-present IfNotPresent 이미지는 작업을 실행하는 노드에 이미 존재하지 않을 경우에만 가져옵니다. 보안 고려 사항을 고려해야 합니다.
always Always 작업이 실행될 때마다 이미지를 가져옵니다.
never Never 이미지를 가져오지 않으며, 노드에 이미 있어야 합니다.

컨테이너 기능 설정

컨테이너에서 사용할 Kubernetes 기능을 지정할 수 있습니다.

컨테이너 기능을 지정하려면 config.toml에서 cap_addcap_drop 옵션을 사용합니다. 컨테이너 런타임은 또한 Docker콘테이너와 같이 기본 기능 목록을 정의할 수 있습니다.

러너가 기본적으로 삭제하는 기능 목록이 있습니다. cap_add 옵션에 나열하는 기능은 삭제되지 않습니다.

config.toml 파일의 예시 구성:

concurrent = 1
check_interval = 30
[[runners]]
  name = "myRunner"
  url = "gitlab.example.com"
  executor = "kubernetes"
  [runners.kubernetes]
    # ...
    cap_add = ["SYS_TIME", "IPC_LOCK"]
    cap_drop = ["SYS_ADMIN"]
    # ...

기능을 지정할 때:

  • 사용자 정의 cap_drop이 사용자 정의 cap_add보다 우선권을 가집니다. 두 설정에서 동일한 기능을 정의하면, cap_drop에서만 기능이 컨테이너로 전달됩니다.
  • 컨테이너 구성에 전달되는 기능 식별자에서 CAP_ 접두사를 제거합니다. 예를 들어, CAP_SYS_TIME 기능을 추가하거나 제거하려면 구성 파일에 SYS_TIME이라는 문자열을 입력합니다.
  • Kubernetes 클러스터의 소유자는 PodSecurityPolicy를 정의하여 특정 기능을 허용하거나 제한하거나 기본적으로 추가할 수 있습니다. 이러한 규칙은 사용자 정의 구성보다 우선합니다.

컨테이너 리소스 덮어쓰기

각 CI/CD 작업에 대해 Kubernetes CPU 및 메모리 할당을 덮어쓸 수 있습니다. 빌드, 헬퍼 및 서비스 컨테이너에 대한 요청 및 제한 설정을 적용할 수 있습니다.

컨테이너 리소스를 덮어쓰려면 .gitlab-ci.yml 파일에서 다음 변수를 사용하십시오.

변수의 값은 해당 리소스의 최대 덮어쓰기 설정으로 제한됩니다. 리소스에 대한 최대 덮어쓰기가 설정되지 않은 경우 해당 변수는 사용되지 않습니다.

 variables:
   KUBERNETES_CPU_REQUEST: "3"
   KUBERNETES_CPU_LIMIT: "5"
   KUBERNETES_MEMORY_REQUEST: "2Gi"
   KUBERNETES_MEMORY_LIMIT: "4Gi"
   KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "512Mi"
   KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "1Gi"

   KUBERNETES_HELPER_CPU_REQUEST: "3"
   KUBERNETES_HELPER_CPU_LIMIT: "5"
   KUBERNETES_HELPER_MEMORY_REQUEST: "2Gi"
   KUBERNETES_HELPER_MEMORY_LIMIT: "4Gi"
   KUBERNETES_HELPER_EPHEMERAL_STORAGE_REQUEST: "512Mi"
   KUBERNETES_HELPER_EPHEMERAL_STORAGE_LIMIT: "1Gi"

   KUBERNETES_SERVICE_CPU_REQUEST: "3"
   KUBERNETES_SERVICE_CPU_LIMIT: "5"
   KUBERNETES_SERVICE_MEMORY_REQUEST: "2Gi"
   KUBERNETES_SERVICE_MEMORY_LIMIT: "4Gi"
   KUBERNETES_SERVICE_EPHEMERAL_STORAGE_REQUEST: "512Mi"
   KUBERNETES_SERVICE_EPHEMERAL_STORAGE_LIMIT: "1Gi"

서비스 목록 정의

config.toml에서 services 목록을 정의하십시오.

concurrent = 1
check_interval = 30
  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"
    [runners.kubernetes]
      helper_image = "gitlab-registy.example.com/helper:latest"
      [[runners.kubernetes.services]]
        name = "postgres:12-alpine"
        alias = "db1"
      [[runners.kubernetes.services]]
        name = "registry.example.com/svc1"
        alias = "svc1"
        entrypoint = ["entrypoint.sh"]
        command = ["executable","param1","param2"]
        environment = ["ENV=value1", "ENV2=value2"]

서비스 환경에 HEALTHCHECK_TCP_PORT가 포함된 경우, GitLab Runner는 사용자 CI 스크립트를 시작하기 전에 해당 포트에서 서비스 응답을 대기합니다. 또한 .gitlab-ci.ymlservices 섹션에서 HEALTHCHECK_TCP_PORT 환경 변수를 구성할 수 있습니다.

서비스 컨테이너 리소스 덮어쓰기

작업에 여러 서비스 컨테이너가 있는 경우 각 서비스 컨테이너에 명시적인 리소스 요청과 제한을 설정할 수 있습니다. .gitlab-ci.yml에서 지정된 컨테이너 리소스를 덮어쓰려면 각 서비스의 변수 속성을 사용하십시오.

  services:
    - name: redis:5
      alias: redis5
      variables:
        KUBERNETES_SERVICE_CPU_REQUEST: "3"
        KUBERNETES_SERVICE_CPU_LIMIT: "6"
        KUBERNETES_SERVICE_MEMORY_REQUEST: "3Gi"
        KUBERNETES_SERVICE_MEMORY_LIMIT: "6Gi"
        KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "2Gi"
        KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "3Gi"
    - name: postgres:12
      alias: MY_relational-database.12
      variables:
        KUBERNETES_CPU_REQUEST: "2"
        KUBERNETES_CPU_LIMIT: "4"
        KUBERNETES_MEMORY_REQUEST: "1Gi"
        KUBERNETES_MEMORY_LIMIT: "2Gi"
        KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "1Gi"
        KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "2Gi"

이러한 구체적인 설정은 작업의 일반 설정보다 우선합니다. 값은 여전히 해당 리소스의 최대 덮어쓰기 설정으로 제한됩니다.

기본 Kubernetes 서비스 계정 덮어쓰기

.gitlab-ci.yml 파일에서 각 CI/CD 작업의 Kubernetes 서비스 계정을 덮어쓰려면 KUBERNETES_SERVICE_ACCOUNT_OVERWRITE 변수를 설정하십시오.

이 변수를 사용하여 네임스페이스에 연결된 서비스 계정을 지정할 수 있으며, 복잡한 RBAC 구성에 필요할 수 있습니다.

variables:
  KUBERNETES_SERVICE_ACCOUNT_OVERWRITE: ci-service-account

CI 실행 중에 지정된 서비스 계정만 사용하도록 보장하려면 다음 중 하나에 대한 정규 표현식을 정의하십시오.

  • service_account_overwrite_allowed 설정.
  • KUBERNETES_SERVICE_ACCOUNT_OVERWRITE_ALLOWED 환경 변수.

둘 중 하나도 설정하지 않으면 덮어쓰기가 비활성화됩니다.

RuntimeClass 설정

runtime_class_name을 사용하여 각 작업 컨테이너의 RuntimeClass를 설정하십시오.

RuntimeClass 이름을 지정하고 클러스터에 구성되지 않았거나 해당 기능이 지원되지 않는 경우, 실행자는 작업을 만들지 못합니다.

concurrent = 1
check_interval = 30
  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"
    [runners.kubernetes]
      runtime_class_name = "myclass"

빌드 로그 및 스크립트의 기본 디렉터리 변경

emptyDir 볼륨이 빌드 로그와 스크립트를 위해 팟에 연결된 디렉터리를 변경할 수 있습니다. 다음을 사용할 수 있습니다.

  • 수정된 이미지로 작업 팟 실행.
  • 특권 없는 사용자로 실행.
  • SecurityContext 설정 사용자화.

디렉터리를 변경하려면 다음을 설정하십시오.

  • 빌드 로그의 경우 logs_base_dir 설정.
  • 빌드 스크립트의 경우 scripts_base_dir 설정.

예상되는 값은 슬래시로 끝나지 않는 기본 디렉터리를 나타내는 문자열입니다 (예: /tmp 또는 /mydir/example). 디렉터리는 이미 존재해야 합니다.

이 값은 빌드 로그 및 스크립트의 생성된 경로에 앞쪽에 추가됩니다. 예를 들어:

  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"
    [runners.kubernetes]
      logs_base_dir = "/tmp"
      scripts_base_dir = "/tmp"

이 구성은 다음과 같이 emptyDir 볼륨이 마운트됩니다:

  • 빌드 로그의 경우 /tmp/logs-${CI_PROJECT_ID}-${CI_JOB_ID} 기본 /logs-${CI_PROJECT_ID}-${CI_JOB_ID} 대신.
  • 빌드 스크립트의 경우 /tmp/scripts-${CI_PROJECT_ID}-${CI_JOB_ID}.

사용자 네임스페이스

Kubernetes 1.30 이후 버전에서는 사용자 네임스페이스를 사용하여 컨테이너 내에서 실행되는 사용자를 호스트의 사용자와 분리할 수 있습니다. 컨테이너에서 루트로 실행되는 프로세스는 호스트에서 다른 특권 없는 사용자로 실행될 수 있습니다.

사용자 네임스페이스를 사용하면 CI/CD 작업에 사용될 이미지를 보다 세밀하게 제어할 수 있습니다. 또한 루트로 실행하는 추가 구성(예: 특권 실행)이 호스트의 추가적인 공격 표면을 열지 않고도 작동할 수 있습니다.

이 기능을 사용하려면 클러스터가 적절히 구성되었는지 확인하세요. 다음 예제는 hostUsers 키를 pod_spec에 추가하고 특권 있는 파드와 특권 승격을 모두 비활성화합니다:

  [[runners]]
    environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true"]
    builds_dir = "/tmp/builds"
  [runners.kubernetes]
    logs_base_dir = "/tmp"
    scripts_base_dir = "/tmp"
    privileged = false
    allowPrivilegeEscalation = false
  [[runners.kubernetes.pod_spec]]
    name = "hostUsers"
    patch = '''
      [{"op": "add", "path": "/hostUsers", "value": false}]
    '''
    patch_type = "json"

사용자 네임스페이스를 사용하면 빌드 디렉토리(builds_dir), 빌드 로그(logs_base_dir), 빌드 스크립트(scripts_base_dir)의 기본 경로를 사용할 수 없습니다. 그렇지 않으면 컨테이너의 루트 사용자조차 컨테이너 파일 시스템의 루트에 볼륨을 마운트하거나 디렉토리를 생성할 권한이 없습니다.

대신 빌드 로그와 스크립트의 기본 디렉토리를 변경할 수 있습니다. 또는 [[runners]].builds_dir을 설정하여 빌드 디렉토리를 변경할 수 있습니다.

운영 체제, 아키텍처 및 Windows 커널 버전

Kubernetes 실행자를 사용하는 GitLab Runner는 구성된 클러스터에 해당 운영 체제를 실행하는 노드가 있는 경우 다른 운영 체제에서 빌드를 실행할 수 있습니다.

시스템은 도우미 이미지의 운영 체제, 아키텍처 및 (해당하는 경우) Windows 커널 버전을 결정한 후, 빌드의 다른 측면(예: 사용할 컨테이너 또는 이미지)에 해당 매개변수를 사용합니다.

다음 다이어그램은 시스템이 이러한 세부 정보를 어떻게 감지하는지 설명합니다:

%%|fig-align: center flowchart TB init[<b>초기 기본값</b>:<br/>운영 체제: 리눅스</br>아키텍처: amd64] hasAutoset{구성<br/><tt><a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html">helper_image_autoset_arch_and_os</a> == true</tt>?} setArch[<b>업데이트</b>:<br/>아키텍처: <i>실행자와 동일</i>] isWin{GitLab Runner가 Windows에서 실행됩니까?} setWin[<b>업데이트</b>:<br/>운영 체제: 윈도우<br/>커널 버전: <i>실행자와 동일</i>] hasNodeSel{<a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html"><tt>node_selector</tt></a>가<br/><tt>runners.kubernetes</tt> 섹션에 구성되었습니까?} hasNodeSelOverride{<tt>node_selector</tt>가<br/><a href="https://docs.gitlab.com/runner/executors/kubernetes/#overwrite-the-node-selector">덮어씌움으로</a> 구성되었습니까?} updateNodeSel[<b>설정에서<br/><tt>node_selector</tt></b>로 업데이트(설정된 경우):<br/>운영 체제: <tt>kubernetes.io/os</tt>에서<br/>아키텍처: <tt>kubernetes.io/arch</tt>에서<br/>커널 버전: <tt>node.kubernetes.io/windows-build</tt>에서] updateNodeSelOverride[<b>덮어씌움에서<br/><tt>node_selector</tt>로 업데이트(설정된 경우):</b><br/>운영 체제: <tt>kubernetes.io/os</tt>에서<br/>아키텍처: <tt>kubernetes.io/arch</tt>에서<br/>커널 버전: <tt>node.kubernetes.io/windows-build</tt>에서] result[최종 <b>운영 체제</b>, <b>아키텍처</b>, <b>커널 버전</b>] init --> hasAutoset hasAutoset -->|false | hasNodeSel hasAutoset -->|true | setArch setArch --> isWin isWin -->|false | hasNodeSel isWin -->|true | setWin setWin --> hasNodeSel hasNodeSel -->|false | hasNodeSelOverride hasNodeSel -->|true | updateNodeSel updateNodeSel --> hasNodeSelOverride hasNodeSelOverride -->|false | result hasNodeSelOverride -->|true | updateNodeSelOverride updateNodeSelOverride --> result

다음은 빌드의 운영 체제, 아키텍처 및 Windows 커널 버전 선택에 영향을 주는 유일한 매개변수입니다.

  • helper_image_autoset_arch_and_os 구성
  • 다음에서 가져온 kubernetes.io/os, kubernetes.io/arch, node.kubernetes.io/windows-build 라벨 셀렉터:
    • node_selector 구성
    • 덮어씌움으로 구성된 node_selector

다른 매개변수는 위에 개요된 선택 프로세스에 영향을 미치지 않습니다. 그러나 예를 들어 affinity 구성과 같은 다른 매개변수는 빌드가 예약될 노드를 더 제한하는 데 사용될 수 있습니다.

노드

빌드를 실행할 노드 지정

node_selector 옵션을 사용하여 쿠버네티스 클러스터의 어떤 노드를 빌드 실행에 사용할지 지정할 수 있습니다. 이것은 key=value 쌍으로, string=string 형식(환경 변수의 경우 string:string)입니다.

이 정보를 사용하여 실행에 사용할 운영 체제와 아키텍처를 결정합니다. 이는 올바른 도우미 이미지가 사용됨을 보장합니다. 기본 운영 체제 및 아키텍처는 linux/amd64입니다.

특정 레이블을 사용하여 다른 운영 체제와 아키텍처를 갖는 노드에 빌드를 예약할 수 있습니다.

linux/arm64의 예

  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"

    [runners.kubernetes.node_selector]
      "kubernetes.io/arch" = "arm64"
      "kubernetes.io/os" = "linux"

windows/amd64 예제

Windows용 Kubernetes에는 특정한 제한이 있습니다. 프로세스 격리를 사용하는 경우, 특정 Windows 빌드 버전도 함께 제공해야 합니다. 이 메시지는 node.kubernetes.io/windows-build 레이블에 대한 내용입니다.

  [[runners]]
    name = "myRunner"
    url = "gitlab.example.com"
    executor = "kubernetes"

    # FF_USE_POWERSHELL_PATH_RESOLVER 기능 플래그는 리눅스 환경에서 동작하면서
    # Windows 노드를 대상으로 할 때 PowerShell이 Windows의 경로를 올바르게 해석하도록 해야 합니다.
    environment = ["FF_USE_POWERSHELL_PATH_RESOLVER=true"]

    [runners.kubernetes.node_selector]
      "kubernetes.io/arch" = "amd64"
      "kubernetes.io/os" = "windows"
      "node.kubernetes.io/windows-build" = "10.0.20348"

노드 선택기 덮어쓰기

노드 선택기를 덮어쓰려면 다음을 수행하세요:

  1. config.toml 또는 Helm values.yaml 파일에서 노드 선택기 덮어쓰기를 활성화합니다:

    runners:
     ...
     config: |
       [[runners]]
         [runners.kubernetes]
           node_selector_overwrite_allowed = ".*"
    
  2. .gitlab-ci.yml 파일에서 노드 선택기를 덮어쓰려면 다음 변수를 정의하세요:

    variables:
      KUBERNETES_NODE_SELECTOR_* = ''
    

노드 아키텍처를 덮어쓰기 위해 아래 예제에서 config.toml.gitlab-ci.yml 파일에 설정을 구성합니다.

config.toml
concurrent = 1
check_interval = 1
log_level = "debug"
shutdown_timeout = 0

listen_address = ':9252'

[session_server]
  session_timeout = 1800

[[runners]]
  name = ""
  url = "https://gitlab.com/"
  id = 0
  token = "__REDACTED__"
  token_obtained_at = "0001-01-01T00:00:00Z"
  token_expires_at = "0001-01-01T00:00:00Z"
  executor = "kubernetes"
  shell = "bash"
  [runners.kubernetes]
    host = ""
    bearer_token_overwrite_allowed = false
    image = "alpine"
    namespace = ""
    namespace_overwrite_allowed = ""
    pod_labels_overwrite_allowed = ""
    service_account_overwrite_allowed = ""
    pod_annotations_overwrite_allowed = ""
    node_selector_overwrite_allowed = "kubernetes.io/arch=.*" # <--- 아키텍처 덮어쓰기 허용
.gitlab-ci.yml
job:
  image: IMAGE_NAME
  variables:
    KUBERNETES_NODE_SELECTOR_ARCH: 'kubernetes.io/arch=amd64'  # <--- 아키텍처 선택

노드 어필리티 목록 정의

빌드 시에 파드 사양에 추가할 노드 어필리티 목록을 정의합니다.

참고: node_affinities는 빌드가 실행될 운영 체제를 결정하지 않습니다. 오직 node_selectors만을 결정합니다. 자세한 내용은 운영 체제, 아키텍처 및 Windows 커널 버전을 참조하세요.

config.toml에서의 예제 구성:

concurrent = 1
[[runners]]
  name = "myRunner"
  url = "gitlab.example.com"
  executor = "kubernetes"
  [runners.kubernetes]
    [runners.kubernetes.affinity]
      [runners.kubernetes.affinity.node_affinity]
        [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution]]
          weight = 100
          [runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference]
            [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_expressions]]
              key = "cpu_speed"
              operator = "In"
              values = ["fast"]
            [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_expressions]]
              key = "mem_speed"
              operator = "In"
              values = ["fast"]
        [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution]]
          weight = 50
          [runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference]
            [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_expressions]]
              key = "core_count"
              operator = "In"
              values = ["high", "32"]
            [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_fields]]
              key = "cpu_type"
              operator = "In"
              values = ["arm64"]
      [runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution]
        [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms]]
          [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms.match_expressions]]
            key = "kubernetes.io/e2e-az-name"
            operator = "In"
            values = [
              "e2e-az1",
              "e2e-az2"
            ]

파드를 예정된 노드에 정의하기

다른 파드의 레이블에 기반하여 파드를 예정할 수 있는 노드를 제한하는 데 pod 어필리티 및 안티-어필리티를 사용하세요. config.toml에서의 예제 구성:

concurrent = 1
[[runners]]
  name = "myRunner"
  url = "gitlab.example.com"
  executor = "kubernetes"
  [runners.kubernetes]
    [runners.kubernetes.affinity]
      [runners.kubernetes.affinity.pod_affinity]
        [[runners.kubernetes.affinity.pod_affinity.required_during_scheduling_ignored_during_execution]]
          topology_key = "failure-domain.beta.kubernetes.io/zone"
          namespaces = ["namespace_1", "namespace_2"]
          [runners.kubernetes.affinity.pod_affinity.required_during_scheduling_ignored_during_execution.label_selector]
            [[runners.kubernetes.affinity.pod_affinity.required_during_scheduling_ignored_during_execution.label_selector.match_expressions]]
              key = "security"
              operator = "In"
              values = ["S1"]
        [[runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution]]
        weight = 100
        [runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term]
          topology_key = "failure-domain.beta.kubernetes.io/zone"
          [runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector]
            [[runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector.match_expressions]]
              key = "security_2"
              operator = "In"
              values = ["S2"]
      [runners.kubernetes.affinity.pod_anti_affinity]
        [[runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution]]
          topology_key = "failure-domain.beta.kubernetes.io/zone"
          namespaces = ["namespace_1", "namespace_2"]
          [runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.label_selector]
            [[runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.label_selector.match_expressions]]
              key = "security"
              operator = "In"
              values = ["S1"]
          [runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.namespace_selector]
            [[runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.namespace_selector.match_expressions]]
              key = "security"
              operator = "In"
              values = ["S1"]
        [[runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution]]
        weight = 100
        [runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term]
          topology_key = "failure-domain.beta.kubernetes.io/zone"
          [runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector]
            [[runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector.match_expressions]]
              key = "security_2"
              operator = "In"
              values = ["S2"]
          [runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.namespace_selector]
            [[runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.namespace_selector.match_expressions]]
              key = "security_2"
              operator = "In"
              values = ["S2"]

네트워킹

컨테이너 라이프사이클 후크 구성

컨테이너 라이프사이클 후크를 사용하여 해당 라이프사이클 후크가 실행될 때 구성된 핸들러 코드를 실행합니다.

두 가지 유형의 후크를 구성할 수 있습니다: PreStopPostStart. 각각의 후크는 하나의 유형의 핸들러만 설정할 수 있습니다.

config.toml 파일에서의 예제 구성:

[[runners]]
  name = "kubernetes"
  url = "https://gitlab.example.com/"
  executor = "kubernetes"
  token = "yrnZW46BrtBFqM7xDzE7dddd"
  [runners.kubernetes]
    image = "alpine:3.11"
    privileged = true
    namespace = "default"
    [runners.kubernetes.container_lifecycle.post_start.exec]
      command = ["touch", "/builds/postStart.txt"]
    [runners.kubernetes.container_lifecycle.pre_stop.http_get]
      port = 8080
      host = "localhost"
      path = "/test"
      [[runners.kubernetes.container_lifecycle.pre_stop.http_get.http_headers]]
        name = "header_name_1"
        value = "header_value_1"
      [[runners.kubernetes.container_lifecycle.pre_stop.http_get.http_headers]]
        name = "header_name_2"
        value = "header_value_2"

각 라이프사이클 후크를 구성하는 데 사용하는 설정은 다음과 같습니다:

옵션 유형 필수 설명
exec KubernetesLifecycleExecAction 아니오 Exec은 수행할 동작을 지정합니다.
http_get KubernetesLifecycleHTTPGet 아니오 HTTPGet은 수행할 HTTP 요청을 지정합니다.
tcp_socket KubernetesLifecycleTcpSocket 아니오 TCPsocket은 TCP 포트를 사용하는 동작을 지정합니다.

KubernetesLifecycleExecAction

옵션 유형 필수 설명
command 문자열 리스트 컨테이너 내에서 실행할 명령줄입니다.

KubernetesLifecycleHTTPGet

옵션 유형 필수 설명
port 정수 컨테이너에서 액세스할 포트 번호입니다.
host 문자열 아니오 연결할 호스트 이름으로, 기본값은 pod IP입니다 (선택사항).
path 문자열 아니오 HTTP 서버에서 액세스할 경로입니다 (선택사항).
scheme 문자열 아니오 호스트에 연결하는 데 사용되는 스키마입니다. 기본값은 HTTP입니다 (선택사항).
http_headers KubernetesLifecycleHTTPGetHeader 리스트 아니오 요청에 설정할 사용자 정의 헤더입니다 (선택사항).

KubernetesLifecycleHTTPGetHeader

옵션 유형 필수 설명
name 문자열 HTTP 헤더 이름
value 문자열 HTTP 헤더 값

KubernetesLifecycleTcpSocket

옵션 유형 필수 설명
port 정수 컨테이너에서 액세스할 포트 번호입니다.
host 문자열 아니오 연결할 호스트 이름으로, 기본값은 pod IP입니다 (선택사항).

팟 DNS 설정 구성

팟의 DNS 설정을 구성하기 위해 다음 옵션을 사용합니다.

옵션 유형 필수 설명
nameservers 문자열 리스트 아니오 팟의 DNS 서버로 사용될 IP 주소 목록입니다.
options KubernetesDNSConfigOption 아니오 각 객체는 이름 속성 (필수) 및 값 속성 (선택사항)을 가질 수 있는 선택적 객체 목록입니다.
searches 문자열 리스트 아니오 팟에서 호스트 이름 조회를 위한 DNS 검색 도메인 목록입니다.

config.toml 파일에서의 예제 구성:

concurrent = 1
check_interval = 30
[[runners]]
  name = "myRunner"
  url = "https://gitlab.example.com"
  token = "__REDACTED__"
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine:latest"
    [runners.kubernetes.dns_config]
      nameservers = [
        "1.2.3.4",
      ]
      searches = [
        "ns1.svc.cluster-domain.example",
        "my.dns.search.suffix",
      ]

      [[runners.kubernetes.dns_config.options]]
        name = "ndots"
        value = "2"

      [[runners.kubernetes.dns_config.options]]
        name = "edns0"

KubernetesDNSConfigOption

옵션 유형 필수 설명
name 문자열 구성 옵션 이름
value *문자열 아니오 구성 옵션 값

기본 삭제된 기능 목록

GitLab Runner는 기본적으로 다음 기능을 삭제합니다.

사용자 정의 cap_add는 기본 삭제된 기능 목록보다 우선합니다. 기본적으로 삭제된 기능을 추가하려면 cap_add에 추가하면 됩니다.

  • NET_RAW

추가 호스트 별칭 추가

이 기능은 Kubernetes 1.7 이상에서 사용할 수 있습니다.

컨테이너 내의 /etc/hosts 파일에 항목을 추가하도록 Kubernetes에 지시하기 위해 호스트 별칭을 구성합니다.

다음 옵션을 사용합니다:

옵션 유형 필수 설명
IP 문자열 호스트를 첨부할 IP 주소입니다.
호스트명 문자열 리스트 해당 IP에 첨부될 호스트명 별칭 목록입니다.

config.toml 파일에서의 예제 구성:

concurrent = 4

[[runners]]
  # 일반적인 구성
  executor = "kubernetes"
  [runners.kubernetes]
    [[runners.kubernetes.host_aliases]]
      ip = "127.0.0.1"
      hostnames = ["web1", "web2"]
    [[runners.kubernetes.host_aliases]]
      ip = "192.168.1.1"
      hostnames = ["web14", "web15"]

또한 JSON 입력을 사용하여 명령줄 매개변수 --kubernetes-host_aliases로 호스트 별칭을 구성할 수도 있습니다. 예:

gitlab-runner register --kubernetes-host_aliases '[{"ip":"192.168.1.100","hostnames":["myservice.local"]},{"ip":"192.168.1.101","hostnames":["otherservice.local"]}]'

볼륨

쿠버네티스 실행기와 캐시 사용하기

캐시를 쿠버네티스 실행기와 함께 사용할 때 /cache라는 볼륨이 팟에 장착됩니다. 작업 실행 중에 캐시된 데이터가 필요한 경우 실행기는 캐시된 데이터의 유무를 확인합니다. 압축된 파일이 캐시 볼륨에 있는 경우 캐시된 데이터를 사용할 수 있습니다.

캐시 볼륨을 설정하려면 config.toml 파일의 cache_dir 설정을 사용하세요.

  • 사용 가능한 경우, 압축 파일이 빌드 폴더로 추출되어 작업에서 사용될 수 있습니다.
  • 사용 불가능한 경우, 구성된 저장소에서 캐시된 데이터를 다운로드하고 cache dir에 압축 파일로 저장합니다. 그런 다음 압축 파일이 build 폴더로 추출됩니다.

볼륨 유형 구성

다음과 같은 볼륨 유형을 장착할 수 있습니다:

  • hostPath
  • persistentVolumeClaim
  • configMap
  • secret
  • emptyDir
  • csi

여러 볼륨 유형이 있는 구성 예시:

concurrent = 4

[[runners]]
  # 일반적인 구성
  executor = "kubernetes"
  [runners.kubernetes]
    [[runners.kubernetes.volumes.host_path]]
      name = "hostpath-1"
      mount_path = "/path/to/mount/point"
      read_only = true
      host_path = "/path/on/host"
    [[runners.kubernetes.volumes.host_path]]
      name = "hostpath-2"
      mount_path = "/path/to/mount/point_2"
      read_only = true
    [[runners.kubernetes.volumes.pvc]]
      name = "pvc-1"
      mount_path = "/path/to/mount/point1"
    [[runners.kubernetes.volumes.config_map]]
      name = "config-map-1"
      mount_path = "/path/to/directory"
      [runners.kubernetes.volumes.config_map.items]
        "key_1" = "relative/path/to/key_1_file"
        "key_2" = "key_2"
    [[runners.kubernetes.volumes.secret]]
      name = "secrets"
      mount_path = "/path/to/directory1"
      read_only = true
      [runners.kubernetes.volumes.secret.items]
        "secret_1" = "relative/path/to/secret_1_file"
    [[runners.kubernetes.volumes.empty_dir]]
      name = "empty-dir"
      mount_path = "/path/to/empty_dir"
      medium = "Memory"
    [[runners.kubernetes.volumes.csi]]
      name = "csi-volume"
      mount_path = "/path/to/csi/volume"
      driver = "my-csi-driver"
      [runners.kubernetes.volumes.csi.volume_attributes]
        size = "2Gi"

hostPath 볼륨

hostPath 볼륨을 구성하여 컨테이너에 지정된 호스트 경로를 장착하도록 쿠버네티스에 지시합니다.

config.toml 파일에서 다음 옵션을 사용하세요:

옵션 유형 필수 설명
name string Yes 볼륨의 이름.
mount_path string Yes 볼륨이 장착된 컨테이너 내부의 경로.
sub_path string No 루트 대신 볼륨의 하위 경로를 장착합니다.
host_path string No 볼륨으로 장착할 호스트 경로. 지정되지 않은 경우 mount_path와 같은 경로로 설정됩니다.
read_only boolean No 볼륨을 읽기 전용 모드로 설정합니다(기본값은 false).

persistentVolumeClaim 볼륨

persistentVolumeClaim 볼륨을 구성하여 쿠버네티스에 지시하여 쿠버네티스 클러스터에서 정의된 persistentVolumeClaim를 사용하고 컨테이너에 장착합니다.

config.toml 파일에서 다음 옵션을 사용하세요:

옵션 유형 필수 설명
name string Yes 볼륨의 이름이자 사용해야 하는 PersistentVolumeClaim의 이름입니다. 변수를 지원합니다. 자세한 내용은 Persistent per-concurrency build volumes를 참조하세요.
mount_path string Yes 볼륨이 장착된 컨테이너 내부의 경로.
read_only boolean No 볼륨을 읽기 전용 모드로 설정합니다(기본값은 false).
sub_path string No 루트 대신 볼륨의 하위 경로를 장착합니다.

configMap 볼륨

configMap 볼륨을 구성하여 쿠버네티스에 지시하여 쿠버네티스 클러스터에서 정의된 configMap을 사용하고 컨테이너에 장착합니다.

config.toml에서 다음 옵션을 사용하세요:

옵션 유형 필수 설명
name string Yes 볼륨의 이름이자 사용해야 하는 _configMap_의 이름입니다.
mount_path string Yes 볼륨이 장착된 컨테이너 내부의 경로.
read_only boolean No 볼륨을 읽기 전용 모드로 설정합니다(기본값은 false).
sub_path string No 루트 대신 볼륨의 하위 경로를 장착합니다.
items map[string]string no 사용해야 하는 _configMap_의 키에 대한 키-경로 매핑

configMap의 각 키는 파일로 변경되어 장착 경로에 저장됩니다. 기본적으로:

  • 모든 키가 포함됩니다.
  • configMap 키가 파일 이름으로 사용됩니다.
  • 값은 파일 컨텐츠에 저장됩니다.

기본 키 및 값 저장을 변경하려면 items 옵션을 사용하세요. items 옵션을 사용하는 경우 지정된 키만 볼륨에 추가되고 다른 모든 키는 건너뜁니다.

참고: 존재하지 않는 키를 사용하는 경우, 팟 생성 단계에서 작업이 실패합니다.

secret 볼륨

Kubernetes에게 지정된 secret을 사용하도록 지시하고 컨테이너에 마운트하는 secret 볼륨을 구성합니다.

config.toml 파일에서 다음 옵션을 사용하십시오.

옵션 타입 필수 설명
name string Yes 볼륨의 이름 및 동시에 사용해야 할 _secret_의 이름입니다.
mount_path string Yes 볼륨을 마운트해야 하는 컨테이너 내부 경로입니다.
read_only boolean No 볼륨을 읽기 전용 모드로 설정합니다 (기본값은 false입니다).
sub_path string No 루트가 아닌 볼륨 내의 서브 경로를 마운트합니다.
items map[string]string No 사용해야 하는 _configMap_의 키에 대한 키-경로 매핑입니다.

선택된 secret의 각 키는 선택된 마운트 경로에 저장된 파일로 변경됩니다. 기본 설정은 다음과 같습니다.

  • 모든 키가 포함됩니다.
  • configMap 키가 파일 이름으로 사용됩니다.
  • 값은 파일 내용에 저장됩니다.

기본 키 및 값을 변경하려면 items 옵션을 사용하십시오. items 옵션을 사용하면 지정된 키만 볼륨에 추가되고 다른 모든 키는 건너뜁니다.

참고: 존재하지 않는 키를 사용하면 pod 생성 단계에서 작업이 실패합니다.

emptyDir 볼륨

Kubernetes에게 컨테이너 내부에 빈 디렉토리를 마운트하도록 지시하고 emptyDir 볼륨을 구성합니다.

config.toml 파일에서 다음 옵션을 사용하십시오.

옵션 타입 필수 설명
name string Yes 볼륨의 이름입니다.
mount_path string Yes 볼륨을 마운트해야 하는 컨테이너 내부 경로입니다.
sub_path string No 루트가 아닌 볼륨 내의 서브 경로를 마운트합니다.
medium string No “Memory”는 tmpfs를 제공하며, 그렇지 않으면 노드 디스크 저장소(기본값은 ““)에 기본 설정됩니다.
size_limit string No emptyDir 볼륨에 필요한 로컬 저장소의 총량입니다.

csi 볼륨

컨테이너 내에서 임의의 저장 시스템을 마운트하기 위해 사용자 정의 csi 드라이버를 사용하도록 Kubernetes에게 지시하는 컨테이너 스토리지 인터페이스(csi) 볼륨을 구성합니다.

config.toml에서 다음 옵션을 사용하십시오.

옵션 타입 필수 설명
name string Yes 볼륨의 이름입니다.
mount_path string Yes 볼륨을 마운트해야 하는 컨테이너 내부 경로입니다.
driver string Yes 사용할 볼륨 드라이버의 이름을 지정하는 문자열 값입니다.
fs_type string No 파일 시스템 유형의 이름을 지정하는 문자열 값입니다 (예: “ext4”, “xfs”, “ntfs”.).
volume_attributes map[string]string No CSI 볼륨의 속성에 대한 키-값 쌍 매핑입니다.
sub_path string No 루트가 아닌 볼륨 내의 서브 경로를 마운트합니다.
read_only boolean No 볼륨을 읽기 전용 모드로 설정합니다 (기본값은 false입니다).

서비스 컨테이너에 볼륨 마운트

빌드 컨테이너에 정의된 볼륨은 모든 서비스 컨테이너에 자동으로 마운트됩니다. 이 기능을 사용하여 services_tmpfs (Docker executor에서만 사용 가능)의 대안으로 사용하고 테스트를 가속화하기 위해 RAM에 데이터베이스 저장소를 마운트할 수 있습니다.

config.toml 파일의 예제 구성:

[[runners]]
  # 일반적인 구성
  executor = "kubernetes"
  [runners.kubernetes]
    [[runners.kubernetes.volumes.empty_dir]]
      name = "mysql-tmpfs"
      mount_path = "/var/lib/mysql"
      medium = "Memory"

사용자 정의 볼륨 마운트

작업용 빌드 디렉토리를 저장하려면 구성된 builds_dir (/builds가 기본)에 대한 사용자 정의 볼륨 마운트를 정의하십시오. PVC 볼륨을 사용하는 경우, 액세스 모드에 따라 하나의 노드에서만 작업을 실행할 수 있는 제한이 있을 수 있습니다.

config.toml 파일의 예제 구성:

concurrent = 4

[[runners]]
  # 일반적인 구성
  executor = "kubernetes"
  builds_dir = "/builds"
  [runners.kubernetes]
    [[runners.kubernetes.volumes.empty_dir]]
      name = "repo"
      mount_path = "/builds"
      medium = "Memory"

지속적으로 병행하는 빌드 볼륨

  • GitLab 16.3에서 pvc.name에 대한 변수 주입 지원 발표.

기본적으로 Kubernetes CI 작업의 빌드 디렉토리는 단기간입니다. GIT_STRATEGY=fetch를 사용하여 Git 클론을 지속하려면 빌드 폴더에 대한 지속 볼륨 클레임을 마운트해야 합니다. 여러 작업이 동시에 실행될 수 있으므로 ReadWriteMany 볼륨을 사용하거나 각 잠재적인 병행 작업에 대한 볼륨을 하나씩 가져야 합니다. 후자가 성능상 더 좋을 가능성이 높습니다. 다음은 이러한 구성의 예입니다:

concurrent = 4

[[runners]]
  executor = "kubernetes"
  builds_dir = "/mnt/builds"
  [runners.kubernetes]
    [[runners.kubernetes.volumes.pvc]]
      # CI_CONCURRENT_ID는 동일한 러너의 병렬 작업을 식별합니다.
      name = "build-pvc-$CI_CONCURRENT_ID"
      mount_path = "/mnt/builds"

이 예에서는 build-pvc-0에서 build-pvc-3까지의 지속 볼륨 클레임을 직접 생성하십시오. 러너의 동시성 설정에 따라 많이 만드십시오.

도우미 이미지 사용

보안 정책을 설정한 후 도우미 이미지는 해당 정책을 준수해야 합니다. 이 이미지는 루트 그룹에서 권한을받지 않으므로 사용자 ID가 루트 그룹의 일부인지 확인해야 합니다.

참고: nonroot 환경만 필요한 경우 GitLab Runner UBIGitLab Runner Helper UBI OpenShift (OCP) 이미지 대신 도우미 이미지를 사용할 수 있습니다.

다음 예제는 nonroot라는 사용자 및 그룹을 생성하고 도우미 이미지를 해당 사용자로 실행하도록 설정합니다.

ARG tag
FROM registry.gitlab.com/gitlab-org/ci-cd/gitlab-runner-ubi-images/gitlab-runner-helper-ocp:${tag}
USER root
RUN groupadd -g 59417 nonroot && \
    useradd -u 59417 nonroot -g nonroot
WORKDIR /home/nonroot
USER 59417:59417

빌드에서 도커 사용

빌드에서 도커를 사용하는 경우 고려해야 할 사항이 있습니다.

노출된 /var/run/docker.sock

runners.kubernetes.volumes.host_path 옵션을 사용하여 호스트의 /var/run/docker.sock을 빌드 컨테이너로 노출하는 경우 일부 위험이 발생할 수 있습니다. 노드의 컨테이너는 빌드 컨테이너에서 접근 가능하며, 프로덕션 컨테이너와 동일한 클러스터에서 빌드를 실행하는 경우 그렇게 하는 것이 현명하지 않을 수 있습니다.

docker:dind 사용

docker:dind, 즉 docker-in-docker 이미지를 실행하는 경우 컨테이너는 특권 모드로 실행되어야 합니다. 이로 인해 잠재적인 위험이 발생하고 추가 문제가 발생할 수 있습니다.

도커 데몬은 서비스로 시작되기 때문에 파드 내에서 별도의 컨테이너로 실행됩니다. 파드의 컨테이너는 할당된 볼륨과 localhost를 사용하여 서로 통신하는 IP 주소를 공유합니다. docker:dind 컨테이너는 /var/run/docker.sock을 공유하지 않으며 docker 바이너리는 기본적으로 사용하려고 시도합니다.

다른 컨테이너에서 Docker 데몬에 연락하기 위해 클라이언트를 구성하려면 빌드 컨테이너의 환경 변수를 포함하세요.

  • TLS 연결을 사용하지 않는 경우 DOCKER_HOST=tcp://<hostname>:2375.
  • TLS 연결을 사용하는 경우 DOCKER_HOST=tcp://<hostname>:2376.

hostname에 대한 값으로 다음을 설정합니다.

  • GitLab Runner 12.7 및 이전 버전, Kubernetes 1.6 및 이전 버전의 경우 localhost.
  • GitLab Runner 12.8 및 이후 버전, Kubernetes 1.7 및 이후 버전의 경우 docker.

Docker 19.03 이후에는 TLS가 기본적으로 사용되지만 클라이언트에 인증서를 매핑해야 합니다. DIND에 대해 TLS 연결을 사용하지 않거나 인증서를 마운트할 수 있습니다. 자세한 내용은 Docker 실행자를 사용한 Docker In Docker Workflow를 참조하세요.

호스트 커널 노출 방지

docker:dind 또는 /var/run/docker.sock을 사용하는 경우 도커 데몬은 호스트 머신의 기본 커널에 액세스할 수 있습니다. 이는 쿠버네티스로 생성된 빌드 컨테이너에서 설정된 limits가 작동하지 않음을 의미합니다. 도커 빌드 컨테이너를 시작하는 노드장에서의 제약이 없이 풀 용량을 보고합니다.

특권 모드로 빌드 컨테이너를 실행하거나 /var/run/docker.sock을 노출하는 경우 호스트 커널이 빌드 컨테이너에 노출될 수 있습니다. 노출을 최소화하기 위해 node_selector 옵션에 레이블을 지정하세요. 이렇게 하면 컨테이너가 배포되기 전에 노드가 레이블과 일치하는지 확인됩니다. 예를 들어, role=ci 레이블을 지정하면 빌드 컨테이너는 role=ci로 레이블이 지정된 노드에서만 실행되며, 모든 다른 프로덕션 서비스는 다른 노드에서 실행됩니다.

빌드 컨테이너를 더욱 분리하기 위해 노드 taints를 사용할 수 있습니다. Taints를 사용하면 다른 파드가 빌드 파드와 동일한 노드에 예약되지 않도록 추가 구성할 필요 없이 빌드 파드를 별도로 분리할 수 있습니다.

Docker 이미지 및 서비스 제한

  • GitLab Runner 14.2에서 Kubernetes 실행자에 추가됨.

사용되는 Docker 이미지를 제한할 수 있습니다. 이를 위해 와일드카드 패턴을 지정합니다. 예를 들어, 개인 Docker 레지스트리에서 이미지만 허용하려면 다음과 같이 지정합니다.

[[runners]]
  (...)
  executor = "kubernetes"
  [runners.kubernetes]
    (...)
    allowed_images = ["my.registry.tld:5000/*:*"]
    allowed_services = ["my.registry.tld:5000/*:*"]

또는 이 레지스트리의 특정 이미지 목록으로 제한할 수 있습니다.

[[runners]]
  (...)
  executor = "kubernetes"
  [runners.kubernetes]
    (...)
    allowed_images = ["my.registry.tld:5000/ruby:*", "my.registry.tld:5000/node:*"]
    allowed_services = ["postgres:9.4", "postgres:latest"]

Docker Pull 정책 제한

.gitlab-ci.yml 파일에서 Pull 정책을 지정할 수 있습니다. 이 정책은 CI/CD 작업이 이미지를 가져오는 방법을 결정합니다.

.gitlab-ci.yml 파일에서 사용할 수 있는 Pull 정책을 제한하려면 allowed_pull_policies를 사용할 수 있습니다.

예를 들어, alwaysif-not-present Pull 정책만 허용하려면:

[[runners]]
  (...)
  executor = "kubernetes"
  [runners.kubernetes]
    (...)
    allowed_pull_policies = ["always", "if-not-present"]
  • allowed_pull_policies를 지정하지 않으면 기본값은 pull_policy 키워드의 값입니다.
  • pull_policy를 지정하지 않으면 클러스터의 이미지 기본 Pull 정책이 사용됩니다.
  • 기존의 pull_policy 키워드에는 allowed_pull_policies에 지정되지 않은 Pull 정책이 포함되어서는 안 됩니다. 그렇게 되면 작업이 오류를 반환합니다.

작업 실행

  • 기본적으로 사용 가능한 기능 플래그 FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY를 통해 활성화됩니다.
  • GitLab Runner 14.0에서 기본적으로 attach 사용.

GitLab Runner는 기본적으로 kube exec 대신 kube attach를 사용합니다. 이렇게 함으로써, 불안정한 네트워크 환경에서 작업이 중간에 성공으로 표시될 때 발생하는 문제와 같은 문제를 방지할 수 있습니다.

GitLab Runner 14.0으로 업데이트한 후 문제가 발생하면 특성 플래그 FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGYtrue로 전환하고 이슈를 제출하세요.

렬 #27976](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27976)을 참고하여 레거시 실행 전략의 진행 상황을 확인하세요.

Kubernetes API로의 요청 시도 횟수 구성

기본적으로 Kubernetes 실행자는 Kubernetes API로의 특정 요청을 5회의 실패한 시도 이후에 다시 시도합니다. 지연은 500밀리초의 바닥과 기본값으로 2초의 사용자 정의 천장을 사용하는 백오프 알고리즘에 의해 제어됩니다. 재시도 회수와 백오프 천장을 구성하려면 각각 retry_limitretry_backoff_max 옵션을 config.toml 파일에서 사용하세요. 다음과 같은 실패는 자동으로 재시도됩니다:

각 오류에 대한 재시도 횟수를 제어하려면 retry_limits 옵션을 사용하세요. rety_limits는 각 오류에 대한 재시도 횟수를 별도로 지정하며, 오류 메시지에서 재시도 회수로의 맵핑입니다. 오류 메시지는 Kubernetes API에서 반환된 오류 메시지의 부분 문자열일 수 있습니다. retry_limits 옵션은 retry_limit 옵션보다 우선합니다.

예를 들어, 환경에서 TLS 관련 오류의 횟수를 제어해야 한다면, retry_limits 옵션을 구성하여 해당 오류를 기본 5회가 아닌 10회로 재시도할 수 있습니다:

[[runners]]
  name = "myRunner"
  url = "https://gitlab.example.com/"
  executor = "kubernetes"
  [runners.kubernetes]
    retry_limit = 5

    [runners.kubernetes.retry_limits]
        "TLS handshake timeout" = 10
        "tls: internal error" = 10

20회로 전체적으로 다른 오류를 재시도하려면, 예를 들어 exceeded quota인 경우:

[[runners]]
  name = "myRunner"
  url = "https://gitlab.example.com/"
  executor = "kubernetes"
  [runners.kubernetes]
    retry_limit = 5

    [runners.kubernetes.retry_limits]
        "exceeded quota" = 20

컨테이너 엔트리포인트 알려진 문제

참고: GitLab Runner 15.0에서 kube attach를 사용하는 경우, Docker 이미지에서 정의된 엔트리포인트가 사용됩니다. GitLab 15.1부터는 FF_KUBERNETES_HONOR_ENTRYPOINT가 설정된 경우 Kubernetes 실행자와 함께 Docker 이미지에서 정의된 엔트리포인트가 사용됩니다.

컨테이너 엔트리포인트에는 다음과 같은 알려진 문제가 있습니다:

  • Dockerfile에서 이미지의 엔트리포인트가 정의된 경우, 유효한 셸을 열어야 합니다. 그렇지 않으면 작업이 대기 상태에 머무릅니다.

    • 셸을 열려면 시스템이 빌드 컨테이너의 args 으로 명령을 전달합니다.
  • 엔트리포인트가 실행될 때 파일 유형 CI/CD 변수 는 디스크에 기록되지 않습니다. 파일은 스크립트 실행 중에만 접근할 수 있습니다.
  • 다음과 같은 CI/CD 변수는 엔트리포인트에서 접근할 수 없습니다. 스크립트 명령을 실행하기 전에 before_script를 사용하여 설정 변경을 수행할 수 있습니다:

GitLab Runner 17.4 이전:

  • 엔트리포인트 로그는 빌드 로그로 전달되지 않았습니다.
  • kube exec를 사용하는 Kubernetes 실행자의 경우, GitLab Runner는 엔트리포인트가 셸을 열기를 기다리지 않았습니다(위의 항목 참조).

GitLab Runner 17.4부터 엔트리포인트 로그가 전달됩니다. 시스템은 엔트리포인트가 실행되고 셸을 생성하기를 기다립니다. 이에 따라 다음과 같은 영향이 있습니다:

  • FF_KUBERNETES_HONOR_ENTRYPOINT가 설정되고 이미지의 엔트리포인트가 poll_timeout(기본값: 180초)보다 오랜 시간이 걸린다면 빌드가 실패합니다. 엔트리포인트가 예상보다 오랜 시간이 걸리면 poll_timeout 값(그리고 잠재적으로 poll_interval 값)을 조정해야 합니다.
  • FF_KUBERNETES_HONOR_ENTRYPOINTFF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY가 설정된 경우 시스템은 빌드 컨테이너에 startup probe를 추가하여 엔트리포인트가 셸을 스폰하는 시점을 알 수 있습니다. 사용자 정의 엔트리포인트가 args를 통해 예상되는 셸을 스폰하는 경우에는 startup probe가 자동으로 해결됩니다. 그러나 컨테이너 이미지가 args를 통해서가 아닌 엔트리포인트를 생성하는 경우, 엔트리포인트는 빌드 디렉토리의 루트에 .gitlab-startup-marker라는 파일을 생성하여 startup probe를 직접 해결해야 합니다. startup probe는 .gitlab-startup-marker 파일을 poll_interval마다 확인합니다. poll_timeout 내에 파일이 없으면 pod가 위험 상태로 간주되고 시스템은 빌드를 중단합니다.

작업 변수 액세스 제한

Kubernetes 실행기를 사용할 때 Kubernetes 클러스터에 액세스 권한이 있는 사용자는 작업에서 사용되는 변수를 읽을 수 있습니다. 기본적으로 작업 변수는 다음 위치에 저장됩니다:

  • Pod의 환경 섹션

작업 변수 데이터 액세스를 제한하려면, GitLab 관리자 만이 GitLab Runner가 사용하는 네임스페이스에 액세스할 수 있도록 역할 기반 액세스 제어(RBAC)를 사용해야 합니다.

다른 사용자가 GitLab Runner 네임스페이스에 액세스해야 하는 경우, 다음 동사를 설정하여 GitLab Runner 네임스페이스에서 사용자가 가지는 액세스 유형을 제한해야합니다:

  • podsconfigmaps에 대해:
    • get
    • watch
    • list
  • pods/execpods/attach에 대해 create를 사용하세요.

인가된 사용자를 위한 예시 RBAC 정의:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: gitlab-runner-authorized-users
rules:
- apiGroups: [""]
  resources: ["configmaps", "pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: [""]
  resources: ["pods/exec", "pods/attach"]
  verbs: ["create"]

준비 단계 중 리소스 확인

필수 구성 요소:

  • image_pull_secrets 또는 service_account가 설정되어 있어야 합니다.
  • resource_availability_check_max_attempts는 0보다 큰 숫자로 설정되어 있어야 합니다.
  • Kubernetes serviceAccountgetlist 권한으로 사용됩니다.

GitLab Runner는 새로운 서비스 계정 또는 비밀을 사용 가능한지 5초 간격으로 확인합니다.

  • GitLab 15.0 및 15.1에서는 이 기능을 비활성화할 수 없으며 음수 값으로 설정되면 기본적으로 5로 설정됩니다.
  • GitLab 15.0.1, 15.1.1, 15.2 및 이후 버전에서는 이 기능이 기본적으로 비활성화됩니다. 이 기능을 활성화하려면 resource_availability_check_max_attempts0이 아닌 다른 값으로 설정하세요. 설정한 값은 Runner가 서비스 계정 또는 비밀을 확인하는 횟수를 정의합니다.

Kubernetes 네임스페이스 덮어쓰기

필수 구성 요소:

  • GitLab Runner Helm 차트의 values.yml 파일에서 rbac.clusterWideAccesstrue로 설정되어 있어야 합니다.
  • Runner가 핵심 API 그룹에 구성된 권한이 있어야 합니다.

CI 목적으로 네임스페이스를 지정하고 사용자 지정 pod 세트를 배포하려면 Kubernetes 네임스페이스를 덮어쓸 수 있습니다. Runner에 의해 생성된 pod는 CI 단계에서 컨테이너 간 액세스를 가능하게 하기 위해 덮어쓰인 네임스페이스에 있습니다.

각 CI/CD 작업에 대해 Kubernetes 네임스페이스를 덮어쓰려면 .gitlab-ci.yml 파일에서 KUBERNETES_NAMESPACE_OVERWRITE 변수를 설정하세요.

variables:
  KUBERNETES_NAMESPACE_OVERWRITE: ci-${CI_COMMIT_REF_SLUG}

참고: 이 변수는 클러스터에서 네임스페이스를 생성하지 않습니다. 작업을 실행하기 전에 해당 네임스페이스가 존재하는지 확인하세요.

CI 실행 중에 지정된 네임스페이스만 사용하려면 config.toml 파일에서 namespace_overwrite_allowed에 대한 정규 표현식을 정의하세요:

[runners.kubernetes]
    ...
    namespace_overwrite_allowed = "ci-.*"

Kubernetes 클러스터의 고장 허용

GitLab Runner의 고장 허용 기능은 Runner 관리자가 다시 시작될 때 Kubernetes pod 및 작업이 Running 상태로 멈춰있는 오리피닝 리소스(예: Kubernetes pod)를 방지하는 데 도움을 줍니다.

다음 단계에서는 전형적인 조건 하에서 작업 실행 방법에 대해 설명합니다. Runner 관리자:

  1. GitLab에서 작업을 수신합니다.
  2. Kubernetes에서 작업 pod를 생성합니다.
  3. 작업 pod에서 실행할 명령을 전송합니다.
  4. 작업 로그와 상태를 읽고 해당 정보를 GitLab으로 다시 전송합니다. 그런 다음, GitLab은 UI를 새로 고칩니다.
%%{init: { "fontFamily": "GitLab Sans" }}%% flowchart LR accTitle: Kubernetes에서 전형적인 작업 실행 흐름. accDescr: 작업 실행 흐름을 나타내는 다이어그램이며, 여기서 작업은 GitLab에서 Runner 관리자로, 그리고 Kubernetes 작업 pod로 이동합니다. gitlab[(GitLab)] -.->|Job| manager((Runner 관리자)) manager ===> |Job logs/status| gitlab manager -.->|Create| pod[[Kubernetes 작업 Pod]] manager -.->|Send Commands| pod manager -.->|Cleanup| pod pod ====>|Job logs/status| manager

Kubernetes에서 Runner 관리자 pod을 호스팅하는 노드가 클러스터에서 제거될 때, Runner pod는 오립니다. 이러한 pod은 다른 메커니즘에 의해 제거될 때까지 계속 실행됩니다. 새로운 Runner 관리자는 활성화된 Runner pod 및 관련된 CI/CD 작업에 액세스할 수 없습니다. 결과적으로, 오립된 Runner pod는 클러스터에서 계속해서 리소스를 소비합니다. 작업이 구성된 타임아웃으로 인해 최종적으로 실패할 때까지, GitLab UI는 작업 상태를 업데이트하지 않습니다.

고장 허용 기능을 사용하면, GitLab Runner가 작업을 중단한 곳에서 다시 실행합니다.

GitLab Runner는 각 작업의 Job실행 상태구성된 저장소에 저장합니다. 새로운 작업을 요청하기 전에 GitLab은 이미 실행 중인 작업에 대한 저장소를 확인합니다.

고장 허용 Runner 관리자:

  1. Stateful Executor인 경우, 구성된 저장소를 생성합니다.

    • 구성된 저장소가 설정되어 있지 않지만, 실행기가 Stateful인 경우, no-op (no operation) 저장소가 사용됩니다. 추가 로직 분기 없이 데이터 호출을 줄일 수 있도록 no-op 저장소를 사용할 수 있습니다.

      store := NewNoopStore()
      if isStatefulExecutor := executor.(StatefulExecutor); isStatefulExecutor {
       store, _ = provider.GetStore(runnerConfig)
      }
      
  2. 일반적으로 작업을 실행하지만, 주기적으로 또는 특정 이벤트에서 그들을 저장소에 기록합니다.
  3. 다시 시작 시 저장소에서 실행 중인 작업을 확인합니다.

    최근에 업데이트되지 않은 작업이 있는 경우, Runner는:

    1. 작업을 재개합니다.
    2. 작업 실행 시작 시 Runner가 많은 작업 로그를 생성하므로, 로그 중복을 방지하기 위해 모든 추적 로그를 비활성화합니다.
    3. 먼저 Kubernetes 실행기에서 State Metadata를 복원합니다.

      type executorStateMetadata struct {
        // 실행기에 의해 생성된 비밀
       Credentials *api.Secret   `json:"credentials"`
       // 빌드 pod
       Pod         *api.Pod      `json:"pod"`
       // 서비스
       Services    []api.Service `json:"services"`
       // 작업 로그를 읽기 시작할 오프셋
       Offset      int64         `json:"offset"`
      }
      
      // 이러한 리소스의 이름과 네임스페이스만이 저장소에 직렬화됩니다.
      /*
      {
       credentials: { name: "", namespace: "" }
       pod: { name: "", namespace: "" }
       services: [{ name: "", namespace: "" }]
       offset: 0
      }
      */
      
    4. 실행기의 Prepare 메서드를 호출하여 작업 처리를 설정합니다.
    5. 추적 로깅을 다시 사용하고 작업을 재개합니다.
    6. StatefulExecutor 인터페이스의 일부인 Restore 메서드를 호출합니다. 이 메서드는 전체 API 개체를 가져오기 위해 Kubernetes 클러스터에 쿼리를 실행합니다.

      func (s *executor) Restore(ctx context.Context) error {
       s.state.Pod, _ = s.kubeClient.CoreV1().Pods(s.state.Pod.Namespace).Get(s.state.Pod.Name)
       s.state.Credentials, _ = s.kubeClient.CoreV1().Secrets(s.state.Credentials.Namespace).Get(s.state.Credentials.Name)
       // 서비스에 대해서도 동일한 작업을 수행합니다
      
       return nil
      }
      
    7. 일반적인 Run 메서드가 아닌 StatefulExecutor 인터페이스에서 Resume 메서드를 호출합니다. Resume 메서드는 Pod에 다시 연결하고 작업 추적 및 상태를 GitLab에 계속해서 전송합니다.

재시작 후 새로운 작업 실행 메커니즘이 다음과 같이 작동합니다:

%%{init: { "fontFamily": "GitLab Sans" }}%% flowchart LR accTitle: 다시 시작 후 고장 허용 작업 실행 흐름. accDescr: Runner 관리자가 저장소에서 작업을 복원하고 재시작 후 Kubernetes 작업 pod에서 실행을 재개하는 방법을 보여주는 다이어그램입니다. store[(저장소)] -.->|작업 복원|manager((Runner 관리자)) manager -.->|재개| pod[[Kubernetes 작업 Pod]] manager ===> |Job logs/status| gitlab[(GitLab)] pod ====>|Job logs/status| manager