This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
proposed @ajwalker @johnwparent @ayufan @DarrenEastman @engineering-manager devops 2023-03-07

GitLab Runner 입합 컨트롤러

GitLab admission controller은 수정되거나 실행 대기열에 추가되기 전에 작업을 가로채는 제안된 기술적 솔루션입니다, Kubernetes admission controller concept에서 영감을 받았습니다.

입합 컨트롤러는 GitLab 인스턴스에 등록되고 작성할 작업이 포함된 페이로드를 받을 수 있습니다. Admission controller는 mutating, validating, 또는 이 둘을 모두 수행할 수 있습니다.

  • _mutating_일 때 수정 가능한 작업 정보를 수정하고 GitLab 인스턴스로 되돌려 보낼 수 있습니다. 작업은 조직 정책, 보안 요구 사항에 부합하도록 수정될 수 있거나, 예를 들어 태그 디렉터리을 수정하여 특정 Runner로 라우팅되도록 변경될 수 있습니다.
  • _validating_일 때 작업은 실행을 거부할 수 있습니다.

동기

책임의 분리, 조직 정책 또는 보안 요구 사항을 준수하기 위해 금융 서비스, 미국 연방 정부 시장 세그먼트 또는 기타 엄격히 규제되는 산업에 속하는 고객은 특정 CI 작업 환경과 관련된 Runner의 사용을 허용해야 합니다.

이 문맥에서 환경이라는 용어를 사용하는 것은 GitLab CI environments 및 deployments 문서에서 사용되는 환경의 정의와 같지 않습니다. SLSA 가이드의 정의에서 환경은 “작업이 실행되는 기계, 컨테이너, 가상 머신 또는 유사한” 것입니다.

또한 이에 추가적인 요구 사항은 Lawrence Livermore National Laboratory의 원격 컴퓨팅 활성화(Remote Computing Enablement, RCE) 그룹에서 나왔습니다. 이 예시에서 사용자는 CI 작업을 실행하기 위해 대상 Runner CI 빌드 환경에 사용자 ID가 있어야 합니다. 전체 사용자 베이스를 대상으로 간단하게 관리하기 위해 RCE는 Runner를 GitLab 사용자 엔터티에 연결할 수 있어야 합니다.

현재의 GitLab CI 작업 처리 메커니즘

더 나아가기 전에, GitLab CI와 GitLab Runner의 현재 작업 처리 메커니즘을 수준 맞추기 위해 도움이 되는 정보입니다.

  • 먼저, GitLab 인스턴스에 연결된 Runner는 지속적으로 GitLab 인스턴스 API를 쿼리하여 실행할 수 있는 새 작업이 있는지 확인합니다.
  • .gitlab-ci.yml 파일이 프로젝트 리포지터리에 푸시될 때마다, GitLab 인스턴스에 있는 CI 서비스가 이벤트를 포착하고 새 CI 작업을 트리거합니다.
  • CI 작업은 Runner가 인스턴스에서 작업을 요청할 때까지 대기열에서 대기 상태에 있습니다.
  • Runner가 작업을 실행하도록 API에 대해 작업을 요청할 때, 데이터베이스는 작업 매개변수가 Runner와 일치하는지를 검증합니다. 다시 말해, Runner가 실행할 작업을 지정된 기준과 일치하면 작업이 할당됩니다.
  • 작업이 해당 Runner와 일치한다면, GitLab 인스턴스가 작업을 Runner에 연결하고 작업 상태를 실행 중으로 변경합니다.
  • Runner는 태그가 지정되지 않은 작업을 실행하도록 구성할 수 있습니다. 오늘날 고객이 일부 특정 유형의 작업이 실행되도록 하려는 주요 메커니즘은 태그입니다.
  • Runner는 인스턴스, 그룹 또는 프로젝트에 범위가 지정될 수 있지만, 현재 추가적인 액세스 제어 메커니즘이 사용되지 않아 사용자 또는 그룹 식별자에 기반하여 Runner의 액세스를 거부할 수 있는 확장할 수 있는 메커니즘이 없습니다.

현재 CI 작업 대기열 논리는 다음과 같습니다. **참고 - 코드에서는 여전히 매우 오래된 build 네이밍 구조를 사용하지만, 제품과 문서에서는 build에서 job으로 이관한 상태입니다.

