InfoGrab Docs

Kubernetes executor

요약

Kubernetes executor를 사용하여 빌드에 Kubernetes 클러스터를 활용합니다. Kubernetes executor는 빌드를 여러 단계로 나눕니다: 다음 다이어그램은 GitLab 인스턴스와 Kubernetes 클러스터에 호스팅된 Runner 간의 상호 작용을 보여줍니다.

Kubernetes executor를 사용하여 빌드에 Kubernetes 클러스터를 활용합니다. executor는 Kubernetes 클러스터 API를 호출하고 각 GitLab CI 작업에 대해 파드를 생성합니다.

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

  1. Prepare: Kubernetes 클러스터에 파드를 생성합니다. 빌드 및 서비스 실행에 필요한 컨테이너를 생성합니다.
  2. Pre-build: 이전 스테이지에서 클론, 캐시 복원, 아티팩트 다운로드를 수행합니다. 이 단계는 파드의 일부인 특수 컨테이너에서 실행됩니다.
  3. Build: 사용자 빌드.
  4. Post-build: 캐시 생성, GitLab에 아티팩트 업로드. 이 단계도 파드의 일부인 특수 컨테이너를 사용합니다.

Runner가 Kubernetes 파드를 생성하는 방법#

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

파드는 .gitlab-ci.yml 또는 config.toml 파일에 정의된 각 service에 대해 다음 컨테이너로 구성됩니다:

  • build으로 정의된 빌드 컨테이너.
  • helper로 정의된 헬퍼 컨테이너.
  • 다음 로직을 사용하여 이름이 지정된 서비스 컨테이너:

서비스에 유효한 DNS 레이블 이름인 별칭이 있고 다른 서비스 컨테이너에서 이미 사용되지 않은 경우, 해당 별칭이 컨테이너 이름으로 사용됩니다.

유효한 별칭이 없으면 컨테이너는 svc-N으로 이름이 지정됩니다. 여기서 N은 0부터 시작하는 순차 인덱스입니다.

히스토리
  • 별칭 기반 이름 지정은 GitLab Runner 17.9에서 도입되었습니다.

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

  • 서비스는 DNS 이름을 통해 접근할 수 있습니다. 이전 버전을 사용하는 경우 localhost를 사용해야 합니다.
  • 동일한 포트를 사용하는 여러 서비스를 사용할 수 없습니다. 예를 들어, 두 개의 mysql 서비스를 동시에 사용할 수 없습니다.
Mermaid 다이어그램 (16줄)
소스 코드 보기
sequenceDiagram
    participant G as GitLab instance
    participant R as Runner on Kubernetes cluster
    participant Kube as Kubernetes API
    participant P as POD
    R->>+G: Get a CI job.
        loop
        G-->R: ;
    end
    Note over R,G: POST /api/v4/jobs/request
    G->>+R: CI job data.
    R-->>-Kube: Create a POD to run the CI job.
    Note over R,Kube: POST to Kube API
    P->>+P: Execute job.
    Note over P: CI build job = Prepare + Pre-build + Build + Post-build
    P->>+G: Job logs

다이어그램의 상호 작용은 모든 Kubernetes 클러스터에 유효합니다. 예를 들어, 주요 퍼블릭 클라우드 제공업체에서 호스팅되는 턴키 솔루션이나 자체 관리 Kubernetes 설치에 적용됩니다.

Kubernetes API에 연결#

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

옵션 설명
host 선택적 Kubernetes API 서버 호스트 URL (지정하지 않으면 자동 검색 시도).
context kubectl 구성에서 사용할 선택적 Kubernetes 컨텍스트 이름. host를 지정하지 않을 때 이 옵션을 사용합니다.
cert_file 선택적 Kubernetes API 서버 사용자 인증 인증서.
key_file 선택적 Kubernetes API 서버 사용자 인증 개인 키.
ca_file 선택적 Kubernetes API 서버 CA 인증서.

Kubernetes 클러스터에서 GitLab Runner를 실행하는 경우, GitLab Runner가 Kubernetes API를 자동 검색할 수 있도록 이 필드를 생략합니다.

클러스터 외부에서 GitLab Runner를 실행하는 경우, 이 설정은 GitLab Runner가 클러스터의 Kubernetes API에 접근할 수 있도록 합니다. 인증 세부 정보와 함께 host를 지정하거나, context를 사용하여 kubectl 구성에서 특정 컨텍스트를 참조할 수 있습니다.

Kubernetes API 호출을 위한 베어러 토큰 설정#

파드 생성을 위한 API 호출의 베어러 토큰을 설정하려면 KUBERNETES_BEARER_TOKEN 변수를 사용합니다. 이를 통해 프로젝트 소유자가 프로젝트 시크릿 변수를 사용하여 베어러 토큰을 지정할 수 있습니다.

베어러 토큰을 지정할 때는 반드시 Host 구성 설정을 지정해야 합니다.

variables:
  KUBERNETES_BEARER_TOKEN: thebearertokenfromanothernamespace

Runner API 권한 구성#

코어 API 그룹에 대한 권한을 구성하려면 GitLab Runner Helm 차트의 values.yml 파일을 업데이트합니다.

다음 중 하나를 수행할 수 있습니다:

  • rbac.createtrue로 설정합니다.
  • values.yml 파일에서 다음 권한을 가진 서비스 계정 serviceAccount.name: <service_account_name>을 지정합니다.
