CI 설정 성능
GitLab v19.4요약
기본적으로 모든 job은 인터럽트 가능합니다. 머지 리퀘스트에 새 커밋을 푸시하더라도 실행 중인 파이프라인을 끝까지 완료하고 싶다면, 푸시하기 전에 dont-interrupt-me job을 먼저 시작합니다. GitLab.com은 pack-objects 캐시를 사용하므로, 같은 파이프라인 ref에 대한 동시 Git fetch는 Gitaly 서버에서 항상 중복 제거되며 캐시가 있으면 캐시에서 제공됩니다.
인터럽트 가능 파이프라인#
기본적으로 모든 job은 인터럽트 가능합니다. 다만
dont-interrupt-me job은 예외로, main에서는 자동으로 실행되고 그 외에는
manual로 동작합니다.
머지 리퀘스트에 새 커밋을 푸시하더라도 실행 중인 파이프라인을 끝까지 완료하고 싶다면,
푸시하기 전에 dont-interrupt-me job을 먼저 시작합니다.
Git fetch 캐싱#
GitLab.com은 pack-objects 캐시를 사용하므로, 같은 파이프라인 ref에 대한 동시 Git fetch는 Gitaly 서버에서 항상 중복 제거되며 캐시가 있으면 캐시에서 제공됩니다.
이 방식이 잘 동작하는 이유는 다음과 같습니다.
- GitLab.com의 모든 Gitaly 서버에서 pack-objects 캐시가 활성화되어 있습니다.
gitlab-org/gitlab의 CI/CD Git 전략 설정이 Git clone 이어서 모든 job이 같은 데이터를 fetch 하므로 캐시 적중률이 최대가 됩니다.- job마다 전체 Git 히스토리를 내려받지 않도록 shallow clone을 사용합니다.
Gitaly에서 클론하거나 fetch 하는 대신 아티팩트로 리포지터리 가져오기#
최근 Gitaly에서 다음과 같은 오류가 나타납니다(해당 이슈 참고).
fatal: remote error: GitLab is currently unable to handle this request due to load.
GitLab.com 이 pack-objects 캐시를 사용하더라도 Gitaly가 감당하기에 부하가 여전히 큰 경우가 있고, 비슷한 시각에 리포지터리를 클론하는 job이 많기 때문에 thundering herd 문제도 우려됩니다.
Gitaly의 부하를 줄이기 위해, 일부 job은 모두 한꺼번에 Gitaly에서 클론하는 대신 한 job의 아티팩트에서 리포지터리를 가져오도록 변경했습니다.
현재는 대부분의 파이프라인에서 동시 실행 job이 가장 많은 RSpec job에 주로 적용됩니다. 아티팩트에서 가져오는 편이 클론보다 조금 더 빠르므로 속도도 약간 개선되었지만, 파이프라인마다 저장하는 아티팩트가 늘어나는 비용이 따릅니다.
Fetch repo from artifacts for RSpec jobs의 2023-12-20 기준 수치로 보면, 추가 스토리지 비용은 파이프라인당 약 280M 이고, RSpec job마다 15초를 절약합니다.
다른 job에 의존하지 않는 job은 시작이 지연되지 않도록 이 방식을 적용하지 않습니다.
이 동작은 CI_FETCH_REPO_GIT_STRATEGY 변수로 제어할 수 있습니다.
none으로 설정하면.repo-from-artifacts를 사용하는 job이 클론 대신clone-gitlab-repojob의 아티팩트에서 리포지터리를 가져옵니다.clone으로 설정하면.repo-from-artifacts를 사용하는 job이 평소처럼 리포지터리를 클론합니다. 이때clone-gitlab-repojob은 실행되지 않습니다.
비활성화하려면 CI_FETCH_REPO_GIT_STRATEGY를 clone으로 설정하고, 활성화하려면
none으로 설정합니다.
캐싱 전략#
GitLab CI/CD 파이프라인의 캐시는 다음 기준을 따라야 합니다.
- pull-push 구성과 pull 전용 구성: 파이프라인 시작 시점에 실행되는
syncStage에서 캐시를 채우는 job은 pull-push 구성을 사용하고, 캐시를 소비하는 job은 브랜치에 종속되지 않고 특정 브랜치 파이프라인 실행분의 캐시를 채우도록 pull 전용 구성을 사용합니다. - 파일별 체크섬: 모든 캐시 키는 해당 파일의 체크섬과 연결해, 의존성이 바뀌면 캐시가 올바르게 무효화되도록 합니다.
- 언어 버전 연계: 캐시 키에는 해당하는 경우 언어별 버전을 포함해, 언어 버전을 올릴 때 캐시가 적절히 무효화되도록 합니다.
- sync Stage 배치: 캐시 갱신 job은 파이프라인 맨 앞에서 실행되도록
syncStage에 정의합니다. - 재사용 가능한 정의: 재사용 가능한 캐시 키 정의는 프로젝트 전체에서 일관성을 유지하도록
.gitlab/ci/global.gitlab-ci.yml파일에 둡니다.
pull-push 기본값의 예외#
일부 캐시는 기본 브랜치에서만 푸시되고 기본 브랜치가 아닌 파이프라인에서는 풀만 이루어집니다. 이러한 캐시는 기본 브랜치가 아닌 파이프라인에서 올바르게 풀되도록 unprotect: true를 사용해야 합니다.
복잡한 체크섬 계산#
캐시 키에 여러 파일에 걸친 복잡한 체크섬 계산이 필요하다면, sync Stage에 별도 job을 추가해 캐시 체크섬을 계산하고 dotenv 유형 리포트 아티팩트로 저장하여 환경 변수로 제공합니다. 이렇게 하면 이후의 모든 job이 미리 계산된 체크섬을 사용해 파이프라인 전체에서 일관된 캐시 키를 생성할 수 있습니다.
아티팩트 전략#
업로드·다운로드 시간과 비용, 아티팩트 스토리지를 줄이기 위해 job이 저장하고 가져오는 아티팩트를 최소한으로 제한합니다.
스트립된 바이너리#
기본적으로 setup-test-env는 스트립된 바이너리를 담은 아티팩트를 생성하여 이후 CI job의
스토리지를 절약하고 아티팩트 다운로드 속도를 높입니다.
스트립된 바이너리의 크래시를 더 쉽게 디버깅하려면 scripts/gitlab_component_helpers.sh 셸 스크립트의
setup_test_env 함수에서 strip_executable_binaries 줄을 주석 처리하고 새 파이프라인을 시작합니다.
머지 리퀘스트 제목으로 파이프라인 건너뛰기#
머지 결과 파이프라인을 사용할 때는
머지 리퀘스트 제목에 [ci skip] 또는 [skip ci]를 추가해 파이프라인을 건너뛸 수 있습니다.
머지 결과 파이프라인이 커밋 메시지에 머지 리퀘스트 제목을 포함하는 가상 커밋을 만들기 때문에
건너뛰기 플래그가 감지됩니다.
이는 문서화되지 않은 부수 효과이며 머지 결과 파이프라인이 활성화된 경우에만 동작합니다. 기본 머지 리퀘스트 파이프라인이나 머지 충돌이 있는 경우에는 동작하지 않습니다. 이 방법은 주로 GitLab.com 내부에서 파이프라인 부하를 줄이는 데 사용합니다.
파이프라인을 건너뛰는 방법은 다음과 같습니다.
- 머지 리퀘스트 제목에
[ci skip]또는[skip ci]를 추가합니다. 제목에서 이 플래그를 지울 때까지 파이프라인이 건너뛰어집니다. - 커밋 메시지에
[ci skip]또는[skip ci]를 추가합니다. 해당 커밋의 파이프라인만 건너뜁니다.