CI 구성 내부 구조
GitLab v19.1GitLab 프로젝트의 파이프라인은 GitLab CI/CD의 workflow:rules 키워드 기능을 사용하여 생성됩니다. 파이프라인은 다음 시나리오에서 항상 생성됩니다: main 브랜치 (스케줄, 푸시, 머지 등 포함)
워크플로 규칙#
GitLab 프로젝트의 파이프라인은 GitLab CI/CD의 workflow:rules 키워드 기능을 사용하여 생성됩니다.
파이프라인은 다음 시나리오에서 항상 생성됩니다:
-
main브랜치 (스케줄, 푸시, 머지 등 포함) -
머지 리퀘스트
-
태그
-
Stable,
auto-deploy, 보안 브랜치
파이프라인 생성은 다음 CI/CD 변수에도 영향을 받습니다:
-
$FORCE_GITLAB_CI가 설정된 경우 파이프라인이 생성됩니다. 사용을 권장하지 않습니다.$FORCE_GITLAB_CI사용 금지를 참조하세요. -
$GITLAB_INTERNAL이 설정되지 않은 경우 파이프라인이 생성되지 않습니다.
그 외의 경우(예: MR이 없는 브랜치에 푸시할 때)에는 파이프라인이 생성되지 않습니다.
이 워크플로 규칙의 단일 진실 공급원(Single Source Of Truth, SSOT)은 .gitlab-ci.yml에 정의되어 있습니다.
$FORCE_GITLAB_CI 사용 금지#
파이프라인은 매우 복잡하며 어떤 종류의 파이프라인을 트리거할지 명확하게 이해해야 합니다. 어떤 job을 실행해야 하고 어떤 job은 실행하지 않아야 하는지 알아야 합니다.
$FORCE_GITLAB_CI를 사용하여 파이프라인을 강제로 트리거하면,
어떤 종류의 파이프라인인지 실제로 알 수 없습니다.
그 결과 원하는 job이 실행되지 않거나, 관심 없는 job이 너무 많이 실행될 수 있습니다.
더 많은 컨텍스트와 배경 정보는 다음에서 확인할 수 있습니다: 예기치 않은 실행을 방지하기 위한 포괄적인 변경 금지
현재 이 변수가 사용되고 있는 곳의 목록이며, 점차 $FORCE_GITLAB_CI 사용을 줄여 나가야 합니다.
$FORCE_GITLAB_CI를 사용하지 않고 파이프라인을 활성화하는 방법은 다음 섹션을 참조하세요.
$FORCE_GITLAB_CI의 대안#
기본적으로 서로 다른 변수를 사용하여 서로 다른 파이프라인을 활성화합니다.
이를 수행하는 예시가 $START_AS_IF_FOSS입니다.
크로스 프로젝트 FOSS 파이프라인을 트리거하려면 $START_AS_IF_FOSS와 함께
$ENABLE_RSPEC_UNIT, $ENABLE_RSPEC_SYSTEM 등의 변수를 설정하여
as-if-foss 크로스 프로젝트 다운스트림 파이프라인에서 실행할 각 job을 활성화합니다.
$FORCE_GITLAB_CI에 비해 이 방식의 장점은 $START_AS_IF_FOSS가 이 목적에만 사용되기 때문에
파이프라인 실행 방식을 완전히 제어할 수 있다는 것입니다.
이 변수 아래에서 파이프라인 동작을 변경해도 다른 유형의 파이프라인에는 영향을 미치지 않지만,
$FORCE_GITLAB_CI는 여러 목적으로 사용되기 때문에 파이프라인이 정확히 무엇인지 알 수 없습니다.
기본 이미지#
기본 이미지는 .gitlab-ci.yml에 정의되어 있습니다.
여기에는 Ruby, Go, Git, Git LFS, Chrome, Node, Yarn, PostgreSQL, Graphics Magick이 포함됩니다.
파이프라인에서 사용하는 이미지는
gitlab-org/gitlab-build-images
프로젝트에서 구성되며, 이중화를 위해 gitlab/gitlab-build-images로
푸시 미러링됩니다.
현재 빌드 이미지 버전은 "GitLab에서 사용 중인 섹션"에서 확인할 수 있습니다.
기본 변수#
사전 정의된 CI/CD 변수 외에도,
각 파이프라인에는 .gitlab-ci.yml에 정의된 기본 변수가 포함됩니다.
변수 명명 규칙#
2025년 3월부터 모놀리스 CI 파이프라인에서만 사용되는 새 환경 변수에 GLCI_ 접두사를 붙이기 시작했습니다.
이를 통해 환경 변수가 CI(GLCI_), 제품(GITLAB_), 또는 당사가 소유하지 않는 도구 및 시스템 중 어느 것을 위한 것인지 추적할 수 있습니다.
이는 파이프라인 구성에서 환경 변수 변경의 영향을 보다 잘 평가하는 데 도움이 됩니다.
필수 CI 변수#
일부 CI/CD job은 실행하기 위해 특정 변수가 필요합니다. 선택적 변수와 달리, 이 변수들이 정의되지 않으면 해당 job은 완전히 건너뜁니다.
GLCI_MEDIUM_RUNNER_REQUIRED#
이 변수는 최소 4코어 및 16GB RAM이 있는 러너가 필요한 시스템(기능) 테스트 job을 활성화합니다. Chrome 버전 133 이상은 안정적으로 실행하기 위해 추가 컴퓨팅 리소스가 필요합니다. 그렇지 않으면 PostgreSQL 데이터베이스와 Rails 애플리케이션에 리소스가 부족하여 시스템 테스트 job이 예측 불가능하게 불안정해집니다.
CI/CD 설정에서 이 변수를 정의하고 최소 4코어 및 16GB RAM이 있는 러너 태그로 설정합니다. 전체 구성 세부 정보는 이 변수를 도입한 MR의 테스트 섹션을 참조하세요.
정의되지 않은 경우(기본값은 빈 문자열), 시스템 테스트 job이 실행되지 않습니다. 이를 통해 기여자의 개인 포크 등 러너 용량이 충분하지 않은 환경에서 리소스 집약적인 테스트가 실행되는 것을 방지합니다.
시스템 테스트를 실행해야 하는 환경에 필요하며, 다음이 포함됩니다:
-
정규
gitlab-org/gitlab프로젝트 -
GitLab 커뮤니티 포크
-
보안 포크
-
dev.gitlab.org포크
환경별 세부 정보는 동일한 MR의 테스트 환경 섹션을 참조하세요.
Stage#
현재 Stage는 다음과 같습니다:
-
sync: 이 Stage는gitlab-org/gitlab에서gitlab-org/gitlab-foss로 변경 사항을 동기화하는 데 사용됩니다. -
prepare: 이 Stage는 후속 Stage의 job에 필요한 아티팩트를 준비하는 job을 포함합니다. -
build-images: 이 Stage는 후속 Stage 또는 다운스트림 파이프라인의 job에 필요한 Docker 이미지를 준비하는 job을 포함합니다. -
fixtures: 이 Stage는 프론트엔드 테스트에 필요한 픽스처를 준비하는 job을 포함합니다. -
lint: 이 Stage는 린팅 및 정적 분석 job을 포함합니다. -
test: 이 Stage는 대부분의 테스트와 DB/마이그레이션 job을 포함합니다. -
post-test: 이 Stage는testStage의 job에서 보고서를 빌드하거나 데이터를 수집하는 job을 포함합니다(예: 커버리지, Knapsack 메타데이터 등). Docs Review App job도 여기에 포함됩니다. -
qa: 이 Stage는reviewStage에서 배포된 Review App에 대해 QA 작업을 수행하는 job을 포함합니다. -
post-qa: 이 Stage는qaStage의 job에서 보고서를 빌드하거나 데이터를 수집하는 job을 포함합니다(예: Review App 성능 보고서). -
pages: 이 Stage는 GitLab Pages로 다양한 보고서를 배포하는 job을 포함합니다(예:coverage-ruby,webpack-report(https://gitlab-org.gitlab.io/gitlab/webpack-report/에 있으나 배포 문제가 있음)). -
notify: 이 Stage는 다양한 장애를 Slack에 알리는 job을 포함합니다.
Dependency Proxy#
일부 job은 Docker Hub의 이미지를 사용하며, Dependency Proxy에서 이미지를 가져오도록 이미지 경로에 ${GITLAB_DEPENDENCY_PROXY_ADDRESS}를 접두사로 사용합니다.
기본적으로 이 변수는 ${GITLAB_DEPENDENCY_PROXY} 값으로 설정됩니다.
-
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX는 GitLab 사전 정의 CI/CD 변수로, Dependency Proxy를 통해 이미지를 가져오기 위한 최상위 그룹 이미지 접두사를 제공합니다. -
GITLAB_DEPENDENCY_PROXY는gitlab-org및gitlab-com그룹의 CI/CD 변수입니다.${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/로 정의됩니다. -
GITLAB_DEPENDENCY_PROXY_ADDRESS는gitlab-org/gitlab프로젝트에 정의됩니다. 기본값은"${GITLAB_DEPENDENCY_PROXY}"이지만 일부 경우에는 재정의됩니다(아래 워크어라운드 섹션 참조).
gitlab-org/gitlab에서는 워크어라운드로 인해 GITLAB_DEPENDENCY_PROXY_ADDRESS를 사용합니다. gitlab-org 및 gitlab-com 그룹의 다른 곳에서는 Dependency Proxy를 사용하기 위해 GITLAB_DEPENDENCY_PROXY를 사용해야 합니다. 다른 프로젝트의 경우 사전 정의된 CI/CD 변수인 CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX를 사용하여 Dependency Proxy를 활성화할 수 있습니다:
# gitlab-org/gitlab 프로젝트에서
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}alpine:edge
# gitlab-org 및 gitlab-com 그룹의 다른 프로젝트에서
image: ${GITLAB_DEPENDENCY_PROXY}alpine:edge
# gitlab-org 및 gitlab-com 그룹 외부 프로젝트에서
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine:edge
다른 개인 네임스페이스 또는 그룹에 있는 포크는 해당 위치에 GITLAB_DEPENDENCY_PROXY가 정의되어 있지 않으면 Docker Hub로 폴백됩니다.
프로젝트 액세스 토큰 사용자가 파이프라인을 시작할 때의 워크어라운드#
프로젝트 액세스 토큰 사용자(예: 메인 프로젝트에서 사용하는 Gitaly 버전을 자동으로 업데이트하는 release-tools approver bot 사용자)가 파이프라인을 시작할 경우,
Dependency proxy에 접근할 수 없어
Preparing the "docker+machine" executor 단계에서 job이 실패합니다.
이를 해결하기 위해 특별 워크플로 규칙을 사용하여 해당 경우에 Dependency proxy가 사용되지 않도록
${GITLAB_DEPENDENCY_PROXY_ADDRESS} 변수를 재정의합니다:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
variables:
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
그룹 수준 변수는 .gitlab-ci.yml 변수보다 우선순위가 높기 때문에 ${GITLAB_DEPENDENCY_PROXY} 변수를 직접 재정의하지 않습니다.
외부 CI/CD 시크릿#
https://gitlab.com/groups/gitlab-org/quality/engineering-productivity/-/epics/46의 일환으로, 2024년 2월에 GCP Secret Manager 사용을 도그푸딩하여
ADD_JH_FILES_TOKEN CI 변수를 저장하기 시작했습니다.
이 과정에서 qual-ci-secret-mgmt-e78c9b95 GCP 프로젝트가 생성되었습니다.
공통 job 정의#
대부분의 job은 단일 구성 키워드로 범위가 지정된
.gitlab/ci/global.gitlab-ci.yml에 정의된
몇 가지 CI 정의를 extends합니다.
| Job 정의 | 설명 |
|---|---|
| .default-retry | unknown_failure, api_failure, runner_system_failure, job_execution_timeout, stuck_or_timeout_failure 발생 시 job이 재시도할 수 있도록 합니다. |
| .default-before_script | 데이터베이스가 실행 중이어야 할 수 있는 Ruby/Rails 작업(예: 테스트)에 적합한 기본 before_script 정의를 job에서 사용할 수 있도록 합니다. |
| .repo-from-artifacts | 클론 대신 clone-gitlab-repo의 아티팩트에서 리포지터리를 가져올 수 있도록 합니다. 이를 통해 GitLab.com Gitaly 부하를 줄이고 아티팩트에서 다운로드하는 것이 클론보다 빠르기 때문에 속도도 약간 향상됩니다. 단, 모든 job을 가능한 한 빨리 시작하기 위해 needs: []가 있는 job에는 사용을 피해야 합니다. 이 패턴은 클론보다 더 오래 기다리지 않도록 다른 의존성이 있는 job에만 사용하세요. 이 동작은 CI_FETCH_REPO_GIT_STRATEGY를 통해 제어할 수 있습니다. 자세한 내용은 Gitaly에서 클론/패치 대신 아티팩트로 리포지터리 가져오기를 참조하세요. |
| .setup-test-env-cache | 후속 Ruby/Rails 작업을 위한 테스트 환경 설정에 적합한 기본 캐시 정의를 job에서 사용할 수 있도록 합니다. |
| .ruby-cache | Ruby 작업에 적합한 기본 캐시 정의를 job에서 사용할 수 있도록 합니다. |
| .static-analysis-cache | 정적 분석 작업에 적합한 기본 캐시 정의를 job에서 사용할 수 있도록 합니다. |
| .qa-cache | QA 작업에 적합한 기본 캐시 정의를 job에서 사용할 수 있도록 합니다. |
| .yarn-cache | yarn install을 수행하는 프론트엔드 job에 적합한 기본 캐시 정의를 job에서 사용할 수 있도록 합니다. |
| .assets-compile-cache | 에셋을 컴파일하는 프론트엔드 job에 적합한 기본 캐시 정의를 job에서 사용할 수 있도록 합니다. |
| .use-pg16 | postgres 16, redis, rediscluster 서비스를 job에서 사용할 수 있도록 합니다(.gitlab/ci/global.gitlab-ci.yml에서 서비스의 특정 버전 확인). |
| .use-pg16-ee | .use-pg16과 동일하지만 elasticsearch 서비스도 사용합니다(.gitlab/ci/global.gitlab-ci.yml에서 서비스의 특정 버전 확인). |
| .use-pg17 | postgres 17, redis, rediscluster 서비스를 job에서 사용할 수 있도록 합니다(.gitlab/ci/global.gitlab-ci.yml에서 서비스의 특정 버전 확인). |
| .use-pg17-ee | .use-pg17과 동일하지만 elasticsearch 서비스도 사용합니다(.gitlab/ci/global.gitlab-ci.yml에서 서비스의 특정 버전 확인). |
| .use-pg18 | postgres 18, redis, rediscluster 서비스를 job에서 사용할 수 있도록 합니다(.gitlab/ci/global.gitlab-ci.yml에서 서비스의 특정 버전 확인). |
| .use-pg18-ee | .use-pg18과 동일하지만 elasticsearch 서비스도 사용합니다(.gitlab/ci/global.gitlab-ci.yml에서 서비스의 특정 버전 확인). |
| .use-buildx | docker buildx 도구를 사용하여 Docker 이미지를 빌드할 수 있도록 합니다. |
| .as-if-foss | FOSS_ONLY='1' CI/CD 변수를 설정하여 FOSS 프로젝트를 시뮬레이션합니다. |
| .use-docker-in-docker | Docker in Docker 사용을 허용합니다. 자세한 내용은 CI/CD 구성에 관한 핸드북을 참조하세요. |
rules, if: 조건과 changes: 패턴#
rules 키워드를 광범위하게 사용하고 있습니다.
모든 rules 정의는
rules.gitlab-ci.yml에 정의되고,
extends를 통해 개별 job에 포함됩니다.
rules 정의는 if: 조건과 changes: 패턴으로 구성되며,
이 역시 rules.gitlab-ci.yml에 정의되고
YAML 앵커를 통해 rules 정의에 포함됩니다.
if: 조건#
| if: 조건 | 설명 | 참고 |
|---|---|---|
| if-not-canonical-namespace | 프로젝트가 정규(gitlab-org/ 및 gitlab-cn/) 또는 보안(gitlab-org/security) 네임스페이스에 없는 경우 일치합니다. | 포크에 대한 job을 생성(when: on_success 또는 when: manual 사용)하거나 포크에 대한 job을 생성하지 않기 위해(when: never 사용) 사용합니다. |
| if-not-ee | 프로젝트가 EE가 아닌 경우(즉, 프로젝트 이름이 gitlab 또는 gitlab-ee가 아닌 경우) 일치합니다. | FOSS 프로젝트에서만 job을 생성(when: on_success 또는 when: manual 사용)하거나 프로젝트가 EE인 경우 job을 생성하지 않기 위해(when: never 사용) 사용합니다. |
| if-not-foss | 프로젝트가 FOSS가 아닌 경우(즉, 프로젝트 이름이 gitlab-foss, gitlab-ce, gitlabhq가 아닌 경우) 일치합니다. | EE 프로젝트에서만 job을 생성(when: on_success 또는 when: manual 사용)하거나 프로젝트가 FOSS인 경우 job을 생성하지 않기 위해(when: never 사용) 사용합니다. |
| if-default-refs | 파이프라인이 master, main, /^[\d-]+-stable(-ee)?$/(stable 브랜치), /^\d+-\d+-auto-deploy-\d+$/(auto-deploy 브랜치), /^security// (보안 브랜치), 머지 리퀘스트, 태그를 위한 것인 경우 일치합니다. | 이 기본 구성으로는 브랜치에 대해 job이 생성되지 않습니다. |
| if-master-refs | 현재 브랜치가 master 또는 main인 경우 일치합니다. | |
| if-master-push | 현재 브랜치가 master 또는 main이고 파이프라인 소스가 push인 경우 일치합니다. | |
| if-master-schedule-maintenance | 현재 브랜치가 master 또는 main이고 파이프라인이 2시간 스케줄로 실행되는 경우 일치합니다. | |
| if-master-schedule-nightly | 현재 브랜치가 master 또는 main이고 파이프라인이 야간 스케줄로 실행되는 경우 일치합니다. | |
| if-auto-deploy-branches | 현재 브랜치가 auto-deploy 브랜치인 경우 일치합니다. | |
| if-master-or-tag | 파이프라인이 master 또는 main 브랜치나 태그를 위한 것인 경우 일치합니다. | |
| if-merge-request | 파이프라인이 머지 리퀘스트를 위한 것인 경우 일치합니다. | |
| if-merge-request-title-as-if-foss | 파이프라인이 머지 리퀘스트를 위한 것이고 MR에 ~"pipeline:run-as-if-foss" 라벨이 있는 경우 일치합니다. | |
| if-merge-request-title-update-caches | 파이프라인이 머지 리퀘스트를 위한 것이고 MR에 ~"pipeline:update-cache" 라벨이 있는 경우 일치합니다. | |
| if-merge-request-labels-run-all-rspec | 파이프라인이 머지 리퀘스트를 위한 것이고 MR에 ~"pipeline:run-all-rspec" 라벨이 있는 경우 일치합니다. | |
| if-security-merge-request | 파이프라인이 보안 머지 리퀘스트를 위한 것인 경우 일치합니다. | |
| if-security-schedule | 파이프라인이 보안 스케줄 파이프라인을 위한 것인 경우 일치합니다. | |
| if-nightly-master-schedule | 파이프라인이 $NIGHTLY가 설정된 master 스케줄 파이프라인을 위한 것인 경우 일치합니다. | |
| if-dot-com-gitlab-org-schedule | GitLab.com의 gitlab-org 그룹에 대해 스케줄 파이프라인으로 job 생성을 제한합니다. | |
| if-dot-com-gitlab-org-master | GitLab.com의 gitlab-org 그룹에 대해 master 또는 main 브랜치로 job 생성을 제한합니다. | |
| if-dot-com-gitlab-org-merge-request | GitLab.com의 gitlab-org 그룹에 대해 머지 리퀘스트로 job 생성을 제한합니다. | |
| if-dot-com-ee-schedule | GitLab.com의 gitlab-org/gitlab 프로젝트에 대해 스케줄 파이프라인으로 job을 제한합니다. |
changes: 패턴#
| changes: 패턴 | 설명 |
|---|---|
| ci-patterns | CI 구성 관련 변경 사항에 대해서만 job을 생성합니다. |
| ci-build-images-patterns | build-images Stage 관련 CI 구성 변경 사항에 대해서만 job을 생성합니다. |
| ci-review-patterns | review Stage 관련 CI 구성 변경 사항에 대해서만 job을 생성합니다. |
| ci-qa-patterns | qa Stage 관련 CI 구성 변경 사항에 대해서만 job을 생성합니다. |
| yaml-lint-patterns | YAML 관련 변경 사항에 대해서만 job을 생성합니다. |
| docs-patterns | 문서 관련 변경 사항에 대해서만 job을 생성합니다. |
| frontend-dependency-patterns | 프론트엔드 의존성이 업데이트될 때(예: package.json, yarn.lock 변경)만 job을 생성합니다. |
| frontend-patterns-for-as-if-foss | FOSS에 영향을 미치는 프론트엔드 관련 변경 사항에 대해서만 job을 생성합니다. |
| backend-patterns | 백엔드 관련 변경 사항에 대해서만 job을 생성합니다. |
| db-patterns | DB 관련 변경 사항에 대해서만 job을 생성합니다. |
| backstage-patterns | 백스테이지 관련 변경 사항(즉, Danger, 픽스처, RuboCop, 스펙)에 대해서만 job을 생성합니다. |
| code-patterns | 코드 관련 변경 사항에 대해서만 job을 생성합니다. |
| qa-patterns | QA 관련 변경 사항에 대해서만 job을 생성합니다. |
| code-backstage-patterns | code-patterns와 backstage-patterns의 조합입니다. |
| code-qa-patterns | code-patterns와 qa-patterns의 조합입니다. |
| code-backstage-qa-patterns | code-patterns, backstage-patterns, qa-patterns의 조합입니다. |
| static-analysis-patterns | 정적 분석 구성 관련 변경 사항에 대해서만 job을 생성합니다. |
커스텀 종료 코드#
아래 표는 자동 재시도에 사용하는 커스텀 종료 코드를 나열합니다(정의는 GitLab 전역 CI 구성의 재시도 규칙 참조):
| 종료 코드 | 설명 |
|---|---|
| 201 | 디스크 공간 부족 |
새로운 장애 패턴이 나타남에 따라 이 목록은 확장될 수 있습니다. 충돌을 방지하기 위해 201-255 범위의 종료 코드를 사용하세요.
모범 사례#
extends:, <<: *xyz (YAML 앵커), !reference 사용 시기#
핵심 요점#
-
해시를 확장해야 하는 경우
extends를 사용합니다. -
배열을 확장해야 하는 경우
!reference또는 최후 수단으로YAML 앵커를 사용합니다. -
더 복잡한 경우(예: 배열 내 해시 확장, 해시 내 배열 확장 등)에는
!reference또는YAML 앵커를 사용해야 합니다.
extends와 YAML 앵커로 무엇을 할 수 있나요?#
extends#
-
해시에 대한 딥 머지
-
배열에 대한 머지 없음. 덮어씁니다(소스)
YAML 앵커#
-
해시에 대한 딥 머지 없음, 하지만 해시를 확장하는 데 사용할 수 있습니다(아래 예시 참조)
-
배열에 대한 머지 없음, 하지만 배열을 확장하는 데 사용할 수 있습니다(아래 예시 참조)
좋은 예시#
이 예시는 !reference와 YAML 앵커로 복잡한 YAML 데이터 구조를 확장하는 방법을 보여줍니다:
.strict-ee-only-rules:
# `rules` is an array of hashes
rules:
- if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/ '
when: never
# `if-security-merge-request` is a hash
.if-security-merge-request: &if-security-merge-request
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security"'
# `code-qa-patterns` is an array
.code-qa-patterns: &code-qa-patterns
- "{package.json,yarn.lock}"
- ".browserslistrc"
- "babel.config.js"
- "jest.config.{base,integration,unit}.js"
.qa:rules:as-if-foss:
rules:
# We extend the `rules` array with an array of hashes directly
- !reference [".strict-ee-only-rules", rules]
# We extend a single array entry with a hash
- <<: *if-security-merge-request
# `changes` is an array, so we pass it an entire array
changes: *code-qa-patterns
qa:selectors-as-if-foss:
# We include the rules from .qa:rules:as-if-foss in this job
extends:
- .qa:rules:as-if-foss
.fast-no-clone-job job 확장하기#
정규 프로젝트의 브랜치를 다운로드하는 데 20~30초가 걸립니다.
일부 job은 제한된 수의 파일만 필요하며, GitLab API를 통해 다운로드할 수 있습니다.
job에 다음 패턴을 추가하면 job의 git clone/git fetch를 건너뛸 수 있습니다.
시나리오 1: job에 before_script가 정의되어 있지 않은 경우#
이는 job이 extends하는 상위 섹션에도 적용됩니다.
.fast-no-clone-job을 extends하면 됩니다:
변경 전:
# Note: No `extends:` is present in the job
a-job:
script:
- source scripts/rspec_helpers.sh scripts/slack
- echo "No need for a git clone!"
변경 후:
# Note: No `extends:` is present in the job
a-job:
extends:
- .fast-no-clone-job
variables:
FILES_TO_DOWNLOAD: >
scripts/rspec_helpers.sh
scripts/slack
script:
- source scripts/rspec_helpers.sh scripts/slack
- echo "No need for a git clone!"
시나리오 2: job(또는 extends하는 job)에 before_script 블록이 이미 정의되어 있는 경우#
이 시나리오에서는 다음을 수행해야 합니다:
-
첫 번째 시나리오처럼
.fast-no-clone-job을 extends합니다(이렇게 하면FILES_TO_DOWNLOAD변수가 다른 변수들과 합쳐집니다). -
이 job에 사용하는
before_script에서.fast-no-clone-job의before_script섹션이 참조되도록 합니다.
변경 전:
.base-job:
before_script:
echo "Hello from .base-job"
a-job:
extends:
- .base-job
script:
- source scripts/rspec_helpers.sh scripts/slack
- echo "No need for a git clone!"
변경 후:
.base-job:
before_script:
echo "Hello from .base-job"
a-job:
extends:
- .base-job
- .fast-no-clone-job
variables:
FILES_TO_DOWNLOAD: >
scripts/rspec_helpers.sh
scripts/slack
before_script:
- !reference [".fast-no-clone-job", before_script]
- !reference [".base-job", before_script]
script:
- source scripts/rspec_helpers.sh scripts/slack
- echo "No need for a git clone!"
주의 사항#
-
스크립트가 리포지터리에 접근하기 위해
git에 의존하는 경우 이 패턴은 작동하지 않습니다. 클론이나 패치 없이는 리포지터리가 없기 때문입니다. -
이 패턴을 사용하는 job에는
curl이 필요합니다. -
job에서
bundle install을 실행해야 하는 경우(BUNDLE_ONLY사용 포함), 다음이 필요합니다:
gitlab-org/gitlab 프로젝트에 저장된 젬을 다운로드합니다.
이를 위해 download_local_gems 셸 명령어를 사용할 수 있습니다.
Gemfile,Gemfile.lock,Gemfile.checksum(해당되는 경우)을 포함합니다.
이 패턴은 어디서 사용되나요?#
- 현재 다음 job에서 이 패턴을 사용하며, 프라이빗 리포지터리를 차단하지 않습니다:
rspec:coverage의 경우:
config/bundler_setup.rb
-
Gemfile -
Gemfile.checksum -
Gemfile.lock -
scripts/merge-simplecov -
spec/simplecov_env_core.rb -
spec/simplecov_env.rb -
prepare-as-if-foss-env의 경우:
scripts/setup/generate-as-if-foss-env.rb
또한 이 패턴이 사용될 때 scripts/utils.sh는 항상 API에서 다운로드됩니다(이 파일에는 .fast-no-clone-job의 코드가 포함되어 있습니다).
러너 태그#
GitLab.com에서는 비특권 및 특권 러너를 모두 사용할 수 있습니다.
gitlab-org 그룹의 프로젝트와 해당 프로젝트의 포크의 경우, 다음 태그 중 하나만 job에 추가해야 합니다:
-
gitlab-org: 기본적으로 사용되지만 job이 특권 모드에서 실행될 필요가 없는 경우에만 해당합니다. -
gitlab-org-docker: job이 특권 모드에서 실행되어야 하는 경우. Docker in Docker 지원이 필요하다면gitlab-org대신gitlab-org-docker를 사용하세요.
gitlab-org-docker 태그는 위에서 설명한 .use-docker-in-docker job 정의에 의해 추가됩니다.
포크와의 호환성을 보장하려면 gitlab-org와 gitlab-org-docker를 동시에 사용하지 마세요.
어떤 인스턴스 러너도 gitlab-org와 gitlab-org-docker 태그를 모두 가지고 있지 않습니다.
gitlab-org 프로젝트의 포크의 경우, 두 태그가 모두 제공되면 일치하는 러너가 없어 job이 stuck 상태가 됩니다.
자세한 내용은 GitLab 리포지터리 핸드북 페이지를 참조하세요.
정규 프로젝트에서 gitlab Ruby 젬 사용하기#
정규 프로젝트에서 require 'gitlab'을 호출하면, $LOAD_PATH에 lib가 있을 때(애플리케이션(config/application.rb) 또는 테스트(spec/spec_helper.rb)를 로드할 때 발생) lib/gitlab.rb 파일을 require합니다.
이는 위의 조건에서 gitlab 젬을 로드할 수 없다는 것을 의미하며, 로드할 수 있더라도 상수 이름이 충돌하여 내부 가정이 깨지고 무작위 오류가 발생합니다.
gitlab Ruby 젬을 사용하는 스크립트를 작업하는 경우 몇 가지 주의 사항을 따라야 합니다:
1 - 젬의 조건부 require#
잠재적인 충돌을 방지하려면 Gitlab 상수가 정의되어 있지 않은 경우에만 gitlab 젬을 require합니다:
# Bad
require 'gitlab'
# Good
if Object.const_defined?(:RSpec)
# Ok, we're testing, we know we're going to stub `Gitlab`, so we just ignore
else
require 'gitlab'
if Gitlab.singleton_class.method_defined?(:com?)
abort 'lib/gitlab.rb is loaded, and this means we can no longer load the client and we cannot proceed'
end
end
2 - 스펙에서 gitlab 젬 전체를 모킹하기#
스펙에서 require 'gitlab'은 lib/gitlab.rb 파일을 참조합니다:
# Bad
allow(GitLab).to receive(:a_method).and_return(...)
# Good
client = double('GitLab')
# In order to easily stub the client, consider using a method to return the client.
# We can then stub the method to return our fake client, which we can further stub its methods.
#
# This is the pattern followed below
let(:instance) { described_class.new }
allow(instance).to receive(:gitlab).and_return(client)
allow(client).to receive(:a_method).and_return(...)
job을 쿼리해야 하는 경우 다음 스니펫이 유용합니다:
# Bad
allow(GitLab).to receive(:pipeline_jobs).and_return(...)
# Good
#
# rubocop:disable RSpec/VerifiedDoubles -- We do not load the Gitlab client directly
client = double('GitLab')
allow(instance).to receive(:gitlab).and_return(client)
jobs = ['job1', 'job2']
allow(client).to yield_jobs(:pipeline_jobs, jobs)
def yield_jobs(api_method, jobs)
messages = receive_message_chain(api_method, :auto_paginate)
jobs.inject(messages) do |stub, job_name|
stub.and_yield(double(name: job_name))
end
end
# rubocop:enable RSpec/VerifiedDoubles
3 - bundle exec로 스크립트를 호출하지 않기#
bundle exec로 실행하면 Ruby의 $LOAD_PATH가 변경되어 require 'gitlab' 호출 시 lib/gitlab.rb를 로드합니다:
# Bad
bundle exec scripts/my-script.rb
# Good
scripts/my-script.rb
CI 구성 테스팅#
업데이트된 YAML 파일로 파이프라인 생성을 시뮬레이션하여 CI 구성 변경 사항을 검증하는 RSpec 테스트가 있습니다. 이 테스트와 현재 테스트 커버리지 문서는 spec/dot_gitlab_ci/job_dependency_spec.rb에서 확인할 수 있습니다.
테스트 작동 방식#
Ci::CreatePipelineService의 도움으로 브랜치 이름, MR 라벨, 파이프라인 소스(스케줄 vs 푸시), 파이프라인 유형(머지 트레인 vs 머지 결과) 등 다양한 속성으로 파이프라인 생성을 시뮬레이션할 수 있습니다. 이는 CI/CD 구성 검증을 위한 GitLab CI Lint API에서도 활용하는 동일한 서비스입니다.
이 테스트는 CI 구성을 업데이트하는 머지 리퀘스트에 대해 자동으로 실행됩니다. 하지만 팀원들은 머지 리퀘스트에 ~"pipeline:skip-ci-validation" 라벨을 추가하여 이 테스트를 건너뛸 수 있습니다.
로컬에서 이 테스트를 실행하는 것을 권장하며, 가장 빠른 피드백을 제공합니다.