리소스 그룹

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

기본적으로 GitLab CI/CD의 파이프라인은 동시에 실행됩니다. 동시성은 병합 요청의 피드백 루프를 개선하는 데 중요한 요소이지만, 배포 작업의 동시성을 제한하고 순차적으로 실행하려는 상황도 있습니다. 리소스 그룹을 사용하여 작업의 동시성을 전략적으로 제어하여 지속적인 배포 워크플로우를 안전하게 최적화할 수 있습니다.

리소스 그룹 추가

다음 파이프라인 구성이 있는 경우(.gitlab-ci.yml 파일이 저장소에 있는 경우):

build:
  stage: build
  script: echo "빌드 스크립트"

deploy:
  stage: deploy
  script: echo "배포 스크립트"
  environment: production

새로운 커밋을 브랜치에 푸시할 때마다 builddeploy라는 두 작업이 있는 새 파이프라인이 실행됩니다. 그러나 짧은 시간 간격으로 여러 커밋을 푸시하는 경우, 여러 파이프라인이 동시에 실행되기도 합니다. 예를 들면,

  • 첫 번째 파이프라인은 build -> deploy 작업을 실행합니다.
  • 두 번째 파이프라인은 build -> deploy 작업을 실행합니다.

이 경우, 다른 파이프라인에서 production 환경으로의 deploy 작업이 동시에 실행될 수 있습니다. 동일한 인프라에 대해 여러 배포 스크립트를 실행하는 것은 최악의 경우 인스턴스를 손상시키거나 혼란스럽게 할 수 있습니다.

deploy 작업이 한 번에 한 번만 실행되도록 보장하려면 동시성에 민감한 작업에 resource_group 키워드를 지정할 수 있습니다:

deploy:
  ...
  resource_group: production

이 구성을 통해 배포의 안전성은 보장되며 여전히 파이프라인의 효율성을 극대화할 수 있습니다.

전제 조건

제약 사항

리소스 그룹에는 하나의 리소스만 연결할 수 있습니다.

프로세스 모드

작업 동시성을 전략적으로 제어하기 위해 프로세스 모드를 선택할 수 있습니다. 지원되는 모드는 다음과 같습니다:

  • 순서 없음(Unordered): 실행 작업의 동시성을 제한하는 기본 프로세스 모드입니다. 작업의 실행 순서에 대해 걱정할 필요가 없는 경우 가장 쉽게 사용할 수 있는 옵션입니다. 작업이 실행할 준비가 되면 처리를 시작합니다.
  • 가장 오래된 것부터(Oldest first): 이 프로세스 모드는 작업의 동시성을 제한합니다. 리소스가 여유로울 때, 파이프라인 ID로 정렬된 다가오는 작업 목록 (created, scheduled, 또는 waiting_for_resource 상태)에서 첫 번째 작업을 선택합니다. 이 모드는 작업이 가장 오래된 파이프라인에서 실행되도록 보장하는 데 효과적입니다. 파이프라인의 효율성 측면에서 순서 없음 모드보다 효율성이 낮지만, 지속적인 배포에 대해 더 안전합니다.
  • 가장 최근 것부터(Newest first): 이 프로세스 모드는 작업의 동시성을 제한합니다. 리소스가 여유로울 때, 파이프라인 ID로 정렬된 다가오는 작업 목록 (created, scheduled, 또는 waiting_for_resource 상태)에서 첫 번째 작업을 선택합니다. 이 모드는 작업이 가장 최근 파이프라인에서 실행되도록 보장하는 데 유용하며 누락된 구식 배포 작업 방지 기능을 사용하여 모든 오래된 배포 작업을 방지합니다. 파이프라인 효율성 측면에서는 가장 효율적인 옵션이지만, 각 배포 작업이 멱등성을 보장해야 합니다.

프로세스 모드 변경

리소스 그룹의 프로세스 모드를 변경하려면 API를 사용하고 process_mode를 지정하여 기존 리소스 그룹 편집 요청을 보내어야 합니다:

  • unordered
  • oldest_first
  • newest_first

프로세스 모드 간 차이점 예시

다음 .gitlab-ci.yml을 고려해 보겠습니다. 여기에는 각각 고유한 스테이지에서 실행되는 두 작업 builddeploy가 있으며, deploy 작업에는 production으로 설정된 리소스 그룹이 있습니다:

build:
  stage: build
  script: echo "빌드 스크립트"

deploy:
  stage: deploy
  script: echo "배포 스크립트"
  environment: production
  resource_group: production

