InfoGrab Docs

GitLab CI/CD 캐싱

요약

캐시는 Job이 다운로드하고 저장하는 하나 이상의 파일입니다. .gitlab-ci.yml 파일에서 캐시를 정의하는 방법은 cache 참조를 참조하세요. 고급 캐시 키 전략을 위해 다음을 사용할 수 있습니다: 더 많은 사용 사례 및 예시는 CI/CD 캐싱 예시를 참조하세요.

캐시는 Job이 다운로드하고 저장하는 하나 이상의 파일입니다. 동일한 캐시를 사용하는 후속 Job은 파일을 다시 다운로드할 필요가 없으므로 더 빠르게 실행됩니다.

.gitlab-ci.yml 파일에서 캐시를 정의하는 방법은 cache 참조를 참조하세요.

고급 캐시 키 전략을 위해 다음을 사용할 수 있습니다:

더 많은 사용 사례 및 예시는 CI/CD 캐싱 예시를 참조하세요.

캐시와 아티팩트의 차이점#

인터넷에서 다운로드하는 패키지와 같은 종속성에 캐시를 사용합니다. 캐시는 GitLab Runner가 설치된 곳에 저장되고 분산 캐시가 활성화된 경우 S3에 업로드됩니다.

Stage 간에 중간 빌드 결과를 전달하는 데 아티팩트를 사용합니다. 아티팩트는 Job에 의해 생성되고 GitLab에 저장되며 다운로드할 수 있습니다.

아티팩트와 캐시 모두 프로젝트 디렉토리를 기준으로 경로를 정의하며 그 외부의 파일에 링크할 수 없습니다.

캐시#

  • cache 키워드를 사용하여 Job별로 캐시를 정의합니다. 그렇지 않으면 비활성화됩니다.
  • 후속 파이프라인이 캐시를 사용할 수 있습니다.
  • 종속성이 동일한 경우 동일한 파이프라인의 후속 Job이 캐시를 사용할 수 있습니다.
  • 서로 다른 프로젝트는 캐시를 공유할 수 없습니다.
  • 기본적으로 보호된 브랜치와 보호되지 않은 브랜치는 캐시를 공유하지 않습니다. 하지만 이 동작을 변경할 수 있습니다.

아티팩트#

  • Job별로 아티팩트를 정의합니다.
  • 동일한 파이프라인의 이후 Stage에 있는 후속 Job이 아티팩트를 사용할 수 있습니다.
  • 아티팩트는 기본적으로 30일 후에 만료됩니다. 사용자 정의 만료 시간을 정의할 수 있습니다.
  • 최신 아티팩트 유지가 활성화된 경우 최신 아티팩트는 만료되지 않습니다.
  • dependencies를 사용하여 어떤 Job이 아티팩트를 가져오는지 제어합니다.

좋은 캐싱 관행#

캐시의 최대 가용성을 보장하려면 다음 중 하나 이상을 수행합니다:

러너가 캐시를 효율적으로 사용하려면 다음 중 하나를 수행해야 합니다:

  • 모든 Job에 단일 러너를 사용합니다.
  • 캐시가 S3 버킷에 저장되는 분산 캐싱이 있는 여러 러너를 사용합니다. GitLab.com의 인스턴스 러너는 이 방식으로 동작합니다. 이러한 러너는 자동 확장 모드에 있을 수 있지만 반드시 그럴 필요는 없습니다. 캐시 객체를 관리하려면 일정 기간 후 캐시 객체를 삭제하는 수명 주기 규칙을 적용합니다. 수명 주기 규칙은 객체 스토리지 서버에서 사용할 수 있습니다.
  • 동일한 아키텍처의 여러 러너를 사용하고 이 러너들이 캐시를 저장하기 위해 공통 네트워크 마운트 디렉토리를 공유합니다. 이 디렉토리는 NFS 또는 유사한 것을 사용해야 합니다. 이러한 러너는 자동 확장 모드여야 합니다.

여러 캐시 사용#

Job별로 최대 4개의 캐시를 가질 수 있습니다:

test-job:
  stage: build
  cache:
    - key:
        files:
          - Gemfile.lock
      paths:
        - vendor/ruby
    - key:
        files:
          - yarn.lock
      paths:
        - .yarn-cache/
  script:
    - bundle config set --local path 'vendor/ruby'
    - bundle install
    - yarn install --cache-folder .yarn-cache
    - echo Run tests...

여러 캐시가 폴백 캐시 키와 결합되면 캐시를 찾지 못할 때마다 전역 폴백 캐시가 가져와집니다.

폴백 캐시 키 사용#

캐시별 폴백 키#

히스토리

각 캐시 항목은 fallback_keys 키워드를 사용하여 최대 5개의 폴백 키를 지원합니다. Job이 캐시 키를 찾지 못하면 Job은 대신 폴백 캐시를 가져오려고 합니다. 폴백 키는 캐시가 발견될 때까지 순서대로 검색됩니다. 캐시가 없으면 Job은 캐시를 사용하지 않고 실행됩니다. 예를 들면:

test-job:
  stage: build
  cache:
    - key: cache-$CI_COMMIT_REF_SLUG
      fallback_keys:
        - cache-$CI_DEFAULT_BRANCH
        - cache-default
      paths:
        - vendor/ruby
  script:
    - bundle config set --local path 'vendor/ruby'
    - bundle install
    - echo Run tests...

