- キャッシュとアーティファクトの違い
- 良いキャッシングの実践例
- 複数のキャッシュの使用
- フォールバック・キャッシュ・キーの使用
- 特定のジョブのキャッシュを無効にします。
- グローバル設定を継承し、ジョブごとに特定の設定を上書きします。
- キャッシュの一般的な使用例
- キャッシュの可用性
- キャッシュのクリア
- トラブルシューティング
GitLab CI/CDでのキャッシング
キャッシュとは、ジョブがダウンロードして保存する一つ以上のファイルのことです。同じキャッシュを使う後続のジョブはファイルを再度ダウンロードする必要がないので、より速く実行できます。
.gitlab-ci.yml
ファイルでキャッシュを定義する方法については、cache
リファレンス を参照してください。
キャッシュとアーティファクトの違い
インターネットからダウンロードしたパッケージのような依存関係にはキャッシュを使います。キャッシュはGitLab Runnerがインストールされている場所に保存され、ディストリビューションキャッシュが有効な場合はS3にアップロードされます。
ステージ間で中間ビルド結果を渡すためにアーティファクトを使用します。アーティファクトはジョブによって生成され、GitLabに保存され、ダウンロードすることができます。
アーティファクトもキャッシュもプロジェクトディレクトリからの相対パスで定義され、プロジェクトディレクトリ外のファイルにはリンクできません。
キャッシュ
-
cache
キーワードを使用して、ジョブごとにキャッシュを定義します。そうでない場合は無効になります。 - 後続のパイプラインはキャッシュを使用できます。
- 依存関係が同じであれば、同じパイプライン内の後続のジョブもキャッシュを使用できます。
- 異なるプロジェクトはキャッシュを共有できません。
- デフォルトでは、保護されたブランチと保護されていないブランチはキャッシュを共有しません。しかし、この動作を変更することができます。
アーティファクト
- ジョブごとにアーティファクトを定義します。
- 同じパイプラインの後のステージのジョブは、アーティファクトを使用できます。
- 異なるプロジェクトでアーティファクトを共有することはできません。
- アーティファクトの有効期限は、デフォルトで 30 日です。カスタムで有効期限を定義できます。
- 最新のアーティファクトを保持]が有効になっている場合、最新のアーティファクトは失効しません。
- 依存関係を使用して、どのジョブがアーティファクトを取得するかを制御します。
良いキャッシングの実践例
キャッシュの可用性を最大にするために、以下の1つ以上を実行してください:
- ランナーにタグを付け、キャッシュを共有するジョブにタグを使用します。
- 特定のプロジェクトでのみ利用可能なRunnerを使用してください。
-
ワークフローに合った
key
を使いましょう。たとえば、ブランチごとに異なるキャッシュを設定できます。
Runnerがキャッシュを効率的に使用するには、以下のいずれかを行う必要があります:
- すべてのジョブに単一のRunnerを使用します。
- キャッシュがS3バケットに保存されるディストリビューションキャッシュを持つ複数のRunnerを使用してください。GitLab.comの共有ランナーはこのように動作します。これらのランナーはオートスケールモードにすることができますが、そうする必要はありません。
- 同じアーキテクチャの複数のRunnerを使い、これらのRunnerで共通のネットワークマウントされたディレクトリを共有してキャッシュを保存します。このディレクトリはNFSかそれに類するものを使用します。これらのランナーはオートスケールモードでなければなりません。
複数のキャッシュの使用
最大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
も見つからない場合、ジョブは2番目の予備オプションとしてcache-default
を探します。 - 見つからなかった場合、ジョブはキャッシュを使わずにすべてのRubyの依存関係をダウンロードしますが、ジョブが完了したときに
cache-$CI_COMMIT_REF_SLUG
。
フォールバックキーはcache:key
と同じ処理ロジックに従います:
- 手動でキャッシュを消去した場合、キャッシュごとのフォールバック・キーは他のキャッシュ・キーと同様にインデックスが付加されます。
-
Use separate caches for protected branches (保護されたブランチに個別のキャッシュを使用する)] 設定が有効になっている場合、キャッシュごとのフォールバック・キーには
-protected
または-non_protected
が付加されます。
グローバル・フォールバック・キー
GitLab Runner 13.4で導入されました。
$CI_COMMIT_REF_SLUG
の定義済み変数を使用して、cache:key
を指定することができます。例えば、$CI_COMMIT_REF_SLUG
がtest
, test
である場合、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: []
グローバル設定を継承し、ジョブごとに特定の設定を上書きします。
アンカーを使うことでグローバルキャッシュを上書きせずにキャッシュ設定をオーバーライドできます。たとえば、1つのジョブに対して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
を参照してください。
キャッシュの一般的な使用例
通常、ジョブを実行するたびに依存関係やライブラリのようなコンテンツをダウンロードするのを避けるためにキャッシュを使用します。Node.jsパッケージ、PHPパッケージ、Ruby gems、Pythonライブラリなどをキャッシュできます。
例については、GitLab CI/CDテンプレートを参照してください。
同じブランチ内のジョブ間でキャッシュを共有
各ブランチのジョブに同じキャッシュを使わせるには、key: $CI_COMMIT_REF_SLUG
:
cache:
key: $CI_COMMIT_REF_SLUG
この設定は、誤ってキャッシュを上書きすることを防ぎます。しかし、マージリクエストの最初のパイプラインは遅くなります。次にコミットがブランチにプッシュされると、キャッシュが再利用され、ジョブの実行速度が速くなります。
ジョブ単位およびブランチ単位のキャッシングを有効にしたい場合:
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 "This job pulls and pushes the cache depending on the branch"
- echo "Downloading dependencies..."
この例では、ジョブのキャッシュポリシーは次のとおりです:
-
pull-push
です。 -
pull
他のブランチへの変更。
Node.jsの依存関係をキャッシュ
プロジェクトがnpmを使用して Node.js の依存関係をインストールする場合、次の例ではデフォルトのcache
を定義して、すべてのジョブがそれを継承するようにしています。デフォルトでは、npm はキャッシュデータをホームフォルダ (~/.npm
) に保存します。しかし、プロジェクトディレクトリの外にキャッシュすることはできません。代わりに、./.npm
を使うように npm に指示し、ブランチごとにキャッシュします:
default:
image: node:latest
cache: # Cache modules in between jobs
key: $CI_COMMIT_REF_SLUG
paths:
- .npm/
before_script:
- npm ci --cache .npm --prefer-offline
test_async:
script:
- node ./specs/start.js ./specs/async.spec.js
ロックファイルからキャッシュキーを計算します。
cache:key:files
を使用して、package-lock.json
やyarn.lock
のようなロック・ファイルからキャッシュ・キーを計算し、多くのジョブで再利用することができます。
default:
cache: # Cache modules using lock file
key:
files:
- package-lock.json
paths:
- .npm/
Yarnを使用している場合、yarn-offline-mirror
を使用して、圧縮されたnode_modules
tarballをキャッシュすることができます。圧縮するファイルが少なくなるため、キャッシュの生成がより速くなります:
job:
script:
- echo 'yarn-offline-mirror ".yarn-cache/"' >> .yarnrc
- echo 'yarn-offline-mirror-pruning true' >> .yarnrc
- yarn install --frozen-lockfile --no-progress
cache:
key:
files:
- yarn.lock
paths:
- .yarn-cache/
PHP の依存関係のキャッシュ
プロジェクトがComposer を使って PHP 依存関係をインストールする場合、以下の例ではデフォルトのcache
を定義して、すべてのジョブがそれを継承するようにしています。PHP ライブラリモジュールはvendor/
にインストールされ、ブランチごとにキャッシュされます:
default:
image: php:7.2
cache: # Cache libraries in between jobs
key: $CI_COMMIT_REF_SLUG
paths:
- vendor/
before_script:
# Install and run 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's cache doesn't store the python packages
paths: # https://pip.pypa.io/en/stable/topics/caching/
- .cache/pip
before_script:
- python -V # Print out python version for debugging
- pip install virtualenv
- virtualenv venv
- source venv/bin/activate
variables: # Change pip's cache directory to be inside the project directory since we can only cache local items.
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
test:
script:
- python setup.py test
- pip install ruff
- ruff --format=gitlab .
Ruby 依存のキャッシュ
プロジェクトがBundlerを使ってgemの依存関係をインストールする場合、次の例ではデフォルトのcache
。gem はvendor/ruby/
にインストールされ、ブランチごとにキャッシュされます:
default:
image: ruby:2.6
cache: # Cache gems in between builds
key: $CI_COMMIT_REF_SLUG
paths:
- vendor/ruby
before_script:
- ruby -v # Print out ruby version for debugging
- bundle config set --local path 'vendor/ruby' # The location to install the specified gems to
- bundle install -j $(nproc) # Install dependencies into ./vendor/ruby
rspec:
script:
- rspec spec
異なるgemを必要とするジョブがある場合は、グローバルcache
定義でprefix
キーワードを使用します。この設定はジョブごとに異なるキャッシュを生成します。
例えば、テストジョブは本番環境にデプロイするジョブと同じgemsを必要としないかもしれません:
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' # The location to install the specified gems to
- bundle install --without test
script:
- bundle exec deploy
Goの依存関係をキャッシュ
プロジェクトがGo モジュールを使って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
](../yaml/index.md#cache)で[キャッシュを定義した後、キャッシュの可用性は以下に依存します:
- ランナーのエクゼキューター・タイプ。
- ジョブ間でキャッシュを受け渡すために異なる Runner を使用するかどうか。
キャッシュの格納場所
ジョブに対して定義されたすべてのキャッシュは、単一のcache.zip
ファイルにアーカイブされます。ファイルがどこに保存されるかは Runner 設定で定義します。デフォルトでは、キャッシュは GitLab Runner がインストールされているマシンに保存されます。場所はまた、エクゼキューターのタイプによって異なります。
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マシン(オートスケールランナー) | Docker Executorと同じです。 |
キャッシュとアーティファクトを使用して同じパスをジョブに保存する場合、キャッシュはアーティファクトよりも先にリストアされるため、キャッシュが上書きされる可能性があります。
キャッシュ・キー名
GitLab 15.0 で導入されました。
グローバルフォールバックキャッシュキーを除き、キャッシュキーにサフィックスが追加されます。
例として、cache.key
が$CI_COMMIT_REF_SLUG
に設定され、main
とfeature
の 2 つのブランチがあるとすると、以下の表は結果のキャッシュ・キーを表しています:
Branch name | キャッシュ・キー |
---|---|
main | main-protected |
feature | feature-non_protected |
すべてのブランチで同じキャッシュを使用します。
GitLab 15.0 で導入されました。
キャッシュキー名を使いたくない場合は、すべてのブランチ(protectedとunprotected)で同じキャッシュを使うことができます。
キャッシュキー名によるキャッシュの分離はセキュリティ機能であり、Developer ロールを持つすべてのユーザーが高度に信頼されている環境でのみ無効にしてください。
すべてのブランチで同じキャッシュを使用するには:
- 左のサイドバーで「検索」または「移動」を選択してあなたのプロジェクトを検索します。
- Settings > CI/CDを選択します。
- 一般的なパイプラインを拡大する。
- 保護ブランチに個別のキャッシュを使用する]チェックボックスをオフにします。
- 変更を保存を選択します。
アーカイブと抽出の仕組み
この例では、2つのジョブを2つの連続したステージで示しています:
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
1台のマシンに1つのRunnerがインストールされている場合、プロジェクトのすべてのジョブは同じホスト上で実行されます:
- パイプライン開始。
-
job A
が実行されます。 - キャッシュが抽出されます(見つかった場合)。
-
before_script
が実行されます。 -
script
が実行されます。 -
after_script
が実行されます。 -
cache
が実行され、vendor/
ディレクトリがcache.zip
にzip圧縮されます。このファイ ル は 、ラ ン ナ ー の 設 定に 基 づ い て デ ィ レ ク ト リ に 保 存 さ れ 、cache: key
. -
job B
が実行されます。 - キャッシュが抽出されます(見つかった場合)。
-
before_script
が実行されます。 -
script
が実行されます。 - パイプライン完了
1つのマシン上で1つのRunnerを使用することで、job B
がjob A
とは異なるRunner上で実行されるかもしれないというイシューは発生しません。このセットアップでは、ステージ間でキャッシュを再利用できることが保証されます。これは、同じランナー/マシンでbuild
ステージからtest
ステージまで実行される場合にのみ機能します。そうでない場合、キャッシュは利用できないかもしれません。
キャッシングのプロセスで、考慮すべき点もいくつかあります。
- 別のキャッシュ設定を持つ他のジョブが同じzipファイルにキャッシュを保存していた場合、それは上書きされます。S3ベースの共有キャッシュが使用されている場合、ファイルはキャッシュキーに基づいたオブジェクトに追加でS3にアップロードされます。そのため、パスが異なるがキャッシュキーが同じ2つのジョブは、それらのキャッシュを上書きします。
-
cache.zip
からキャッシュを展開する場合、zip ファイル内のすべてがジョブの作業ディレクトリ (通常はプルダウンされたリポジトリ) に展開されます。job A
のアーカイブがjob B
のアーカイブ内のものを上書きしても、ランナーは気にしません。
あるRunnerのために作成されたキャッシュは、別のRunnerで使用されるときには有効でないことが多いため、このように動作します。異なるRunnerは異なるアーキテクチャで実行されるかもしれません(例えば、キャッシュがバイナリファイルを含む場合)。また、異なるステップは異なるマシン上で実行されるランナーによって実行されるかもしれないので、これは安全なデフォルトです。
キャッシュのクリア
Runnerは既存のデータを再利用することでジョブの実行を高速化するためにキャッシュを使用します。これは時に一貫性のない動作につながることがあります。
キャッシュの新しいコピーから始めるには2つの方法があります。
キャッシュをクリアするにはcache:key
.gitlab-ci.yml
ファイルのcache: key
の値を変更します。次にパイプラインが実行されると、キャッシュは別の場所に保存されます。
手動でキャッシュをクリアします。
GitLab UIでキャッシュをクリアすることができます:
- 左のサイドバーで「検索」または「移動」を選択してあなたのプロジェクトを検索します。
- 左サイドバーでBuild > Pipelines を選択します。
- 右上隅で、Clear runner cachesを選択します。
次のコミットで、CI/CDジョブは新しいキャッシュを使用します。
cache-<index>
という形式を使い、インデックスは1ずつ増加します。古いキャッシュは削除されません。これらのファイルは、Runnerストレージから手動で削除できます。トラブルシューティング
キャッシュの不一致
キャッシュの不一致がある場合は、以下の手順に従ってトラブルシューティングを行ってください。
キャッシュの不一致の理由 | 修正方法 |
---|---|
複数のスタンドアロンランナー(オートスケールモードではない)を、共有キャッシュなしで1つのプロジェクトにアタッチして使用しています。 | プロジェクトに1つのランナーだけを使用するか、ディストリビューション・キャッシュを有効にして複数のランナーを使用します。 |
分散キャッシュを有効にせずにオートスケールモードでランナーを使用します。 | 分散キャッシュを使用するようにオートスケールランナーを設定します。 |
Runnerがインストールされているマシンのディスク容量が少ないか、分散キャッシュを設定している場合、キャッシュが保存されているS3バケットに十分な容量がありません。 | 新しいキャッシュを保存できるように、スペースを確保してください。これを自動的に行う方法はありません。 |
異なるパスをキャッシュするジョブには同じkey 。 | キャッシュアーカイブが異なる場所に保存され、間違ったキャッシュを上書きしないように、異なるキャッシュキーを使用してください。 |
ランナーでディストリビューション・ランナー・キャッシュを有効にしていません。 |
Shared = false を設定し、Runnerを再プロビジョニングしてください。 |
キャッシュの不一致の例1
プロジェクトに割り当てられたRunnerが1つだけの場合、キャッシュはデフォルトでRunnerのマシンに保存されます。
2つのジョブのキャッシュキーが同じでパスが異なる場合、キャッシュは上書きされます。例えば
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/
-
job A
が実行されます。 -
public/
はcache.zip
としてキャッシュされます。 -
job B
が実行されます。 - 前のキャッシュがあれば、それを解凍します。
-
vendor/
はcache.zip
としてキャッシュされ、前のものを上書きします。 - 次に
job A
が実行されると、job B
のキャッシュが使用されますが、これは異なるものであるため、効果的ではありません。
このイシューを解決するには、ジョブごとに異なるkeys
。
キャッシュの不一致の例 2
この例では、プロジェクトに複数のRunnerが割り当てられていて、ディストリビューションキャッシュが有効になっていません。
2回目のパイプラインの実行時に、job A
とjob 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
が異なっていても、その後のパイプラインでジョブが異なる Runner で実行された場合、各ステージの前にキャッシュされたファイルが「クリーニング」される可能性があります。