프로젝트에 세 개의 커밋이 짧은 간격으로 푸시된다면, 거의 동시에 세 개의 파이프라인이 실행됩니다:

  • 첫 번째 파이프라인은 build -> deploy 작업을 실행합니다. 이 배포 작업을 deploy-1이라고 합시다.
  • 두 번째 파이프라인은 build -> deploy 작업을 실행합니다. 이 배포 작업을 deploy-2이라고 합시다.
  • 세 번째 파이프라인은 build -> deploy 작업을 실행합니다. 이 배포 작업을 deploy-3이라고 합시다.

리소스 그룹의 프로세스 모드에 따라:

  • 프로세스 모드가 unordered로 설정된 경우:
    • deploy-1, deploy-2, deploy-3은 동시에 실행되지 않습니다.
    • 실행 순서에 대한 보장이 없으며, 예를 들어 deploy-1deploy-3보다 먼저 실행될 수도 있고 그 반대일 수도 있습니다.
  • 프로세스 모드가 oldest_first로 설정된 경우:
    • deploy-1, deploy-2, deploy-3은 동시에 실행되지 않습니다.
    • deploy-1이 먼저 실행되고, deploy-2가 두 번째로 실행되며, deploy-3이 마지막으로 실행됩니다.
  • 프로세스 모드가 newest_first로 설정된 경우:
    • deploy-1, deploy-2, deploy-3은 동시에 실행되지 않습니다.
    • deploy-3이 먼저 실행되고, deploy-2가 두 번째로 실행되며, deploy-1이 마지막으로 실행됩니다.

파이프라인 수준의 동시성 제어와 교차 프로젝트/상위-하위 파이프라인

동시 실행에 민감한 하위 파이프라인에 대해 resource_group를 정의할 수 있습니다. trigger 키워드를 사용하여 하위 파이프라인을 트리거하고 resource_group 키워드를 함께 사용할 수 있습니다. resource_group는 배포 파이프라인의 동시성을 효과적으로 제어하는 데 도움이 되며, 다른 작업은 계속하여 동시에 실행될 수 있습니다.

다음 예시에서는 프로젝트에 두 가지 파이프라인 구성이 있습니다. 파이프라인이 실행되면, 민감하지 않은 작업은 먼저 실행되고 다른 파이프라인의 동시 실행에 영향을 받지 않습니다. 그러나 GitLab은 배포(하위) 파이프라인을 트리거하기 전에 다른 배포 파이프라인이 실행 중이 아님을 보장합니다. 다른 배포 파이프라인이 실행 중이면, GitLab은 다른 하나를 실행하기 전에 해당 파이프라인이 완료될 때까지 기다립니다.

# .gitlab-ci.yml (상위 파이프라인)

build:
  stage: build
  script: echo "빌드 중..."

test:
  stage: test
  script: echo "테스트 중..."

deploy:
  stage: deploy
  trigger:
    include: deploy.gitlab-ci.yml
    strategy: depend
  resource_group: AWS-production
# deploy.gitlab-ci.yml (하위 파이프라인)

stages:
  - provision
  - deploy

provision:
  stage: provision
  script: echo "준비 중..."

deployment:
  stage: deploy
  script: echo "배포 중..."
  environment: production

trigger 키워드와 함께 strategy: depend를 정의해야 합니다. 이렇게 하면 하위 파이프라인이 완료될 때까지 잠금이 해제되지 않습니다.

관련 주제

문제 해결

파이프라인 구성시 데드락 피하기

oldest_first 프로세스 모드로 인해 작업이 파이프라인 순서대로 실행되도록 강제될 때, 다른 CI 기능과 잘 작동되지 않을 수 있습니다.

예를 들어, 부모 파이프라인에서 동일한 리소스 그룹을 필요로 하는 하위 파이프라인을 실행하는 경우 데드락이 발생할 수 있습니다. 다음은 잘못된 설정의 예입니다:

# 잘못된 설정
test:
  stage: test
  trigger:
    include: child-pipeline-requires-production-resource-group.yml
    strategy: depend

deploy:
  stage: deploy
  script: echo
  resource_group: production
  environment: production

부모 파이프라인에서 test 작업을 실행한 후 하위 파이프라인을 실행하고, strategy: depend 옵션으로 test 작업이 하위 파이프라인이 완료될 때까지 대기합니다. 부모 파이프라인은 다음 단계에서 production 리소스 그룹에서 리소스를 필요로 하는 deploy 작업을 실행합니다. oldest_first 프로세스 모드인 경우, 작업은 가장 오래된 파이프라인부터 실행되므로 deploy 작업이 그 다음에 실행됩니다.