이 예시에서:

  1. Job은 cache-$CI_COMMIT_REF_SLUG 캐시를 찾습니다.
  2. cache-$CI_COMMIT_REF_SLUG가 없으면 Job은 폴백 옵션으로 cache-$CI_DEFAULT_BRANCH를 찾습니다.
  3. cache-$CI_DEFAULT_BRANCH도 없으면 Job은 두 번째 폴백 옵션으로 cache-default를 찾습니다.
  4. 아무것도 없으면 Job은 캐시를 사용하지 않고 모든 Ruby 종속성을 다운로드하지만 Job이 완료되면 cache-$CI_COMMIT_REF_SLUG에 대한 새 캐시를 만듭니다.

폴백 키는 cache:key와 동일한 처리 로직을 따릅니다:

전역 폴백 키#

$CI_COMMIT_REF_SLUG 사전 정의된 변수를 사용하여 cache:key를 지정할 수 있습니다. 예를 들어 $CI_COMMIT_REF_SLUGtest이면 test로 태그된 캐시를 다운로드하도록 Job을 설정할 수 있습니다.

이 태그의 캐시가 없는 경우 CACHE_FALLBACK_KEY를 사용하여 캐시가 없을 때 사용할 캐시를 지정할 수 있습니다.

다음 예시에서 $CI_COMMIT_REF_SLUG를 찾지 못하면 Job은 CACHE_FALLBACK_KEY 변수로 정의된 키를 사용합니다:

variables:
  CACHE_FALLBACK_KEY: fallback-key

job1:
  script:
    - echo
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
      - binaries/

캐시 추출 순서는 다음과 같습니다:

  1. cache:key 검색 시도
  2. fallback_keys의 각 항목에 대한 검색 시도 순서
  3. CACHE_FALLBACK_KEY의 전역 폴백 키 검색 시도

캐시 추출 프로세스는 첫 번째로 성공적인 캐시를 가져온 후 중단됩니다.

특정 Job에 대한 캐시 비활성화#

캐시를 전역으로 정의하면 각 Job이 동일한 정의를 사용합니다. 각 Job별로 이 동작을 재정의할 수 있습니다.

Job에 대해 완전히 비활성화하려면 빈 목록을 사용합니다:

job:
  cache: []

전역 구성 상속, 하지만 Job별로 특정 설정 재정의#

앵커를 사용하여 전역 캐시를 덮어쓰지 않고 캐시 설정을 재정의할 수 있습니다. 예를 들어, 한 Job에 대한 policy를 재정의하려면:

default:
  cache: &global_cache
    key: $CI_COMMIT_REF_SLUG
    paths:
      - node_modules/
      - public/
      - vendor/
    policy: pull-push

job:
  cache:
    # inherit all global cache settings
    <<: *global_cache
    # override the policy
    policy: pull

자세한 내용은 cache: policy를 참조하세요.

캐시 키 이름#

히스토리
  • GitLab 15.0에서 도입됨.
  • Maintainer 권한 이상에 대한 -protected 접미사가 GitLab 18.4.5에서 도입됨.

전역 폴백 캐시 키를 제외하고 캐시 키에 접미사가 추가됩니다.

파이프라인이 다음 경우에 캐시 키는 -protected 접미사를 받습니다:

  • 보호된 브랜치나 태그에 대해 실행됩니다. 사용자는 보호된 브랜치에 머지하거나 보호된 태그를 만들 수 있는 권한이 있어야 합니다.
  • Maintainer 또는 Owner 권한을 가진 사용자가 시작했습니다.

다른 파이프라인에서 생성된 키는 non_protected 접미사를 받습니다.

예를 들어:

  • cache:key$CI_COMMIT_REF_SLUG로 설정된 경우.
  • main이 보호된 브랜치인 경우.
  • feature가 보호되지 않은 브랜치인 경우.
브랜치 Developer 권한 캐시 키 Maintainer 권한 캐시 키
main main-protected main-protected
feature feature-non_protected feature-protected

또한 태그에 대한 파이프라인의 경우 파이프라인이 실행되는 브랜치가 아닌 태그의 보호 상태가 접미사에 우선합니다. 이 동작은 트리거하는 참조가 캐시 액세스 권한을 결정하기 때문에 일관된 보안 경계를 보장합니다.

예를 들어:

  • cache:key$CI_COMMIT_TAG로 설정된 경우.
  • main이 보호된 브랜치인 경우.
  • feature가 보호되지 않은 브랜치인 경우.
  • 1.0.0이 보호된 태그인 경우.
  • 1.1.1-rc1이 보호되지 않은 태그인 경우.
태그 브랜치 Developer 권한 캐시 키 Maintainer 권한 캐시 키
1.0.0 main 1.0.0-protected 1.0.0-protected
1.0.0 feature 1.0.0-protected 1.0.0-protected
1.1.1-rc1 main 1.1.1-rc1-non_protected 1.1.1-rc1-protected
1.1.1-rc1 feature 1.1.1-rc1-non_protected 1.1.1-rc1-protected

모든 브랜치에 동일한 캐시 사용#

히스토리