jobs =
  if runner.instance_type?
   jobs_for_shared_runner
  elsif runner.group_type?
    jobs_for_group_runner
  else
    jobs_for_project_runner
  end

# Runner에서 알려진 태그를 가진 작업만 선택합니다.
jobs = jobs.matches_tag_ids(runner.tags.ids)

# 필요한 경우 적어도 하나의 태그가 있는 빌드를 선택합니다.
unless runner.run_untagged?
  jobs = jobs.with_any_tags
end

목표

  • 기본 작업 세부 정보 (사용자, 그룹 또는 프로젝트 멤버십과 같은)를 기반으로, 특정 Runner 엔터티에서 CI 작업 실행을 허용, 거부, 또는 리디렉션하는 쉽게 구성하고 사용할 수 있는 초기 솔루션을 구현합니다.

비목표

  • CI 작업 대기열 메커니즘을 다시 설계하는 것은 이 청사진의 범위에 포함되지 않습니다.

제안

CI 작업을 가로채기 위한 Mechanism, admission controllers를 구현하여, 작업을 수정하거나 유효성을 검사하거나 둘 다 수행할 수 있습니다. Admission controller는 CI 작업이 CI 작업 대기열에 삽입되기 전에 호출되는 mutating webhook입니다.

지침 원칙

  • webhook 페이로드 스키마는 우리의 공개 API의 일부가 될 것입니다.
  • webhook 페이로드를 확장할 때 거꾸로 호환성을 유지해야 합니다.
  • Controller는 idempotent해야 합니다.

admissions controller는 어떻게 작동합니까?

시나리오 1: 특정 Runner에 대한 액세스를 거부하려고 합니다.

  1. 특정 프로젝트에서만 작업을 수락하도록 admissions controller를 구성합니다.
  2. 작업이 생성될 때, project 정보 (project_id, job_id, api_token)가 GitLab에서 특정 세부 정보를 쿼리하는 데 사용됩니다.
  3. project 정보가 허용 디렉터리과 일치하는 경우, 작업 페이로드는 수정되지 않고 작업이 대상 Runner에서 실행되도록 허용됩니다.
  4. project 정보가 허용 디렉터리과 일치하지 않는 경우, 작업 페이로드는 수정되지 않고 작업이 삭제됩니다.
  5. 작업 태그는 변경되지 않습니다.
  6. Admission controller는 거절 결정이 내려진 이유에 대한 임의의 텍스트 설명을 선택적으로 되돌릴 수 있습니다.

시나리오 2: 공통 구성 및 태그를 사용하는 대규모 Runner 풀

각 Runner에는 zone_a, zone_b와 같은 태그가 있습니다. 이 시나리오에서 고객은 특정 작업이 어느 곳에서 실행될지 알 수 없으며, 일부 사용자는 zone_a에 액세스할 수 있고, 일부 사용자는 zone_b에 액세스할 수 있습니다. 고객은 zone_a에서 실행되어야 하는 특정 작업이 잘못 태그가 되어있을 때 작업이 실패하기를 원하지 않지만 대신 작업을 리디렉션하기를 원합니다.

  1. admissions controller를 구성하여 user_id에 기반하여 작업을 변형합니다.
  2. 작업이 생성될 때, project 정보 (project_id, job_id, api_token)가 GitLab에서 특정 세부 정보를 쿼리하는 데 사용됩니다.
  3. user_id가 일치하는 경우, admissions controller는 작업 태그 디렉터리을 수정합니다. 컨트롤러는 작업을 트리거한 사용자의 작업이 zone_a에서 실행되어야 함을 감지했기 때문에 zone_a가 태그 디렉터리에 추가됩니다.

시나리오 3: 특정 태그 체계를 사용하는 Runner 풀, 사용자는 특정 부분 집합에만 액세스 권한이 있는 경우