그러나 하위 파이프라인도 production 리소스 그룹에서 리소스가 필요합니다. 하위 파이프라인은 부모 파이프라인보다 더 최근이기 때문에 하위 파이프라인은 deploy 작업이 완료될 때까지 기다립니다.

이 경우, 부모 파이프라인 구성에서 resource_group 키워드를 명시해야 합니다:

# 올바른 설정
test:
  stage: test
  trigger:
    include: child-pipeline.yml
    strategy: depend
  resource_group: production # 부모 파이프라인에서 리소스 그룹을 명시

deploy:
  stage: deploy
  script: echo
  resource_group: production
  environment: production

작업이 “리소스 대기 중”에 멈추는 경우

가끔 작업이 “리소스 대기 중: "이라는 메시지와 함께 멈출 때가 있습니다. 이를 해결하려면, 먼저 리소스 그룹이 올바르게 작동하는지 확인해야 합니다:

  1. 작업 상세 페이지로 이동합니다.
  2. 리소스가 작업에 할당된 경우 현재 리소스를 사용하는 작업 보기를 선택하고 작업 상태를 확인합니다.

    • 상태가 running 또는 pending인 경우, 기능이 올바르게 작동 중입니다. 작업이 완료되고 리소스가 해제될 때까지 기다립니다.
    • 상태가 created이고 process mode가장 오래된 것 먼저, 가장 최신 것 먼저 중 하나인 경우, 기능이 올바르게 작동합니다. 작업이 차단된 상위 스테이지나 작업을 확인하고 이를 해결합니다.
    • 위의 조건 중 어느 것도 해당되지 않는다면, 기능이 올바르게 작동하지 않을 수 있습니다. GitLab에 이슈 신고합니다.
  3. 현재 리소스를 사용하는 작업 보기를 사용할 수 없는 경우, 리소스가 작업에 할당되지 않았습니다. 대신, 리소스의 예정된 작업을 확인합니다.

    1. REST API를 사용하여 리소스의 예정된 작업을 가져옵니다.
    2. 작업의 process mode가장 오래된 것 먼저인지 확인합니다.
    3. 예정된 작업 목록에서 첫 번째 작업을 찾아 GraphQL을 사용하여 작업 상세를 가져옵니다.
    4. 첫 번째 작업의 파이프라인이 더 오래된 경우, 파이프라인이나 작업 자체를 취소해 보십시오.
    5. 선택 사항: 문제가 계속되면, GitLab에 이슈 신고합니다.

GraphQL을 통해 작업 세부정보 가져오기

GraphQL API에서 작업 정보를 가져올 수 있습니다. 파이프라인-레벨 동시성 제어와 교차 프로젝트/상위-하위 파이프라인를 사용하는 경우 UI에서 트리거된 작업에는 접근할 수 없으므로 GraphQL API를 사용해야 합니다.

GraphQL API에서 작업 정보를 가져오려면 다음을 수행하세요:

  1. 파이프라인 세부정보 페이지로 이동합니다.
  2. 작업 탭을 선택하고 멈춰있는 작업의 ID를 찾습니다.
  3. 대화형 GraphQL 탐색기로 이동합니다.
  4. 다음 쿼리를 실행합니다:

     {
       project(fullPath: "<프로젝트의 전체 경로>") {
         name
         job(id: "gid://gitlab/Ci::Build/<작업-ID>") {
           name
           status
           detailedStatus {
             action {
               path
               buttonTitle
             }
           }
         }
       }
     }
    

    job.detailedStatus.action.path 필드에는 해당 리소스를 사용하여 작업 ID가 포함됩니다.

  5. 다음 쿼리를 실행하여 위의 기준에 따라 job.status 필드를 확인합니다. 또한 pipeline.path 필드에서 파이프라인 페이지를 방문할 수도 있습니다.

     {
       project(fullPath: "<프로젝트의 전체 경로>") {
         name
         job(id: "gid://gitlab/Ci::Build/<현재 리소스를 사용하는 작업-ID>") {
           name
           status
           pipeline {
             path
           }
         }
       }
     }
    

이슈 보고

다음 정보로 새 이슈를 열어 문제를 보고합니다:

  • 영향을 받는 작업의 ID.
  • 작업 상태.
  • 문제가 발생하는 빈도.
  • 문제를 재현하는 단계.

    더 많은 지원 또는 개발팀과 연락하려면 지원팀에 연락해도 됩니다.