캐시 키 이름을 사용하지 않으려면 모든 브랜치(보호됨 및 보호되지 않음)가 동일한 캐시를 사용하도록 설정할 수 있습니다.

캐시 키 이름을 사용한 캐시 분리는 보안 기능으로, Developer 권한을 가진 모든 사용자가 매우 신뢰받는 환경에서만 비활성화해야 합니다.

모든 브랜치에 동일한 캐시를 사용하려면:

  1. 상단 바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. 왼쪽 사이드바에서 Settings > CI/CD를 선택합니다.
  3. General pipelines를 확장합니다.
  4. Use separate caches for protected branches 체크박스를 지웁니다.
  5. Save changes를 선택합니다.

캐시 가용성#

캐싱은 최적화이지만 항상 작동한다는 보장이 없습니다. 각 Job에서 캐시된 파일을 재생성해야 할 수도 있습니다.

.gitlab-ci.yml에서 캐시를 정의한 후 캐시 가용성은 다음에 따라 달라집니다:

  • 러너의 실행기 유형.
  • Job 간에 캐시를 전달하는 데 서로 다른 러너가 사용되는지 여부.

캐시가 저장되는 위치#

Job에 대해 정의된 모든 캐시는 단일 cache.zip 파일에 아카이브됩니다. 러너 구성은 파일이 저장되는 위치를 정의합니다. 기본적으로 캐시는 GitLab Runner가 설치된 머신에 저장됩니다. 위치는 또한 실행기 유형에 따라 달라집니다.

러너 실행기 캐시 기본 경로
Shell 로컬, gitlab-runner 사용자의 홈 디렉토리 아래: /home/gitlab-runner/cache/<user>/<project>/<cache-key>/cache.zip.
Docker 로컬, Docker 볼륨 아래: /var/lib/docker/volumes/<volume-id>/_data/<user>/<project>/<cache-key>/cache.zip.
Docker Machine (자동 확장 러너) Docker 실행기와 동일.

Job에서 동일한 경로를 저장하는 데 캐시와 아티팩트를 모두 사용하면, 아티팩트 전에 캐시가 복원되기 때문에 캐시가 덮어쓰여질 수 있습니다.

아카이빙 및 추출 작동 방식#

이 예시는 두 개의 연속 Stage의 두 Job을 보여줍니다:

stages:
  - build
  - test

default:
  cache:
    key: build-cache
    paths:
      - vendor/
  before_script:
    - echo "Hello"

job A:
  stage: build
  script:
    - mkdir vendor/
    - echo "build" > vendor/hello.txt
  after_script:
    - echo "World"

job B:
  stage: test
  script:
    - cat vendor/hello.txt

머신에 러너 하나가 설치된 경우, 프로젝트의 모든 Job이 동일한 호스트에서 실행됩니다:

  1. 파이프라인이 시작됩니다.
  2. job A가 실행됩니다.
  3. 캐시가 추출됩니다(있는 경우).
  4. before_script가 실행됩니다.
  5. script가 실행됩니다.
  6. after_script가 실행됩니다.
  7. cache가 실행되고 vendor/ 디렉토리가 cache.zip으로 압축됩니다. 이 파일은 러너의 설정cache: key를 기반으로 디렉토리에 저장됩니다.
  8. job B가 실행됩니다.
  9. 캐시가 추출됩니다(있는 경우).
  10. before_script가 실행됩니다.
  11. script가 실행됩니다.
  12. 파이프라인이 완료됩니다.

단일 머신에서 단일 러너를 사용하면 job Bjob A와 다른 러너에서 실행될 수 있는 문제가 발생하지 않습니다. 이 설정은 Stage 간에 캐시를 재사용할 수 있도록 보장합니다. 동일한 러너/머신에서 build Stage에서 test Stage로 실행이 진행될 때만 작동합니다. 그렇지 않으면 캐시를 사용할 수 없을 수도 있습니다.

캐싱 프로세스 중 몇 가지 고려해야 할 사항이 있습니다:

  • 다른 캐시 구성의 다른 Job이 동일한 zip 파일에 캐시를 저장한 경우 덮어쓰여집니다. S3 기반 공유 캐시가 사용되는 경우 파일은 추가로 캐시 키를 기반으로 한 객체에 S3에 업로드됩니다. 따라서 서로 다른 경로를 가지지만 동일한 캐시 키를 가진 두 Job은 캐시를 덮어씁니다.
  • cache.zip에서 캐시를 추출할 때 zip 파일의 모든 것이 Job의 작업 디렉토리(보통 다운로드된 리포지터리)에 추출되며, 러너는 job A의 아카이브가 job B의 아카이브에 있는 것을 덮어쓰는 것을 신경 쓰지 않습니다.

이렇게 작동하는 이유는 한 러너를 위해 만들어진 캐시가 다른 러너에서 사용될 때 종종 유효하지 않기 때문입니다. 다른 러너는 다른 아키텍처에서 실행될 수 있습니다(예: 캐시에 바이너리 파일이 포함된 경우). 또한 다른 단계가 다른 머신에서 실행되는 러너에 의해 실행될 수 있기 때문에 이것이 안전한 기본값입니다.

캐시 지우기#

