리소스 그룹
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
기본적으로 GitLab CI/CD의 파이프라인은 동시에 실행됩니다. 하나의 리소스 그룹에는 리소스를 하나만 추가할 수 있습니다. 다음과 같은 파이프라인 설정(리포지터리의 .gitlab-ci.yml 파일)이 있다고 가정합니다.
기본적으로 GitLab CI/CD의 파이프라인은 동시에 실행됩니다. 동시성은 머지 리퀘스트의 피드백 루프를 개선하는 데 중요한 요소입니다. 하지만 배포 job의 동시성을 제한하여 하나씩 순서대로 실행하고 싶은 경우도 있습니다. 리소스 그룹을 사용하면 지속적 배포 워크플로를 안전하게 최적화하도록 job의 동시성을 전략적으로 제어할 수 있습니다.
리소스 그룹 추가#
하나의 리소스 그룹에는 리소스를 하나만 추가할 수 있습니다.
다음과 같은 파이프라인 설정(리포지터리의 .gitlab-ci.yml 파일)이 있다고 가정합니다.
build:
stage: build
script: echo "Your build script"
deploy:
stage: deploy
script: echo "Your deployment script"
environment: production
브랜치에 새 커밋을 푸시할 때마다 build와 deploy 두 job으로 구성된 새 파이프라인이
실행됩니다. 하지만 짧은 시간 간격으로 여러 커밋을 푸시하면 다음과 같이 여러
파이프라인이 동시에 실행되기 시작합니다.
- 첫 번째 파이프라인은
build->deployjob을 실행합니다 - 두 번째 파이프라인은
build->deployjob을 실행합니다
이 경우 서로 다른 파이프라인의 deploy job 이 production 환경에 동시에 실행될 수
있습니다. 동일한 인프라에 여러 배포 스크립트를 실행하면 인스턴스에 문제가 발생하거나
혼란을 일으킬 수 있으며, 최악의 경우 손상된 상태로 남을 수 있습니다.
deploy job 이 한 번에 하나씩만 실행되도록 하려면 동시성에 민감한 job에
resource_group 키워드를 지정할 수 있습니다.
deploy:
# ...
resource_group: production
이 설정을 사용하면 배포의 안전성을 보장하면서도 build job은 계속 동시에 실행하여
파이프라인 효율성을 극대화할 수 있습니다.
사전 요구 사항#
- GitLab CI/CD 파이프라인에 대한 이해
- GitLab 환경 및 배포에 대한 이해
- CI/CD 파이프라인을 설정하려면 프로젝트에 대한 Developer, Maintainer 또는 Owner 권한이 필요합니다.
처리 모드#
배포 환경에 맞게 job 동시성을 제어하는 처리 모드를 선택할 수 있습니다. 다음 모드를 지원합니다.
| 처리 모드 | 설명 | 사용 시점 |
|---|---|---|
unordered |
기본 처리 모드입니다. job 이 실행 준비가 될 때마다 처리합니다. | job의 실행 순서가 중요하지 않은 경우입니다. 가장 사용하기 쉬운 옵션입니다. |
oldest_first |
리소스가 확보되면 파이프라인 ID 오름차순으로 정렬된 예정 job 목록에서 첫 번째 job을 선택합니다. | 가장 오래된 파이프라인의 job부터 실행하고 싶은 경우입니다. unordered 모드보다 효율은 낮지만 지속적 배포에는 더 안전합니다. |
newest_first |
리소스가 확보되면 파이프라인 ID 내림차순으로 정렬된 예정 job 목록에서 첫 번째 job을 선택합니다. | 가장 최신 파이프라인의 job을 실행하고 오래된 배포 job 실행 방지를 하고 싶은 경우입니다. 각 job은 멱등이어야 합니다. |
newest_ready_first |
리소스가 확보되면 해당 리소스를 대기 중인 예정 job 목록에서 첫 번째 job을 선택합니다. job은 파이프라인 ID 내림차순으로 정렬됩니다. | newest_first가 현재 파이프라인을 배포하기 전에 새 파이프라인을 우선시하지 않도록 하고 싶은 경우입니다. newest_first보다 빠릅니다. 각 job은 멱등이어야 합니다. |
처리 모드 변경#
리소스 그룹의 처리 모드를 변경하려면 API를 사용해 process_mode를 지정하여
기존 리소스 그룹 편집 요청을 보내야 합니다.
unorderedoldest_firstnewest_firstnewest_ready_first
처리 모드별 차이 예시#
build job과 deploy job 이 있는 다음 .gitlab-ci.yml을 살펴보겠습니다.
각 job은 별도의 스테이지에서 실행되며, deploy job에는 production으로
설정된 리소스 그룹이 지정되어 있습니다.
build:
stage: build
script: echo "Your build script"
deploy:
stage: deploy
script: echo "Your deployment script"
environment: production
resource_group: production
프로젝트에 짧은 시간 간격으로 커밋 3개가 푸시되면 세 파이프라인이 거의 동시에 실행됩니다.
- 첫 번째 파이프라인은
build->deployjob을 실행합니다. 이 배포 job을deploy-1이라고 부르겠습니다. - 두 번째 파이프라인은
build->deployjob을 실행합니다. 이 배포 job을deploy-2라고 부르겠습니다. - 세 번째 파이프라인은
build->deployjob을 실행합니다. 이 배포 job을deploy-3이라고 부르겠습니다.
리소스 그룹의 처리 모드에 따라 다음과 같이 동작합니다.
- 처리 모드가
unordered인 경우:deploy-1,deploy-2,deploy-3는 동시에 실행되지 않습니다.- job 실행 순서는 보장되지 않습니다. 예를 들어
deploy-1은deploy-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은
배포 파이프라인의 동시성을 효율적으로 제어하는 동시에 다른 job은 계속 동시에 실행되도록
할 수 있습니다.
다음 예시는 한 프로젝트에 두 개의 파이프라인 설정이 있는 경우입니다. 파이프라인이 실행을 시작하면 민감하지 않은 job 이 먼저 실행되며, 다른 파이프라인의 동시 실행에 영향을 받지 않습니다. 하지만 GitLab은 배포(자식) 파이프라인을 트리거하기 전에 다른 배포 파이프라인이 실행 중이지 않음을 보장합니다. 다른 배포 파이프라인이 실행 중이면 GitLab은 해당 파이프라인이 끝날 때까지 대기한 후 다음 파이프라인을 실행합니다.
# .gitlab-ci.yml (parent pipeline)
build:
stage: build
script: echo "Building..."
test:
stage: test
script: echo "Testing..."
deploy:
stage: deploy
trigger:
include: deploy.gitlab-ci.yml
strategy: mirror
resource_group: AWS-production
# deploy.gitlab-ci.yml (child pipeline)
stages:
- provision
- deploy
provision:
stage: provision
script: echo "Provisioning..."
deployment:
stage: deploy
script: echo "Deploying..."
environment: production
다운스트림 파이프라인이 끝날 때까지 잠금이 해제되지 않도록 하려면
trigger:strategy를 정의해야 합니다.
관련 주제#
문제 해결#
파이프라인 설정에서 교착 상태(dead lock) 방지#
oldest_first 처리 모드는 파이프라인 순서대로 job 이 실행되도록
강제하므로, 다른 CI 기능과 잘 맞지 않는 경우가 있습니다.
예를 들어 부모 파이프라인과 동일한 리소스 그룹을 필요로 하는 자식 파이프라인을 실행하면 교착 상태가 발생할 수 있습니다. 다음은 잘못된 설정의 예시입니다.
# BAD
test:
stage: test
trigger:
include: child-pipeline-requires-production-resource-group.yml
strategy: mirror
deploy:
stage: deploy
script: echo
resource_group: production
environment: production
부모 파이프라인은 test job을 실행하고 이어서 자식 파이프라인을 실행하며,
strategy: mirror 옵션에 의해 test job은 자식
파이프라인이 끝날 때까지 대기합니다. 부모 파이프라인은 다음 스테이지에서
production 리소스 그룹의 리소스를 필요로 하는 deploy job을 실행합니다.
처리 모드가 oldest_first 이면 가장 오래된 파이프라인부터 job을 실행하므로
다음으로 deploy job 이 실행됩니다.
하지만 자식 파이프라인도 production 리소스 그룹의 리소스를 필요로 합니다.
자식 파이프라인이 부모 파이프라인보다 최신이므로, 자식 파이프라인은 deploy job 이
끝날 때까지 대기하게 되는데 이는 결코 일어나지 않습니다.
이 경우 대신 부모 파이프라인 설정에 resource_group 키워드를 지정해야 합니다.
# GOOD
test:
stage: test
trigger:
include: child-pipeline.yml
strategy: mirror
resource_group: production # Specify the resource group in the parent pipeline
deploy:
stage: deploy
script: echo
resource_group: production
environment: production
job 이 Waiting for resource 상태에서 멈추는 경우#
가끔 job 이 Waiting for resource: <resource_group> 메시지와 함께 멈추는 경우가
있습니다. 해결하려면 먼저 리소스 그룹이 정상적으로 동작하는지 확인합니다.
-
job 상세 페이지로 이동합니다.
-
리소스가 job에 할당되어 있으면 View job currently using resource를 선택하고 job 상태를 확인합니다.
- 상태가
running또는pending이면 기능이 정상적으로 동작하는 것입니다. job 이 끝나 리소스를 해제할 때까지 기다립니다. - 상태가
created이고 처리 모드가 Oldest first 또는 Newest first 이면 기능이 정상적으로 동작하는 것입니다. job의 파이프라인 페이지를 방문해 어떤 상위 스테이지나 job 이 실행을 막고 있는지 확인합니다. - 위 조건에 모두 해당하지 않으면 기능이 정상적으로 동작하지 않을 수 있습니다. GitLab에 이슈를 제보합니다.
- 상태가
-
View job currently using resource를 사용할 수 없으면 리소스가 어떤 job에도 할당되어 있지 않은 것입니다. 대신 해당 리소스의 예정 job을 확인합니다.
- REST API로 리소스의 예정 job을 조회합니다.
- 리소스 그룹의 처리 모드가 Oldest first 인지 확인합니다.
- 예정 job 목록에서 첫 번째 job을 찾아 GraphQL 로 job 상세 정보를 확인합니다.
- 첫 번째 job의 파이프라인이 오래된 파이프라인이면 해당 파이프라인이나 job 자체를 취소해봅니다.
- 선택 사항입니다. 다음 예정 job 이 더 이상 실행되지 않아야 할 오래된 파이프라인에 있다면 이 과정을 반복합니다.
- 문제가 계속되면 GitLab에 이슈를 제보합니다.
복잡하거나 부하가 많은 파이프라인의 경합 조건(race condition)#
위 해결 방법으로도 문제가 해결되지 않으면 알려진 경합 조건 문제를 겪고 있을 수 있습니다. 이 경합 조건은 복잡하거나 부하가 많은 파이프라인에서 발생합니다. 예를 들어 다음과 같은 경우 경합 조건을 겪을 수 있습니다.
- 여러 자식 파이프라인을 가진 파이프라인
- 여러 파이프라인이 동시에 실행되는 단일 프로젝트
이 문제를 겪고 있다고 생각되면 GitLab에 이슈를 제보하고 새로 생성한 이슈 링크와 함께 이슈 436988에 댓글을 남깁니다. 문제를 확인하기 위해 GitLab 이 전체 파이프라인 설정 등 추가 정보를 요청할 수 있습니다.
임시 해결 방법으로 다음을 시도할 수 있습니다.
-
새 파이프라인을 시작합니다.
-
멈춘 job과 동일한 리소스 그룹을 가진, 이미 끝난 job을 다시 실행합니다.
예를 들어 동일한 리소스 그룹을 가진
setup_job과deploy_job이 있는 경우,deploy_job이waiting for resource상태로 멈춰 있는 동안setup_job은 끝났을 수 있습니다.setup_job을 다시 실행하면 전체 과정을 다시 시작하여deploy_job이 끝날 수 있도록 합니다.
GraphQL로 job 상세 정보 확인#
GraphQL API로 job 정보를 확인할 수 있습니다. 프로젝트 간/부모-자식 파이프라인을 사용한 파이프라인 수준 동시성 제어를 사용하는 경우 트리거 job은 UI에서 접근할 수 없으므로 GraphQL API를 사용해야 합니다.
GraphQL API로 job 정보를 확인하려면 다음과 같이 합니다.
-
파이프라인 상세 페이지로 이동합니다.
-
Jobs 탭을 선택하고 멈춘 job의 ID를 찾습니다.
-
대화형 GraphQL 탐색기로 이동합니다.
-
다음 쿼리를 실행합니다.
{ project(fullPath: "<fullpath-to-your-project>") { name job(id: "gid://gitlab/Ci::Build/<job-id>") { name status detailedStatus { action { path buttonTitle } } } } }job.detailedStatus.action.path필드에는 리소스를 사용 중인 job의 ID가 들어 있습니다. -
다음 쿼리를 실행하고 위 기준에 따라
job.status필드를 확인합니다.pipeline.path필드로 파이프라인 페이지를 방문할 수도 있습니다.{ project(fullPath: "<fullpath-to-your-project>") { name job(id: "gid://gitlab/Ci::Build/<job-id-currently-using-the-resource>") { name status pipeline { path } } } }
이슈 제보#
다음 정보와 함께 새 이슈를 생성합니다.
-
영향을 받은 job의 ID
-
job 상태
-
문제가 발생하는 빈도
-
문제를 재현하는 단계
추가 지원이 필요하거나 개발팀에 문의하려면 지원팀에 문의할 수도 있습니다.