- 캐시와 아티팩트의 차이
- 여러 개의 캐시 사용
- 대체 캐시 키 사용
- 특정 작업에 대한 캐시 비활성화
- 전역 구성 상속, 하지만 작업별 특정 설정 재정의
- 캐시의 공통 사용 사례
- 캐시의 이용 가능성
- 캐시 지우기
- 문제 해결
GitLab CI/CD에서의 캐싱
자세한 내용은 .gitlab-ci.yml 파일에서 캐시를 정의하는 방법을 확인하세요.
캐시와 아티팩트의 차이
의존성인 패키지와 같은 것에 대해 캐시를 사용하세요. 캐시는 GitLab Runner가 설치된 위치에 저장되며, 분산 캐시가 활성화된 경우 S3에 업로드됩니다.
중간 빌드 결과를 스테이지 간에 전달하기 위해 아티팩트를 사용하세요. 아티팩트는 작업에 의해 생성되며 GitLab에 저장되어 다운로드할 수 있습니다.
아티팩트나 캐시는 프로젝트 디렉터리 기준으로 경로를 정의하며, 디렉터리 외부 파일에 연결할 수 없습니다.
… ### 캐시
-
cache
키워드를 사용하여 작업별로 캐시를 정의하세요. 그렇지 않으면 비활성화됩니다. - 이후의 파이프라인에서 캐시를 사용할 수 있습니다.
- 동일한 파이프라인의 후속 작업은 의존성이 동일한 경우 캐시를 사용할 수 있습니다.
- 서로 다른 프로젝트는 캐시를 공유할 수 없습니다.
- 기본적으로 보호 및 비보호 브랜치는 캐시를 공유하지 않습니다. 그러나 이 동작을 변경할 수 있습니다.
아티팩트
- 작업별로 아티팩트를 정의하세요.
- 동일 파이프라인의 후속 작업은 아티팩트를 사용할 수 있습니다.
- 서로 다른 프로젝트는 아티팩트를 공유할 수 없습니다.
- 아티팩트는 기본적으로 30일 후에 만료됩니다. 사용자 정의 만료 시간을 정의할 수 있습니다.
- 최신 아티팩트 유지가 활성화된 경우 최신 아티팩트는 만료되지 않습니다.
- 어떤 작업이 아티팩트를 가져올지 제어하려면 의존성을 사용하세요.
…
여러 개의 캐시 사용
- GitLab 13.10에서 도입됨.
- GitLab 13.12에서 피처 플래그가 제거됨.
최대 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...
여러 캐시가 대체 키와 함께 결합되는 경우, 캐시를 찾지 못할 때 전역 대체 캐시가 매번 가져옵니다.
…
대체 캐시 키 사용
캐시용 대체 키
- GitLab 16.0에서 도입됨
각 캐시 항목은 fallback_keys
키워드로 최대 5개의 대체 키를 지원합니다. 작업이 캐시 키를 찾지 못하면 대체 캐시를 가져오려고 시도합니다. 대체 키는 순서대로 검색되며 캐시가 찾아지면 작업이 계속됩니다. 캐시를 찾지 못한 경우 캐시 없이 작업이 실행됩니다.
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...
이 예시에서:
- 작업은
cache-$CI_COMMIT_REF_SLUG
캐시를 찾습니다. -
cache-$CI_COMMIT_REF_SLUG
를 찾지 못하면 작업은 대체 옵션으로cache-$CI_DEFAULT_BRANCH
를 찾습니다. -
cache-$CI_DEFAULT_BRANCH
를 찾지 못하면 작업은 두 번째 대체 옵션으로cache-default
를 찾습니다. - 찾지 못하면 작업은 Ruby 의존성을 모두 다시 다운로드하고, 작업이 완료되면
cache-$CI_COMMIT_REF_SLUG
용 새로운 캐시를 생성합니다.
대체 키는 cache:key
와 동일한 처리 로직을 따릅니다:
- 매뉴얼으로 캐시를 지우는 경우, 캐시용 대체 키는 다른 캐시 키들처럼 색인이 추가됩니다.
-
보호 브랜치용 별도의 캐시 사용 설정 활성화된 경우, 캐시용 대체 키에는
-protected
또는-non_protected
가 추가됩니다.
전역 대체 키
- GitLab Runner 13.4에서 소개되었습니다.
$CI_COMMIT_REF_SLUG
사전 정의된 변수를 사용하여
cache:key
를 지정할 수 있습니다. 예를 들어, $CI_COMMIT_REF_SLUG
가 test
인 경우 test
로 태그된 캐시를 다운로드하는 작업을 설정할 수 있습니다.
이 태그가 지정된 캐시가 없는 경우, 존재하지 않을 때 사용할 캐시를 지정하기 위해 CACHE_FALLBACK_KEY
를 사용할 수 있습니다.
다음 예에서, $CI_COMMIT_REF_SLUG
를 찾을 수 없는 경우, 작업은 CACHE_FALLBACK_KEY
변수에서 정의된 키를 사용합니다:
variables:
CACHE_FALLBACK_KEY: fallback-key
job1:
script:
- echo
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- binaries/
캐시 추출 과정은 다음과 같습니다:
-
cache:key
를 가져오기 시도 -
fallback_keys
에 정의된 순서대로 각 항목을 가져오기 시도 -
CACHE_FALLBACK_KEY
에서 전역 대체 키를 가져오기 시도
캐시 추출 프로세스는 첫 번째 성공적인 캐시를 가져온 후 중지됩니다.
특정 작업에 대한 캐시 비활성화
캐시를 전역적으로 정의하면 각 작업이 동일한 정의를 사용합니다. 각 작업에 대해 이 동작을 재정의할 수 있습니다.
작업에서 완전히 비활성화하려면 빈 디렉터리을 사용하세요:
job:
cache: []
전역 구성 상속, 하지만 작업별 특정 설정 재정의
전역 캐시를 덮어쓰지 않고도 작업별로 캐시 설정을 재정의할 수 있도록 앵커를 사용할 수 있습니다. 예를 들어, 하나의 작업에 대해 policy
를 재정의하려면:
default:
cache: &global_cache
key: $CI_COMMIT_REF_SLUG
paths:
- node_modules/
- public/
- vendor/
policy: pull-push
job:
cache:
# 모든 전역 캐시 설정 상속
<<: *global_cache
# 정책 재정의
policy: pull
자세한 내용은 cache: policy
을 참조하세요.
캐시의 공통 사용 사례
보통 캐시를 사용하여 각 작업을 실행할 때마다 의존성 또는 라이브러리와 같은 콘텐츠를 다운로드하는 것을 피합니다. Node.js 패키지, PHP 패키지, Ruby 젬, Python 라이브러리 및 기타를 캐시할 수 있습니다.
예제는 GitLab CI/CD 템플릿을 참조하세요.
동일한 브랜치 내 작업 간 캐시 공유
각 브랜치에 있는 작업이 동일한 캐시를 사용하려면 key: $CI_COMMIT_REF_SLUG
로 캐시를 정의하세요:
cache:
key: $CI_COMMIT_REF_SLUG
이 구성은 실수로 캐시를 덮어쓰지 않도록 방지합니다. 그러나, Merge Request에 대한 첫 번째 파이프라인은 느립니다. 브랜치로 다음 번에 커밋한 경우, 캐시가 재사용되어 작업이 더 빨리 실행됩니다.
작업 및 브랜치별 캐싱을 활성화하려면:
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
단계별 및 브랜치별 캐싱을 활성화하려면:
cache:
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
다른 브랜치의 작업 간 캐시 공유
모든 브랜치 및 모든 작업 간에 캐시를 공유하려면 모든 것에 동일한 키를 사용하세요:
cache:
key: one-key-to-rule-them-all
브랜치 간에 캐시를 공유하되, 각 작업에 대해 고유한 캐시를 사용하려면:
cache:
key: $CI_JOB_NAME
변수를 사용하여 작업의 캐시 정책 제어
- GitLab 16.1에서 소개되었습니다.
기본 브랜치에 대한 변경이 있는 경우에만 풀 정책이 다른 작업의 중복을 줄이기 위해 CI/CD 변수를 사용할 수 있습니다.
예를 들어:
conditional-policy:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
variables:
POLICY: pull-push
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
variables:
POLICY: pull
stage: build
cache:
key: gems
policy: $POLICY
paths:
- vendor/bundle
script:
- echo "이 작업은 브랜치에 따라 캐시를 다운로드하고 업로드합니다"
- echo "의존성 다운로드 중..."
이 예제에서 작업의 캐시 정책은 다음과 같습니다:
- 기본 브랜치에 대한 변경이 있는 경우
pull-push
- 다른 브랜치에 대한 변경이 있는 경우
pull
PHP 의존성 캐시
만약 당신의 프로젝트가 PHP 의존성을 설치하기 위해 Composer를 사용한다면, 다음의 예시는 모든 작업에서 상속받는 기본 cache
를 정의합니다. PHP 라이브러리 모듈은 vendor/
에 설치되며 브랜치 별로 캐시됩니다:
default:
image: php:7.2
cache: # 작업 간에 라이브러리 캐시
key: $CI_COMMIT_REF_SLUG
paths:
- vendor/
before_script:
# Composer 설치 및 실행
- curl --show-error --silent "https://getcomposer.org/installer" | php
- php composer.phar install
test:
script:
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
Python 의존성 캐시
만약 당신의 프로젝트가 Python 의존성을 설치하기 위해 pip를 사용한다면, 다음의 예시는 모든 작업에서 상속받는 기본 cache
를 정의합니다. pip의 캐시는 .cache/pip/
아래에 정의되고 브랜치 별로 캐시됩니다:
default:
image: python:latest
cache: # pip의 캐시는 파이썬 패키지를 저장하지 않습니다
paths: # https://pip.pypa.io/en/stable/topics/caching/
- .cache/pip
before_script:
- python -V # 디버깅용 파이썬 버전 출력
- pip install virtualenv
- virtualenv venv
- source venv/bin/activate
variables: # 로컬 항목만 캐시할 수 있기 때문에 pip의 캐시 디렉터리를 프로젝트 디렉터리 내부로 변경합니다.
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
test:
script:
- python setup.py test
- pip install ruff
- ruff --format=gitlab .
Ruby 의존성 캐시
만약 당신의 프로젝트가 gem 의존성을 설치하기 위해 Bundler를 사용한다면, 다음의 예시는 모든 작업에서 상속받는 기본 cache
를 정의합니다. Gems는 vendor/ruby/
에 설치되며 브랜치 별로 캐시됩니다:
default:
image: ruby:2.6
cache: # 빌드 간에 젬 캐시
key: $CI_COMMIT_REF_SLUG
paths:
- vendor/ruby
before_script:
- ruby -v # 디버깅용 루비 버전 출력
- bundle config set --local path 'vendor/ruby' # 지정된 gem을 설치할 위치
- bundle install -j $(nproc) # ./vendor/ruby에 의존성 설치
rspec:
script:
- rspec spec
만약 다른 gem이 필요한 작업이 있다면, 전역 cache
정의에서 prefix
키워드를 사용하세요. 이 구성은 각 작업을 위해 다른 캐시를 생성합니다.
예를 들어, 테스팅 작업은 프로덕션으로 배포하는 작업과 동일한 gem이 필요하지 않을 수 있습니다:
default:
cache:
key:
files:
- Gemfile.lock
prefix: $CI_JOB_NAME
paths:
- vendor/ruby
test_job:
stage: test
before_script:
- bundle config set --local path 'vendor/ruby'
- bundle install --without production
script:
- bundle exec rspec
deploy_job:
stage: production
before_script:
- bundle config set --local path 'vendor/ruby' # 지정된 gem을 설치할 위치
- bundle install --without test
script:
- bundle exec deploy
Go 의존성 캐시
만약 당신의 프로젝트가 Go Modules를 사용하여 Go 의존성을 설치한다면, 다음의 예시는 어떤 작업이든 확장할 수 있는 go-cache
템플릿에서 cache
를 정의합니다. Go 모듈은 ${GOPATH}/pkg/mod/
에 설치되며 모든 go
프로젝트에 대해 캐시됩니다:
.go-cache:
variables:
GOPATH: $CI_PROJECT_DIR/.go
before_script:
- mkdir -p .go
cache:
paths:
- .go/pkg/mod/
test:
image: golang:1.13
extends: .go-cache
script:
- go test ./... -v -short
캐시의 이용 가능성
캐싱은 최적화이지만 항상 작동하는 것은 아닙니다. 필요한 경우 캐시된 파일을 각 작업에서 다시 생성해야 할 수 있습니다.
.gitlab-ci.yml
에서 캐시를 정의한 후, 캐시의 이용 가능성은 다음에 달려 있습니다:
- 러너의 실행자 유형.
- 작업 사이에서 캐시를 전달하는 데 사용되는 다른 러너가 있는지 여부.
캐시가 저장된 위치
작업에 정의된 모든 캐시는 단일 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 실행자와 동일합니다. |
작업에서 캐시와 아티팩트를 같은 경로에 저장하면, 캐시가 아티팩트 앞에 복원되기 때문에 캐시가 덮어씌워질 수 있습니다.
캐시 키 이름
- GitLab 15.0에서 도입.
캐시 키에 접미사가 추가되며, 전역 대체 캐시 키를 제외한 경우입니다.
예를 들어, cache.key
가 $CI_COMMIT_REF_SLUG
로 설정되고 main
과 feature
두 개의 브랜치가 있다면, 다음 표는 결과적으로 생성된 캐시 키를 나타냅니다:
브랜치 이름 | 캐시 키 |
---|---|
main
| main-protected
|
feature
| feature-non_protected
|
모든 브랜치에서 동일한 캐시 사용
- GitLab 15.0에 도입됨(소개됨).
캐시 키 이름을 사용하고 싶지 않다면, 모든 브랜치(보호된 브랜치 및 보호되지 않은 브랜치 모두)에서 동일한 캐시를 사용할 수 있습니다.
캐시 키 이름으로 캐시를 나누는 것은 보안 기능이며, 개발자 역할을 하는 모든 사용자가 매우 신뢰할 수 있는 환경에서만 비활성화해야 합니다.
모든 브랜치에서 동일한 캐시를 사용하려면:
- 왼쪽 사이드바에서 검색 또는 이동을 선택하여 프로젝트를 찾습니다.
- 설정 > CI/CD를 선택합니다.
- 일반 파이프라인을 확장합니다.
- 보호된 브랜치용 별도의 캐시 사용 확인란을 해제합니다.
- 변경 사항 저장를 선택합니다.
아카이빙 및 추출 작업 방식
다음 예제에서 두 개의 작업이 두 연이은 단계에서 수행됩니다:
stages:
- build
- test
default:
cache:
key: build-cache
paths:
- vendor/
before_script:
- echo "Hello"
작업 A:
stage: build
script:
- mkdir vendor/
- echo "build" > vendor/hello.txt
after_script:
- echo "World"
작업 B:
stage: test
script:
- cat vendor/hello.txt
한 대의 머신에 한 개의 실행 러너가 설치된 경우 프로젝트의 모든 작업은 동일한 호스트에서 실행됩니다:
- 파이프라인 시작.
-
작업 A
실행. - 캐시가 추출됨(있는 경우).
-
before_script
가 실행됨. -
script
가 실행됨. -
after_script
가 실행됨. -
cache
가 실행되어vendor/
디렉터리가cache.zip
으로 압축됩니다. 그런 다음 러너 설정 및cache: key
에 따라 이 파일이 디렉터리에 저장됩니다. -
작업 B
실행. - 캐시가 추출됨(있는 경우).
-
before_script
가 실행됨. -
script
가 실행됨. - 파이프라인 완료.
단일 러너와 단일 머신을 사용하면 작업 B
가 작업 A
와 다른 러너에서 실행되는 문제가 없습니다.
이러한 설정은 단계 간에 캐시를 재사용할 수 있도록 보장합니다. 이 설정은 build
단계에서 test
단계로 실행이 동일한 러너/머신에서 이뤄질 때만 작동합니다. 그렇지 않으면 캐시가 사용할 수 없을 수 있습니다.
캐싱 과정 중에 고려해야 할 몇 가지 사항도 있습니다:
- 다른 캐시 구성으로 캐시를 저장한 다른 작업이 같은 zip 파일에 저장되면 덮어씁니다. S3 기반 공유 캐시를 사용하는 경우 파일이 캐시 키에 따라 S3에 추가로 업로드됩니다. 따라서 경로가 다르지만 동일한 캐시 키를 가진 두 작업은 캐시를 덮어쓸 수 있습니다.
-
cache.zip
에서 캐시를 추출할 때 zip 파일의 모든 것이 작업의 작업 디렉터리(보통 다운로드된 리포지터리)에 추출되며,job A
의 아카이브가job B
의 아카이브에 덮어써도 러너는 신경쓰지 않습니다.
러너로 생성된 캐시는 종종 다른 러너에서 사용할 때 유효하지 않습니다. 다른 러너는 다른 아키텍처(예: 캐시에 이진 파일이 포함된 경우)에서 실행될 수 있습니다. 또한 다른 단계가 서로 다른 머신에서 실행될 수 있기 때문에, 이는 안전한 기본 설정입니다.
캐시 지우기
러너는 기존 데이터를 재사용하여 작업 실행 속도를 높이기 위해 캐시를 사용합니다. 이로 인해 때로는 일관되지 않은 동작이 발생할 수 있습니다.
캐시의 새로운 복사본으로 시작하는 두 가지 방법이 있습니다.
cache:key
를 변경하여 캐시 지우기
.gitlab-ci.yml
파일에서 cache: key
의 값을 변경합니다.
다음번에 파이프라인이 실행되면 캐시가 다른 위치에 저장됩니다.
매뉴얼으로 캐시 지우기
다음 방법으로 GitLab UI에서 캐시를 지울 수 있습니다:
- 왼쪽 사이드바에서 검색 또는 이동을 선택하여 프로젝트를 찾습니다.
- 빌드 > 파이프라인을 선택합니다.
- 오른쪽 상단 모서리에서 러너 캐시 지우기를 선택합니다.
다음 커밋에서 CI/CD 작업은 새로운 캐시를 사용합니다.
cache-<index>
형식을 사용하며, 인덱스가 하나씩 증가합니다. 이전 캐시가 삭제되지는 않습니다. 이러한 파일은 러너 리포지터리에서 매뉴얼으로 삭제할 수 있습니다.문제 해결
캐시 불일치
캐시 불일치가 있는 경우 다음 단계를 따라 문제를 해결하세요.
캐시 불일치의 이유 | 해결 방법 |
---|---|
프로젝트에 공유 캐시가 없는 독립적인 러너(자동 확장 모드 아님)를 여러 개 사용합니다. | 프로젝트에는 한 개의 러너만 사용하거나 분산 캐시를 사용하도록 여러 러너를 설정합니다. |
분산 캐시를 활성화하지 않은 자동 확장 모드 러너를 사용합니다. | 자동 확장 러너를 구성하여 분산 캐시를 사용하도록 설정합니다. |
러너가 설치된 머신의 디스크 공간이 부족하거나, 분산 캐시가 설정된 경우에는 캐시를 저장하는 S3 버킷에 충분한 공간이 없습니다. | 새로운 캐시를 저장할 수 있도록 공간을 확보하기 위해 공간을 정리해야 합니다. 자동으로 할 수 있는 방법은 없습니다. |
동일한 key 를 가진 작업에서 다른 경로를 캐시할 경우입니다.
| 캐시 아카이브가 다른 위치에 저장되고 잘못된 캐시를 덮어쓰지 않도록 서로 다른 캐시 키를 사용합니다. |
러너에서 러너 분산 캐싱을 활성화하지 않은 경우 |
Shared = false 로 설정하고 러너를 다시 프로비저닝합니다.
|
캐시 불일치 예제 1
프로젝트에 한 개의 러너만 할당되어 있으면 캐시는 기본적으로 러너 머신에 저장됩니다.
두 작업이 동일한 캐시 키를 가지지만 다른 경로를 가진 경우, 캐시가 덮어씌워질 수 있습니다. 예를 들어:
stages:
- build
- test
작업 A:
stage: build
script: make build
cache:
key: same-key
paths:
- public/
작업 B:
stage: test
script: make test
cache:
key: same-key
paths:
- vendor/
-
작업 A
실행됨. -
public/
이cache.zip
으로 캐싱됨. -
작업 B
실행됨. - 이전 캐시가 있다면 압축 해제됨.
-
vendor/
가cache.zip
으로 캐싱되어 이전 것을 덮어씁니다. -
작업 A
가 다음에 실행되면 다른작업 B
의 캐시를 사용하게 되고, 그래서 효과가 없습니다.
이 문제를 해결하려면 각 작업에 서로 다른 key
를 사용하세요.
캐시 불일치 예제 2
이 예에서는 프로젝트에 여러 러너가 할당되어 있고 분산 캐시가 활성화되어 있지 않은 경우입니다.
파이프라인이 두 번째로 실행되었을 때 작업 A
와 작업 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
가 다르더라도, 다음 파이프라인에서 각 작업이 다른 러너에서 실행된다면 캐시된 파일이 각 스테이지마다 “정리”될 수 있습니다.
동시 실행 러너에서 로컬 캐시가 누락된 경우
도커 실행자로 여러 개의 동시 실행 러너를 구성한 경우, 예상대로 동시에 실행되는 작업들에게 로컬로 캐시된 파일이 존재하지 않을 수 있습니다. 캐시 볼륨의 이름은 각 러너 인스턴스마다 고유하게 생성되므로 한 러너 인스턴스에 의해 캐시된 파일은 다른 러너 인스턴스에서 캐시에서 찾을 수 없습니다.
동시 실행 러너 간에 캐시를 공유하려면 다음 중 하나를 사용할 수 있습니다:
- 각 컨테이너에서
/cache
로 매핑되는 호스트에서 단일 마운트 지점을 설정하여 고유한 볼륨 이름을 생성하지 않도록 하는 러너의config.toml
의[runners.docker]
섹션을 사용합니다. - 분산 캐시를 사용합니다.