각 Runner에는 해당 Runner에 고유한 태그 식별자가 있습니다. 예: DiscoveryOne, tugNostromo, MVSeamus 등. 사용자는 이러한 Runners에 임의로 액세스할 수 있지만, 액세스 거부 시 작업이 실패하는 대신 사용자가 액세스할 수 없는 Runner에서 작업이 실행되지 않도록 하고 싶습니다. 이 작업을 실행할 수 있는 Runner 풀을 줄이고 싶지는 않습니다.

  1. admissions controller를 구성하여 user_id에 기반하여 작업을 변형합니다.
  2. 작업이 생성될 때, project 정보 (project_id, job_id, api_token)가 GitLab에서 특정 세부 정보를 쿼리하는 데 사용됩니다.
  3. admission controller는 user_id와 연관된 사용 가능한 Runners를 쿼리하고 사용자가 권한이 없는 작업이 실행될 수 없는 모든 Runners를 수집합니다. 이 모든 Runners에 대해 admission controller가 작업을 거부할 경우, 작업이 삭제됩니다. 태그가 수정되지 않으며, 이유를 나타내는 메시지가 포함됩니다. 사용자가 권한이 있는 Runner가 있는 경우, admission controller는 해당 Runner를 필터링하여 사용 권한이 없는 Runner를 수집합니다.

MVC

Admission controller

  1. 단일 admissions controller는 인스턴스 수준에만 등록할 수 있습니다.
  2. admissions controller는 1시간 이내에 응답해야 합니다.
  3. admissions controller는 개별 작업을 받게 됩니다. 응답은 해당 작업에 대한 응답만 포함해야 합니다.
  4. 거부 및 수락을 위한 API 콜백을 받게 되며, 승인 콜백에서는 변형 매개변수를 수용해야 합니다.

Job Lifecycle

  1. preparing 작업 상태는 검증 프로세스 전제 조건을 포함하도록 확장될 것입니다.

    stateDiagram-v2 created --> preparing state preparing { [*] --> accept [*] --> reject } reject --> failed accept --> pending pending --> running: 러너에 의해 선택됨 running --> executed state executed { [*] --> failed [*] --> success [*] --> canceled } executed --> created: 재시도
  2. 상태가 preparing일 때, 변이 웹훅 페이로드는 입학 컨트롤러로 비동기적으로 전송됩니다. 이는 필요에 따라 여러 번 재시도될 것입니다.
  3. preparing 상태는 웹훅으로부터 응답을 기다리거나 타임아웃까지 기다립니다.
  4. UI는 작업 전제 조건 및 입학의 현재 상태로 업데이트되어야 합니다.
  5. 웹훅이 타임아웃되는 작업(1시간)에 대해서는 일반적인 상황에서는 드물지만, 입학이 거부되었다는 이유로 상태가 설정되어야 합니다.
  6. 입학이 거부된 작업은 재시도될 수 있습니다. 재시도된 작업은 태그 변이나 러너 필터링 재설정 없이 입학 컨트롤러로 다시 전송될 것입니다.
  7. allow_failure은 거부된 입학에서 실패하는 작업을 지원하도록 업데이트되어야 합니다. 예를 들어:

    job:
      script:
        - echo "I will fail admission"
      allow_failure:
        on_denied_admission: true
    
  8. UI는 작업 변이(제공된 경우) 또는 거절의 이유를 표시해야 합니다.
  9. 입학 컨트롤러에 의해 적용된 태그 변경 사항은 시스템에 연관 이유와 함께 지속되어야 합니다.

Payload

  1. 페이로드는 작업 ID로 구성된 개별 작업 항목으로 이루어져 있습니다:
  2. 응답 페이로드는 개별 작업 항목으로 이루어진 개별 작업 항목으로 구성되어 있습니다.
    • 작업 ID
    • 입학 상태: accepted 또는 denied
    • 변이: additionsremovals. additions는 기존 태그 집합을 보충하며, removal은 현재 태그 디렉터리에서 태그를 제거합니다.
    • 이유: 컨트롤러는 입학 및 변이에 대한 이유를 제공할 수 있습니다.
    • 허용된 러너: 작업 매칭을 위해 고려해야 하는 러너, 모든 러너와 일치하도록 비워둘 수 있습니다.
    • 거부된 러너: 작업 매칭을 위해 고려되지 말아야 하는 러너, 모든 러너와 일치하도록 비워둘 수 있습니다.
