Kubernetes executor

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-Managed

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

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

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

러너가 Kubernetes pod를 생성하는 방법

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

Pod는 .gitlab-ci.yml이나 config.toml 파일에서 정의된 각 service에 대해 다음과 같은 컨테이너로 구성됩니다:

  • build로 정의된 빌드 컨테이너.
  • helper로 정의된 도우미 컨테이너.
  • svc-X(여기서 X[0-9]+임)로 정의된 서비스 컨테이너.

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

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

다이어그램의 상호 작용은 모든 Kubernetes 클러스터에 유효합니다. 예를 들어, 주요 공개 클라우드 제공 업체에 호스팅된 키턴 엔터프라이즈 솔루션 또는 Self-Managed형 Kubernetes 설치 등이 있습니다.

Kubernetes API에 연결

Kubernetes API에 연결하기 위해 다음 옵션을 사용합니다. 제공된 사용자 계정에는 지정된 네임스페이스에서 Pod를 만들고 나열하고 첨부할 수 있는 권한이 있어야 합니다.

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

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

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

Kubernetes API 호출용 bearer 토큰 설정

pod를 생성하는 API 호출에 bearer 토큰을 설정하려면 KUBERNETES_BEARER_TOKEN 변수를 사용합니다. 이를 통해 프로젝트 소유자는 프로젝트 비밀 변수를 사용하여 bearer 토큰을 지정할 수 있습니다.

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

variables:
  KUBERNETES_BEARER_TOKEN: 다른 네임스페이스의 bearertoken

러너 API 권한 구성

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

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

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