러너는 캐시를 사용하여 기존 데이터를 재사용함으로써 Job 실행을 빠르게 합니다. 이는 때때로 일관성 없는 동작으로 이어질 수 있습니다.

새 캐시 복사본으로 시작하는 두 가지 방법이 있습니다.

cache:key를 변경하여 캐시 지우기#

.gitlab-ci.yml 파일에서 cache: key 값을 변경합니다. 다음 파이프라인이 실행될 때 캐시는 다른 위치에 저장됩니다.

캐시 수동으로 지우기#

GitLab UI에서 캐시를 지울 수 있습니다:

  1. 상단 바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. 왼쪽 사이드바에서 Build > Pipelines를 선택합니다.
  3. 오른쪽 상단 모서리에서 Clear runner caches를 선택합니다.

다음 커밋에서 CI/CD Job은 새 캐시를 사용합니다.

Note

캐시를 수동으로 지울 때마다 내부 캐시 이름이 업데이트됩니다. 이름은 cache-<index> 형식을 사용하며 인덱스는 하나씩 증가합니다. 이전 캐시는 삭제되지 않습니다. 러너 스토리지에서 이 파일을 수동으로 삭제할 수 있습니다.

문제 해결#

캐시 불일치#

캐시 불일치가 있는 경우 다음 단계에 따라 문제를 해결합니다.

캐시 불일치 이유 해결 방법
공유 캐시 없이 프로젝트에 연결된 여러 독립 실행형 러너(자동 확장 모드 아님)를 사용합니다. 프로젝트에 러너 하나만 사용하거나 분산 캐시가 활성화된 여러 러너를 사용합니다.
분산 캐시가 활성화되지 않은 자동 확장 모드의 러너를 사용합니다. 분산 캐시를 사용하도록 자동 확장 러너를 구성합니다.
러너가 설치된 머신의 디스크 공간이 부족하거나, 분산 캐시를 설정한 경우 캐시가 저장된 S3 버킷의 공간이 충분하지 않습니다. 새 캐시를 저장할 수 있도록 공간을 지웁니다. 이를 자동으로 수행할 방법은 없습니다.
서로 다른 경로를 캐시하는 Job에 동일한 key를 사용합니다. 캐시 아카이브가 다른 위치에 저장되고 잘못된 캐시를 덮어쓰지 않도록 서로 다른 캐시 키를 사용합니다.
러너에서 분산 러너 캐싱을 활성화하지 않았습니다. Shared = false를 설정하고 러너를 다시 프로비저닝합니다.

캐시 불일치 예시 1#

프로젝트에 러너 하나만 할당된 경우, 캐시는 기본적으로 러너의 머신에 저장됩니다.

두 Job이 동일한 캐시 키를 가지지만 경로가 다른 경우 캐시가 덮어쓰여질 수 있습니다. 예를 들면:

stages:
  - build
  - test

job A:
  stage: build
  script: make build
  cache:
    key: same-key
    paths:
      - public/

job B:
  stage: test
  script: make test
  cache:
    key: same-key
    paths:
      - vendor/
  1. job A가 실행됩니다.
  2. public/cache.zip으로 캐시됩니다.
  3. job B가 실행됩니다.
  4. 이전 캐시가 있으면 압축이 해제됩니다.
  5. vendor/cache.zip으로 캐시되고 이전 것을 덮어씁니다.
  6. 다음에 job A가 실행되면 다르고 따라서 효과적이지 않은 job B의 캐시를 사용합니다.

이 문제를 해결하려면 각 Job에 다른 key를 사용합니다.

캐시 불일치 예시 2#

이 예시에서는 프로젝트에 두 개 이상의 러너가 할당되어 있고 분산 캐시가 활성화되지 않은 경우입니다.

두 번째 파이프라인이 실행될 때 job Ajob B가 캐시를 재사용하길 원합니다(이 경우 서로 다름):

stages:
  - build
  - test

job A:
  stage: build
  script: build
  cache:
    key: keyA
    paths:
      - vendor/

job B:
  stage: test
  script: test
  cache:
    key: keyB
    paths:
      - vendor/

key가 다르더라도, 후속 파이프라인에서 Job이 서로 다른 러너에서 실행되는 경우 각 Stage 이전에 캐시된 파일이 "정리"될 수 있습니다.

동시 러너의 로컬 캐시 누락#

Docker 실행기로 여러 동시 러너를 구성한 경우, 동시에 실행 중인 Job에서 예상한 대로 로컬에 캐시된 파일이 없을 수 있습니다. 캐시 볼륨의 이름은 각 러너 인스턴스에 대해 고유하게 구성되므로, 한 러너 인스턴스가 캐시한 파일은 다른 러너 인스턴스의 캐시에서 찾을 수 없습니다.

동시 러너 간에 캐시를 공유하려면 다음 중 하나를 수행할 수 있습니다:

  • 러너의 config.toml[runners.docker] 섹션을 사용하여 각 컨테이너에서 /cache에 매핑된 호스트의 단일 마운트 포인트를 구성합니다. 예: volumes = ["/mnt/gitlab-runner/cache-for-all-concurrent-jobs:/cache"]. 이 접근 방식은 러너가 동시 Job에 대해 고유한 볼륨 이름을 만드는 것을 방지합니다.
  • 분산 캐시를 사용합니다.