리소스 동사 (선택적 기능/구성 플래그)
events list (print_pod_warning_events=true), watch (FF_PRINT_POD_EVENTS=true)
namespaces create (kubernetes.NamespacePerJob=true), delete (kubernetes.NamespacePerJob=true)
poddisruptionbudgets create (pod_disruption_budget=true), get (pod_disruption_budget=true)
pods create, delete, get, list (Informer 사용), watch (Informer 사용, FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/attach create (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), delete (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), get (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), patch (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/exec create, delete, get, patch
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

필요한 권한을 가진 역할을 생성하려면 다음 YAML 역할 정의를 사용할 수 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: gitlab-runner
  namespace: default
rules:
- apiGroups: [""]
  resources: ["events"]
  verbs:
  - "list" # Required when `print_pod_warning_events=true`
  - "watch" # Required when `FF_PRINT_POD_EVENTS=true`
- apiGroups: [""]
  resources: ["namespaces"]
  verbs:
  - "create" # Required when `kubernetes.NamespacePerJob=true`
  - "delete" # Required when `kubernetes.NamespacePerJob=true`
- apiGroups: ["policy"]
  resources: ["poddisruptionbudgets"]
  verbs:
  - "create" # Required when `pod_disruption_budget=true`
  - "get" # Required when `pod_disruption_budget=true`
- apiGroups: [""]
  resources: ["pods"]
  verbs:
  - "create"
  - "delete"
  - "get"
  - "list" # Required when using Informers (https://docs.gitlab.com/runner/executors/kubernetes/#informers)
  - "watch" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`, using Informers (https://docs.gitlab.com/runner/executors/kubernetes/#informers)
- apiGroups: [""]
  resources: ["pods/attach"]
  verbs:
  - "create" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
  - "delete" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
  - "get" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
  - "patch" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs:
  - "create"
  - "delete"
  - "get"
  - "patch"
- apiGroups: [""]
  resources: ["pods/log"]
  verbs:
  - "get" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`, `FF_WAIT_FOR_POD_TO_BE_REACHABLE=true`
  - "list" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
- apiGroups: [""]
  resources: ["secrets"]
  verbs:
  - "create"
  - "delete"
  - "get"
  - "update"
- apiGroups: [""]
  resources: ["serviceaccounts"]
  verbs:
  - "get"
- apiGroups: [""]
  resources: ["services"]
  verbs:
  - "create"
  - "get"

추가 세부 정보:

Informer#

GitLab Runner 17.9.0 이상에서는 Kubernetes informer가 빌드 파드 변경 사항을 추적합니다. 이를 통해 executor가 변경 사항을 더 빠르게 감지할 수 있습니다.

informer는 pods에 대한 listwatch 권한이 필요합니다. executor가 빌드를 시작할 때 Kubernetes API에서 권한을 확인합니다. 모든 권한이 부여되면 executor는 informer를 사용합니다. 권한이 누락된 경우 GitLab Runner는 경고를 기록합니다. 빌드는 계속되며 이전 메커니즘을 사용하여 빌드 파드의 상태와 변경 사항을 추적합니다.

구성 설정#

Kubernetes executor를 구성하려면 config.toml 파일에서 다음 설정을 사용합니다.

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 요청 덮어쓰기 기능을 비활성화합니다.
pod_cpu_limit 빌드 파드에 할당된 CPU.
pod_cpu_limit_overwrite_max_allowed 빌드 파드에 대해 CPU 할당을 덮어쓸 수 있는 최대량. 비어 있으면 CPU 제한 덮어쓰기 기능을 비활성화합니다.
pod_cpu_request 빌드 파드에 요청된 CPU 할당.
pod_cpu_request_overwrite_max_allowed 빌드 파드에 대해 CPU 할당 요청을 덮어쓸 수 있는 최대량. 비어 있으면 CPU 요청 덮어쓰기 기능을 비활성화합니다.
Note

파드 수준 리소스 사양은 Kubernetes v1.32에서 알파 기능으로 도입되었으며 Kubernetes v1.34에서 베타로 승급되었습니다.

메모리 요청 및 제한#

설정 설명
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 서비스 컨테이너에 대해 메모리 할당 요청을 덮어쓸 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능을 비활성화합니다.
pod_memory_limit 빌드 파드에 할당된 메모리 양.
pod_memory_limit_overwrite_max_allowed 빌드 파드에 대해 메모리 할당을 덮어쓸 수 있는 최대량. 비어 있으면 메모리 제한 덮어쓰기 기능을 비활성화합니다.
pod_memory_request 빌드 파드에 요청된 메모리 양.
pod_memory_request_overwrite_max_allowed 빌드 파드에 대해 메모리 할당 요청을 덮어쓸 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능을 비활성화합니다.

헬퍼 컨테이너 메모리 크기 권장 사항#

최적의 성능을 위해 워크로드 요구 사항에 따라 헬퍼 컨테이너 메모리 제한을 설정합니다:

  • 캐싱 및 아티팩트 생성이 있는 워크로드: 최소 250 MiB
  • 캐시/아티팩트 없는 기본 워크로드: 더 낮은 제한(128-200 MiB)으로 작동할 수 있음

기본 구성 예시:

[[runners]]
  executor = "kubernetes"
  [runners.kubernetes]
    helper_memory_limit = "250Mi"
    helper_memory_request = "250Mi"
    helper_memory_limit_overwrite_max_allowed = "1Gi"

작업별 메모리 덮어쓰기:

관리자 변경 없이 특정 작업에 대해 메모리를 조정하려면 KUBERNETES_HELPER_MEMORY_LIMIT 변수를 사용합니다:

job_with_higher_helper_memory_limit:
  variables:
    KUBERNETES_HELPER_MEMORY_LIMIT: "512Mi"
  script:

이 접근 방식을 통해 개발자는 helper_memory_limit_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 빌드를 실행할 노드를 결정하는 어피니티 규칙을 지정합니다. 노드 어피니티 사용에 대해 자세히 알아보세요.
allow_privilege_escalation allowPrivilegeEscalation 플래그를 활성화한 상태로 모든 컨테이너를 실행합니다. 비어 있으면 컨테이너 SecurityContextallowPrivilegeEscalation 플래그를 정의하지 않으며 Kubernetes가 기본 권한 상승 동작을 사용하도록 합니다.
allowed_groups 컨테이너 그룹에 지정할 수 있는 그룹 ID 배열. 존재하지 않으면 모든 그룹이 허용됩니다. 자세한 내용은 컨테이너 사용자 및 그룹 구성을 참조하세요.
allowed_images .gitlab-ci.yml에서 지정할 수 있는 이미지의 와일드카드 목록. 존재하지 않으면 모든 이미지가 허용됩니다(["*/*:*"]와 동일). 세부 정보 보기.
allowed_pull_policies .gitlab-ci.yml 파일이나 config.toml 파일에서 지정할 수 있는 풀 정책 목록.
allowed_services .gitlab-ci.yml에서 지정할 수 있는 서비스의 와일드카드 목록. 존재하지 않으면 모든 이미지가 허용됩니다(["*/*:*"]와 동일). 세부 정보 보기.
allowed_users 컨테이너 사용자에 지정할 수 있는 사용자 ID 배열. 존재하지 않으면 모든 사용자가 허용됩니다. 자세한 내용은 컨테이너 사용자 및 그룹 구성을 참조하세요.
automount_service_account_token 빌드 파드에서 서비스 계정 토큰이 자동으로 마운트되는지 여부를 제어하는 부울 값.
bearer_token 빌드 파드를 시작하는 데 사용되는 기본 베어러 토큰.
bearer_token_overwrite_allowed 프로젝트가 빌드 파드를 생성하는 데 사용되는 베어러 토큰을 지정할 수 있도록 하는 부울 값.
build_container_security_context 빌드 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
cap_add 작업 파드 컨테이너에 추가해야 할 Linux 기능을 지정합니다. Kubernetes executor에서 기능 구성에 대해 자세히 알아보기.
cap_drop 작업 파드 컨테이너에서 제거해야 할 Linux 기능을 지정합니다. Kubernetes executor에서 기능 구성에 대해 자세히 알아보기.
cleanup_grace_period_seconds 작업이 완료되면 파드가 정상적으로 종료되는 시간(초). 이 기간 이후 프로세스는 kill 시그널로 강제 종료됩니다. terminationGracePeriodSeconds가 지정되면 무시됩니다.
context kubectl 구성에서 사용할 Kubernetes 컨텍스트 이름(host가 지정되지 않은 경우).
dns_policy 파드 구성 시 사용할 DNS 정책을 지정합니다: none, default, cluster-first, cluster-first-with-host-net. 설정하지 않으면 Kubernetes 기본값(cluster-first)이 사용됩니다.
dns_config 파드 구성 시 사용할 DNS 구성을 지정합니다. 파드 DNS 설정 구성에 대해 자세히 알아보기.
helper_container_security_context 헬퍼 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
helper_image (고급) 리포지터리 클론 및 아티팩트 업로드에 사용되는 기본 헬퍼 이미지를 재정의합니다.
helper_image_flavor 헬퍼 이미지 플레이버를 설정합니다(alpine, alpine3.21 또는 ubuntu). 기본값은 alpine입니다. alpine을 사용하는 것은 alpine3.21과 동일합니다.
host_aliases 모든 컨테이너에 추가되는 추가 호스트 이름 별칭 목록. 추가 호스트 별칭 사용에 대해 자세히 알아보기.
image_pull_secrets 비공개 레지스트리에서 Docker 이미지 풀링 인증에 사용되는 Kubernetes docker-registry 시크릿 이름을 포함하는 항목 배열.
init_permissions_container_security_context init-permissions 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
namespace Kubernetes 파드를 실행할 네임스페이스.
namespace_per_job 별도의 네임스페이스에서 작업을 격리합니다. 활성화되면 namespacenamespace_overwrite_allowed가 무시됩니다.
namespace_overwrite_allowed 네임스페이스 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식(아래 문서 참조). 비어 있으면 네임스페이스 덮어쓰기 기능을 비활성화합니다.
node_selector string=string 형식(환경 변수의 경우 string:string)의 key=valuetable. 이를 설정하면 모든 key=value 쌍과 일치하는 Kubernetes 노드에서만 파드가 생성됩니다. 노드 선택기 사용에 대해 자세히 알아보기.
node_tolerations string=string:string 형식의 "key=value" = "Effect"table. 이를 설정하면 모든 또는 일부 톨러레이션된 테인트가 있는 노드에 파드를 스케줄링할 수 있습니다. 환경 변수 구성을 통해 하나의 톨러레이션만 제공할 수 있습니다. key, valueeffect는 Kubernetes 파드 톨러레이션 구성의 해당 필드 이름과 일치합니다.
pod_annotations string=string 형식의 key=valuetable. Runner가 생성한 각 빌드 파드에 추가할 어노테이션 목록을 포함합니다. 이 값에는 확장을 위한 환경 변수를 포함할 수 있습니다. 파드 어노테이션은 각 빌드에서 덮어쓸 수 있습니다.
pod_annotations_overwrite_allowed 파드 어노테이션 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식. 비어 있으면 파드 어노테이션 덮어쓰기 기능을 비활성화합니다.
pod_labels string=string 형식의 key=valuetable. Runner가 생성한 각 빌드 파드에 추가할 레이블 목록을 포함합니다. 이 값에는 확장을 위한 환경 변수를 포함할 수 있습니다. 파드 레이블은 pod_labels_overwrite_allowed를 사용하여 각 빌드에서 덮어쓸 수 있습니다.
pod_labels_overwrite_allowed 파드 레이블 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식. 비어 있으면 파드 레이블 덮어쓰기 기능을 비활성화합니다. runner.gitlab.com 레이블 네임스페이스의 파드 레이블은 덮어쓸 수 없습니다.
pod_security_context 구성 파일을 통해 구성되며, 빌드 파드에 대한 파드 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
pod_termination_grace_period_seconds 파드 내 프로세스가 종료 시그널을 받은 후 kill 시그널로 강제 종료되기까지의 시간(초)을 결정하는 파드 수준 설정. terminationGracePeriodSeconds가 지정되면 무시됩니다.
poll_interval Runner가 방금 생성한 Kubernetes 파드의 상태를 확인하기 위해 폴링하는 빈도(초)(기본값 = 3).
poll_timeout Runner가 방금 생성한 컨테이너에 연결을 시도하기 전에 경과해야 하는 시간(초). 클러스터가 한 번에 처리할 수 있는 것보다 더 많은 빌드를 대기열에 넣을 때 이 설정을 사용합니다(기본값 = 180).
cleanup_resources_timeout 작업 완료 후 Kubernetes 리소스를 정리하는 총 시간. 지원되는 구문: 1h30m, 300s, 10m. 기본값은 5분(5m).
priority_class_name 파드에 설정할 Priority Class를 지정합니다. 설정하지 않으면 기본값이 사용됩니다.
privileged privileged 플래그로 컨테이너를 실행합니다.
pull_policy 이미지 풀 정책을 지정합니다: never, if-not-present, always. 설정하지 않으면 클러스터의 이미지 기본 풀 정책이 사용됩니다. 여러 풀 정책 설정 방법에 대한 자세한 내용은 풀 정책 사용을 참조하세요. if-not-present, never 보안 고려 사항도 참조하세요. 풀 정책 제한도 가능합니다.
resource_availability_check_max_attempts 리소스(서비스 계정 및/또는 풀 시크릿) 세트가 사용 가능한지 확인하는 최대 시도 횟수. 각 시도 사이에 5초 간격이 있습니다. 준비 단계에서의 리소스 확인에 대해 자세히 알아보기.
runtime_class_name 생성된 모든 파드에 사용할 Runtime class. 클러스터에서 이 기능이 지원되지 않으면 작업이 종료되거나 실패합니다.
service_container_security_context 서비스 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
scheduler_name 빌드 파드 스케줄링에 사용할 스케줄러.
service_account 작업/executor 파드가 Kubernetes API와 통신하는 데 사용하는 기본 서비스 계정.
service_account_overwrite_allowed 서비스 계정 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식. 비어 있으면 서비스 계정 덮어쓰기 기능을 비활성화합니다.
services 사이드카 패턴을 사용하여 빌드 컨테이너에 연결된 서비스 목록. 서비스 사용에 대해 자세히 알아보기.
use_service_account_image_pull_secrets 활성화되면 executor가 생성한 파드에 imagePullSecrets가 없습니다. 이로 인해 설정된 경우 서비스 계정의 imagePullSecrets를 사용하여 파드가 생성됩니다.
terminationGracePeriodSeconds 파드 내 프로세스가 종료 시그널을 받은 후 kill 시그널로 강제 종료되기까지의 시간. cleanup_grace_period_secondspod_termination_grace_period_seconds를 위해 더 이상 사용되지 않습니다.
volumes 구성 파일을 통해 구성되며, 빌드 컨테이너에 마운트되는 볼륨 목록. 볼륨 사용에 대해 자세히 알아보기.
pod_spec 이 설정은 실험적입니다. CI 작업을 실행하는 데 사용되는 파드에 설정된 구성 목록으로 Runner 매니저가 생성한 파드 사양을 덮어씁니다. Kubernetes Pod Specification에 나열된 모든 속성을 설정할 수 있습니다. 자세한 내용은 생성된 파드 사양 덮어쓰기(실험)를 참조하세요.
retry_limit Kubernetes API와 통신하는 최대 시도 횟수. 각 시도 간의 재시도 간격은 500ms에서 시작하는 백오프 알고리즘을 기반으로 합니다.
retry_backoff_max 각 시도에 대한 재시도 간격이 도달할 사용자 정의 최대 백오프 값(밀리초). 기본값은 2000ms이며 500ms 미만으로 설정할 수 없습니다. 각 시도에 대한 기본 최대 재시도 간격은 2초이며 retry_backoff_max로 사용자 정의할 수 있습니다.
retry_limits 각 요청 오류를 재시도하는 횟수.
logs_base_dir 빌드 로그를 저장하기 위해 생성된 경로 앞에 추가할 기본 디렉토리. 자세한 내용은 빌드 로그 및 스크립트의 기본 디렉토리 변경을 참조하세요.
scripts_base_dir 빌드 스크립트를 저장하기 위해 생성된 경로 앞에 추가할 기본 디렉토리. 자세한 내용은 빌드 로그 및 스크립트의 기본 디렉토리 변경을 참조하세요.
print_pod_warning_events 활성화되면 작업 실패 시 파드와 관련된 모든 경고 이벤트를 검색합니다. 이 기능은 기본적으로 활성화되어 있으며 최소 events: list 권한이 있는 서비스 계정이 필요합니다.
pod_disruption_budget 활성화되면 노드 드레인 및 클러스터 업그레이드와 같은 자발적 중단 중 축출을 방지하기 위해 각 작업 파드에 대해 PodDisruptionBudget이 생성됩니다. 기본적으로 비활성화되어 있습니다. poddisruptionbudgets 권한이 있는 서비스 계정이 필요합니다.

구성 예시#

다음 샘플은 Kubernetes executor를 위한 config.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 플래그를 사용할 수 있습니다.

파드 및 컨테이너#

작업 실행 방식을 제어하기 위해 파드와 컨테이너를 구성할 수 있습니다.

작업 파드의 기본 레이블#

Warning

Runner 구성이나 .gitlab-ci.yml 파일을 통해 이 레이블을 재정의할 수 없습니다. runner.gitlab.com 네임스페이스의 레이블을 설정하거나 수정하려는 시도는 무시되며 디버그 메시지로 기록됩니다.

설명
project.runner.gitlab.com/id GitLab 인스턴스 내 프로젝트 간 고유한 프로젝트 ID.
project.runner.gitlab.com/name 프로젝트 이름.
project.runner.gitlab.com/namespace-id 프로젝트 네임스페이스의 ID.
project.runner.gitlab.com/namespace 프로젝트 네임스페이스의 이름.
project.runner.gitlab.com/root-namespace 프로젝트 루트 네임스페이스의 ID. 예: /gitlab-org/group-a/subgroup-a/project, 여기서 루트 네임스페이스는 gitlab-org
manager.runner.gitlab.com/name 이 작업을 시작한 Runner 구성의 이름.
manager.runner.gitlab.com/id-short 작업을 시작한 Runner 구성의 ID.
job.runner.gitlab.com/pod Kubernetes executor가 사용하는 내부 레이블.

작업 파드의 기본 어노테이션#

다음 어노테이션은 작업을 실행하는 파드에 기본적으로 추가됩니다:

설명
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 작업 이름.
job.runner.gitlab.com/timeout 시간 형식의 작업 실행 타임아웃. 예: 2h3m0.5s.
project.runner.gitlab.com/id 작업의 프로젝트 ID.

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

파드 수명 주기#

파드의 수명 주기는 다음에 의해 영향을 받을 수 있습니다:

  • TOML 구성 파일에서 pod_termination_grace_period_seconds 속성을 설정합니다. 파드에서 실행 중인 프로세스는 TERM 시그널이 전송된 후 지정된 기간 동안 실행할 수 있습니다. 이 기간 후에 파드가 성공적으로 종료되지 않으면 kill 시그널이 전송됩니다.
  • FF_USE_POD_ACTIVE_DEADLINE_SECONDS 기능 플래그를 활성화합니다. 활성화되고 작업이 시간 초과되면 CI/CD 작업을 실행하는 파드가 실패로 표시되고 모든 관련 컨테이너가 종료됩니다. GitLab에서 먼저 작업이 시간 초과되도록 하기 위해 activeDeadlineSeconds구성된 타임아웃 + 1초로 설정됩니다.
Note

FF_USE_POD_ACTIVE_DEADLINE_SECONDS 기능 플래그를 활성화하고 pod_termination_grace_period_seconds를 0이 아닌 값으로 설정하면 CI/CD 작업 파드가 즉시 종료되지 않습니다. 파드 terminationGracePeriods는 만료된 경우에만 파드가 종료되도록 합니다.

작업 파드를 축출로부터 보호#

히스토리

노드 드레인 및 클러스터 업그레이드와 같은 자발적 중단으로부터 작업 파드를 보호하려면 pod_disruption_budget 옵션을 활성화합니다.

활성화되면 이 설정은 minAvailable: 1로 각 작업 파드에 대해 PodDisruptionBudget을 생성합니다. 이 작업은 자발적 중단 중에 Kubernetes 축출 API가 파드를 축출하는 것을 방지합니다.

[runners.kubernetes]
  pod_disruption_budget = true

PodDisruptionBudget:

  • Kubernetes 소유자 참조를 통해 작업 파드가 삭제될 때 자동으로 삭제됩니다.
  • 노드 장애나 메모리 부족 종료와 같은 비자발적 중단으로부터는 보호하지 않습니다.
  • 추가 RBAC 권한이 필요합니다. 자세한 내용은 Runner API 권한 구성을 참조하세요.
Warning

PodDisruptionBudget을 활성화하면 작업이 실행 중일 때 노드 드레인이 중단될 수 있습니다. 클러스터 업그레이드 전략이 잠재적인 노드 드레인 지연을 고려하도록 하거나, 작업 타임아웃을 사용하여 작업 실행 시간을 제한하세요.

파드 톨러레이션 덮어쓰기#

Kubernetes 파드 톨러레이션을 덮어쓰려면:

  1. config.toml 또는 Helm values.yaml 파일에서 CI 작업 파드 톨러레이션의 덮어쓰기를 활성화하려면 node_tolerations_overwrite_allowed에 대한 정규 표현식을 정의합니다. 이 정규 표현식은 KUBERNETES_NODE_TOLERATIONS_로 시작하는 CI 변수 이름의 값을 검증합니다.

    runners:
     ...
     config: |
       [[runners]]
         [runners.kubernetes]
           node_tolerations_overwrite_allowed = ".*"
    
  2. .gitlab-ci.yml 파일에서 CI 작업 파드 톨러레이션을 덮어쓰기 위해 하나 이상의 CI 변수를 정의합니다.

    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: '' # 모든 테인트 톨러레이트
    

파드 레이블 덮어쓰기#

각 CI/CD 작업에 대해 Kubernetes 파드 레이블을 덮어쓰려면:

  1. .config.yaml 파일에서 pod_labels_overwrite_allowed에 대한 정규 표현식을 정의합니다.

  2. .gitlab-ci.yml 파일에서 key=value 값을 가진 KUBERNETES_POD_LABELS_* 변수를 설정합니다. 파드 레이블이 key=value로 덮어쓰여집니다. 여러 값을 적용할 수 있습니다:

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

runner.gitlab.com 네임스페이스의 레이블은 읽기 전용입니다. GitLab은 이러한 GitLab 내부 레이블을 추가, 수정 또는 제거하려는 시도를 무시합니다.

파드 어노테이션 덮어쓰기#

각 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]]
  # usual configuration
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine"
    pod_annotations_overwrite_allowed = ".*"
    [runners.kubernetes.pod_annotations]
      "Key1" = "Val1"
      "Key2" = "Val2"
      "Key3" = "Val3"
      "Key4" = "Val4"

생성된 파드 사양 덮어쓰기#

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

기능이 일반적으로 사용 가능해지기 전에 피드백을 추가하려면 이슈 556286에 댓글을 남겨주세요.

Runner 매니저가 생성한 PodSpec을 수정하려면 config.toml 파일에서 pod_spec 설정을 사용합니다.

Runner operator별 구성에 대해서는 패치 구조를 참조하세요.

pod_spec 설정:

  • 생성된 파드 사양의 필드를 덮어쓰고 완성합니다.
  • [runners.kubernetes] 아래의 config.toml에서 설정되었을 수 있는 구성 값을 덮어씁니다.

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

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

동일한 pod_spec 구성에서 patch_pathpatch를 설정할 수 없으며, 그렇지 않으면 오류가 발생합니다.

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 구성 예시. 이 구성에서는 기존 nodeSelector에 새로운 key: value pair가 추가됩니다. 기존 값은 덮어쓰여지지 않습니다.

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"

전략적 패치 전략#

strategic 패치 전략은 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가 생성한 사양에 부정적인 영향을 미치지 않도록 합니다.
  • 복잡한 파드 사양 업데이트에는 merge 패치 전략을 사용하지 마세요.
  • 가능한 경우 구성이 사용 가능할 때 config.toml을 사용합니다. 예를 들어, 다음 구성은 기존 목록에 환경 변수 세트를 추가하는 대신 사용자 정의 pod_spec에서 설정한 환경 변수로 GitLab Runner가 설정한 첫 번째 환경 변수를 대체합니다.
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"

Pod Spec을 수정하여 각 빌드 작업에 대한 PVC 생성#

각 빌드 작업에 대해 PersistentVolumeClaim을 생성하려면 Pod Spec 기능을 활성화하는 방법을 확인하세요.

Kubernetes를 사용하면 파드의 수명 주기에 연결된 임시 PersistentVolumeClaim을 생성할 수 있습니다. 이 접근 방식은 Kubernetes 클러스터에서 동적 프로비저닝이 활성화된 경우 작동합니다. 각 PVC는 새 볼륨을 요청할 수 있습니다. 볼륨도 파드의 수명 주기에 연결됩니다.

동적 프로비저닝이 활성화된 후 임시 PVC를 생성하기 위해 config.toml을 다음과 같이 수정할 수 있습니다:

[[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: 
            accessModes: [ ReadWriteOnce ]
            resources:
              requests:
                storage: 1Gi
  '''

파드에 대한 보안 정책 설정#

빌드 파드에 대한 보안 정책을 설정하려면 config.toml에서 보안 컨텍스트를 구성합니다.

다음 옵션을 사용합니다:

옵션 타입 필수 설명
fs_group int 아니오 파드의 모든 컨테이너에 적용되는 특수 보조 그룹.
run_as_group int 아니오 컨테이너 프로세스의 진입점을 실행할 GID.
run_as_non_root boolean 아니오 컨테이너가 비root 사용자로 실행되어야 함을 나타냅니다.
run_as_user int 아니오 컨테이너 프로세스의 진입점을 실행할 UID.
supplemental_groups int list 아니오 컨테이너의 기본 GID 외에 각 컨테이너에서 실행되는 첫 번째 프로세스에 적용되는 그룹 목록.
selinux_type string 아니오 파드의 모든 컨테이너에 적용되는 SELinux 타입 레이블.

config.toml에서 파드 보안 컨텍스트의 예시:

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

이전 Runner 파드 제거#

때때로 이전 Runner 파드가 정리되지 않을 수 있습니다. 이는 Runner 매니저가 올바르게 종료되지 않았을 때 발생할 수 있습니다.

이 상황을 처리하려면 GitLab Runner Pod Cleanup 애플리케이션을 사용하여 이전 파드의 정리를 예약할 수 있습니다. 자세한 내용은 다음을 참조하세요:

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

컨테이너에 대한 보안 정책 설정#

빌드, 헬퍼 또는 서비스 파드에 대한 컨테이너 보안 정책을 설정하려면 config.toml executor에서 컨테이너 보안 컨텍스트를 구성합니다.

다음 옵션을 사용합니다:

옵션 타입 필수 설명
run_as_group int 아니오 컨테이너 프로세스의 진입점을 실행할 GID.
run_as_non_root boolean 아니오 컨테이너가 비root 사용자로 실행되어야 함을 나타냅니다.
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

풀 정책 설정#

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

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

단일 풀 정책:

[runners.kubernetes]
  pull_policy = "never"

여러 풀 정책:

[runners.kubernetes]
  # use multiple pull policies
  pull_policy = ["always", "if-not-present"]

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

실패한 풀을 재시도하려면:

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

GitLab 명명 규칙은 Kubernetes와 다릅니다.

Runner 풀 정책 Kubernetes 풀 정책 설명
none none Kubernetes에서 지정한 기본 정책을 사용합니다.
if-not-present IfNotPresent 작업을 실행하는 노드에 이미 존재하지 않는 경우에만 이미지를 풀합니다. 이 풀 정책을 사용하기 전에 보안 고려 사항을 검토하세요.
always Always 작업이 실행될 때마다 이미지를 풀합니다.
never Never 이미지를 풀하지 않으며 노드에 이미 있어야 합니다.

컨테이너 기능 지정#

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

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

Runner가 기본적으로 제거하는 기능 목록이 있습니다. 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를 정의하여 특정 기능을 허용, 제한 또는 기본적으로 추가할 수 있습니다. 이 규칙은 모든 사용자 정의 구성보다 우선합니다.

컨테이너 사용자 및 그룹 구성#

히스토리
  • Support for security context-based user configuration introduced in GitLab Runner 18.4.

Kubernetes 보안 컨텍스트 구성을 사용하여 컨테이너에서 실행되는 사용자와 그룹을 구성합니다. 관리자는 컨테이너 보안을 제어하고 작업이 특정 컨테이너 유형에 대해 사용자를 지정할 수 있도록 허용할 수 있습니다.

Note

Windows에서는 작업 정의에서 runAsUser, runAsGroup 또는 image:user 설정이 지원되지 않습니다. 대신 FF_USE_ADVANCED_POD_SPEC_CONFIGURATION을 통해 runAsUserName 설정을 권장합니다.

구성 우선순위#

Runner는 다음 순서로 사용자 구성을 적용합니다:

빌드 및 서비스 컨테이너:

  1. 컨테이너 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 이 구성을 제어
  2. 파드 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 파드 수준 기본값을 제어
  3. 작업 구성 (.gitlab-ci.yml): 사용자가 이 구성을 제어

헬퍼 컨테이너:

  1. 헬퍼 컨테이너 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 이 구성을 제어
  2. 파드 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 파드 수준 기본값을 제어

보안 격리를 위해 작업 구성은 헬퍼 컨테이너에 적용되지 않습니다.

관리자는 보안 준수를 위해 사용자가 지정한 값을 재정의할 수 있습니다. 헬퍼 컨테이너는 작업 사양으로부터 격리됩니다.

Kubernetes 요구 사항#

Kubernetes는 사용자 및 그룹 ID에 숫자 값을 요구합니다:

  • 사용자 및 그룹 ID는 정수여야 합니다
  • SecurityContextrun_as_userrun_as_group을 사용하며 숫자 값만 허용합니다
  • 작업 구성에서 사용자만 지정할 때는 "1000"을, 사용자와 그룹을 지정할 때는 "1000:1001"을 사용합니다

사용자 및 그룹 설정 재정의#

파드 및 컨테이너별 보안 컨텍스트를 사용하여 사용자 및 그룹 설정을 재정의합니다:

[[runners]]
  name = "k8s-runner"
  url = "https://gitlab.example.com"
  executor = "kubernetes"
  [runners.kubernetes]
    allowed_users = ["1000", "1001", "65534"]
    allowed_groups = ["1001", "65534"]

    # Pod security context - provides defaults for all containers
    [runners.kubernetes.pod_security_context]
      run_as_user = 1500
      run_as_group = 1500

    # Build container security context - overrides pod context
    [runners.kubernetes.build_container_security_context]
      run_as_user = 2000
      run_as_group = 2001

    # Helper container security context - overrides pod context
    [runners.kubernetes.helper_container_security_context]
      run_as_user = 3000
      run_as_group = 3001

    # Service container security context - overrides pod context
    [runners.kubernetes.service_container_security_context]
      run_as_user = 4000
      run_as_group = 4001

이 예시에서:

  • 파드 보안 컨텍스트는 특정 구성이 없는 컨테이너에 대한 기본값(1500:1500)을 설정합니다
  • 컨테이너 보안 컨텍스트가 파드 기본값을 재정의합니다
  • 사용자 1500, 2000, 3000, 4000은 allowed_users 목록에 없지만, 이 값은 허용 목록 검증을 우회하므로 보안 컨텍스트에서 사용할 수 있습니다
  • 이 기능은 관리자에게 파드 및 컨테이너 수준에서 제한 없는 재정의 제어를 제공합니다

각 컨테이너 유형을 독립적으로 구성할 수 있습니다. 보안 컨텍스트 구성은 작업 구성의 모든 사용자 사양보다 우선합니다.

작업 구성에서 사용자 지정#

작업은 이미지 구성에서 사용자를 지정할 수 있습니다:

# Job with custom user
job:
  image:
    name: alpine:latest
    kubernetes:
      user: "1000"
  script:
    - whoami
    - id

# Job with user and group
job_with_group:
  image:
    name: alpine:latest
    kubernetes:
      user: "1000:1001"
  script:
    - whoami
    - id

# Job using environment variable
job_dynamic:
  image:
    name: alpine:latest
    kubernetes:
      user: "${CUSTOM_USER_ID}"
  variables:
    CUSTOM_USER_ID: "1000"
  script:
    - whoami

보안 검증#

Runner는 작업 수준 구성에 대해서만 허용 목록에 대해 사용자 및 그룹 ID를 검증합니다:

  • Root 사용자/그룹 (UID/GID 0): 작업 구성에 대해 항상 명시적 허용 목록 권한이 필요합니다
  • 비어 있는 allowed_users: 비root 작업 사용자는 모두 허용됩니다
  • 지정된 allowed_users: 나열된 작업 사용자만 허용됩니다
  • 비어 있는 allowed_groups: 비root 작업 그룹은 모두 허용됩니다
  • 지정된 allowed_groups: 나열된 작업 그룹만 허용됩니다
  • 보안 컨텍스트 구성: 허용 목록에 대해 검증되지 않습니다 (관리자 재정의)
[runners.kubernetes]
  allowed_users = ["1000", "65534"]
  allowed_groups = ["1001", "65534"]

컨테이너 동작 및 우선순위#

보안 컨텍스트 구성은 다음 우선순위(높은 것부터 낮은 것)를 따릅니다:

  1. 컨테이너 보안 컨텍스트
  2. 파드 보안 컨텍스트
  3. 작업 구성
[runners.kubernetes]
  # Pod-level defaults
  [runners.kubernetes.pod_security_context]
    run_as_user = 1500
    run_as_group = 1500

  # Container-specific overrides
  [runners.kubernetes.build_container_security_context]
    run_as_user = 1000
    run_as_group = 1001
  [runners.kubernetes.helper_container_security_context]
    run_as_user = 1000
    run_as_group = 1001
job:
  image:
    name: alpine:latest
    kubernetes:
      user: "2000:2001"  # Ignored - container security context uses 1000:1001

각 컨테이너 유형은 파드 수준 폴백과 함께 보안 컨텍스트 구성을 사용합니다:

  • 빌드 컨테이너: 먼저 build_container_security_context를 사용하고, 그 다음 pod_security_context를, 그 다음 .gitlab-ci.yml의 작업 수준 사용자 구성을 사용합니다.
  • 헬퍼 컨테이너: 먼저 helper_container_security_context를 사용하고, 그 다음 pod_security_context를 사용합니다. 작업 수준 사용자 구성을 상속하지 않습니다.
  • 서비스 컨테이너: 먼저 service_container_security_context를 사용하고, 그 다음 pod_security_context를, 그 다음 작업 수준 사용자 구성을 사용합니다.

이 접근 방식은 헬퍼 컨테이너를 작업 사양으로부터 격리하면서 각 컨테이너 유형의 보안 구성에 대한 세밀한 제어를 제공합니다.

Docker executor와 비교#

기능 Docker executor Kubernetes executor
사용자 형식 사용자 이름 또는 UID (root 또는 1000) 숫자 UID만 (1000)
그룹 형식 사용자 필드에서 지원되지 않음 숫자 GID (1000:1001)
관리자 재정의 방법 Runner user 필드 컨테이너 및 파드 보안 컨텍스트
우선순위 Runner > Job 컨테이너 컨텍스트 > 파드 컨텍스트 > Job
보안 검증 사용자 이름 허용 목록 숫자 UID/GID 허용 목록
관리자 재정의 지원됨 지원됨 (파드 및 컨테이너 수준)
헬퍼 컨테이너 사용자 빌드 컨테이너와 동일 자체 helper_container_security_context 사용
파드 수준 기본값 사용 불가 pod_security_context

사용자 및 그룹 구성 문제 해결#

오류: failed to parse UID 또는 failed to parse GID#
  • 사용자 ID가 숫자인지 확인: "user"가 아닌 "1000"
  • 형식 확인: 사용자와 그룹의 경우 "1000:1001"
  • 음수 값은 허용되지 않습니다
오류: user "1000" is not in the allowed list#

이 오류는 작업 수준 사용자 구성(.gitlab-ci.yml)에서만 발생합니다. Runner 구성에서 allowed_users에 사용자를 추가하거나 allowed_users를 제거하여 비root 작업 사용자를 모두 허용합니다. 보안 컨텍스트 및 파드 보안 컨텍스트 사용자는 허용 목록에 대해 검증되지 않습니다.

오류: group "1001" is not in the allowed list#

이 오류는 작업 수준 그룹 구성(.gitlab-ci.yml)에서만 발생합니다. Runner 구성에서 allowed_groups에 그룹을 추가하거나 allowed_groups를 제거하여 비root 작업 그룹을 모두 허용합니다. 보안 컨텍스트 및 파드 보안 컨텍스트 그룹은 허용 목록에 대해 검증되지 않습니다.

오류: user "0" is not in the allowed list (Root 사용자 차단)#

이 오류는 작업 구성(.gitlab-ci.yml)에서 root가 지정된 경우에만 발생합니다. 작업 구성의 Root 사용자(UID 0)는 명시적 권한이 필요합니다: allowed_users"0"을 추가합니다. 또는 보안 컨텍스트나 파드 보안 컨텍스트를 사용하여 root 사용자를 설정합니다: run_as_user = 0 (허용 목록 검증 우회).

컨테이너가 예상과 다른 사용자로 실행됨#

Runner 구성이 보안 컨텍스트로 작업 구성을 재정의하는지 확인합니다(보안 컨텍스트가 항상 우선). 작업 구성만 사용하는 경우 allowed_users에 원하는 사용자 ID가 포함되어 있는지 확인합니다. 보안 컨텍스트 값은 허용 목록에 대해 검증되지 않으며 관리자 재정의 기능을 제공합니다.

컨테이너 리소스 덮어쓰기#

각 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에서 서비스 목록을 정의합니다.

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에 지정된 컨테이너 리소스를 덮어쓰려면 각 서비스에서 variables 속성을 사용합니다.

  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 이름을 지정했지만 클러스터에서 구성하지 않았거나 기능이 지원되지 않는 경우 executor가 작업 생성에 실패합니다.

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

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

히스토리
  • GitLab Runner 17.2에서 도입되었습니다.

빌드 로그 및 스크립트를 위해 emptyDir 볼륨이 pod에 마운트되는 디렉토리를 변경할 수 있습니다. 이 디렉토리를 사용하여 다음 작업을 수행할 수 있습니다:

  • 수정된 이미지로 job pod를 실행합니다.
  • 비권한 사용자로 실행합니다.
  • 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 볼륨을 생성합니다:

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

사용자 네임스페이스#

Kubernetes 1.30 이상에서는 사용자 네임스페이스를 사용하여 컨테이너에서 실행 중인 사용자를 호스트의 사용자와 분리할 수 있습니다. 컨테이너에서 root로 실행되는 프로세스는 호스트에서 다른 비권한 사용자로 실행될 수 있습니다.

사용자 네임스페이스를 사용하면 CI/CD job을 실행하는 데 사용되는 이미지를 더 세밀하게 제어할 수 있습니다. 추가 설정이 필요한 작업(root로 실행 등)도 호스트에서 추가적인 공격 표면을 열지 않고 작동할 수 있습니다.

이 기능을 사용하려면 클러스터가 적절히 구성되어 있는지 확인하십시오. 다음 예시는 hostUsers 키에 대한 pod_spec을 추가하고 권한 pod와 권한 에스컬레이션을 모두 비활성화합니다:

[[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)의 기본 경로를 사용할 수 없습니다. 컨테이너의 root 사용자도 볼륨을 마운트할 권한이 없습니다. 또한 컨테이너 파일 시스템의 루트에 디렉토리를 생성할 수도 없습니다.

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

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

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

시스템은 helper 이미지의 운영 체제, 아키텍처, Windows 커널 버전(해당하는 경우)을 결정합니다. 그런 다음 해당 파라미터를 사용할 컨테이너 또는 이미지 등 빌드의 다른 측면에 활용합니다.

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

Mermaid 다이어그램 (26줄)
소스 코드 보기
%%|fig-align: center
flowchart TB
  init[<b>초기 기본값</b>:<br/>OS: linux</br>Arch: amd64]
  hasAutoset{구성<br/><tt><a href="https://docs.gitlab.com/runner/configuration/advanced-configuration/">helper_image_autoset_arch_and_os</a> == true</tt>?}
  setArch[<b>업데이트</b>:<br/>Arch: <i>runner와 동일</i>]
  isWin{GitLab Runner가 Windows에서 실행 중?}
  setWin[<b>업데이트</b>:<br/>OS: windows<br/>KernelVersion: <i>runner와 동일</i>]
  hasNodeSel{<a href="https://docs.gitlab.com/runner/configuration/advanced-configuration/"><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><tt>node_selector</tt>에서 업데이트</b> (설정된 경우):<br/>OS: <tt>kubernetes.io/os</tt>에서<br/>Arch: <tt>kubernetes.io/arch</tt>에서<br/>KernelVersion: <tt>node.kubernetes.io/windows-build</tt>에서]
  updateNodeSelOverride[<b><tt>node_selector</tt> 덮어쓰기에서 업데이트</b> (설정된 경우):</br>OS: <tt>kubernetes.io/os</tt>에서<br/>Arch: <tt>kubernetes.io/arch</tt>에서<br/>KernelVersion: <tt>node.kubernetes.io/windows-build</tt>에서]
  result[최종 <b>OS</b>, <b>Arch</b>, <b>kernelVersion</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 옵션을 사용하여 Kubernetes 클러스터에서 빌드를 실행하는 데 사용할 수 있는 노드를 지정합니다. 이는 string=string 형식의 key=value 쌍입니다(환경 변수의 경우 string:string).

Runner는 제공된 정보를 사용하여 빌드의 운영 체제와 아키텍처를 결정합니다. 이를 통해 올바른 helper 이미지가 사용됩니다. 기본 운영 체제와 아키텍처는 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에는 특정 제한 사항이 있습니다. 프로세스 격리를 사용하는 경우 node.kubernetes.io/windows-build 레이블로 특정 Windows 빌드 버전도 제공해야 합니다.

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

  # Runner가 Linux 환경에서 작동하지만 Windows 노드를 대상으로 할 때
  # PowerShell이 Windows 경로를 올바르게 확인하려면
  # FF_USE_POWERSHELL_PATH_RESOLVER 기능 플래그를 활성화해야 합니다.
  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_* = ''
    

다음 예시에서 Kubernetes 노드 아키텍처를 덮어쓰기 위해 config.toml.gitlab-ci.yml 파일에 설정이 구성됩니다:

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=.*" # <--- 아키텍처 덮어쓰기 허용
job:
  image: IMAGE_NAME
  variables:
    KUBERNETES_NODE_SELECTOR_ARCH: 'kubernetes.io/arch=amd64'  # <--- 아키텍처 선택

노드 어피니티 목록 정의#

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

Note

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가 예약될 노드 정의#

pod 어피니티 및 안티-어피니티를 사용하여 다른 pod의 레이블을 기반으로 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 아니오 수행할 HTTP 요청을 지정하는 HTTPGet.
tcp_socket KubernetesLifecycleTcpSocket 아니오 TCP 포트와 관련된 액션을 지정하는 TCPsocket.

KubernetesLifecycleExecAction#

옵션 타입 필수 여부 설명
command string 목록 컨테이너 내부에서 실행할 명령줄.

KubernetesLifecycleHTTPGet#

옵션 타입 필수 여부 설명
port int 컨테이너에서 접근할 포트 번호.
host string 아니오 연결할 호스트 이름, 기본값은 pod IP (선택 사항).
path string 아니오 HTTP 서버에서 접근할 경로 (선택 사항).
scheme string 아니오 호스트에 연결하는 데 사용되는 스킴. 기본값은 HTTP (선택 사항).
http_headers KubernetesLifecycleHTTPGetHeader 목록 아니오 요청에 설정할 사용자 지정 헤더 (선택 사항).

KubernetesLifecycleHTTPGetHeader#

옵션 타입 필수 여부 설명
name string HTTP 헤더 이름.
value string HTTP 헤더 값.

KubernetesLifecycleTcpSocket#

옵션 타입 필수 여부 설명
port int 컨테이너에서 접근할 포트 번호.
host string 아니오 연결할 호스트 이름, 기본값은 pod IP (선택 사항).

pod DNS 설정 구성#

pod의 DNS 설정을 구성하려면 다음 옵션을 사용합니다.

옵션 타입 필수 여부 설명
nameservers string 목록 아니오 pod의 DNS 서버로 사용되는 IP 주소 목록.
options KubernetesDNSConfigOption 아니오 각 객체가 name 속성(필수)과 value 속성(선택 사항)을 가질 수 있는 선택적 객체 목록.
searches string 목록 아니오 pod에서 호스트 이름 조회를 위한 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 string 구성 옵션 이름.
value *string 아니오 구성 옵션 값.

기본 드롭 기능 목록#

GitLab Runner는 기본적으로 다음 기능을 드롭합니다.

사용자 정의 cap_add는 기본 드롭 기능 목록보다 우선순위가 높습니다. 기본적으로 드롭된 기능을 추가하려면 cap_add에 추가합니다.

  • NET_RAW

추가 호스트 별칭 추가#

이 기능은 Kubernetes 1.7 이상에서 사용 가능합니다.

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

다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
IP string 호스트를 연결할 IP 주소.
Hostnames string 목록 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"]

명령줄 파라미터 --kubernetes-host_aliases와 JSON 입력을 사용하여 호스트 별칭을 구성할 수도 있습니다. 예를 들어:

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

볼륨#

Kubernetes executor에서 캐시 사용#

Kubernetes executor에서 캐시를 사용하면 pod에 /cache라는 볼륨이 마운트됩니다. job 실행 중 캐시된 데이터가 필요한 경우 runner는 캐시된 데이터가 사용 가능한지 확인합니다. 캐시된 데이터는 캐시 볼륨에 압축 파일이 있는 경우 사용 가능합니다.

캐시 볼륨을 설정하려면 config.toml 파일의 cache_dir 설정을 사용합니다.

  • 사용 가능한 경우 압축 파일이 빌드 폴더에 압축 해제되고 job에서 사용할 수 있습니다.
  • 사용 가능하지 않은 경우 캐시된 데이터가 구성된 스토리지에서 다운로드되어 압축 파일로 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 볼륨을 구성하여 Kubernetes에 컨테이너에 지정된 호스트 경로를 마운트하도록 지시합니다.

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름.
mount_path string 컨테이너에서 볼륨이 마운트되는 경로.
sub_path string 아니오 루트 대신 마운트된 볼륨 내부의 서브 경로.
host_path string 아니오 볼륨으로 마운트된 호스트의 경로. 값을 지정하지 않으면 mount_path와 동일한 경로로 기본 설정됩니다.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다. 기본값은 false.
mount_propagation string 아니오 컨테이너 간에 마운트된 볼륨을 공유합니다. 자세한 내용은 마운트 전파를 참조하십시오.

persistentVolumeClaim 볼륨#

persistentVolumeClaim 볼륨을 구성하여 Kubernetes 클러스터에 정의된 persistentVolumeClaim을 사용하여 컨테이너에 마운트하도록 Kubernetes에 지시합니다.

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름이자 사용할 PersistentVolumeClaim의 이름. 변수를 지원합니다. 자세한 내용은 동시성별 영속 빌드 볼륨을 참조하십시오.
mount_path string 볼륨이 마운트되는 컨테이너의 경로.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다 (기본값: false).
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
mount_propagation string 아니오 볼륨의 마운트 전파 모드를 설정합니다. 자세한 내용은 Kubernetes 마운트 전파를 참조하십시오.

configMap 볼륨#

configMap 볼륨을 구성하여 Kubernetes에 Kubernetes 클러스터에 정의된 configMap을 사용하여 컨테이너에 마운트하도록 지시합니다.

config.toml에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름이자 사용할 configMap의 이름.
mount_path string 볼륨이 마운트되는 컨테이너의 경로.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다 (기본값: false).
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
items map[string]string 아니오 사용할 configMap의 키에 대한 키-경로 매핑.

선택한 configMap의 각 키는 파일로 변환되어 마운트 경로에 저장됩니다. 기본적으로:

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

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

Note

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

secret 볼륨#

secret 볼륨을 구성하여 Kubernetes에 Kubernetes 클러스터에 정의된 secret을 사용하여 컨테이너에 마운트하도록 지시합니다.

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름이자 사용할 _secret_의 이름.
mount_path string 볼륨이 마운트되어야 하는 컨테이너 내부 경로.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다 (기본값: false).
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
items map[string]string 아니오 사용할 configMap의 키에 대한 키-경로 매핑.

선택한 secret의 각 키는 선택한 마운트 경로에 저장된 파일로 변환됩니다. 기본적으로:

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

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

Note

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

emptyDir 볼륨#

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

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름.
mount_path string 볼륨이 마운트되어야 하는 컨테이너 내부 경로.
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
medium string 아니오 "Memory"는 tmpfs를 제공하고, 그렇지 않으면 노드 디스크 스토리지로 기본 설정됩니다 (기본값: "").
size_limit string 아니오 emptyDir 볼륨에 필요한 로컬 스토리지의 총 용량.

csi 볼륨#

Container Storage Interface(csi) 볼륨을 구성하여 Kubernetes에 사용자 지정 csi 드라이버를 사용하여 컨테이너에 임의의 스토리지 시스템을 마운트하도록 지시합니다.

config.toml에서 다음 옵션을 사용합니다:

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

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

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

config.toml 파일의 예시 구성:

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

사용자 지정 볼륨 마운트#

job의 빌드 디렉토리를 저장하려면 구성된 builds_dir(기본값: /builds)에 사용자 지정 볼륨 마운트를 정의합니다. 액세스 모드에 따라 pvc 볼륨을 사용하면 하나의 노드에서만 job을 실행하도록 제한될 수 있습니다.

config.toml 파일의 예시 구성:

concurrent = 4

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

동시성별 영속 빌드 볼륨#

히스토리
  • pvc.name에 대한 변수 주입 지원이 GitLab 16.3에서 도입되었습니다.

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

concurrent = 4

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

이 예시에서 build-pvc-0부터 build-pvc-3까지 이름이 지정된 영속 볼륨 클레임을 직접 생성합니다. runner의 concurrent 설정에서 지정하는 수만큼 생성합니다.

helper 이미지 사용#

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

Note

nonroot 환경만 필요한 경우 helper 이미지 대신 GitLab Runner UBI OpenShift Container Platform 이미지를 사용할 수 있습니다. GitLab Runner Helper UBI OpenShift Container Platform 이미지도 사용할 수 있습니다.

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

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

빌드에서 Docker 사용#

빌드에서 Docker를 사용할 때 알아야 할 몇 가지 고려 사항이 있습니다.

노출된 /var/run/docker.sock#

runners.kubernetes.volumes.host_path 옵션을 사용하여 호스트의 /var/run/docker.sock을 빌드 컨테이너에 노출하면 위험이 있습니다. 프로덕션 컨테이너와 동일한 클러스터에서 빌드를 실행할 때 주의하십시오. 노드의 컨테이너는 빌드 컨테이너에서 액세스할 수 있습니다.

docker:dind 사용#

docker:dind라고도 불리는 docker-in-docker 이미지를 실행하면 컨테이너가 권한 모드로 실행되어야 합니다. 이는 잠재적인 위험이 있으며 추가적인 문제를 야기할 수 있습니다.

Docker 데몬은 일반적으로 .gitlab-ci.yml에서 service로 시작되기 때문에 pod의 별도 컨테이너로 실행됩니다. pod의 컨테이너는 할당된 볼륨과 서로 localhost로 통신하는 데 사용하는 IP 주소만 공유합니다. docker:dind 컨테이너는 /var/run/docker.sock을 공유하지 않으며, docker 바이너리는 기본적으로 이를 사용하려 합니다.

다른 컨테이너에서 클라이언트가 TCP를 사용하여 Docker 데몬에 접속하도록 구성하려면 빌드 컨테이너의 환경 변수를 포함합니다:

  • TLS 없는 연결의 경우 DOCKER_HOST=tcp://docker:2375.
  • TLS 연결의 경우 DOCKER_HOST=tcp://docker:2376.

Docker 19.03 이상에서는 TLS가 기본적으로 활성화되어 있지만 인증서를 클라이언트에 매핑해야 합니다. Docker-in-Docker에 대해 TLS 없는 연결을 활성화하거나 인증서를 마운트할 수 있습니다. 자세한 내용은 Docker-in-Docker와 함께 Docker executor 사용을 참조하십시오.

호스트 커널 노출 방지#

docker:dind 또는 /var/run/docker.sock을 사용하면 Docker 데몬이 호스트 머신의 기반 커널에 액세스할 수 있습니다. 즉, Docker 이미지가 빌드될 때 pod에 설정된 limits가 작동하지 않습니다. Docker 데몬은 Kubernetes에 의해 Docker 빌드 컨테이너에 부과된 제한과 관계없이 노드의 전체 용량을 보고합니다.

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

빌드 컨테이너를 더 분리하려면 노드 taint를 사용할 수 있습니다. Taint는 다른 pod에 추가 구성 없이 빌드 pod와 동일한 노드에서 다른 pod가 예약되는 것을 방지합니다.

Docker 이미지 및 서비스 제한#

job을 실행하는 데 사용되는 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 job이 이미지를 가져오는 방법을 결정합니다.

.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 정책이 사용됩니다.
  • job은 pull_policyallowed_pull_policies 모두에 나열된 pull 정책만 사용합니다. 유효한 pull 정책은 pull_policy 키워드allowed_pull_policies의 정책을 비교하여 결정됩니다. GitLab은 이 두 정책 목록의 교집합을 사용합니다. 예를 들어 pull_policy["always", "if-not-present"]이고 allowed_pull_policies["if-not-present"]이면 두 목록 모두에 정의된 유일한 pull 정책이므로 job은 if-not-present만 사용합니다.
  • 기존 pull_policy 키워드에는 allowed_pull_policies에 지정된 pull 정책이 하나 이상 포함되어야 합니다. pull_policy 값 중 allowed_pull_policies와 일치하는 것이 없으면 job이 실패합니다.

Job 실행#

GitLab Runner는 기본적으로 kube exec 대신 kube attach를 사용합니다. 이렇게 하면 불안정한 네트워크 환경에서 job이 도중에 성공으로 표시되는 문제를 방지할 수 있습니다.

레거시 실행 전략 제거 진행 상황은 이슈 #27976을 참조하십시오.

Kubernetes API 요청 재시도 횟수 구성#

기본적으로 Kubernetes executor는 5번의 실패 후 Kubernetes API에 대한 특정 요청을 재시도합니다. 지연은 500밀리초 하한과 기본값 2초의 사용자 지정 가능한 상한이 있는 백오프 알고리즘으로 제어됩니다. 재시도 횟수를 구성하려면 config.toml 파일의 retry_limit 옵션을 사용합니다. 마찬가지로 백오프 상한의 경우 retry_backoff_max 옵션을 사용합니다. 다음 실패는 자동으로 재시도됩니다:

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

예를 들어 환경의 TLS 관련 오류를 기본 5번 대신 10번 재시도하도록 retry_limits 옵션을 구성합니다:

[[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

exceeded quota와 같이 완전히 다른 오류를 20번 재시도하려면:

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

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

컨테이너 진입점의 알려진 문제#

Note

GitLab 15.1 이상에서는 FF_KUBERNETES_HONOR_ENTRYPOINT가 설정되면 Docker 이미지에 정의된 진입점이 Kubernetes executor와 함께 사용됩니다.

컨테이너 진입점에는 다음과 같은 알려진 문제가 있습니다:

  • 이미지의 Dockerfile에 진입점이 정의되어 있는 경우 유효한 셸을 열어야 합니다. 그렇지 않으면 job이 멈춥니다.

    • 셸을 열기 위해 시스템은 빌드 컨테이너의 args로 명령을 전달합니다.
  • 파일 유형 CI/CD 변수는 진입점이 실행될 때 디스크에 기록되지 않습니다. 파일은 스크립트 실행 중에만 job에서 액세스할 수 있습니다.

  • 다음 CI/CD 변수는 진입점에서 액세스할 수 없습니다. 스크립트 명령을 실행하기 전에 설정 변경을 수행하려면 before_script를 사용할 수 있습니다:

GitLab Runner 17.4 이전:

  • 진입점 로그가 빌드 로그에 전달되지 않았습니다.
  • kube exec를 사용하는 Kubernetes executor에서 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는 poll_interval마다 .gitlab-startup-marker 파일을 확인합니다. poll_timeout 내에 파일이 없으면 pod가 비정상으로 간주되어 시스템이 빌드를 중단합니다.

Job 변수 접근 제한#

Kubernetes executor를 사용할 때 Kubernetes 클러스터에 접근하는 사용자는 job에서 사용되는 변수를 읽을 수 있습니다. 기본적으로 job 변수는 다음에 저장됩니다:

  • Pod의 환경 섹션

Job 변수 데이터 접근을 제한하려면 역할 기반 접근 제어(RBAC)를 사용해야 합니다. RBAC를 사용하면 GitLab 관리자만 GitLab Runner에서 사용하는 네임스페이스에 접근할 수 있습니다.

다른 사용자가 GitLab Runner 네임스페이스에 접근해야 하는 경우 다음 verbs를 설정하여 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보다 큰 숫자로 설정되어 있습니다.
  • getlist 권한이 있는 Kubernetes serviceAccount가 사용됩니다.

GitLab Runner는 각 시도 사이에 5초 간격으로 새로운 서비스 계정 또는 시크릿이 사용 가능한지 확인합니다.

  • 이 기능은 기본적으로 비활성화되어 있습니다. 이 기능을 활성화하려면 resource_availability_check_max_attempts0 이외의 값으로 설정합니다. 설정한 값은 runner가 서비스 계정 또는 시크릿을 확인하는 횟수를 정의합니다.

Kubernetes 네임스페이스 덮어쓰기#

필수 조건:

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

CI 목적을 위한 네임스페이스를 지정하고 사용자 지정 pod 세트를 배포하기 위해 Kubernetes 네임스페이스를 덮어쓸 수 있습니다. runner가 생성한 pod는 CI 단계 중 컨테이너 간 접근을 가능하게 하기 위해 덮어쓴 네임스페이스에 있습니다.

각 CI/CD job에 대한 Kubernetes 네임스페이스를 덮어쓰려면 .gitlab-ci.yml 파일에서 KUBERNETES_NAMESPACE_OVERWRITE 변수를 설정합니다.

variables:
  KUBERNETES_NAMESPACE_OVERWRITE: ci-${CI_COMMIT_REF_SLUG}
Note

이 변수는 클러스터에 네임스페이스를 생성하지 않습니다. job을 실행하기 전에 네임스페이스가 존재하는지 확인하십시오.

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

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

Kubernetes executor

Tier: Free, Premium, Ultimate
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
원문 보기
요약

Kubernetes executor를 사용하여 빌드에 Kubernetes 클러스터를 활용합니다. Kubernetes executor는 빌드를 여러 단계로 나눕니다: 다음 다이어그램은 GitLab 인스턴스와 Kubernetes 클러스터에 호스팅된 Runner 간의 상호 작용을 보여줍니다.

Kubernetes executor를 사용하여 빌드에 Kubernetes 클러스터를 활용합니다. executor는 Kubernetes 클러스터 API를 호출하고 각 GitLab CI 작업에 대해 파드를 생성합니다.

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

  1. Prepare: Kubernetes 클러스터에 파드를 생성합니다. 빌드 및 서비스 실행에 필요한 컨테이너를 생성합니다.
  2. Pre-build: 이전 스테이지에서 클론, 캐시 복원, 아티팩트 다운로드를 수행합니다. 이 단계는 파드의 일부인 특수 컨테이너에서 실행됩니다.
  3. Build: 사용자 빌드.
  4. Post-build: 캐시 생성, GitLab에 아티팩트 업로드. 이 단계도 파드의 일부인 특수 컨테이너를 사용합니다.

Runner가 Kubernetes 파드를 생성하는 방법#

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

파드는 .gitlab-ci.yml 또는 config.toml 파일에 정의된 각 service에 대해 다음 컨테이너로 구성됩니다:

  • build으로 정의된 빌드 컨테이너.
  • helper로 정의된 헬퍼 컨테이너.
  • 다음 로직을 사용하여 이름이 지정된 서비스 컨테이너:

서비스에 유효한 DNS 레이블 이름인 별칭이 있고 다른 서비스 컨테이너에서 이미 사용되지 않은 경우, 해당 별칭이 컨테이너 이름으로 사용됩니다.

유효한 별칭이 없으면 컨테이너는 svc-N으로 이름이 지정됩니다. 여기서 N은 0부터 시작하는 순차 인덱스입니다.

히스토리
  • 별칭 기반 이름 지정은 GitLab Runner 17.9에서 도입되었습니다.

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

  • 서비스는 DNS 이름을 통해 접근할 수 있습니다. 이전 버전을 사용하는 경우 localhost를 사용해야 합니다.
  • 동일한 포트를 사용하는 여러 서비스를 사용할 수 없습니다. 예를 들어, 두 개의 mysql 서비스를 동시에 사용할 수 없습니다.
Mermaid 다이어그램 (16줄)
소스 코드 보기
sequenceDiagram
    participant G as GitLab instance
    participant R as Runner on Kubernetes cluster
    participant Kube as Kubernetes API
    participant P as POD
    R->>+G: Get a CI job.
        loop
        G-->R: ;
    end
    Note over R,G: POST /api/v4/jobs/request
    G->>+R: CI job data.
    R-->>-Kube: Create a POD to run the CI job.
    Note over R,Kube: POST to Kube API
    P->>+P: Execute job.
    Note over P: CI build job = Prepare + Pre-build + Build + Post-build
    P->>+G: Job logs

다이어그램의 상호 작용은 모든 Kubernetes 클러스터에 유효합니다. 예를 들어, 주요 퍼블릭 클라우드 제공업체에서 호스팅되는 턴키 솔루션이나 자체 관리 Kubernetes 설치에 적용됩니다.

Kubernetes API에 연결#

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

옵션 설명
host 선택적 Kubernetes API 서버 호스트 URL (지정하지 않으면 자동 검색 시도).
context kubectl 구성에서 사용할 선택적 Kubernetes 컨텍스트 이름. host를 지정하지 않을 때 이 옵션을 사용합니다.
cert_file 선택적 Kubernetes API 서버 사용자 인증 인증서.
key_file 선택적 Kubernetes API 서버 사용자 인증 개인 키.
ca_file 선택적 Kubernetes API 서버 CA 인증서.

Kubernetes 클러스터에서 GitLab Runner를 실행하는 경우, GitLab Runner가 Kubernetes API를 자동 검색할 수 있도록 이 필드를 생략합니다.

클러스터 외부에서 GitLab Runner를 실행하는 경우, 이 설정은 GitLab Runner가 클러스터의 Kubernetes API에 접근할 수 있도록 합니다. 인증 세부 정보와 함께 host를 지정하거나, context를 사용하여 kubectl 구성에서 특정 컨텍스트를 참조할 수 있습니다.

Kubernetes API 호출을 위한 베어러 토큰 설정#

파드 생성을 위한 API 호출의 베어러 토큰을 설정하려면 KUBERNETES_BEARER_TOKEN 변수를 사용합니다. 이를 통해 프로젝트 소유자가 프로젝트 시크릿 변수를 사용하여 베어러 토큰을 지정할 수 있습니다.

베어러 토큰을 지정할 때는 반드시 Host 구성 설정을 지정해야 합니다.

variables:
  KUBERNETES_BEARER_TOKEN: thebearertokenfromanothernamespace

Runner API 권한 구성#

코어 API 그룹에 대한 권한을 구성하려면 GitLab Runner Helm 차트의 values.yml 파일을 업데이트합니다.

다음 중 하나를 수행할 수 있습니다:

  • rbac.createtrue로 설정합니다.
  • values.yml 파일에서 다음 권한을 가진 서비스 계정 serviceAccount.name: <service_account_name>을 지정합니다.
리소스 동사 (선택적 기능/구성 플래그)
events list (print_pod_warning_events=true), watch (FF_PRINT_POD_EVENTS=true)
namespaces create (kubernetes.NamespacePerJob=true), delete (kubernetes.NamespacePerJob=true)
poddisruptionbudgets create (pod_disruption_budget=true), get (pod_disruption_budget=true)
pods create, delete, get, list (Informer 사용), watch (Informer 사용, FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/attach create (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), delete (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), get (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), patch (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/exec create, delete, get, patch
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

필요한 권한을 가진 역할을 생성하려면 다음 YAML 역할 정의를 사용할 수 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: gitlab-runner
  namespace: default
rules:
- apiGroups: [""]
  resources: ["events"]
  verbs:
  - "list" # Required when `print_pod_warning_events=true`
  - "watch" # Required when `FF_PRINT_POD_EVENTS=true`
- apiGroups: [""]
  resources: ["namespaces"]
  verbs:
  - "create" # Required when `kubernetes.NamespacePerJob=true`
  - "delete" # Required when `kubernetes.NamespacePerJob=true`
- apiGroups: ["policy"]
  resources: ["poddisruptionbudgets"]
  verbs:
  - "create" # Required when `pod_disruption_budget=true`
  - "get" # Required when `pod_disruption_budget=true`
- apiGroups: [""]
  resources: ["pods"]
  verbs:
  - "create"
  - "delete"
  - "get"
  - "list" # Required when using Informers (https://docs.gitlab.com/runner/executors/kubernetes/#informers)
  - "watch" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`, using Informers (https://docs.gitlab.com/runner/executors/kubernetes/#informers)
- apiGroups: [""]
  resources: ["pods/attach"]
  verbs:
  - "create" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
  - "delete" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
  - "get" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
  - "patch" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs:
  - "create"
  - "delete"
  - "get"
  - "patch"
- apiGroups: [""]
  resources: ["pods/log"]
  verbs:
  - "get" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`, `FF_WAIT_FOR_POD_TO_BE_REACHABLE=true`
  - "list" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`
- apiGroups: [""]
  resources: ["secrets"]
  verbs:
  - "create"
  - "delete"
  - "get"
  - "update"
- apiGroups: [""]
  resources: ["serviceaccounts"]
  verbs:
  - "get"
- apiGroups: [""]
  resources: ["services"]
  verbs:
  - "create"
  - "get"

추가 세부 정보:

Informer#

GitLab Runner 17.9.0 이상에서는 Kubernetes informer가 빌드 파드 변경 사항을 추적합니다. 이를 통해 executor가 변경 사항을 더 빠르게 감지할 수 있습니다.

informer는 pods에 대한 listwatch 권한이 필요합니다. executor가 빌드를 시작할 때 Kubernetes API에서 권한을 확인합니다. 모든 권한이 부여되면 executor는 informer를 사용합니다. 권한이 누락된 경우 GitLab Runner는 경고를 기록합니다. 빌드는 계속되며 이전 메커니즘을 사용하여 빌드 파드의 상태와 변경 사항을 추적합니다.

구성 설정#

Kubernetes executor를 구성하려면 config.toml 파일에서 다음 설정을 사용합니다.

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 요청 덮어쓰기 기능을 비활성화합니다.
pod_cpu_limit 빌드 파드에 할당된 CPU.
pod_cpu_limit_overwrite_max_allowed 빌드 파드에 대해 CPU 할당을 덮어쓸 수 있는 최대량. 비어 있으면 CPU 제한 덮어쓰기 기능을 비활성화합니다.
pod_cpu_request 빌드 파드에 요청된 CPU 할당.
pod_cpu_request_overwrite_max_allowed 빌드 파드에 대해 CPU 할당 요청을 덮어쓸 수 있는 최대량. 비어 있으면 CPU 요청 덮어쓰기 기능을 비활성화합니다.
Note

파드 수준 리소스 사양은 Kubernetes v1.32에서 알파 기능으로 도입되었으며 Kubernetes v1.34에서 베타로 승급되었습니다.

메모리 요청 및 제한#

설정 설명
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 서비스 컨테이너에 대해 메모리 할당 요청을 덮어쓸 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능을 비활성화합니다.
pod_memory_limit 빌드 파드에 할당된 메모리 양.
pod_memory_limit_overwrite_max_allowed 빌드 파드에 대해 메모리 할당을 덮어쓸 수 있는 최대량. 비어 있으면 메모리 제한 덮어쓰기 기능을 비활성화합니다.
pod_memory_request 빌드 파드에 요청된 메모리 양.
pod_memory_request_overwrite_max_allowed 빌드 파드에 대해 메모리 할당 요청을 덮어쓸 수 있는 최대량. 비어 있으면 메모리 요청 덮어쓰기 기능을 비활성화합니다.

헬퍼 컨테이너 메모리 크기 권장 사항#

최적의 성능을 위해 워크로드 요구 사항에 따라 헬퍼 컨테이너 메모리 제한을 설정합니다:

  • 캐싱 및 아티팩트 생성이 있는 워크로드: 최소 250 MiB
  • 캐시/아티팩트 없는 기본 워크로드: 더 낮은 제한(128-200 MiB)으로 작동할 수 있음

기본 구성 예시:

[[runners]]
  executor = "kubernetes"
  [runners.kubernetes]
    helper_memory_limit = "250Mi"
    helper_memory_request = "250Mi"
    helper_memory_limit_overwrite_max_allowed = "1Gi"

작업별 메모리 덮어쓰기:

관리자 변경 없이 특정 작업에 대해 메모리를 조정하려면 KUBERNETES_HELPER_MEMORY_LIMIT 변수를 사용합니다:

job_with_higher_helper_memory_limit:
  variables:
    KUBERNETES_HELPER_MEMORY_LIMIT: "512Mi"
  script:

이 접근 방식을 통해 개발자는 helper_memory_limit_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 빌드를 실행할 노드를 결정하는 어피니티 규칙을 지정합니다. 노드 어피니티 사용에 대해 자세히 알아보세요.
allow_privilege_escalation allowPrivilegeEscalation 플래그를 활성화한 상태로 모든 컨테이너를 실행합니다. 비어 있으면 컨테이너 SecurityContextallowPrivilegeEscalation 플래그를 정의하지 않으며 Kubernetes가 기본 권한 상승 동작을 사용하도록 합니다.
allowed_groups 컨테이너 그룹에 지정할 수 있는 그룹 ID 배열. 존재하지 않으면 모든 그룹이 허용됩니다. 자세한 내용은 컨테이너 사용자 및 그룹 구성을 참조하세요.
allowed_images .gitlab-ci.yml에서 지정할 수 있는 이미지의 와일드카드 목록. 존재하지 않으면 모든 이미지가 허용됩니다(["*/*:*"]와 동일). 세부 정보 보기.
allowed_pull_policies .gitlab-ci.yml 파일이나 config.toml 파일에서 지정할 수 있는 풀 정책 목록.
allowed_services .gitlab-ci.yml에서 지정할 수 있는 서비스의 와일드카드 목록. 존재하지 않으면 모든 이미지가 허용됩니다(["*/*:*"]와 동일). 세부 정보 보기.
allowed_users 컨테이너 사용자에 지정할 수 있는 사용자 ID 배열. 존재하지 않으면 모든 사용자가 허용됩니다. 자세한 내용은 컨테이너 사용자 및 그룹 구성을 참조하세요.
automount_service_account_token 빌드 파드에서 서비스 계정 토큰이 자동으로 마운트되는지 여부를 제어하는 부울 값.
bearer_token 빌드 파드를 시작하는 데 사용되는 기본 베어러 토큰.
bearer_token_overwrite_allowed 프로젝트가 빌드 파드를 생성하는 데 사용되는 베어러 토큰을 지정할 수 있도록 하는 부울 값.
build_container_security_context 빌드 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
cap_add 작업 파드 컨테이너에 추가해야 할 Linux 기능을 지정합니다. Kubernetes executor에서 기능 구성에 대해 자세히 알아보기.
cap_drop 작업 파드 컨테이너에서 제거해야 할 Linux 기능을 지정합니다. Kubernetes executor에서 기능 구성에 대해 자세히 알아보기.
cleanup_grace_period_seconds 작업이 완료되면 파드가 정상적으로 종료되는 시간(초). 이 기간 이후 프로세스는 kill 시그널로 강제 종료됩니다. terminationGracePeriodSeconds가 지정되면 무시됩니다.
context kubectl 구성에서 사용할 Kubernetes 컨텍스트 이름(host가 지정되지 않은 경우).
dns_policy 파드 구성 시 사용할 DNS 정책을 지정합니다: none, default, cluster-first, cluster-first-with-host-net. 설정하지 않으면 Kubernetes 기본값(cluster-first)이 사용됩니다.
dns_config 파드 구성 시 사용할 DNS 구성을 지정합니다. 파드 DNS 설정 구성에 대해 자세히 알아보기.
helper_container_security_context 헬퍼 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
helper_image (고급) 리포지터리 클론 및 아티팩트 업로드에 사용되는 기본 헬퍼 이미지를 재정의합니다.
helper_image_flavor 헬퍼 이미지 플레이버를 설정합니다(alpine, alpine3.21 또는 ubuntu). 기본값은 alpine입니다. alpine을 사용하는 것은 alpine3.21과 동일합니다.
host_aliases 모든 컨테이너에 추가되는 추가 호스트 이름 별칭 목록. 추가 호스트 별칭 사용에 대해 자세히 알아보기.
image_pull_secrets 비공개 레지스트리에서 Docker 이미지 풀링 인증에 사용되는 Kubernetes docker-registry 시크릿 이름을 포함하는 항목 배열.
init_permissions_container_security_context init-permissions 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
namespace Kubernetes 파드를 실행할 네임스페이스.
namespace_per_job 별도의 네임스페이스에서 작업을 격리합니다. 활성화되면 namespacenamespace_overwrite_allowed가 무시됩니다.
namespace_overwrite_allowed 네임스페이스 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식(아래 문서 참조). 비어 있으면 네임스페이스 덮어쓰기 기능을 비활성화합니다.
node_selector string=string 형식(환경 변수의 경우 string:string)의 key=valuetable. 이를 설정하면 모든 key=value 쌍과 일치하는 Kubernetes 노드에서만 파드가 생성됩니다. 노드 선택기 사용에 대해 자세히 알아보기.
node_tolerations string=string:string 형식의 "key=value" = "Effect"table. 이를 설정하면 모든 또는 일부 톨러레이션된 테인트가 있는 노드에 파드를 스케줄링할 수 있습니다. 환경 변수 구성을 통해 하나의 톨러레이션만 제공할 수 있습니다. key, valueeffect는 Kubernetes 파드 톨러레이션 구성의 해당 필드 이름과 일치합니다.
pod_annotations string=string 형식의 key=valuetable. Runner가 생성한 각 빌드 파드에 추가할 어노테이션 목록을 포함합니다. 이 값에는 확장을 위한 환경 변수를 포함할 수 있습니다. 파드 어노테이션은 각 빌드에서 덮어쓸 수 있습니다.
pod_annotations_overwrite_allowed 파드 어노테이션 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식. 비어 있으면 파드 어노테이션 덮어쓰기 기능을 비활성화합니다.
pod_labels string=string 형식의 key=valuetable. Runner가 생성한 각 빌드 파드에 추가할 레이블 목록을 포함합니다. 이 값에는 확장을 위한 환경 변수를 포함할 수 있습니다. 파드 레이블은 pod_labels_overwrite_allowed를 사용하여 각 빌드에서 덮어쓸 수 있습니다.
pod_labels_overwrite_allowed 파드 레이블 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식. 비어 있으면 파드 레이블 덮어쓰기 기능을 비활성화합니다. runner.gitlab.com 레이블 네임스페이스의 파드 레이블은 덮어쓸 수 없습니다.
pod_security_context 구성 파일을 통해 구성되며, 빌드 파드에 대한 파드 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
pod_termination_grace_period_seconds 파드 내 프로세스가 종료 시그널을 받은 후 kill 시그널로 강제 종료되기까지의 시간(초)을 결정하는 파드 수준 설정. terminationGracePeriodSeconds가 지정되면 무시됩니다.
poll_interval Runner가 방금 생성한 Kubernetes 파드의 상태를 확인하기 위해 폴링하는 빈도(초)(기본값 = 3).
poll_timeout Runner가 방금 생성한 컨테이너에 연결을 시도하기 전에 경과해야 하는 시간(초). 클러스터가 한 번에 처리할 수 있는 것보다 더 많은 빌드를 대기열에 넣을 때 이 설정을 사용합니다(기본값 = 180).
cleanup_resources_timeout 작업 완료 후 Kubernetes 리소스를 정리하는 총 시간. 지원되는 구문: 1h30m, 300s, 10m. 기본값은 5분(5m).
priority_class_name 파드에 설정할 Priority Class를 지정합니다. 설정하지 않으면 기본값이 사용됩니다.
privileged privileged 플래그로 컨테이너를 실행합니다.
pull_policy 이미지 풀 정책을 지정합니다: never, if-not-present, always. 설정하지 않으면 클러스터의 이미지 기본 풀 정책이 사용됩니다. 여러 풀 정책 설정 방법에 대한 자세한 내용은 풀 정책 사용을 참조하세요. if-not-present, never 보안 고려 사항도 참조하세요. 풀 정책 제한도 가능합니다.
resource_availability_check_max_attempts 리소스(서비스 계정 및/또는 풀 시크릿) 세트가 사용 가능한지 확인하는 최대 시도 횟수. 각 시도 사이에 5초 간격이 있습니다. 준비 단계에서의 리소스 확인에 대해 자세히 알아보기.
runtime_class_name 생성된 모든 파드에 사용할 Runtime class. 클러스터에서 이 기능이 지원되지 않으면 작업이 종료되거나 실패합니다.
service_container_security_context 서비스 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트에 대해 자세히 알아보기.
scheduler_name 빌드 파드 스케줄링에 사용할 스케줄러.
service_account 작업/executor 파드가 Kubernetes API와 통신하는 데 사용하는 기본 서비스 계정.
service_account_overwrite_allowed 서비스 계정 덮어쓰기 환경 변수의 내용을 검증하는 정규 표현식. 비어 있으면 서비스 계정 덮어쓰기 기능을 비활성화합니다.
services 사이드카 패턴을 사용하여 빌드 컨테이너에 연결된 서비스 목록. 서비스 사용에 대해 자세히 알아보기.
use_service_account_image_pull_secrets 활성화되면 executor가 생성한 파드에 imagePullSecrets가 없습니다. 이로 인해 설정된 경우 서비스 계정의 imagePullSecrets를 사용하여 파드가 생성됩니다.
terminationGracePeriodSeconds 파드 내 프로세스가 종료 시그널을 받은 후 kill 시그널로 강제 종료되기까지의 시간. cleanup_grace_period_secondspod_termination_grace_period_seconds를 위해 더 이상 사용되지 않습니다.
volumes 구성 파일을 통해 구성되며, 빌드 컨테이너에 마운트되는 볼륨 목록. 볼륨 사용에 대해 자세히 알아보기.
pod_spec 이 설정은 실험적입니다. CI 작업을 실행하는 데 사용되는 파드에 설정된 구성 목록으로 Runner 매니저가 생성한 파드 사양을 덮어씁니다. Kubernetes Pod Specification에 나열된 모든 속성을 설정할 수 있습니다. 자세한 내용은 생성된 파드 사양 덮어쓰기(실험)를 참조하세요.
retry_limit Kubernetes API와 통신하는 최대 시도 횟수. 각 시도 간의 재시도 간격은 500ms에서 시작하는 백오프 알고리즘을 기반으로 합니다.
retry_backoff_max 각 시도에 대한 재시도 간격이 도달할 사용자 정의 최대 백오프 값(밀리초). 기본값은 2000ms이며 500ms 미만으로 설정할 수 없습니다. 각 시도에 대한 기본 최대 재시도 간격은 2초이며 retry_backoff_max로 사용자 정의할 수 있습니다.
retry_limits 각 요청 오류를 재시도하는 횟수.
logs_base_dir 빌드 로그를 저장하기 위해 생성된 경로 앞에 추가할 기본 디렉토리. 자세한 내용은 빌드 로그 및 스크립트의 기본 디렉토리 변경을 참조하세요.
scripts_base_dir 빌드 스크립트를 저장하기 위해 생성된 경로 앞에 추가할 기본 디렉토리. 자세한 내용은 빌드 로그 및 스크립트의 기본 디렉토리 변경을 참조하세요.
print_pod_warning_events 활성화되면 작업 실패 시 파드와 관련된 모든 경고 이벤트를 검색합니다. 이 기능은 기본적으로 활성화되어 있으며 최소 events: list 권한이 있는 서비스 계정이 필요합니다.
pod_disruption_budget 활성화되면 노드 드레인 및 클러스터 업그레이드와 같은 자발적 중단 중 축출을 방지하기 위해 각 작업 파드에 대해 PodDisruptionBudget이 생성됩니다. 기본적으로 비활성화되어 있습니다. poddisruptionbudgets 권한이 있는 서비스 계정이 필요합니다.

구성 예시#

다음 샘플은 Kubernetes executor를 위한 config.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 플래그를 사용할 수 있습니다.

파드 및 컨테이너#

작업 실행 방식을 제어하기 위해 파드와 컨테이너를 구성할 수 있습니다.

작업 파드의 기본 레이블#

Warning

Runner 구성이나 .gitlab-ci.yml 파일을 통해 이 레이블을 재정의할 수 없습니다. runner.gitlab.com 네임스페이스의 레이블을 설정하거나 수정하려는 시도는 무시되며 디버그 메시지로 기록됩니다.

설명
project.runner.gitlab.com/id GitLab 인스턴스 내 프로젝트 간 고유한 프로젝트 ID.
project.runner.gitlab.com/name 프로젝트 이름.
project.runner.gitlab.com/namespace-id 프로젝트 네임스페이스의 ID.
project.runner.gitlab.com/namespace 프로젝트 네임스페이스의 이름.
project.runner.gitlab.com/root-namespace 프로젝트 루트 네임스페이스의 ID. 예: /gitlab-org/group-a/subgroup-a/project, 여기서 루트 네임스페이스는 gitlab-org
manager.runner.gitlab.com/name 이 작업을 시작한 Runner 구성의 이름.
manager.runner.gitlab.com/id-short 작업을 시작한 Runner 구성의 ID.
job.runner.gitlab.com/pod Kubernetes executor가 사용하는 내부 레이블.

작업 파드의 기본 어노테이션#

다음 어노테이션은 작업을 실행하는 파드에 기본적으로 추가됩니다:

설명
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 작업 이름.
job.runner.gitlab.com/timeout 시간 형식의 작업 실행 타임아웃. 예: 2h3m0.5s.
project.runner.gitlab.com/id 작업의 프로젝트 ID.

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

파드 수명 주기#

파드의 수명 주기는 다음에 의해 영향을 받을 수 있습니다:

  • TOML 구성 파일에서 pod_termination_grace_period_seconds 속성을 설정합니다. 파드에서 실행 중인 프로세스는 TERM 시그널이 전송된 후 지정된 기간 동안 실행할 수 있습니다. 이 기간 후에 파드가 성공적으로 종료되지 않으면 kill 시그널이 전송됩니다.
  • FF_USE_POD_ACTIVE_DEADLINE_SECONDS 기능 플래그를 활성화합니다. 활성화되고 작업이 시간 초과되면 CI/CD 작업을 실행하는 파드가 실패로 표시되고 모든 관련 컨테이너가 종료됩니다. GitLab에서 먼저 작업이 시간 초과되도록 하기 위해 activeDeadlineSeconds구성된 타임아웃 + 1초로 설정됩니다.
Note

FF_USE_POD_ACTIVE_DEADLINE_SECONDS 기능 플래그를 활성화하고 pod_termination_grace_period_seconds를 0이 아닌 값으로 설정하면 CI/CD 작업 파드가 즉시 종료되지 않습니다. 파드 terminationGracePeriods는 만료된 경우에만 파드가 종료되도록 합니다.

작업 파드를 축출로부터 보호#

히스토리

노드 드레인 및 클러스터 업그레이드와 같은 자발적 중단으로부터 작업 파드를 보호하려면 pod_disruption_budget 옵션을 활성화합니다.

활성화되면 이 설정은 minAvailable: 1로 각 작업 파드에 대해 PodDisruptionBudget을 생성합니다. 이 작업은 자발적 중단 중에 Kubernetes 축출 API가 파드를 축출하는 것을 방지합니다.

[runners.kubernetes]
  pod_disruption_budget = true

PodDisruptionBudget:

  • Kubernetes 소유자 참조를 통해 작업 파드가 삭제될 때 자동으로 삭제됩니다.
  • 노드 장애나 메모리 부족 종료와 같은 비자발적 중단으로부터는 보호하지 않습니다.
  • 추가 RBAC 권한이 필요합니다. 자세한 내용은 Runner API 권한 구성을 참조하세요.
Warning

PodDisruptionBudget을 활성화하면 작업이 실행 중일 때 노드 드레인이 중단될 수 있습니다. 클러스터 업그레이드 전략이 잠재적인 노드 드레인 지연을 고려하도록 하거나, 작업 타임아웃을 사용하여 작업 실행 시간을 제한하세요.

파드 톨러레이션 덮어쓰기#

Kubernetes 파드 톨러레이션을 덮어쓰려면:

  1. config.toml 또는 Helm values.yaml 파일에서 CI 작업 파드 톨러레이션의 덮어쓰기를 활성화하려면 node_tolerations_overwrite_allowed에 대한 정규 표현식을 정의합니다. 이 정규 표현식은 KUBERNETES_NODE_TOLERATIONS_로 시작하는 CI 변수 이름의 값을 검증합니다.

    runners:
     ...
     config: |
       [[runners]]
         [runners.kubernetes]
           node_tolerations_overwrite_allowed = ".*"
    
  2. .gitlab-ci.yml 파일에서 CI 작업 파드 톨러레이션을 덮어쓰기 위해 하나 이상의 CI 변수를 정의합니다.

    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: '' # 모든 테인트 톨러레이트
    

파드 레이블 덮어쓰기#

각 CI/CD 작업에 대해 Kubernetes 파드 레이블을 덮어쓰려면:

  1. .config.yaml 파일에서 pod_labels_overwrite_allowed에 대한 정규 표현식을 정의합니다.

  2. .gitlab-ci.yml 파일에서 key=value 값을 가진 KUBERNETES_POD_LABELS_* 변수를 설정합니다. 파드 레이블이 key=value로 덮어쓰여집니다. 여러 값을 적용할 수 있습니다:

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

runner.gitlab.com 네임스페이스의 레이블은 읽기 전용입니다. GitLab은 이러한 GitLab 내부 레이블을 추가, 수정 또는 제거하려는 시도를 무시합니다.

파드 어노테이션 덮어쓰기#

각 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]]
  # usual configuration
  executor = "kubernetes"
  [runners.kubernetes]
    image = "alpine"
    pod_annotations_overwrite_allowed = ".*"
    [runners.kubernetes.pod_annotations]
      "Key1" = "Val1"
      "Key2" = "Val2"
      "Key3" = "Val3"
      "Key4" = "Val4"

생성된 파드 사양 덮어쓰기#

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

기능이 일반적으로 사용 가능해지기 전에 피드백을 추가하려면 이슈 556286에 댓글을 남겨주세요.

Runner 매니저가 생성한 PodSpec을 수정하려면 config.toml 파일에서 pod_spec 설정을 사용합니다.

Runner operator별 구성에 대해서는 패치 구조를 참조하세요.

pod_spec 설정:

  • 생성된 파드 사양의 필드를 덮어쓰고 완성합니다.
  • [runners.kubernetes] 아래의 config.toml에서 설정되었을 수 있는 구성 값을 덮어씁니다.

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

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

동일한 pod_spec 구성에서 patch_pathpatch를 설정할 수 없으며, 그렇지 않으면 오류가 발생합니다.

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 구성 예시. 이 구성에서는 기존 nodeSelector에 새로운 key: value pair가 추가됩니다. 기존 값은 덮어쓰여지지 않습니다.

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"

전략적 패치 전략#

strategic 패치 전략은 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가 생성한 사양에 부정적인 영향을 미치지 않도록 합니다.
  • 복잡한 파드 사양 업데이트에는 merge 패치 전략을 사용하지 마세요.
  • 가능한 경우 구성이 사용 가능할 때 config.toml을 사용합니다. 예를 들어, 다음 구성은 기존 목록에 환경 변수 세트를 추가하는 대신 사용자 정의 pod_spec에서 설정한 환경 변수로 GitLab Runner가 설정한 첫 번째 환경 변수를 대체합니다.
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"

Pod Spec을 수정하여 각 빌드 작업에 대한 PVC 생성#

각 빌드 작업에 대해 PersistentVolumeClaim을 생성하려면 Pod Spec 기능을 활성화하는 방법을 확인하세요.

Kubernetes를 사용하면 파드의 수명 주기에 연결된 임시 PersistentVolumeClaim을 생성할 수 있습니다. 이 접근 방식은 Kubernetes 클러스터에서 동적 프로비저닝이 활성화된 경우 작동합니다. 각 PVC는 새 볼륨을 요청할 수 있습니다. 볼륨도 파드의 수명 주기에 연결됩니다.

동적 프로비저닝이 활성화된 후 임시 PVC를 생성하기 위해 config.toml을 다음과 같이 수정할 수 있습니다:

[[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: 
            accessModes: [ ReadWriteOnce ]
            resources:
              requests:
                storage: 1Gi
  '''

파드에 대한 보안 정책 설정#

빌드 파드에 대한 보안 정책을 설정하려면 config.toml에서 보안 컨텍스트를 구성합니다.

다음 옵션을 사용합니다:

옵션 타입 필수 설명
fs_group int 아니오 파드의 모든 컨테이너에 적용되는 특수 보조 그룹.
run_as_group int 아니오 컨테이너 프로세스의 진입점을 실행할 GID.
run_as_non_root boolean 아니오 컨테이너가 비root 사용자로 실행되어야 함을 나타냅니다.
run_as_user int 아니오 컨테이너 프로세스의 진입점을 실행할 UID.
supplemental_groups int list 아니오 컨테이너의 기본 GID 외에 각 컨테이너에서 실행되는 첫 번째 프로세스에 적용되는 그룹 목록.
selinux_type string 아니오 파드의 모든 컨테이너에 적용되는 SELinux 타입 레이블.

config.toml에서 파드 보안 컨텍스트의 예시:

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

이전 Runner 파드 제거#

때때로 이전 Runner 파드가 정리되지 않을 수 있습니다. 이는 Runner 매니저가 올바르게 종료되지 않았을 때 발생할 수 있습니다.

이 상황을 처리하려면 GitLab Runner Pod Cleanup 애플리케이션을 사용하여 이전 파드의 정리를 예약할 수 있습니다. 자세한 내용은 다음을 참조하세요:

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

컨테이너에 대한 보안 정책 설정#

빌드, 헬퍼 또는 서비스 파드에 대한 컨테이너 보안 정책을 설정하려면 config.toml executor에서 컨테이너 보안 컨텍스트를 구성합니다.

다음 옵션을 사용합니다:

옵션 타입 필수 설명
run_as_group int 아니오 컨테이너 프로세스의 진입점을 실행할 GID.
run_as_non_root boolean 아니오 컨테이너가 비root 사용자로 실행되어야 함을 나타냅니다.
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

풀 정책 설정#

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

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

단일 풀 정책:

[runners.kubernetes]
  pull_policy = "never"

여러 풀 정책:

[runners.kubernetes]
  # use multiple pull policies
  pull_policy = ["always", "if-not-present"]

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

실패한 풀을 재시도하려면:

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

GitLab 명명 규칙은 Kubernetes와 다릅니다.

Runner 풀 정책 Kubernetes 풀 정책 설명
none none Kubernetes에서 지정한 기본 정책을 사용합니다.
if-not-present IfNotPresent 작업을 실행하는 노드에 이미 존재하지 않는 경우에만 이미지를 풀합니다. 이 풀 정책을 사용하기 전에 보안 고려 사항을 검토하세요.
always Always 작업이 실행될 때마다 이미지를 풀합니다.
never Never 이미지를 풀하지 않으며 노드에 이미 있어야 합니다.

컨테이너 기능 지정#

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

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

Runner가 기본적으로 제거하는 기능 목록이 있습니다. 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를 정의하여 특정 기능을 허용, 제한 또는 기본적으로 추가할 수 있습니다. 이 규칙은 모든 사용자 정의 구성보다 우선합니다.

컨테이너 사용자 및 그룹 구성#

히스토리
  • Support for security context-based user configuration introduced in GitLab Runner 18.4.

Kubernetes 보안 컨텍스트 구성을 사용하여 컨테이너에서 실행되는 사용자와 그룹을 구성합니다. 관리자는 컨테이너 보안을 제어하고 작업이 특정 컨테이너 유형에 대해 사용자를 지정할 수 있도록 허용할 수 있습니다.

Note

Windows에서는 작업 정의에서 runAsUser, runAsGroup 또는 image:user 설정이 지원되지 않습니다. 대신 FF_USE_ADVANCED_POD_SPEC_CONFIGURATION을 통해 runAsUserName 설정을 권장합니다.

구성 우선순위#

Runner는 다음 순서로 사용자 구성을 적용합니다:

빌드 및 서비스 컨테이너:

  1. 컨테이너 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 이 구성을 제어
  2. 파드 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 파드 수준 기본값을 제어
  3. 작업 구성 (.gitlab-ci.yml): 사용자가 이 구성을 제어

헬퍼 컨테이너:

  1. 헬퍼 컨테이너 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 이 구성을 제어
  2. 파드 보안 컨텍스트 (run_as_user/run_as_group): 관리자가 파드 수준 기본값을 제어

보안 격리를 위해 작업 구성은 헬퍼 컨테이너에 적용되지 않습니다.

관리자는 보안 준수를 위해 사용자가 지정한 값을 재정의할 수 있습니다. 헬퍼 컨테이너는 작업 사양으로부터 격리됩니다.

Kubernetes 요구 사항#

Kubernetes는 사용자 및 그룹 ID에 숫자 값을 요구합니다:

  • 사용자 및 그룹 ID는 정수여야 합니다
  • SecurityContextrun_as_userrun_as_group을 사용하며 숫자 값만 허용합니다
  • 작업 구성에서 사용자만 지정할 때는 "1000"을, 사용자와 그룹을 지정할 때는 "1000:1001"을 사용합니다

사용자 및 그룹 설정 재정의#

파드 및 컨테이너별 보안 컨텍스트를 사용하여 사용자 및 그룹 설정을 재정의합니다:

[[runners]]
  name = "k8s-runner"
  url = "https://gitlab.example.com"
  executor = "kubernetes"
  [runners.kubernetes]
    allowed_users = ["1000", "1001", "65534"]
    allowed_groups = ["1001", "65534"]

    # Pod security context - provides defaults for all containers
    [runners.kubernetes.pod_security_context]
      run_as_user = 1500
      run_as_group = 1500

    # Build container security context - overrides pod context
    [runners.kubernetes.build_container_security_context]
      run_as_user = 2000
      run_as_group = 2001

    # Helper container security context - overrides pod context
    [runners.kubernetes.helper_container_security_context]
      run_as_user = 3000
      run_as_group = 3001

    # Service container security context - overrides pod context
    [runners.kubernetes.service_container_security_context]
      run_as_user = 4000
      run_as_group = 4001

이 예시에서:

  • 파드 보안 컨텍스트는 특정 구성이 없는 컨테이너에 대한 기본값(1500:1500)을 설정합니다
  • 컨테이너 보안 컨텍스트가 파드 기본값을 재정의합니다
  • 사용자 1500, 2000, 3000, 4000은 allowed_users 목록에 없지만, 이 값은 허용 목록 검증을 우회하므로 보안 컨텍스트에서 사용할 수 있습니다
  • 이 기능은 관리자에게 파드 및 컨테이너 수준에서 제한 없는 재정의 제어를 제공합니다

각 컨테이너 유형을 독립적으로 구성할 수 있습니다. 보안 컨텍스트 구성은 작업 구성의 모든 사용자 사양보다 우선합니다.

작업 구성에서 사용자 지정#

작업은 이미지 구성에서 사용자를 지정할 수 있습니다:

# Job with custom user
job:
  image:
    name: alpine:latest
    kubernetes:
      user: "1000"
  script:
    - whoami
    - id

# Job with user and group
job_with_group:
  image:
    name: alpine:latest
    kubernetes:
      user: "1000:1001"
  script:
    - whoami
    - id

# Job using environment variable
job_dynamic:
  image:
    name: alpine:latest
    kubernetes:
      user: "${CUSTOM_USER_ID}"
  variables:
    CUSTOM_USER_ID: "1000"
  script:
    - whoami

보안 검증#

Runner는 작업 수준 구성에 대해서만 허용 목록에 대해 사용자 및 그룹 ID를 검증합니다:

  • Root 사용자/그룹 (UID/GID 0): 작업 구성에 대해 항상 명시적 허용 목록 권한이 필요합니다
  • 비어 있는 allowed_users: 비root 작업 사용자는 모두 허용됩니다
  • 지정된 allowed_users: 나열된 작업 사용자만 허용됩니다
  • 비어 있는 allowed_groups: 비root 작업 그룹은 모두 허용됩니다
  • 지정된 allowed_groups: 나열된 작업 그룹만 허용됩니다
  • 보안 컨텍스트 구성: 허용 목록에 대해 검증되지 않습니다 (관리자 재정의)
[runners.kubernetes]
  allowed_users = ["1000", "65534"]
  allowed_groups = ["1001", "65534"]

컨테이너 동작 및 우선순위#

보안 컨텍스트 구성은 다음 우선순위(높은 것부터 낮은 것)를 따릅니다:

  1. 컨테이너 보안 컨텍스트
  2. 파드 보안 컨텍스트
  3. 작업 구성
[runners.kubernetes]
  # Pod-level defaults
  [runners.kubernetes.pod_security_context]
    run_as_user = 1500
    run_as_group = 1500

  # Container-specific overrides
  [runners.kubernetes.build_container_security_context]
    run_as_user = 1000
    run_as_group = 1001
  [runners.kubernetes.helper_container_security_context]
    run_as_user = 1000
    run_as_group = 1001
job:
  image:
    name: alpine:latest
    kubernetes:
      user: "2000:2001"  # Ignored - container security context uses 1000:1001

각 컨테이너 유형은 파드 수준 폴백과 함께 보안 컨텍스트 구성을 사용합니다:

  • 빌드 컨테이너: 먼저 build_container_security_context를 사용하고, 그 다음 pod_security_context를, 그 다음 .gitlab-ci.yml의 작업 수준 사용자 구성을 사용합니다.
  • 헬퍼 컨테이너: 먼저 helper_container_security_context를 사용하고, 그 다음 pod_security_context를 사용합니다. 작업 수준 사용자 구성을 상속하지 않습니다.
  • 서비스 컨테이너: 먼저 service_container_security_context를 사용하고, 그 다음 pod_security_context를, 그 다음 작업 수준 사용자 구성을 사용합니다.

이 접근 방식은 헬퍼 컨테이너를 작업 사양으로부터 격리하면서 각 컨테이너 유형의 보안 구성에 대한 세밀한 제어를 제공합니다.

Docker executor와 비교#

기능 Docker executor Kubernetes executor
사용자 형식 사용자 이름 또는 UID (root 또는 1000) 숫자 UID만 (1000)
그룹 형식 사용자 필드에서 지원되지 않음 숫자 GID (1000:1001)
관리자 재정의 방법 Runner user 필드 컨테이너 및 파드 보안 컨텍스트
우선순위 Runner > Job 컨테이너 컨텍스트 > 파드 컨텍스트 > Job
보안 검증 사용자 이름 허용 목록 숫자 UID/GID 허용 목록
관리자 재정의 지원됨 지원됨 (파드 및 컨테이너 수준)
헬퍼 컨테이너 사용자 빌드 컨테이너와 동일 자체 helper_container_security_context 사용
파드 수준 기본값 사용 불가 pod_security_context

사용자 및 그룹 구성 문제 해결#

오류: failed to parse UID 또는 failed to parse GID#
  • 사용자 ID가 숫자인지 확인: "user"가 아닌 "1000"
  • 형식 확인: 사용자와 그룹의 경우 "1000:1001"
  • 음수 값은 허용되지 않습니다
오류: user "1000" is not in the allowed list#

이 오류는 작업 수준 사용자 구성(.gitlab-ci.yml)에서만 발생합니다. Runner 구성에서 allowed_users에 사용자를 추가하거나 allowed_users를 제거하여 비root 작업 사용자를 모두 허용합니다. 보안 컨텍스트 및 파드 보안 컨텍스트 사용자는 허용 목록에 대해 검증되지 않습니다.

오류: group "1001" is not in the allowed list#

이 오류는 작업 수준 그룹 구성(.gitlab-ci.yml)에서만 발생합니다. Runner 구성에서 allowed_groups에 그룹을 추가하거나 allowed_groups를 제거하여 비root 작업 그룹을 모두 허용합니다. 보안 컨텍스트 및 파드 보안 컨텍스트 그룹은 허용 목록에 대해 검증되지 않습니다.

오류: user "0" is not in the allowed list (Root 사용자 차단)#

이 오류는 작업 구성(.gitlab-ci.yml)에서 root가 지정된 경우에만 발생합니다. 작업 구성의 Root 사용자(UID 0)는 명시적 권한이 필요합니다: allowed_users"0"을 추가합니다. 또는 보안 컨텍스트나 파드 보안 컨텍스트를 사용하여 root 사용자를 설정합니다: run_as_user = 0 (허용 목록 검증 우회).

컨테이너가 예상과 다른 사용자로 실행됨#

Runner 구성이 보안 컨텍스트로 작업 구성을 재정의하는지 확인합니다(보안 컨텍스트가 항상 우선). 작업 구성만 사용하는 경우 allowed_users에 원하는 사용자 ID가 포함되어 있는지 확인합니다. 보안 컨텍스트 값은 허용 목록에 대해 검증되지 않으며 관리자 재정의 기능을 제공합니다.

컨테이너 리소스 덮어쓰기#

각 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에서 서비스 목록을 정의합니다.

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에 지정된 컨테이너 리소스를 덮어쓰려면 각 서비스에서 variables 속성을 사용합니다.

  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 이름을 지정했지만 클러스터에서 구성하지 않았거나 기능이 지원되지 않는 경우 executor가 작업 생성에 실패합니다.

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

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

히스토리
  • GitLab Runner 17.2에서 도입되었습니다.

빌드 로그 및 스크립트를 위해 emptyDir 볼륨이 pod에 마운트되는 디렉토리를 변경할 수 있습니다. 이 디렉토리를 사용하여 다음 작업을 수행할 수 있습니다:

  • 수정된 이미지로 job pod를 실행합니다.
  • 비권한 사용자로 실행합니다.
  • 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 볼륨을 생성합니다:

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

사용자 네임스페이스#

Kubernetes 1.30 이상에서는 사용자 네임스페이스를 사용하여 컨테이너에서 실행 중인 사용자를 호스트의 사용자와 분리할 수 있습니다. 컨테이너에서 root로 실행되는 프로세스는 호스트에서 다른 비권한 사용자로 실행될 수 있습니다.

사용자 네임스페이스를 사용하면 CI/CD job을 실행하는 데 사용되는 이미지를 더 세밀하게 제어할 수 있습니다. 추가 설정이 필요한 작업(root로 실행 등)도 호스트에서 추가적인 공격 표면을 열지 않고 작동할 수 있습니다.

이 기능을 사용하려면 클러스터가 적절히 구성되어 있는지 확인하십시오. 다음 예시는 hostUsers 키에 대한 pod_spec을 추가하고 권한 pod와 권한 에스컬레이션을 모두 비활성화합니다:

[[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)의 기본 경로를 사용할 수 없습니다. 컨테이너의 root 사용자도 볼륨을 마운트할 권한이 없습니다. 또한 컨테이너 파일 시스템의 루트에 디렉토리를 생성할 수도 없습니다.

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

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

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

시스템은 helper 이미지의 운영 체제, 아키텍처, Windows 커널 버전(해당하는 경우)을 결정합니다. 그런 다음 해당 파라미터를 사용할 컨테이너 또는 이미지 등 빌드의 다른 측면에 활용합니다.

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

Mermaid 다이어그램 (26줄)
소스 코드 보기
%%|fig-align: center
flowchart TB
  init[<b>초기 기본값</b>:<br/>OS: linux</br>Arch: amd64]
  hasAutoset{구성<br/><tt><a href="https://docs.gitlab.com/runner/configuration/advanced-configuration/">helper_image_autoset_arch_and_os</a> == true</tt>?}
  setArch[<b>업데이트</b>:<br/>Arch: <i>runner와 동일</i>]
  isWin{GitLab Runner가 Windows에서 실행 중?}
  setWin[<b>업데이트</b>:<br/>OS: windows<br/>KernelVersion: <i>runner와 동일</i>]
  hasNodeSel{<a href="https://docs.gitlab.com/runner/configuration/advanced-configuration/"><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><tt>node_selector</tt>에서 업데이트</b> (설정된 경우):<br/>OS: <tt>kubernetes.io/os</tt>에서<br/>Arch: <tt>kubernetes.io/arch</tt>에서<br/>KernelVersion: <tt>node.kubernetes.io/windows-build</tt>에서]
  updateNodeSelOverride[<b><tt>node_selector</tt> 덮어쓰기에서 업데이트</b> (설정된 경우):</br>OS: <tt>kubernetes.io/os</tt>에서<br/>Arch: <tt>kubernetes.io/arch</tt>에서<br/>KernelVersion: <tt>node.kubernetes.io/windows-build</tt>에서]
  result[최종 <b>OS</b>, <b>Arch</b>, <b>kernelVersion</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 옵션을 사용하여 Kubernetes 클러스터에서 빌드를 실행하는 데 사용할 수 있는 노드를 지정합니다. 이는 string=string 형식의 key=value 쌍입니다(환경 변수의 경우 string:string).

Runner는 제공된 정보를 사용하여 빌드의 운영 체제와 아키텍처를 결정합니다. 이를 통해 올바른 helper 이미지가 사용됩니다. 기본 운영 체제와 아키텍처는 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에는 특정 제한 사항이 있습니다. 프로세스 격리를 사용하는 경우 node.kubernetes.io/windows-build 레이블로 특정 Windows 빌드 버전도 제공해야 합니다.

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

  # Runner가 Linux 환경에서 작동하지만 Windows 노드를 대상으로 할 때
  # PowerShell이 Windows 경로를 올바르게 확인하려면
  # FF_USE_POWERSHELL_PATH_RESOLVER 기능 플래그를 활성화해야 합니다.
  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_* = ''
    

다음 예시에서 Kubernetes 노드 아키텍처를 덮어쓰기 위해 config.toml.gitlab-ci.yml 파일에 설정이 구성됩니다:

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=.*" # <--- 아키텍처 덮어쓰기 허용
job:
  image: IMAGE_NAME
  variables:
    KUBERNETES_NODE_SELECTOR_ARCH: 'kubernetes.io/arch=amd64'  # <--- 아키텍처 선택

노드 어피니티 목록 정의#

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

Note

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가 예약될 노드 정의#

pod 어피니티 및 안티-어피니티를 사용하여 다른 pod의 레이블을 기반으로 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 아니오 수행할 HTTP 요청을 지정하는 HTTPGet.
tcp_socket KubernetesLifecycleTcpSocket 아니오 TCP 포트와 관련된 액션을 지정하는 TCPsocket.

KubernetesLifecycleExecAction#

옵션 타입 필수 여부 설명
command string 목록 컨테이너 내부에서 실행할 명령줄.

KubernetesLifecycleHTTPGet#

옵션 타입 필수 여부 설명
port int 컨테이너에서 접근할 포트 번호.
host string 아니오 연결할 호스트 이름, 기본값은 pod IP (선택 사항).
path string 아니오 HTTP 서버에서 접근할 경로 (선택 사항).
scheme string 아니오 호스트에 연결하는 데 사용되는 스킴. 기본값은 HTTP (선택 사항).
http_headers KubernetesLifecycleHTTPGetHeader 목록 아니오 요청에 설정할 사용자 지정 헤더 (선택 사항).

KubernetesLifecycleHTTPGetHeader#

옵션 타입 필수 여부 설명
name string HTTP 헤더 이름.
value string HTTP 헤더 값.

KubernetesLifecycleTcpSocket#

옵션 타입 필수 여부 설명
port int 컨테이너에서 접근할 포트 번호.
host string 아니오 연결할 호스트 이름, 기본값은 pod IP (선택 사항).

pod DNS 설정 구성#

pod의 DNS 설정을 구성하려면 다음 옵션을 사용합니다.

옵션 타입 필수 여부 설명
nameservers string 목록 아니오 pod의 DNS 서버로 사용되는 IP 주소 목록.
options KubernetesDNSConfigOption 아니오 각 객체가 name 속성(필수)과 value 속성(선택 사항)을 가질 수 있는 선택적 객체 목록.
searches string 목록 아니오 pod에서 호스트 이름 조회를 위한 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 string 구성 옵션 이름.
value *string 아니오 구성 옵션 값.

기본 드롭 기능 목록#

GitLab Runner는 기본적으로 다음 기능을 드롭합니다.

사용자 정의 cap_add는 기본 드롭 기능 목록보다 우선순위가 높습니다. 기본적으로 드롭된 기능을 추가하려면 cap_add에 추가합니다.

  • NET_RAW

추가 호스트 별칭 추가#

이 기능은 Kubernetes 1.7 이상에서 사용 가능합니다.

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

다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
IP string 호스트를 연결할 IP 주소.
Hostnames string 목록 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"]

명령줄 파라미터 --kubernetes-host_aliases와 JSON 입력을 사용하여 호스트 별칭을 구성할 수도 있습니다. 예를 들어:

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

볼륨#

Kubernetes executor에서 캐시 사용#

Kubernetes executor에서 캐시를 사용하면 pod에 /cache라는 볼륨이 마운트됩니다. job 실행 중 캐시된 데이터가 필요한 경우 runner는 캐시된 데이터가 사용 가능한지 확인합니다. 캐시된 데이터는 캐시 볼륨에 압축 파일이 있는 경우 사용 가능합니다.

캐시 볼륨을 설정하려면 config.toml 파일의 cache_dir 설정을 사용합니다.

  • 사용 가능한 경우 압축 파일이 빌드 폴더에 압축 해제되고 job에서 사용할 수 있습니다.
  • 사용 가능하지 않은 경우 캐시된 데이터가 구성된 스토리지에서 다운로드되어 압축 파일로 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 볼륨을 구성하여 Kubernetes에 컨테이너에 지정된 호스트 경로를 마운트하도록 지시합니다.

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름.
mount_path string 컨테이너에서 볼륨이 마운트되는 경로.
sub_path string 아니오 루트 대신 마운트된 볼륨 내부의 서브 경로.
host_path string 아니오 볼륨으로 마운트된 호스트의 경로. 값을 지정하지 않으면 mount_path와 동일한 경로로 기본 설정됩니다.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다. 기본값은 false.
mount_propagation string 아니오 컨테이너 간에 마운트된 볼륨을 공유합니다. 자세한 내용은 마운트 전파를 참조하십시오.

persistentVolumeClaim 볼륨#

persistentVolumeClaim 볼륨을 구성하여 Kubernetes 클러스터에 정의된 persistentVolumeClaim을 사용하여 컨테이너에 마운트하도록 Kubernetes에 지시합니다.

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름이자 사용할 PersistentVolumeClaim의 이름. 변수를 지원합니다. 자세한 내용은 동시성별 영속 빌드 볼륨을 참조하십시오.
mount_path string 볼륨이 마운트되는 컨테이너의 경로.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다 (기본값: false).
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
mount_propagation string 아니오 볼륨의 마운트 전파 모드를 설정합니다. 자세한 내용은 Kubernetes 마운트 전파를 참조하십시오.

configMap 볼륨#

configMap 볼륨을 구성하여 Kubernetes에 Kubernetes 클러스터에 정의된 configMap을 사용하여 컨테이너에 마운트하도록 지시합니다.

config.toml에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름이자 사용할 configMap의 이름.
mount_path string 볼륨이 마운트되는 컨테이너의 경로.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다 (기본값: false).
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
items map[string]string 아니오 사용할 configMap의 키에 대한 키-경로 매핑.

선택한 configMap의 각 키는 파일로 변환되어 마운트 경로에 저장됩니다. 기본적으로:

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

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

Note

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

secret 볼륨#

secret 볼륨을 구성하여 Kubernetes에 Kubernetes 클러스터에 정의된 secret을 사용하여 컨테이너에 마운트하도록 지시합니다.

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름이자 사용할 _secret_의 이름.
mount_path string 볼륨이 마운트되어야 하는 컨테이너 내부 경로.
read_only boolean 아니오 볼륨을 읽기 전용 모드로 설정합니다 (기본값: false).
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
items map[string]string 아니오 사용할 configMap의 키에 대한 키-경로 매핑.

선택한 secret의 각 키는 선택한 마운트 경로에 저장된 파일로 변환됩니다. 기본적으로:

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

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

Note

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

emptyDir 볼륨#

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

config.toml 파일에서 다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
name string 볼륨 이름.
mount_path string 볼륨이 마운트되어야 하는 컨테이너 내부 경로.
sub_path string 아니오 루트 대신 볼륨의 서브 경로를 마운트합니다.
medium string 아니오 "Memory"는 tmpfs를 제공하고, 그렇지 않으면 노드 디스크 스토리지로 기본 설정됩니다 (기본값: "").
size_limit string 아니오 emptyDir 볼륨에 필요한 로컬 스토리지의 총 용량.

csi 볼륨#

Container Storage Interface(csi) 볼륨을 구성하여 Kubernetes에 사용자 지정 csi 드라이버를 사용하여 컨테이너에 임의의 스토리지 시스템을 마운트하도록 지시합니다.

config.toml에서 다음 옵션을 사용합니다:

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

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

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

config.toml 파일의 예시 구성:

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

사용자 지정 볼륨 마운트#

job의 빌드 디렉토리를 저장하려면 구성된 builds_dir(기본값: /builds)에 사용자 지정 볼륨 마운트를 정의합니다. 액세스 모드에 따라 pvc 볼륨을 사용하면 하나의 노드에서만 job을 실행하도록 제한될 수 있습니다.

config.toml 파일의 예시 구성:

concurrent = 4

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

동시성별 영속 빌드 볼륨#

히스토리
  • pvc.name에 대한 변수 주입 지원이 GitLab 16.3에서 도입되었습니다.

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

concurrent = 4

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

이 예시에서 build-pvc-0부터 build-pvc-3까지 이름이 지정된 영속 볼륨 클레임을 직접 생성합니다. runner의 concurrent 설정에서 지정하는 수만큼 생성합니다.

helper 이미지 사용#

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

Note

nonroot 환경만 필요한 경우 helper 이미지 대신 GitLab Runner UBI OpenShift Container Platform 이미지를 사용할 수 있습니다. GitLab Runner Helper UBI OpenShift Container Platform 이미지도 사용할 수 있습니다.

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

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

빌드에서 Docker 사용#

빌드에서 Docker를 사용할 때 알아야 할 몇 가지 고려 사항이 있습니다.

노출된 /var/run/docker.sock#

runners.kubernetes.volumes.host_path 옵션을 사용하여 호스트의 /var/run/docker.sock을 빌드 컨테이너에 노출하면 위험이 있습니다. 프로덕션 컨테이너와 동일한 클러스터에서 빌드를 실행할 때 주의하십시오. 노드의 컨테이너는 빌드 컨테이너에서 액세스할 수 있습니다.

docker:dind 사용#

docker:dind라고도 불리는 docker-in-docker 이미지를 실행하면 컨테이너가 권한 모드로 실행되어야 합니다. 이는 잠재적인 위험이 있으며 추가적인 문제를 야기할 수 있습니다.

Docker 데몬은 일반적으로 .gitlab-ci.yml에서 service로 시작되기 때문에 pod의 별도 컨테이너로 실행됩니다. pod의 컨테이너는 할당된 볼륨과 서로 localhost로 통신하는 데 사용하는 IP 주소만 공유합니다. docker:dind 컨테이너는 /var/run/docker.sock을 공유하지 않으며, docker 바이너리는 기본적으로 이를 사용하려 합니다.

다른 컨테이너에서 클라이언트가 TCP를 사용하여 Docker 데몬에 접속하도록 구성하려면 빌드 컨테이너의 환경 변수를 포함합니다:

  • TLS 없는 연결의 경우 DOCKER_HOST=tcp://docker:2375.
  • TLS 연결의 경우 DOCKER_HOST=tcp://docker:2376.

Docker 19.03 이상에서는 TLS가 기본적으로 활성화되어 있지만 인증서를 클라이언트에 매핑해야 합니다. Docker-in-Docker에 대해 TLS 없는 연결을 활성화하거나 인증서를 마운트할 수 있습니다. 자세한 내용은 Docker-in-Docker와 함께 Docker executor 사용을 참조하십시오.

호스트 커널 노출 방지#

docker:dind 또는 /var/run/docker.sock을 사용하면 Docker 데몬이 호스트 머신의 기반 커널에 액세스할 수 있습니다. 즉, Docker 이미지가 빌드될 때 pod에 설정된 limits가 작동하지 않습니다. Docker 데몬은 Kubernetes에 의해 Docker 빌드 컨테이너에 부과된 제한과 관계없이 노드의 전체 용량을 보고합니다.

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

빌드 컨테이너를 더 분리하려면 노드 taint를 사용할 수 있습니다. Taint는 다른 pod에 추가 구성 없이 빌드 pod와 동일한 노드에서 다른 pod가 예약되는 것을 방지합니다.

Docker 이미지 및 서비스 제한#

job을 실행하는 데 사용되는 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 job이 이미지를 가져오는 방법을 결정합니다.

.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 정책이 사용됩니다.
  • job은 pull_policyallowed_pull_policies 모두에 나열된 pull 정책만 사용합니다. 유효한 pull 정책은 pull_policy 키워드allowed_pull_policies의 정책을 비교하여 결정됩니다. GitLab은 이 두 정책 목록의 교집합을 사용합니다. 예를 들어 pull_policy["always", "if-not-present"]이고 allowed_pull_policies["if-not-present"]이면 두 목록 모두에 정의된 유일한 pull 정책이므로 job은 if-not-present만 사용합니다.
  • 기존 pull_policy 키워드에는 allowed_pull_policies에 지정된 pull 정책이 하나 이상 포함되어야 합니다. pull_policy 값 중 allowed_pull_policies와 일치하는 것이 없으면 job이 실패합니다.

Job 실행#

GitLab Runner는 기본적으로 kube exec 대신 kube attach를 사용합니다. 이렇게 하면 불안정한 네트워크 환경에서 job이 도중에 성공으로 표시되는 문제를 방지할 수 있습니다.

레거시 실행 전략 제거 진행 상황은 이슈 #27976을 참조하십시오.

Kubernetes API 요청 재시도 횟수 구성#

기본적으로 Kubernetes executor는 5번의 실패 후 Kubernetes API에 대한 특정 요청을 재시도합니다. 지연은 500밀리초 하한과 기본값 2초의 사용자 지정 가능한 상한이 있는 백오프 알고리즘으로 제어됩니다. 재시도 횟수를 구성하려면 config.toml 파일의 retry_limit 옵션을 사용합니다. 마찬가지로 백오프 상한의 경우 retry_backoff_max 옵션을 사용합니다. 다음 실패는 자동으로 재시도됩니다:

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

예를 들어 환경의 TLS 관련 오류를 기본 5번 대신 10번 재시도하도록 retry_limits 옵션을 구성합니다:

[[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

exceeded quota와 같이 완전히 다른 오류를 20번 재시도하려면:

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

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

컨테이너 진입점의 알려진 문제#

Note

GitLab 15.1 이상에서는 FF_KUBERNETES_HONOR_ENTRYPOINT가 설정되면 Docker 이미지에 정의된 진입점이 Kubernetes executor와 함께 사용됩니다.

컨테이너 진입점에는 다음과 같은 알려진 문제가 있습니다:

  • 이미지의 Dockerfile에 진입점이 정의되어 있는 경우 유효한 셸을 열어야 합니다. 그렇지 않으면 job이 멈춥니다.

    • 셸을 열기 위해 시스템은 빌드 컨테이너의 args로 명령을 전달합니다.
  • 파일 유형 CI/CD 변수는 진입점이 실행될 때 디스크에 기록되지 않습니다. 파일은 스크립트 실행 중에만 job에서 액세스할 수 있습니다.

  • 다음 CI/CD 변수는 진입점에서 액세스할 수 없습니다. 스크립트 명령을 실행하기 전에 설정 변경을 수행하려면 before_script를 사용할 수 있습니다:

GitLab Runner 17.4 이전:

  • 진입점 로그가 빌드 로그에 전달되지 않았습니다.
  • kube exec를 사용하는 Kubernetes executor에서 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는 poll_interval마다 .gitlab-startup-marker 파일을 확인합니다. poll_timeout 내에 파일이 없으면 pod가 비정상으로 간주되어 시스템이 빌드를 중단합니다.

Job 변수 접근 제한#

Kubernetes executor를 사용할 때 Kubernetes 클러스터에 접근하는 사용자는 job에서 사용되는 변수를 읽을 수 있습니다. 기본적으로 job 변수는 다음에 저장됩니다:

  • Pod의 환경 섹션

Job 변수 데이터 접근을 제한하려면 역할 기반 접근 제어(RBAC)를 사용해야 합니다. RBAC를 사용하면 GitLab 관리자만 GitLab Runner에서 사용하는 네임스페이스에 접근할 수 있습니다.

다른 사용자가 GitLab Runner 네임스페이스에 접근해야 하는 경우 다음 verbs를 설정하여 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보다 큰 숫자로 설정되어 있습니다.
  • getlist 권한이 있는 Kubernetes serviceAccount가 사용됩니다.

GitLab Runner는 각 시도 사이에 5초 간격으로 새로운 서비스 계정 또는 시크릿이 사용 가능한지 확인합니다.

  • 이 기능은 기본적으로 비활성화되어 있습니다. 이 기능을 활성화하려면 resource_availability_check_max_attempts0 이외의 값으로 설정합니다. 설정한 값은 runner가 서비스 계정 또는 시크릿을 확인하는 횟수를 정의합니다.

Kubernetes 네임스페이스 덮어쓰기#

필수 조건:

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

CI 목적을 위한 네임스페이스를 지정하고 사용자 지정 pod 세트를 배포하기 위해 Kubernetes 네임스페이스를 덮어쓸 수 있습니다. runner가 생성한 pod는 CI 단계 중 컨테이너 간 접근을 가능하게 하기 위해 덮어쓴 네임스페이스에 있습니다.

각 CI/CD job에 대한 Kubernetes 네임스페이스를 덮어쓰려면 .gitlab-ci.yml 파일에서 KUBERNETES_NAMESPACE_OVERWRITE 변수를 설정합니다.

variables:
  KUBERNETES_NAMESPACE_OVERWRITE: ci-${CI_COMMIT_REF_SLUG}
Note

이 변수는 클러스터에 네임스페이스를 생성하지 않습니다. job을 실행하기 전에 네임스페이스가 존재하는지 확인하십시오.

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

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