리소스 Verb (선택적 피처 플래그)
events list (FF_RETRIEVE_POD_WARNING_EVENTS=true), watch (FF_PRINT_POD_EVENTS=true)
namespaces create, delete
pods attach (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), create, delete, exec, get
pods/logs get (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), list (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
secrets create, delete, get, update
serviceAccounts get
services create, get
  • serviceAccount 권한은 다음과 같을 때만 필요합니다:

    • GitLab 15.0 및 15.1에서.
    • GitLab 15.0.1, 15.1.1 및 15.2에서 resource_availability_check_max_attempts를 0보다 큰 값으로 설정한 경우.
  • GitLab Runner 15.8부터 configmaps 권한은 더 이상 필요하지 않습니다.

  • event 권한은 다음과 같을 때만 필요합니다:

    • GitLab 16.2.1 이후.
  • namespace 권한은 다음과 같을 때만 필요합니다:

    • namespace_per_job을 통해 네임스페이스 분리를 활성화할 때._

구성 설정

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 요청이 덮어쓰기 기능이 비활성화됩니다.

메모리 요청 및 제한

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

리포지터리 요청 및 제한 사항

설정 설명
ephemeral_storage_limit 빌드 컨테이너의 일시적 리포지터리 한도입니다.
ephemeral_storage_limit_overwrite_max_allowed 빌드 컨테이너의 일시적 리포지터리 한도를 덮어쓸 수 있는 최대 금액입니다. 비워 두면 일시적 리포지터리 한도 덮어쓰기 기능이 비활성화됩니다.
ephemeral_storage_request 빌드 컨테이너에 제공된 일시적 리포지터리 요청입니다.
ephemeral_storage_request_overwrite_max_allowed 빌드 컨테이너의 일시적 리포지터리 요청을 덮어쓸 수 있는 최대 금액입니다. 비워 두면 일시적 리포지터리 요청 덮어쓰기 기능이 비활성화됩니다.
helper_ephemeral_storage_limit 헬퍼 컨테이너에 제공된 일시적 리포지터리 한도입니다.
helper_ephemeral_storage_limit_overwrite_max_allowed 헬퍼 컨테이너의 일시적 리포지터리 한도를 덮어쓸 수 있는 최대 금액입니다. 비워 두면 헬퍼 컨테이너의 일시적 리포지터리 요청 덮어쓰기 기능이 비활성화됩니다.
helper_ephemeral_storage_request 헬퍼 컨테이너에 제공된 일시적 리포지터리 요청입니다.
helper_ephemeral_storage_request_overwrite_max_allowed 헬퍼 컨테이너의 일시적 리포지터리 요청을 덮어쓸 수 있는 최대 금액입니다. 비워 두면 헬퍼 컨테이너의 일시적 리포지터리 요청 덮어쓰기 기능이 비활성화됩니다.
service_ephemeral_storage_limit 서비스 컨테이너에 제공된 일시적 리포지터리 한도입니다.
service_ephemeral_storage_limit_overwrite_max_allowed 서비스 컨테이너의 일시적 리포지터리 한도를 덮어쓸 수 있는 최대 금액입니다. 비워 두면 서비스 컨테이너의 일시적 리포지터리 요청 덮어쓰기 기능이 비활성화됩니다.
service_ephemeral_storage_request 서비스 컨테이너에 제공된 일시적 리포지터리 요청입니다.
service_ephemeral_storage_request_overwrite_max_allowed 서비스 컨테이너의 일시적 리포지터리 요청을 덮어쓸 수 있는 최대 금액입니다. 비워 두면 서비스 컨테이너의 일시적 리포지터리 요청 덮어쓰기 기능이 비활성화됩니다.

기타 config.toml 설정

설정 설명
affinity 빌드를 실행하는 노드를 결정하는 친밀도 규칙을 지정합니다. 친밀도에 대해 자세히 알아보려면 친밀도 사용을 참조하세요.
allow_privilege_escalation 모든 컨테이너를 allowPrivilegeEscalation 플래그로 실행합니다. 비워 두면 컨테이너 SecurityContext에서 allowPrivilegeEscalation 플래그를 정의하지 않고 Kubernetes가 기본 권한 상슨 동작을 사용합니다.
allowed_images .gitlab-ci.yml에서 지정할 수 있는 이미지의 와일드카드 디렉터리입니다. 지정되지 않으면 모든 이미지가 허용됩니다(["*/*:*"]과 동등). 세부 정보 보기.
allowed_pull_policies .gitlab-ci.yml 파일이나 config.toml 파일에서 지정할 수 있는 풀 정책 디렉터리입니다.
allowed_services .gitlab-ci.yml에서 지정할 수 있는 서비스의 와일드카드 디렉터리입니다. 지정되지 않으면 모든 이미지가 허용됩니다(["*/*:*"]과 동등). 세부 정보 보기.
automount_service_account_token 빌드 파드에서 서비스 계정 토큰을 자동으로 마운트할지 여부를 나타내는 부울값입니다.
bearer_token 빌드 파드를 시작하는 데 사용되는 기본 베어러 토큰입니다.
bearer_token_overwrite_allowed 프로젝트가 빌드 파드를 생성하는 데 사용할 베어러 토큰을 지정할 수 있는 부울값입니다.
build_container_security_context 빌드 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트 자세히 읽기.
cap_add 작업 파드 컨테이너에 추가할 Linux 기능을 지정합니다. 쿠버네티스 실행기에서 기능 구성에 대해 자세히 읽기](#specify-container-capabilities).
cap_drop 작업 파드 컨테이너에서 삭제할 Linux 기능을 지정합니다. 쿠버네티스 실행기에서 기능 구성에 대해 자세히 읽기](#specify-container-capabilities).
cleanup_grace_period_seconds 작업이 완료된 후 파드가 정상적으로 종료할 수 있는 기간(초)입니다. 이 기간이 지나면 프로세스가 강제로 중지됩니다. terminationGracePeriodSeconds가 지정되면 무시됩니다.
dns_policy 파드를 구성하는 데 사용해야 하는 DNS 정책을 지정합니다: none, default, cluster-first, cluster-first-with-host-net. 설정되지 않으면 쿠버네티스 기본값(cluster-first)이 사용됩니다.
dns_config 파드를 구성하는 데 사용해야 하는 DNS 구성을 지정합니다. 파드의 DNS 구성 사용에 대해 자세히 읽기](#configure-pod-dns-settings).
helper_container_security_context 헬퍼 컨테이너에 대한 컨테이너 보안 컨텍스트를 설정합니다. 보안 컨텍스트 자세히 읽기.
helper_image (고급) 리포지터리를 복제하고 아티팩트를 업로드하는 데 사용하는 기본 헬퍼 이미지를 재정의합니다.
helper_image_flavor 헬퍼 이미지 플레이버(alpine, alpine3.16, alpine3.17, alpine3.18, alpine3.19, 또는 ubuntu)를 설정합니다. 기본값은 alpine입니다. alpine을 사용하는 것은 alpine3.18를 사용하는 것과 동일합니다.
host_aliases 모든 컨테이너에 추가되는 추가 호스트 이름 별칭 디렉터리입니다. 추가 호스트 별칭 사용에 대해 자세히 읽기.
image_pull_secrets 프라이빗 레지스트리에서 Docker 이미지를 인증하기 위해 사용되는 쿠버네티스 docker-registry 시크릿 이름을 포함하는 항목 배열입니다.
### 구성 예시

다음 샘플은 Kubernetes executor를 위한 `config.toml` 파일의 구성 예시를 보여줍니다.

```toml
concurrent = 4

[[runners]]
  name = "myRunner"
  url = "https://gitlab.com/ci"
  token = "......"
  executor = "kubernetes"
  [runners.kubernetes]
    host = "https://45.67.34.123:4892"
    cert_file = "/etc/ssl/kubernetes/api.crt"
    key_file = "/etc/ssl/kubernetes/api.key"
    ca_file = "/etc/ssl/kubernetes/ca.crt"
    namespace = "gitlab"
    namespace_overwrite_allowed = "ci-.*"
    bearer_token_overwrite_allowed = true
    privileged = true
    cpu_limit = "1"
    memory_limit = "1Gi"
    service_cpu_limit = "1"
    service_memory_limit = "1Gi"
    helper_cpu_limit = "500m"
    helper_memory_limit = "100Mi"
    poll_interval = 5
    poll_timeout = 3600
    dns_policy = "cluster-first"
    priority_class_name = "priority-1"
    [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 플래그를 사용할 수 있습니다.

pod과 컨테이너

작업이 실행되는 방식을 제어하기 위해 pod과 컨테이너를 구성할 수 있습니다.

작업 pod을 위한 기본 주석

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

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

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

pod 라이프사이클

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

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

참고: FF_USE_POD_ACTIVE_DEADLINE_SECONDS 피처 플래그가 활성화되어 있고 pod_termination_grace_period_seconds에 0이 아닌 값이 설정된 경우, 작업 시간이 초과되어도 CI 작업 pod이 즉시 종료되지 않습니다. terminationGracePeriods는 pod이 만료된 경우에만 종료되도록 보장합니다.

pod 허용범위 덮어쓰기

Kubernetes pod 허용범위를 덮어쓰려면 다음을 수행합니다:

  1. config.toml이나 Helm values.yaml 파일에서 CI 작업 pod 허용범위를 덮어쓰기를 활성화하려면 node_tolerations_overwrite_allowed에 대한 정규식을 정의하세요. 이 정규식은 KUBERNETES_NODE_TOLERATIONS_로 시작하는 CI 변수 이름의 값을 유효성 검사합니다.

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

    variables:
      KUBERNETES_NODE_TOLERATIONS_1: 'node-role.kubernetes.io/master:NoSchedule'
      KUBERNETES_NODE_TOLERATIONS_2: 'custom.toleration=value:NoSchedule'
      KUBERNETES_NODE_TOLERATIONS_3: 'empty.value=:PreferNoSchedule'
      KUBERNETES_NODE_TOLERATIONS_4: 'onlyKey'
      KUBERNETES_NODE_TOLERATIONS_5: '' # 모든 taint를 용인합니다
    

pod 라벨 덮어쓰기

각 CI/CD 작업에 대해 Kubernetes pod 라벨을 덮어쓰려면 다음을 수행합니다:

  1. .config.yaml 파일에서 pod_labels_overwrite_allowed에 대한 정규식을 정의합니다.
  2. .gitlab-ci.yml 파일에서 KUBERNETES_POD_LABELS_* 변수를 설정하여 key=value의 값을 사용합니다. pod 라벨이 key=value로 덮어씌워집니다. 여러 값을 적용할 수 있습니다:

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

pod 주석 덮어쓰기

각 CI/CD 작업에 대해 Kubernetes pod 주석을 덮어쓰려면 다음을 수행합니다:

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

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

아래 예시에서는 pod_annotationspod_annotations_overwrite_allowed가 설정되어 있습니다. 이 구성은 config.toml에서 구성된 pod_annotations의 덮어쓰기를 허용합니다.

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

### 생성된 Pod 사양 덮어쓰기

DETAILS:
**상태:** 베타

> - [소개됨](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3114) : GitLab Runner 15.10에서.

이 기능은 [베타](https://docs.gitlab.com/ee/policy/experiment-beta-support.html#beta) 단계에 있습니다. 본 기능을 운영 클러스터에서 사용하기 전에 테스트 Kubernetes 클러스터에서 사용하는 것을 강력히 권장합니다.
이 기능을 사용하려면 `FF_USE_ADVANCED_POD_SPEC_CONFIGURATION` [피처 플래그](../../configuration/feature-flags.md)를 활성화해야 합니다.

본 기능이 일반적으로 사용 가능하게 되기 전에 개선 사항을 위한 의견을 추가하려면 [이 이슈](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/29659)을 사용하세요.

러너(runner) 매니저에 의해 생성된 `PodSpec`를 수정하려면 `config.toml` 파일에서 `pod_spec` 설정을 사용하세요.

`pod_spec` 설정:

- 생성된 pod 사양의 필드를 덮어쓰고 보완합니다.
- `[runners.kubernetes]` 아래에서 설정된 구성 값을 덮어쓰기도 합니다.

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

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

`patch_path` 및 `patch`를 동일한 `pod_spec` 구성에 설정하면 오류가 발생합니다.

`config.toml`에 여러 `pod_spec` 구성 예제:

```toml
[[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 패치 전략

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에는 build라는 하나의 컨테이너만이 있고, 두 개의 환경 변수 env1env2를 가집니다. 위의 예시는 다음과 같은 관련 CI 작업이 실패합니다:

  • helper 컨테이너 사양이 제거됩니다.
  • build 컨테이너 사양이 GitLab Runner에 의해 설정된 모든 필요한 구성을 잃었습니다.

위 예시에서 작업이 실패하지 않도록 하려면, pod_spec은 GitLab Runner에 의해 생성된 변경되지 않은 속성을 포함해야 합니다.

JSON 패치 전략

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

json 패치 전략을 사용하는 pod_spec 구성의 예시. 이 구성에서 기존 nodeSelector에 새로운 키:값 쌍이 추가됩니다. 기존 값들은 덮어쓰지 않습니다.

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

[session_server]
  session_timeout = 1800

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

전략적 패치 전략

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

strategic 패치 전략을 사용하는 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 = "cpu request 500m"
      patch = '''
        containers:
        - name: build
          resources:
            requests:
              cpu: "500m"
      '''
      patch_type = "strategic"

이 구성으로 인해 리소스 요청이 빌드 컨테이너에 설정됩니다.

최선의 방법

  • 프로덕션 환경에 배포하기 전에 테스트 환경에서 pod_spec을 추가한 후 테스트하십시오.
  • pod_spec 구성이 GitLab Runner가 생성한 사양을 부정적으로 영향을 미치지 않도록하세요.
  • 복잡한 pod 사양 업데이트에는 merge 패치 전략을 사용하지 마세요.
  • 가능한 경우 구성이 가능할 때 config.toml을 사용하세요. 예를 들어, 다음 구성은 GitLab Runner에 의해 설정된 첫 번째 환경 변수를 기존 디렉터리에 환경 변수를 추가하는 대신 사용자 정의 pod_spec에 설정합니다.
동시성 = 1
체크 간격 = 1
로그 레벨 = "디버그"
셧다운 타임아웃 = 0

[세션 서버]
  세션 타임아웃 = 1800

[[러너(runner)]]
  이름 = ""
  URL = "https://gitlab.example.com"
  아이디 = 0
  토큰 = "__REDACTED__"
  토큰 획득 일시 = 0001-01-01T00:00:00Z
  토큰 만료 일시 = 0001-01-01T00:00:00Z
  실행자 = "쿠버네티스"
   = "bash"
  환경 변수 = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"]
  [러너(runner).쿠버네티스]
    이미지 = "alpine"
    ...
    [[러너(runner).쿠버네티스.pod_spec]]
      이름 = "빌드 환경 변수"
      패치 = '''
        컨테이너:
        - env:
          - name: env1
            value: "value1"
          name: build
      '''
      패치 유형 = "전략적"

각 빌드 작업을 위해 PVC 생성

각 빌드 작업에 대해 PersistentVolumeClaim을 만들려면 생성된 pod 사양을 덮어쓰기하는 방법을 확인하세요.

Kubernetes는 Pod의 수명 주기에 부착된 임시 PersistentVolumeClaim을 생성하는 것을 허용합니다. 이는 귀하의 Kubernetes 클러스터에서 동적 프로비저닝이 활성화되어 있고 각 PVC가 새로운 Volume을 요청할 수 있는 경우에 작동합니다. 볼륨은 Pod의 수명 주기에도 묶입니다.

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

[[러너(runner).쿠버네티스.pod_spec]]
  이름 = "임시 PVC"
  패치 = '''
    컨테이너:
    - 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
  '''

Pod를 위한 보안 정책 설정

빌드 Pod에 대한 보안 정책을 설정하려면 security contextconfig.toml에 구성하세요.

다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
fs_group int 아니요 Pod의 모든 컨테이너에 적용되는 특별한 보조 그룹.
run_as_group int 아니요 컨테이너 프로세스의 GID를 실행합니다.
run_as_non_root boolean 아니요 컨테이너가 반드시 비루트 사용자로 실행되어야 함을 나타냅니다.
run_as_user int 아니요 컨테이너 프로세스의 UID를 실행합니다.
supplemental_groups int list 아니요 첫 번째 컨테이너 프로세스에 적용되는 디렉터리, 컨테이너 주요 그룹 외에 추가 그룹.
selinux_type string 아니요 Pod의 모든 컨테이너에 적용되는 SELinux 유형 라벨.

config.toml에서 Pod 보안 컨텍스트 예시:

concurrent = %(concurrent)s
체크 간격 = 30
  [[러너(runner)]]
    이름 = "내러너(runner)"
    url = "gitlab.example.com"
    실행자 = "쿠버네티스"
    [러너(runner).쿠버네티스]
      helper_image = "gitlab-registry.example.com/helper:latest"
      [러너(runner).쿠버네티스.pod_security_context]
        run_as_non_root = true
        run_as_user = 59417
        run_as_group = 59417
        fs_group = 59417

이전 러너 Pod 제거

가끔 이전 러너 Pod가 지워지지 않을 수 있습니다. 이는 러너 관리자가 잘못 종료된 경우에 발생할 수 있습니다.

이러한 상황을 처리하기 위해 GitLab Runner Pod Cleanup 애플리케이션을 사용하여 이전 Pod의 정리를 예약할 수 있습니다. 자세한 내용은 다음을 참조하십시오:

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

컨테이너를 위한 보안 정책 설정

빌드, helper 또는 서비스 Pod의 컨테이너 보안 정책을 설정하려면 config.toml 실행자 내에서 container security context를 구성하세요.

다음 옵션을 사용합니다:

옵션 타입 필수 여부 설명
run_as_group int 아니요 컨테이너 프로세스의 GID를 실행합니다.
run_as_non_root boolean 아니요 컨테이너가 반드시 비루트 사용자로 실행되어야 함을 나타냅니다.
run_as_user int 아니요 컨테이너 프로세스의 UID를 실행합니다.
capabilities.add string list 아니요 컨테이너를 실행할 때 추가할 기능입니다.
capabilities.drop string list 아니요 컨테이너를 실행할 때 삭제할 기능입니다.
selinux_type string 아니요 컨테이너 프로세스와 관련된 SELinux 유형 라벨입니다.

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

동시성 = 4
체크 간격 = 30
  [[러너(runner)]]
    이름 = "내러너(runner)"
    url = "gitlab.example.com"
    실행자 = "쿠버네티스"
    [러너(runner).쿠버네티스]
      helper_image = "gitlab-registry.example.com/helper:latest"
      [러너(runner).쿠버네티스.pod_security_context]
        run_as_non_root = true
        run_as_user = 59417
        run_as_group = 59417
        fs_group = 59417
      [러너(runner).쿠버네티스.init_permissions_container_security_context]
        run_as_user = 1000
        run_as_group = 1000
      [러너(runner).쿠버네티스.build_container_security_context]
        run_as_user = 65534
        run_as_group = 65534
        [러너(runner).쿠버네티스.build_container_security_context.capabilities]
          add = ["NET_ADMIN"]
      [러너(runner).쿠버네티스.helper_container_security_context]
        run_as_user = 1000
        run_as_group = 1000
      [러너(runner).쿠버네티스.service_container_security_context]
        run_as_user = 1000
        run_as_group = 1000

풀 정책 설정

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

어떤 정책을 사용할지 결정하려면 쿠버네티스 문서의 풀 정책을 참조하십시오.

단일 풀 정책의 예시:

[runners.kubernetes]
  pull_policy = "never"

다중 풀 정책의 예시:

[runners.kubernetes]
  # 다중 풀 정책 사용
  pull_policy = ["always", "if-not-present"]

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

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

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

GitLab의 네이밍 규칙은 쿠버네티스와 다릅니다.

러너 풀 정책 쿠버네티스 풀 정책 설명
blank blank 쿠버네티스에서 지정된 기본 정책을 사용합니다.
if-not-present IfNotPresent 이미지가 작업을 실행하는 노드에 이미 존재하지 않을 경우에만 이미지를 가져옵니다. 알아두어야 할 보안 고려 사항이 있습니다.
always Always 작업을 실행할 때마다 이미지를 가져옵니다.
never Never 이미지를 절대로 가져오지 않으며, 노드에 이미 존재해야 합니다.

컨테이너 기능 지정

컨테이너에서 사용할 쿠버네티스 기능을 지정할 수 있습니다.

컨테이너 기능을 지정하려면 config.toml 파일의 cap_addcap_drop 옵션을 사용하십시오. 컨테이너 런타임은 또한 Dockercontainer와 같이 기본 기능 디렉터리을 정의할 수 있습니다.

러너(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으로 입력하십시오.

  • 쿠버네티스 클러스터 소유자는 PodSecurityPolicy를 정의하여 특정 기능을 허용, 제한 또는 기본적으로 추가할 수 있습니다. 이러한 규칙은 사용자 정의 구성보다 우선합니다.

컨테이너 리소스 덮어쓰기

각 CI/CD 작업에 대해 쿠버네티스 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 환경 변수를 구성할 수 있습니다.

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

작업에 여러 서비스 컨테이너가 있는 경우, 각 서비스 컨테이너에 대해 명시적으로 리소스 요청 및 제한을 설정할 수 있습니다.
각 서비스에서 variables 속성을 사용하여 .gitlab-ci.yml에 지정된 컨테이너 리소스를 덮어쓸 수 있습니다.

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

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

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

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

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

variables:
  KUBERNETES_SERVICE_ACCOUNT_OVERWRITE: ci-service-account

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

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

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

RuntimeClass 설정

  • 소개: GitLab Runner 14.9에 소개되었습니다.

각 작업 컨테이너에 RuntimeClass를 설정하려면 runtime_class_name을 사용하세요.

RuntimeClass 이름을 지정했지만 클러스터에 구성되지 않았거나 해당 기능이 지원되지 않으면 실행자가 작업을 생성하지 못합니다.

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

노드

노드 어핀리티 디렉터리 정의

빌드 시 파드 사양에 추가할 노드 어핀리티 디렉터리을 정의하세요.

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"
            ]

파드가 예정된 노드 정의

  • 소개: GitLab Runner 14.3에 소개되었습니다.

라벨에 기반하여 파드가 예정된 노드를 제약하는 데에 파드 어핀리티 및 안티-어핀리티를 사용하세요.

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"]

노드 셀렉터 덮어쓰기

노드 셀렉터를 덮어쓰려면:

  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에서 구성됩니다.

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

listen_address = ':9252'

[session_server]
  session_timeout = 1800

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

빌드를 실행할 노드 지정

node_selector 옵션을 사용하여 Kubernetes 클러스터의 어떤 노드에서 빌드를 실행할지 지정합니다. 이는 string=string 형식의 key=value 쌍 테이블입니다(환경 변수의 경우 string:string 형식).

러너(runner)는 제공된 정보를 사용하여 빌드의 OS 및 아키텍처를 결정합니다. 이는 올바른 도움말 이미지가 사용되도록 합니다. 기본적으로 OS 및 아키텍쳐는 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"
    
    # Linux 환경에서 Windows 노드를 대상으로 작동하더라도 PowerShell이 Windows의 경로를 올바르게 해석하려면
    # PowerShell의 경로를 올바르게 해석하기 위해 `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"

네트워킹

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

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

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

config.toml 파일의 예제 구성:

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

각 라이프사이클 후크를 구성하는 데 다음 설정을 사용합니다.

옵션 유형 필수 여부 설명
exec KubernetesLifecycleExecAction 아니 Exec는 실행할 작업을 지정합니다.
http_get KubernetesLifecycleHTTPGet 아니 HTTPGet은 수행할 HTTP 요청을 지정합니다.
tcp_socket KubernetesLifecycleTcpSocket 아니 TCPsocket은 TCP 포트와 관련된 작업을 지정합니다.

KubernetesLifecycleExecAction

옵션 유형 필수 여부 설명
command 문자열 디렉터리 컨테이너 내부에서 실행할 커맨드 라인입니다.

KubernetesLifecycleHTTPGet

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

KubernetesLifecycleHTTPGetHeader

옵션 유형 필수 여부 설명
name 문자열 HTTP 헤더 이름입니다.
value 문자열 HTTP 헤더 값입니다.

KubernetesLifecycleTcpSocket

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

파드 DNS 설정 구성

파드의 DNS 설정을 구성하려면 다음 옵션을 사용하세요.

옵션 유형 필수 설명
nameservers string 디렉터리 아니오 파드의 DNS 서버로 사용될 IP 주소 디렉터리입니다.
options KubernetesDNSConfigOption 아니오 각 객체마다 name 속성(필수)과 value 속성(선택적)이 포함될 수 있는 선택적 객체 디렉터리입니다.
searches string 디렉터리 아니오 파드에서 호스트 이름 조회를 위한 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 executor와 함께 캐시 사용

캐시가 Kubernetes executor와 함께 사용될 때, 파드에 /cache 볼륨이 장착됩니다. 작업 실행 중에 캐시된 데이터가 필요한 경우, Runner는 캐시된 데이터가 있는지 확인합니다. 압축 파일이 캐시 볼륨에 있는 경우 캐시된 데이터를 사용할 수 있습니다.

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

  • 사용 가능한 경우, 압축 파일이 빌드 폴더로 추출되어 작업에서 사용할 수 있습니다.
  • 사용할 수 없는 경우, 캐시된 데이터는 구성된 리포지터리에서 다운로드되어 cache dir에 압축 파일로 저장됩니다. 그런 다음 압축 파일이 build 폴더로 추출됩니다.

볼륨 유형 구성

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

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

여러 볼륨 유형을 사용한 구성 예제:

concurrent = 4

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

hostPath 볼륨

Kubernetes에 지정된 호스트 경로를 컨테이너에 장착하도록 hostPath 볼륨을 구성하려면 다음 옵션을 사용하세요.

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

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

persistentVolumeClaim 볼륨

Kubernetes에 persistentVolumeClaim을 사용하도록 persistentVolumeClaim 볼륨을 구성하여 컨테이너에 마운트하도록 지시하려면 config.toml 파일의 다음 옵션을 사용하세요:

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

configMap 볼륨

configMap 볼륨을 구성하여 Kubernetes에게 Kubernetes 클러스터에서 정의된 configMap을 사용하도록 지시하고 컨테이너에 장착하도록 설정하세요.

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

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

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

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

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

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

secret 볼륨

secret 볼륨을 구성하여 Kubernetes가 Kubernetes 클러스터에서 정의된 secret을 사용하도록 지시하고 컨테이너에 장착하도록 설정하세요.

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

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

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

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

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

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

emptyDir 볼륨

emptyDir 볼륨을 구성하여 Kubernetes가 컨테이너 내에 빈 디렉터리를 장착하도록 지시하십시오.

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

옵션 유형 필수 여부 설명
name string Yes 볼륨의 이름입니다.
mount_path string Yes 볼륨이 장착될 컨테이너 내의 경로입니다.
sub_path string No 루트가 아닌 볼륨 내에서 서브 경로를 장착합니다.
medium string No “Memory”는 tmpfs를 제공하며, 그렇지 않은 경우 노드 디스크 리포지터리로 기본 설정됩니다 (기본값은 “”).
size_limit string No emptyDir 볼륨에 필요한 로컬 리포지터리의 총량입니다.

csi 볼륨

Container Storage Interface (csi) 볼륨을 구성하여 Kubernetes가 컨테이너 내에 임의의 스토리지 시스템을 장착하기 위해 사용자 정의 csi 드라이버를 사용하도록 지시하십시오.

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

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

서비스 컨테이너에 볼륨 장착

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

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

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

사용자 정의 볼륨 장착

작업을 위한 빌드 디렉터리를 저장하려면 설정된 builds_dir (/builds가 기본값)에 사용자 정의 볼륨 장착을 정의하세요. PVC 볼륨을 사용하는 경우, 접근 모드에 따라 동일한 노드에서 작업을 실행하는 것에 제한될 수 있습니다.

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

concurrent = 4

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

지속적인 동시성 빌드 볼륨

  • GitLab 16.3에서 pvc.name으로의 변수 주입 지원 소개.

Kubernetes CI 작업의 빌드 디렉터리는 기본적으로 순간적입니다. GIT_STRATEGY=fetch가 작동하도록 Git 복제를 지속하려면 빌드 폴더의 지속적인 볼륨 클레임을 장착해야 합니다. 여러 작업이 동시에 실행될 수 있으므로 ReadWriteMany 볼륨을 사용하거나 동일한 러너에서의 각 잠재적 동시 작업에 대한 하나의 볼륨이 있어야 합니다. 후자가 성능 면에서 더 우수할 가능성이 있습니다. 다음은 해당 구성의 예제입니다:

concurrent = 4

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

이 예에서 build-pvc-0부터 build-pvc-3까지의 지속적인 볼륨 클레임을 직접 작성하세요. 러너의 concurrent 설정이 지시하는대로 많이 만드세요.

도우미 이미지 사용

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

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

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

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

빌드에서 Docker 사용

빌드에 Docker를 사용하는 경우 고려해야 할 사항이 몇 가지 있습니다.

노출된 /var/run/docker.sock

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

docker:dind 사용

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

도커 데몬은 .gitlab-ci.yml의 일부로 시작되는 서비스로 실행되며, 빌드될 때 컨테이너 간에 할당된 볼륨 및 IP 주소를 공유합니다. docker:dind 컨테이너는 /var/run/docker.sock을 공유하지 않으며 기본적으로 docker 바이너리를 사용하려고 합니다.

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

호스트 커널 노출 방지

docker:dind 또는 /var/run/docker.sock을 사용하는 경우 도커 데몬은 호스트 머신의 기본 커널에 액세스할 수 있습니다. 이는 쿠버네티스가 생성한 사용자 지정 한도가 도커 이미지를 빌드할 때 작동하지 않음을 의미합니다. 도커 데몬은 노드의 전체 용량을 보고하며 쿠버네티스가 생성한 Docker 빌드 컨테이너에 부여된 제한과는 상관이 없습니다.

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

빌드 컨테이너를 더 분리하려면 노드 테인트를 사용할 수 있습니다. 테인트를 사용하면 다른 pod가 빌드 pod과 동일한 노드에서 예약되지 않게 할 수 있으며 다른 pod에 대한 추가 구성이 필요하지 않습니다.

Docker 이미지 및 서비스 제한

  • GitLab Runner 14.2의 Kubernetes executor에 추가됨.

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

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

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

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

Docker pull 정책 제한

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

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

예를 들어, alwaysif-not-present pull 정책만 허용하려면 다음과 같이 지정합니다.

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

작업 실행

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

GitLab Runner 14.0으로 업데이트한 후 문제가 발생하는 경우, 피처 플래그 FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGYtrue로 설정하고 이슈를 제출해 주세요.

레거시 실행 전략의 제거 진행 상황은 이슈 #27976에서 확인하세요.

Kubernetes API의 요청 시도 횟수 구성

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

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

예를 들어, 환경에서 TLS 관련 오류의 수를 제어해야 하는 경우, 기본 5회에서가 아닌 해당 오류를 10회로 설정할 수 있습니다:

[[runners]]
  name = "myRunner"
  url = "https://gitlab.example.com/"
  executor = "kubernetes"
  [runners.kubernetes]
    retry_limit = 5
    
    [runners.kubernetes.retry_limits]
        "TLS handshake timeout" = 10
        "tls: internal error" = 10

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
15.0에서 Kubernetes 실행자와 함께 사용될 경우, GitLab Runner는 Docker 이미지에 정의된 진입점을 사용하여 kube attach를 사용합니다. 15.1 이후의 GitLab에서는 FF_KUBERNETES_HONOR_ENTRYPOINT가 설정된 경우에만 Docker 이미지에 정의된 진입점을 Kubernetes 실행자와 함께 사용합니다.

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

  • 이미지의 Dockerfile에 진입점이 정의된 경우, 유효한 셸을 여는 것이 필요합니다. 그렇지 않으면 작업이 멈출 수 있습니다.
  • 파일 유형 CI/CD 변수는 진입점이 실행될 때 디스크에 작성되지 않습니다. 해당 파일은 스크립트 실행 중에만 접근이 가능합니다.
  • 다음과 같은 CI/CD 변수는 진입점에서 접근할 수 없습니다. 작업 명령어를 실행하기 전에 before_script를 사용하여 설정 변경을 할 수 있습니다:

작업 변수 액세스 제한

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

  • Pod의 환경 섹션

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

다른 사용자가 GitLab Runner 네임스페이스에 액세스할 필요가 있다면, 다음 동사를 설정하여 GitLab Runner 네임스페이스에서 사용자의 액세스 유형을 제한해야 합니다:

  • podsconfigmaps의 경우:
    • get
    • watch
    • list
  • pods/execpods/attach의 경우, create를 사용하세요.

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

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

준비 단계에서 리소스 확인

전제 조건:

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

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

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

Kubernetes 네임스페이스 덮어쓰기

전제 조건:

  • GitLab Runner Helm 차트의 values.yml 파일에서 rbac.clusterWideAccesstrue로 설정되어 있어야 합니다.
  • 러너는 코어 API 그룹에 구성된 권한을 가져야 합니다.

CI 용도로 네임스페이스를 지정하고 사용자 정의 pod 세트를 배포하기 위해 Kubernetes 네임스페이스를 덮어쓸 수 있습니다. 러너에 의해 생성된 pod는 CI 단계 중에 컨테이너 간의 액세스를 활성화하기 위해 덮어쓰인 네임스페이스에 속합니다.

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

variables:
  KUBERNETES_NAMESPACE_OVERWRITE: ci-${CI_COMMIT_REF_SLUG}
note
이 변수는 클러스터에 네임스페이스를 생성하지 않습니다. 작업을 실행하기 전에 네임스페이스가 존재하는지 확인하세요.

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

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