GitLab CI/CD 캐싱

Tier: Free, Premium, Ultimate
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
원문 보기
요약

캐시는 Job이 다운로드하고 저장하는 하나 이상의 파일입니다. .gitlab-ci.yml 파일에서 캐시를 정의하는 방법은 cache 참조를 참조하세요. 고급 캐시 키 전략을 위해 다음을 사용할 수 있습니다: 더 많은 사용 사례 및 예시는 CI/CD 캐싱 예시를 참조하세요.

캐시는 Job이 다운로드하고 저장하는 하나 이상의 파일입니다. 동일한 캐시를 사용하는 후속 Job은 파일을 다시 다운로드할 필요가 없으므로 더 빠르게 실행됩니다.

.gitlab-ci.yml 파일에서 캐시를 정의하는 방법은 cache 참조를 참조하세요.

고급 캐시 키 전략을 위해 다음을 사용할 수 있습니다:

더 많은 사용 사례 및 예시는 CI/CD 캐싱 예시를 참조하세요.

캐시와 아티팩트의 차이점#

인터넷에서 다운로드하는 패키지와 같은 종속성에 캐시를 사용합니다. 캐시는 GitLab Runner가 설치된 곳에 저장되고 분산 캐시가 활성화된 경우 S3에 업로드됩니다.

Stage 간에 중간 빌드 결과를 전달하는 데 아티팩트를 사용합니다. 아티팩트는 Job에 의해 생성되고 GitLab에 저장되며 다운로드할 수 있습니다.

아티팩트와 캐시 모두 프로젝트 디렉토리를 기준으로 경로를 정의하며 그 외부의 파일에 링크할 수 없습니다.

캐시#

  • cache 키워드를 사용하여 Job별로 캐시를 정의합니다. 그렇지 않으면 비활성화됩니다.
  • 후속 파이프라인이 캐시를 사용할 수 있습니다.
  • 종속성이 동일한 경우 동일한 파이프라인의 후속 Job이 캐시를 사용할 수 있습니다.
  • 서로 다른 프로젝트는 캐시를 공유할 수 없습니다.
  • 기본적으로 보호된 브랜치와 보호되지 않은 브랜치는 캐시를 공유하지 않습니다. 하지만 이 동작을 변경할 수 있습니다.

아티팩트#

  • Job별로 아티팩트를 정의합니다.
  • 동일한 파이프라인의 이후 Stage에 있는 후속 Job이 아티팩트를 사용할 수 있습니다.
  • 아티팩트는 기본적으로 30일 후에 만료됩니다. 사용자 정의 만료 시간을 정의할 수 있습니다.
  • 최신 아티팩트 유지가 활성화된 경우 최신 아티팩트는 만료되지 않습니다.
  • dependencies를 사용하여 어떤 Job이 아티팩트를 가져오는지 제어합니다.

좋은 캐싱 관행#

캐시의 최대 가용성을 보장하려면 다음 중 하나 이상을 수행합니다:

러너가 캐시를 효율적으로 사용하려면 다음 중 하나를 수행해야 합니다:

  • 모든 Job에 단일 러너를 사용합니다.
  • 캐시가 S3 버킷에 저장되는 분산 캐싱이 있는 여러 러너를 사용합니다. GitLab.com의 인스턴스 러너는 이 방식으로 동작합니다. 이러한 러너는 자동 확장 모드에 있을 수 있지만 반드시 그럴 필요는 없습니다. 캐시 객체를 관리하려면 일정 기간 후 캐시 객체를 삭제하는 수명 주기 규칙을 적용합니다. 수명 주기 규칙은 객체 스토리지 서버에서 사용할 수 있습니다.
  • 동일한 아키텍처의 여러 러너를 사용하고 이 러너들이 캐시를 저장하기 위해 공통 네트워크 마운트 디렉토리를 공유합니다. 이 디렉토리는 NFS 또는 유사한 것을 사용해야 합니다. 이러한 러너는 자동 확장 모드여야 합니다.

여러 캐시 사용#

Job별로 최대 4개의 캐시를 가질 수 있습니다:

test-job:
  stage: build
  cache:
    - key:
        files:
          - Gemfile.lock
      paths:
        - vendor/ruby
    - key:
        files:
          - yarn.lock
      paths:
        - .yarn-cache/
  script:
    - bundle config set --local path 'vendor/ruby'
    - bundle install
    - yarn install --cache-folder .yarn-cache
    - echo Run tests...

여러 캐시가 폴백 캐시 키와 결합되면 캐시를 찾지 못할 때마다 전역 폴백 캐시가 가져와집니다.

폴백 캐시 키 사용#

캐시별 폴백 키#

히스토리

각 캐시 항목은 fallback_keys 키워드를 사용하여 최대 5개의 폴백 키를 지원합니다. Job이 캐시 키를 찾지 못하면 Job은 대신 폴백 캐시를 가져오려고 합니다. 폴백 키는 캐시가 발견될 때까지 순서대로 검색됩니다. 캐시가 없으면 Job은 캐시를 사용하지 않고 실행됩니다. 예를 들면:

test-job:
  stage: build
  cache:
    - key: cache-$CI_COMMIT_REF_SLUG
      fallback_keys:
        - cache-$CI_DEFAULT_BRANCH
        - cache-default
      paths:
        - vendor/ruby
  script:
    - bundle config set --local path 'vendor/ruby'
    - bundle install
    - echo Run tests...

