CI 구성 성능

가로막힘 가능한 파이프라인

기본적으로 모든 작업은 가로막힘 가능 상태이며, dont-interrupt-me 작업은 기본적으로 main에서 자동으로 실행되며, 그 이외에는 수동으로 실행됩니다.

병합 요청에 새로운 커밋을 푸시하더라도 실행 중인 파이프라인이 완료되길 원한다면, 푸시하기 전에 dont-interrupt-me 작업을 시작해야 합니다.

Git fetch 캐싱

GitLab.com은 팩 객체 캐시를 사용하므로, 동일한 파이프라인 참조의 동시 Git fetch는 Gitaly 서버(언제나)에서 중복 처리되며 캐시에서 제공됩니다(사용 가능한 경우).

다음과 같은 이유로 이 기능이 잘 작동합니다.

  • 팩 객체 캐시는 GitLab.com의 모든 Gitaly 서버에서 활성화되어 있습니다.
  • CI/CD Git 전략 설정gitlab-org/gitlab에 대해 Git clone으로 설정되어 있어 모든 작업이 동일한 데이터를 가져오게 하여 캐시 히트 비율을 극대화합니다.
  • 우리는 얕은 복제를 사용하여 모든 작업에 대해 전체 Git 기록을 다운로드하는 것을 피합니다.

Gitaly에서 클론/펫칭하는 대신 아티팩트를 통해 저장소 검색

최근 Gitaly에서 다음과 같은 에러를 발견했습니다: (문제를 보려면 이슈를 확인하세요)

fatal: remote error: GitLab is currently unable to handle this request due to load.

GitLab.com이 팩 객체 캐시를 사용하더라도, 때로는 부하가 Gitaly가 처리하기에 너무 무거워 여전히 문제가 발생하며, 천둥 벌거벗음 또한 여러 작업이 동시에 저장소를 복제하는 것이 고민입니다.

Gitaly의 부하를 완화하고 줄이기 위해 우리는 일부 작업을 한 번에 모두 Gitaly에서 클론하는 대신 작업 내에서 아티팩트에서 저장소를 검색하도록 변경했습니다.

현재 대부분의 RSpec 작업에 이를 적용하고 있는데, 이는 대부분의 파이프라인에서 가장 많은 작업이 동시에 일어나기 때문입니다. 이로 인해 약간의 개선도 이루어졌으며, 아티팩트에서 검색하는 것이 클론하는 것보다 약간 빠르기 때문에 속도도 약간 향상되었습니다. 이로 인해 각 파이프라인의 저장 공간 비용이 약 280M 정도 증가했고, 각 RSpec 작업마다 15초 정도 단축되었습니다.

이 작업은 다른 작업에 의존성이 없는 작업에는 적용하지 않습니다. 왜냐하면 어떤 작업도 시작을 지연시키기 원치 않기 때문입니다.

이러한 동작은 변수 CI_FETCH_REPO_GIT_STRATEGY에 의해 제어됩니다:

  • none으로 설정하면 .repo-from-artifacts를 사용하는 작업은 작업 clone-gitlab-repo에서 아티팩트로부터 저장소를 검색하고, 그외에는 클론합니다.
  • clone으로 설정하면 .repo-from-artifacts를 사용하는 작업은 평소처럼 저장소를 클론합니다. 이 경우 작업 clone-gitlab-repo는 실행되지 않습니다.

비활성화하려면 CI_FETCH_REPO_GIT_STRATEGYclone으로 설정하면 되고, 활성화하려면 CI_FETCH_REPO_GIT_STRATEGYnone으로 설정하면 됩니다.

캐싱 전략

  1. 기본적으로 모든 작업은 캐시를 가져와야 합니다.
  2. 모든 작업은 빈 캐시로도 통화될 수 있어야 합니다. 다시 말해, 캐시는 작업을 가속화하는 데만 사용됩니다.
  3. 현재 .gitlab/ci/global.gitlab-ci.yml에 여러 다른 캐시 정의가 정의되어 있습니다. 고정된 키로:
    • .setup-test-env-cache
    • .ruby-cache
    • .static-analysis-cache
    • .rubocop-cache
    • .ruby-gems-coverage-cache
    • .ruby-node-cache
    • .qa-cache
    • .yarn-cache
    • .assets-compile-cache (키에 ${NODE_ENV}가 포함되어 있으므로 사실상 두 개의 다른 캐시입니다).
  4. 이러한 캐시 정의는 여러 원자적 캐시로 구성되어 있습니다.
  5. 2시간 마다 실행되는 maintenance 스케줄된 파이프라인에서 실행되는 다음 작업들만 캐시에 푸시(즉, 업데이트)할 수 있습니다:
  6. 이러한 작업은 또한 pipeline:update-cache 라벨이 붙은 병합 요청에서 강제로 실행시킬 수 있습니다 (이것은 캐시 키를 업데이트하는 MR에서 캐시를 미리 로드하는 데 유용할 수 있습니다).

아티팩트 전략

작업에 의해 저장 및 검색되는 아티팩트를 최소로 제한하여 업로드/다운로드 시간과 비용, 그리고 아티팩트 저장 공간을 줄입니다.

컴포넌트 캐싱

GitLab의 일부 외부 컴포넌트(GitLab Workhorse 및 프론트엔드 에셋)는 테스트를 실행하기 전에 소스로부터 빌드해야 합니다.

cache-workhorse

이 MR에서, 그리고 이 MR에서, 우리는 새로운 cache-workhorse 작업을 도입했습니다. 이 작업은 다음과 같습니다:

  • 모든 GitLab.com gitlab-org/gitlab 예약 파이프라인에 대해 자동으로 실행됨
  • workhorse/ 폴더를 수정하는 master 커밋에 대해 자동으로 실행됨
  • 캐싱 관련 파일을 수정하는 GitLab.com의 gitlab-org MR에 대해서는 수동으로 실행됨