예시 요청
[
  {
    "id": 123,
    "variables": {
      # 사전 정의된 변수: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
      "CI_PROJECT_ID": 123,
      "CI_PROJECT_NAME": "something",
      "GITLAB_USER_ID": 98123,
      ...
    },
    "tags": [ "docker", "windows" ]
  }
]
[
  {
    "id": 245,
    "variables": {
      "CI_PROJECT_ID": 245,
      "CI_PROJECT_NAME": "foobar",
      "GITLAB_USER_ID": 98123,
      ...
    },
    "tags": [ "linux", "eu-west" ]
  }
]
[
  {
    "id": 666,
    "variables": {
      "CI_PROJECT_ID": 666,
      "CI_PROJECT_NAME": "do-bad-things",
      "GITLAB_USER_ID": 98123,
      ...
    },
    "tags": [ "secure-runner" ]
  },
]
예시 응답
[
  {
    "id": 123,
    "admission": "accepted",
    "reason": "it's always-allow-day-wednesday"
  }
]
[
  {
    "id": 245,
    "admission": "accepted",
    "tags": {
      "add": [ "linux", "us-west" ],
      "remove": [...]
    },
    "runners": {
      "accepted_ids": ["822993167"],
      "rejected_ids": ["822993168"]
    },
    "reason": "user is US employee: retagged region; user only has uid on runner 822993167"
  }
]
[
  {
    "id": 666,
    "admission": "rejected",
    "reason": "you have no power here"
  }
]

MVC +

  1. 그룹 및 프로젝트 수준에서 여러 개의 입학 컨트롤러.
  2. 컨트롤러 체인을 통해 작업 정의 전달(프로젝트에서 시작하여 정의된 모든 그룹 컨트롤러를 거쳐 인스턴스 컨트롤러까지).
  3. 각 수준은 전체 체인에서 이전 컨트롤러에 의해 수정된 정의를 받고 현재 상태에 기반하여 결정을 내립니다.
  4. 여러 컨트롤러에서 보고된 경우 변이 이유는 연결됩니다.
  5. 입학 컨트롤러의 사용은 선택 사항이므로 프로젝트+인스턴스, 프로젝트+그룹+상위 그룹+인스턴스, 프로젝트+그룹, 그룹+인스턴스 등이 포함된 체인을 갖을 수 있습니다.

구현 세부 정보

GitLab

  1. preparing 상태를 확장하여 prerequisite 인터페이스를 통해 검증 프로세스를 실행할 것입니다.
  2. 사용자에게 preparing 상태를 통해 작업 전제 조건에 대한 작업 준비 상태를 UI 및 API를 통해 표시하도록 preparing 상태를 수정할 것입니다.
    1. 각 전제 요소에 대한 상태를 별도로 표시해야 하며, 비동기적으로 이루어집니다.
    2. 전반적인 전제 상태를 나타내어야 합니다.
  3. preparing 전체 상태에 1시간의 타임아웃을 도입할 것입니다.
  4. preparing 상태 의존성에 AdmissionValidation 선행 조건을 도입할 것입니다.
  5. 선행 조건 팩토리와 preparing 상태를 비동기적으로 작동하도록 수정할 것입니다.
  6. PreparingBuildService를 비동기적으로 작동하도록 수정할 것입니다.
  7. PreparingBuildService는 검증의 성공에 따라 작업을 준비 중 또는 실패로 전환시킬 것입니다.
  8. AdmissionValidation은 요청을 보낼 때 합리적인 수의 재시도를 수행할 것입니다.
  9. 웹훅/입학 컨트롤러 응답 콜백을 위한 API 엔드포인트를 추가할 것입니다.
    1. 매개변수를 허용합니다:
      • 수락/거부
      • 이유 문자열
      • 태그 변이(수락된 경우 무시됨)
    2. 콜백은 일회성 인증 토큰을 인코딩합니다.
  10. 검증 거부에 새로운 실패 이유를 도입할 것입니다.
  11. 입학 컨트롤러의 작업에 미치는 영향은 지속되어야 합니다.
  12. 입학 컨트롤러로부터의 응답을 기반으로 작업별 러너 선택 필터링을 추가해야 합니다.

해결할 기술적 문제

문제 해결 방법
대기 웹훅의 규칙 정의  
입학 컨트롤러에게 어떤 데이터를 전송해야 할까요? 일부 또는 모든 사전 정의된 변수의 하위 집합입니까?  
대기 웹훅이 GitLab.com 규모에서 작동할 수 있습니까? GitLab.com에서는 초당 수백만의 웹훅을 트리거하게 되며, 이는 Sidekiq을 과부화할 수 있거나 시스템을 남용하는 데 사용될 수 있습니다.