이 예시에서:

  1. Job은 cache-$CI_COMMIT_REF_SLUG 캐시를 찾습니다.
  2. cache-$CI_COMMIT_REF_SLUG가 없으면 Job은 폴백 옵션으로 cache-$CI_DEFAULT_BRANCH를 찾습니다.
  3. cache-$CI_DEFAULT_BRANCH도 없으면 Job은 두 번째 폴백 옵션으로 cache-default를 찾습니다.
  4. 아무것도 없으면 Job은 캐시를 사용하지 않고 모든 Ruby 종속성을 다운로드하지만 Job이 완료되면 cache-$CI_COMMIT_REF_SLUG에 대한 새 캐시를 만듭니다.

폴백 키는 cache:key와 동일한 처리 로직을 따릅니다:

전역 폴백 키#

$CI_COMMIT_REF_SLUG 사전 정의된 변수를 사용하여 cache:key를 지정할 수 있습니다. 예를 들어 $CI_COMMIT_REF_SLUGtest이면 test로 태그된 캐시를 다운로드하도록 Job을 설정할 수 있습니다.

이 태그의 캐시가 없는 경우 CACHE_FALLBACK_KEY를 사용하여 캐시가 없을 때 사용할 캐시를 지정할 수 있습니다.

다음 예시에서 $CI_COMMIT_REF_SLUG를 찾지 못하면 Job은 CACHE_FALLBACK_KEY 변수로 정의된 키를 사용합니다:

variables:
  CACHE_FALLBACK_KEY: fallback-key

job1:
  script:
    - echo
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
      - binaries/

캐시 추출 순서는 다음과 같습니다:

  1. cache:key 검색 시도
  2. fallback_keys의 각 항목에 대한 검색 시도 순서
  3. CACHE_FALLBACK_KEY의 전역 폴백 키 검색 시도

캐시 추출 프로세스는 첫 번째로 성공적인 캐시를 가져온 후 중단됩니다.

특정 Job에 대한 캐시 비활성화#

캐시를 전역으로 정의하면 각 Job이 동일한 정의를 사용합니다. 각 Job별로 이 동작을 재정의할 수 있습니다.

Job에 대해 완전히 비활성화하려면 빈 목록을 사용합니다:

job:
  cache: []

전역 구성 상속, 하지만 Job별로 특정 설정 재정의#

앵커를 사용하여 전역 캐시를 덮어쓰지 않고 캐시 설정을 재정의할 수 있습니다. 예를 들어, 한 Job에 대한 policy를 재정의하려면:

default:
  cache: &global_cache
    key: $CI_COMMIT_REF_SLUG
    paths:
      - node_modules/
      - public/
      - vendor/
    policy: pull-push

job:
  cache:
    # inherit all global cache settings
    <<: *global_cache
    # override the policy
    policy: pull

자세한 내용은 cache: policy를 참조하세요.

캐시 키 이름#

히스토리
  • GitLab 15.0에서 도입됨.
  • Maintainer 권한 이상에 대한 -protected 접미사가 GitLab 18.4.5에서 도입됨.

전역 폴백 캐시 키를 제외하고 캐시 키에 접미사가 추가됩니다.

파이프라인이 다음 경우에 캐시 키는 -protected 접미사를 받습니다:

  • 보호된 브랜치나 태그에 대해 실행됩니다. 사용자는 보호된 브랜치에 머지하거나 보호된 태그를 만들 수 있는 권한이 있어야 합니다.
  • Maintainer 또는 Owner 권한을 가진 사용자가 시작했습니다.

다른 파이프라인에서 생성된 키는 non_protected 접미사를 받습니다.

예를 들어:

  • cache:key$CI_COMMIT_REF_SLUG로 설정된 경우.
  • main이 보호된 브랜치인 경우.
  • feature가 보호되지 않은 브랜치인 경우.
브랜치 Developer 권한 캐시 키 Maintainer 권한 캐시 키
main main-protected main-protected
feature feature-non_protected feature-protected

또한 태그에 대한 파이프라인의 경우 파이프라인이 실행되는 브랜치가 아닌 태그의 보호 상태가 접미사에 우선합니다. 이 동작은 트리거하는 참조가 캐시 액세스 권한을 결정하기 때문에 일관된 보안 경계를 보장합니다.

예를 들어:

  • cache:key$CI_COMMIT_TAG로 설정된 경우.
  • main이 보호된 브랜치인 경우.
  • feature가 보호되지 않은 브랜치인 경우.
  • 1.0.0이 보호된 태그인 경우.
  • 1.1.1-rc1이 보호되지 않은 태그인 경우.
태그 브랜치 Developer 권한 캐시 키 Maintainer 권한 캐시 키
1.0.0 main 1.0.0-protected 1.0.0-protected
1.0.0 feature 1.0.0-protected 1.0.0-protected
1.1.1-rc1 main 1.1.1-rc1-non_protected 1.1.1-rc1-protected
1.1.1-rc1 feature 1.1.1-rc1-non_protected 1.1.1-rc1-protected

모든 브랜치에 동일한 캐시 사용#

히스토리