이 작업은 GitLab 테스트 스위트에서 필요한 GitLab Workhorse 이진 파일을 포함하는 일반 패키지를 다운로드하려고 시도합니다(tmp/tests/gitlab-workhorse 하위에 위치).

  • 패키지 URL이 404를 반환하는 경우:
    1. scripts/setup-test-env를 실행하여 GitLab Workhorse 이진 파일을 빌드함.
    2. 그런 다음, 해당 이진 파일을 포함하는 아카이브를 생성하고 일반 패키지로 업로드함.
  • 그렇지 않으면, 패키지가 이미 존재하는 경우 작업을 성공적으로 종료합니다.

또한 setup-test-env 작업을 다음과 같이 변경했습니다:

  1. cache-workhorse에 의해 빌드 및 업로드된 GitLab Workhorse 일반 패키지를 먼저 다운로드합니다.
  2. 패키지가 성공적으로 검색된 경우, 해당 내용이 올바른 폴더에 배치되어(tmp/tests/gitlab-workhorse와 같은) 나중에 scripts/setup-test-env가 실행될 때 바이너리를 빌드하는 것을 방지합니다.
  3. 패키지 URL이 404를 반환하는 경우, 현재 방식과 동일하게 행동이 변경되지 않음: scripts/setup-test-env의 일부로 GitLab Workhorse 이진 파일이 빌드됨.

참고: 패키지 버전은 workhorse 트리 SHA(예: git rev-parse HEAD:workhorse)입니다.

cache-assets

이 MR에서, 우리는 다음과 같은 세 가지 새로운 작업인 cache-assets:test, cache-assets:test as-if-foss, cache-assets:production을 도입했습니다. 이 작업들은 다음과 같습니다:

  • $CACHE_ASSETS_AS_PACKAGE == "true"가 아닌 경우에는 절대로 실행되지 않음
  • 모든 GitLab.com gitlab-org/gitlab 예약 파이프라인에 대해 자동으로 실행됨
  • 에셋 관련 폴더를 수정하는 master 커밋에 대해 자동으로 실행됨
  • 캐싱 관련 파일을 수정하는 GitLab.com의 gitlab-org MR에 대해서는 수동으로 실행됨

이 작업은 GitLab 테스트 스위트에서 필요한 GitLab 컴파일된 에셋을 포함하는 일반 패키지를 다운로드하려고 시도합니다(app/assets/javascripts/locale/**/app.jspublic/assets 하위에 위치).

  • 패키지 URL이 404를 반환하는 경우:
    1. bin/rake gitlab:assets:compile를 실행하여 GitLab 에셋을 컴파일함.
    2. 그런 다음, 해당 에셋을 포함하는 아카이브를 생성하고 일반 패키지로 업로드함. 패키지 버전은 에셋 폴더의 해시 합으로 설정됨.
  • 그렇지 않으면, 패키지가 이미 존재하는 경우 작업을 성공적으로 종료합니다.

compile-*-assets

또한 compile-test-assetscompile-production-assets 작업을 다음과 같이 변경했습니다:

  1. “네이티브” 캐시 에셋을 먼저 다운로드합니다. 해당 캐싱에는 다음이 포함됩니다:
    • 컴파일된 에셋.
    • SHA256 해시 암호화된 모든 소스 파일들의 cached-assets-hash.txt 파일을 포함합니다. 이 목록은 비관적인 목록이며 에셋이 의존하는 모든 파일에 대해 포함하지만, 에셋에 의존하지 않을 수도 있습니다. 최악의 경우 에셋을 더 자주 컴파일하지만, 오래된 에셋을 사용하는 것보다 나음입니다.

      이 파일은 에셋이 컴파일된 후 생성됨.

  2. 그런 다음, 현재 체크아웃된 브랜치에 대한 모든 소스 파일의 SHA256 해시 암호화를 계산합니다. 이 해시 암호화는 GITLAB_ASSETS_HASH 변수에 저장됩니다.
  3. $CACHE_ASSETS_AS_PACKAGE == "true"이면, cache-assets:*에 의해 빌드 및 업로드된 일반 패키지를 다운로드합니다.
    • 체크아웃된 브랜치에 대한 캐시가 최신 상태인 경우, 네이티브 캐시 캐시 패키지를 다운로드합니다. 캐시 패키지 대신 네이티브 캐시를 다운로드하는 것이 최적화될 수 있지만, 네이티브 캐시는 실제로 매우 자주 오래됩니다. 왜냐하면 2시간마다 재빌드되기 때문입니다.
  4. assets_compile_script 함수를 실행합니다, 이 함수 자체가 실행됩니다 assets:compile 라케 태스크를 실행합니다.

    이 작업은 에셋을 컴파일할 지 여부를 결정합니다. 그리고 $GITLAB_ASSETS_HASH로부터 HEAD SHA256 해시를 비교합니다.

  5. 해시가 동일하면 아무것도 컴파일하지 않습니다. 다른 경우, 에셋을 컴파일합니다.

스트립트된 이진 파일

기본적으로 setup-test-env는 후속 CI 작업의 아티팩트 다운로드를 절약하고 가속화하기 위해 스트립트된 이진 파일을 포함하는 아티팩트를 생성합니다.

스트립트된 이진 파일에서의 크래시를 디버깅하기 쉽게 만들기 위해 setup-test-job 작업의 strip_executable_binaries 줄을 주석 처리하고 새로운 파이프라인을 시작하세요.