캐시 키 이름을 사용하지 않으려면 모든 브랜치(보호됨 및 보호되지 않음)가 동일한 캐시를 사용하도록 설정할 수 있습니다.

캐시 키 이름을 사용한 캐시 분리는 보안 기능으로, Developer 권한을 가진 모든 사용자가 매우 신뢰받는 환경에서만 비활성화해야 합니다.

모든 브랜치에 동일한 캐시를 사용하려면:

  1. 상단 바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. 왼쪽 사이드바에서 Settings > CI/CD를 선택합니다.
  3. General pipelines를 확장합니다.
  4. Use separate caches for protected branches 체크박스를 지웁니다.
  5. Save changes를 선택합니다.

캐시 가용성#

캐싱은 최적화이지만 항상 작동한다는 보장이 없습니다. 각 Job에서 캐시된 파일을 재생성해야 할 수도 있습니다.

.gitlab-ci.yml에서 캐시를 정의한 후 캐시 가용성은 다음에 따라 달라집니다:

  • 러너의 실행기 유형.
  • Job 간에 캐시를 전달하는 데 서로 다른 러너가 사용되는지 여부.

캐시가 저장되는 위치#

Job에 대해 정의된 모든 캐시는 단일 cache.zip 파일에 아카이브됩니다. 러너 구성은 파일이 저장되는 위치를 정의합니다. 기본적으로 캐시는 GitLab Runner가 설치된 머신에 저장됩니다. 위치는 또한 실행기 유형에 따라 달라집니다.

러너 실행기 캐시 기본 경로
Shell 로컬, gitlab-runner 사용자의 홈 디렉토리 아래: /home/gitlab-runner/cache/<user>/<project>/<cache-key>/cache.zip.
Docker 로컬, Docker 볼륨 아래: /var/lib/docker/volumes/<volume-id>/_data/<user>/<project>/<cache-key>/cache.zip.
Docker Machine (자동 확장 러너) Docker 실행기와 동일.

Job에서 동일한 경로를 저장하는 데 캐시와 아티팩트를 모두 사용하면, 아티팩트 전에 캐시가 복원되기 때문에 캐시가 덮어쓰여질 수 있습니다.

아카이빙 및 추출 작동 방식#

이 예시는 두 개의 연속 Stage의 두 Job을 보여줍니다:

stages:
  - build
  - test

default:
  cache:
    key: build-cache
    paths:
      - vendor/
  before_script:
    - echo "Hello"

job A:
  stage: build
  script:
    - mkdir vendor/
    - echo "build" > vendor/hello.txt
  after_script:
    - echo "World"

job B:
  stage: test
  script:
    - cat vendor/hello.txt

머신에 러너 하나가 설치된 경우, 프로젝트의 모든 Job이 동일한 호스트에서 실행됩니다:

  1. 파이프라인이 시작됩니다.
  2. job A가 실행됩니다.
  3. 캐시가 추출됩니다(있는 경우).
  4. before_script가 실행됩니다.
  5. script가 실행됩니다.
  6. after_script가 실행됩니다.
  7. cache가 실행되고 vendor/ 디렉토리가 cache.zip으로 압축됩니다. 이 파일은 러너의 설정cache: key를 기반으로 디렉토리에 저장됩니다.
  8. job B가 실행됩니다.
  9. 캐시가 추출됩니다(있는 경우).
  10. before_script가 실행됩니다.
  11. script가 실행됩니다.
  12. 파이프라인이 완료됩니다.

단일 머신에서 단일 러너를 사용하면 job Bjob A와 다른 러너에서 실행될 수 있는 문제가 발생하지 않습니다. 이 설정은 Stage 간에 캐시를 재사용할 수 있도록 보장합니다. 동일한 러너/머신에서 build Stage에서 test Stage로 실행이 진행될 때만 작동합니다. 그렇지 않으면 캐시를 사용할 수 없을 수도 있습니다.

캐싱 프로세스 중 몇 가지 고려해야 할 사항이 있습니다:

  • 다른 캐시 구성의 다른 Job이 동일한 zip 파일에 캐시를 저장한 경우 덮어쓰여집니다. S3 기반 공유 캐시가 사용되는 경우 파일은 추가로 캐시 키를 기반으로 한 객체에 S3에 업로드됩니다. 따라서 서로 다른 경로를 가지지만 동일한 캐시 키를 가진 두 Job은 캐시를 덮어씁니다.
  • cache.zip에서 캐시를 추출할 때 zip 파일의 모든 것이 Job의 작업 디렉토리(보통 다운로드된 리포지터리)에 추출되며, 러너는 job A의 아카이브가 job B의 아카이브에 있는 것을 덮어쓰는 것을 신경 쓰지 않습니다.

이렇게 작동하는 이유는 한 러너를 위해 만들어진 캐시가 다른 러너에서 사용될 때 종종 유효하지 않기 때문입니다. 다른 러너는 다른 아키텍처에서 실행될 수 있습니다(예: 캐시에 바이너리 파일이 포함된 경우). 또한 다른 단계가 다른 머신에서 실행되는 러너에 의해 실행될 수 있기 때문에 이것이 안전한 기본값입니다.

캐시 지우기#

러너는 캐시를 사용하여 기존 데이터를 재사용함으로써 Job 실행을 빠르게 합니다. 이는 때때로 일관성 없는 동작으로 이어질 수 있습니다.

새 캐시 복사본으로 시작하는 두 가지 방법이 있습니다.

cache:key를 변경하여 캐시 지우기#

.gitlab-ci.yml 파일에서 cache: key 값을 변경합니다. 다음 파이프라인이 실행될 때 캐시는 다른 위치에 저장됩니다.

캐시 수동으로 지우기#

GitLab UI에서 캐시를 지울 수 있습니다:

  1. 상단 바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. 왼쪽 사이드바에서 Build > Pipelines를 선택합니다.
  3. 오른쪽 상단 모서리에서 Clear runner caches를 선택합니다.

다음 커밋에서 CI/CD Job은 새 캐시를 사용합니다.

Note

캐시를 수동으로 지울 때마다 내부 캐시 이름이 업데이트됩니다. 이름은 cache-<index> 형식을 사용하며 인덱스는 하나씩 증가합니다. 이전 캐시는 삭제되지 않습니다. 러너 스토리지에서 이 파일을 수동으로 삭제할 수 있습니다.

문제 해결#

캐시 불일치#

캐시 불일치가 있는 경우 다음 단계에 따라 문제를 해결합니다.

캐시 불일치 이유 해결 방법
공유 캐시 없이 프로젝트에 연결된 여러 독립 실행형 러너(자동 확장 모드 아님)를 사용합니다. 프로젝트에 러너 하나만 사용하거나 분산 캐시가 활성화된 여러 러너를 사용합니다.
분산 캐시가 활성화되지 않은 자동 확장 모드의 러너를 사용합니다. 분산 캐시를 사용하도록 자동 확장 러너를 구성합니다.
러너가 설치된 머신의 디스크 공간이 부족하거나, 분산 캐시를 설정한 경우 캐시가 저장된 S3 버킷의 공간이 충분하지 않습니다. 새 캐시를 저장할 수 있도록 공간을 지웁니다. 이를 자동으로 수행할 방법은 없습니다.
서로 다른 경로를 캐시하는 Job에 동일한 key를 사용합니다. 캐시 아카이브가 다른 위치에 저장되고 잘못된 캐시를 덮어쓰지 않도록 서로 다른 캐시 키를 사용합니다.
러너에서 분산 러너 캐싱을 활성화하지 않았습니다. Shared = false를 설정하고 러너를 다시 프로비저닝합니다.

캐시 불일치 예시 1#

프로젝트에 러너 하나만 할당된 경우, 캐시는 기본적으로 러너의 머신에 저장됩니다.

두 Job이 동일한 캐시 키를 가지지만 경로가 다른 경우 캐시가 덮어쓰여질 수 있습니다. 예를 들면:

stages:
  - build
  - test

job A:
  stage: build
  script: make build
  cache:
    key: same-key
    paths:
      - public/

job B:
  stage: test
  script: make test
  cache:
    key: same-key
    paths:
      - vendor/
  1. job A가 실행됩니다.
  2. public/cache.zip으로 캐시됩니다.
  3. job B가 실행됩니다.
  4. 이전 캐시가 있으면 압축이 해제됩니다.
  5. vendor/cache.zip으로 캐시되고 이전 것을 덮어씁니다.
  6. 다음에 job A가 실행되면 다르고 따라서 효과적이지 않은 job B의 캐시를 사용합니다.

이 문제를 해결하려면 각 Job에 다른 key를 사용합니다.

캐시 불일치 예시 2#

이 예시에서는 프로젝트에 두 개 이상의 러너가 할당되어 있고 분산 캐시가 활성화되지 않은 경우입니다.

두 번째 파이프라인이 실행될 때 job Ajob B가 캐시를 재사용하길 원합니다(이 경우 서로 다름):

stages:
  - build
  - test

job A:
  stage: build
  script: build
  cache:
    key: keyA
    paths:
      - vendor/

job B:
  stage: test
  script: test
  cache:
    key: keyB
    paths:
      - vendor/

key가 다르더라도, 후속 파이프라인에서 Job이 서로 다른 러너에서 실행되는 경우 각 Stage 이전에 캐시된 파일이 "정리"될 수 있습니다.

동시 러너의 로컬 캐시 누락#

Docker 실행기로 여러 동시 러너를 구성한 경우, 동시에 실행 중인 Job에서 예상한 대로 로컬에 캐시된 파일이 없을 수 있습니다. 캐시 볼륨의 이름은 각 러너 인스턴스에 대해 고유하게 구성되므로, 한 러너 인스턴스가 캐시한 파일은 다른 러너 인스턴스의 캐시에서 찾을 수 없습니다.

동시 러너 간에 캐시를 공유하려면 다음 중 하나를 수행할 수 있습니다:

  • 러너의 config.toml[runners.docker] 섹션을 사용하여 각 컨테이너에서 /cache에 매핑된 호스트의 단일 마운트 포인트를 구성합니다. 예: volumes = ["/mnt/gitlab-runner/cache-for-all-concurrent-jobs:/cache"]. 이 접근 방식은 러너가 동시 Job에 대해 고유한 볼륨 이름을 만드는 것을 방지합니다.
  • 분산 캐시를 사용합니다.