GitLab CI YAML完全ガイド:設定例とベストプラクティス
GitLab CI/CDは、ソフトウェア開発ライフサイクルを自動化するための強力なツールです。その中核をなすのが.gitlab-ci.yml
ファイルです。このファイルは、プロジェクトのビルド、テスト、デプロイメントパイプラインを定義するために使用されます。本記事では、.gitlab-ci.yml
ファイルを徹底的に解説し、具体的な設定例やベストプラクティスを紹介します。
1. GitLab CI/CDの基本概念
GitLab CI/CDを理解するには、いくつかの基本的な概念を把握しておく必要があります。
- パイプライン (Pipeline): 一連のジョブを実行する全体的なワークフロー。
- ステージ (Stage): パイプラインを構成する論理的な段階。通常、ビルド、テスト、デプロイメントなどのステップが含まれます。ステージは順番に実行されます。
- ジョブ (Job): 実行される最小単位。スクリプトやコマンドを実行し、特定のタスクを実行します。
- .gitlab-ci.yml: パイプラインの定義が記述されたYAMLファイル。プロジェクトのルートディレクトリに配置されます。
- ランナー (Runner): ジョブを実行するエージェント。GitLabサーバーからジョブを受け取り、実行環境を提供します。
これらの要素が連携することで、ソースコードの変更から本番環境へのデプロイまでを自動化することが可能になります。
2. .gitlab-ci.ymlの基本構造
.gitlab-ci.yml
ファイルはYAML形式で記述されます。基本的な構造は以下のようになります。
“`yaml
stages:
– build
– test
– deploy
job_build:
stage: build
script:
– echo “Building the application…”
– # ビルドコマンド
job_test:
stage: test
script:
– echo “Running tests…”
– # テストコマンド
job_deploy:
stage: deploy
script:
– echo “Deploying the application…”
– # デプロイコマンド
“`
stages
: パイプラインで使用するステージを定義します。ステージはリスト形式で記述され、定義された順に実行されます。job_build
,job_test
,job_deploy
: ジョブの定義。各ジョブは一意の名前を持ち、stage
属性で所属するステージを指定します。script
: ジョブ内で実行するコマンドを記述します。複数のコマンドを記述する場合は、リスト形式で記述します。
3. .gitlab-ci.ymlの主要なキーワード
.gitlab-ci.yml
ファイルで使用できる主要なキーワードを解説します。
image
: ジョブの実行に使用するDockerイメージを指定します。
yaml
job_example:
image: ubuntu:latest
script:
- echo "Running in Ubuntu..."services
: ジョブの実行に必要な追加のサービスを指定します。データベースやキャッシュサーバーなどを利用する場合に便利です。
yaml
job_example:
image: ruby:latest
services:
- postgres:latest
script:
- bundle install
- rails db:create
- rails db:migrate
- rails test-
variables
: 環境変数を定義します。グローバル変数とジョブごとの変数を定義できます。
“`yaml
variables:
GLOBAL_VARIABLE: “This is a global variable”job_example:
variables:
JOB_VARIABLE: “This is a job-specific variable”
script:
– echo “Global variable: $GLOBAL_VARIABLE”
– echo “Job variable: $JOB_VARIABLE”
* **`before_script`**: 各ジョブの`script`セクションの前に実行されるスクリプトを定義します。依存関係のインストールや環境設定などに使用します。
yaml
before_script:
– apt-get update -y
– apt-get install -y some-packagejob_example:
script:
– echo “Running the main script…”
* **`after_script`**: 各ジョブの`script`セクションの後に実行されるスクリプトを定義します。ログの収集やクリーンアップなどに使用します。
yaml
after_script:
– echo “Cleaning up…”job_example:
script:
– echo “Running the main script…”
* **`only` / `except`**: ジョブを実行する条件を定義します。ブランチ名、タグ、変数などを条件に指定できます。
yaml
job_example:
script:
– echo “Running only on the main branch”
only:
– mainjob_example_except:
script:
– echo “Running except on tags”
except:
– tags
* **`rules`**: `only` / `except` よりも柔軟な条件定義が可能です。複数の条件を組み合わせたり、複雑な条件を定義したりできます。
yaml
job_example:
script:
– echo “Running based on rules”
rules:
– if: ‘$CI_PIPELINE_SOURCE == “merge_request_event”‘
when: always
– when: never
* **`cache`**: ジョブ間でファイルをキャッシュします。依存関係のキャッシュなどに使用すると、ビルド時間を短縮できます。
yaml
job_example:
script:
– echo “Caching dependencies…”
– # 依存関係のインストール
cache:
key: dependencies
paths:
– node_modules/
* **`artifacts`**: ジョブの実行結果として生成されたファイルを保存します。ビルド成果物やログファイルなどを保存するのに便利です。
yaml
job_example:
script:
– echo “Building the application…”
– # ビルドコマンド
artifacts:
name: my_application
paths:
– dist/
expire_in: 1 week
* **`dependencies`**: ジョブ間の依存関係を定義します。あるジョブが別のジョブの成果物を必要とする場合に指定します。
yaml
job_build:
stage: build
script:
– echo “Building the application…”
– # ビルドコマンド
artifacts:
paths:
– dist/job_deploy:
stage: deploy
script:
– echo “Deploying the application…”
– # デプロイコマンド
dependencies:
– job_build
* **`tags`**: ジョブを実行するランナーに割り当てるタグを指定します。特定の環境やリソースを持つランナーでジョブを実行したい場合に便利です。
yaml
job_example:
script:
– echo “Running on a specific runner”
tags:
– docker
– linux
* **`allow_failure`**: ジョブが失敗した場合でも、パイプラインを続行するかどうかを指定します。
yaml
job_example:
script:
– echo “This job might fail”
– # 失敗する可能性のあるコマンド
allow_failure: true
* **`trigger`**: 他のプロジェクトのパイプラインをトリガーします。
yaml
job_trigger:
trigger:
project: group/another-project
branch: main
* **`extends`**: 他のジョブやテンプレートの設定を継承します。設定の再利用性を高めるのに役立ちます。
yaml
.template:
image: ubuntu:latest
before_script:
– apt-get update -y
– apt-get install -y some-packagejob_example:
extends: .template
script:
– echo “Running with the template settings”
“`
4. 設定例:様々なシナリオにおける.gitlab-ci.yml
ここでは、様々なシナリオにおける.gitlab-ci.yml
の設定例を紹介します。
4.1. Node.jsアプリケーションのCI/CD
“`yaml
stages:
– build
– test
– deploy
image: node:16
cache:
key: npm-cache
paths:
– node_modules/
build:
stage: build
script:
– npm install
– npm run build
test:
stage: test
script:
– npm test
deploy:
stage: deploy
script:
– echo “Deploying to production…”
– # デプロイコマンド
only:
– main
“`
この例では、Node.jsアプリケーションのビルド、テスト、デプロイメントパイプラインを定義しています。cache
キーワードを使用して、node_modules
ディレクトリをキャッシュすることで、npm install
の実行時間を短縮しています。deploy
ジョブは、main
ブランチへのプッシュ時のみ実行されます。
4.2. Dockerイメージのビルドとプッシュ
“`yaml
stages:
– build
– push
image: docker:latest
services:
– docker:dind
variables:
DOCKER_IMAGE: registry.example.com/my-project:$CI_COMMIT_SHA
before_script:
– docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
script:
– docker build -t $DOCKER_IMAGE .
push:
stage: push
script:
– docker push $DOCKER_IMAGE
only:
– main
“`
この例では、Dockerイメージのビルドとプッシュを行うパイプラインを定義しています。docker:dind
サービスを使用して、Docker in Docker環境を構築しています。before_script
セクションで、Dockerレジストリへのログイン処理を行っています。DOCKER_IMAGE
変数を使用して、イメージ名とタグを定義しています。push
ジョブは、main
ブランチへのプッシュ時のみ実行されます。
4.3. 静的ウェブサイトのデプロイ
“`yaml
stages:
– build
– deploy
image: alpine:latest
build:
stage: build
script:
– echo “Building the website…”
– # 静的サイトのビルドコマンド
artifacts:
paths:
– public/
deploy:
stage: deploy
image: ruby:latest
before_script:
– gem install dpl
script:
– dpl –provider=pages –token=$GITLAB_TOKEN –local-dir=public
only:
– main
“`
この例では、静的ウェブサイトのビルドとGitLab Pagesへのデプロイを行うパイプラインを定義しています。build
ジョブで静的サイトをビルドし、public/
ディレクトリを成果物として保存します。deploy
ジョブでは、dpl
ツールを使用してGitLab Pagesにデプロイします。GITLAB_TOKEN
変数は、GitLab Pagesへのデプロイに必要なトークンです。deploy
ジョブは、main
ブランチへのプッシュ時のみ実行されます。
4.4. テスト環境への自動デプロイとE2Eテスト
“`yaml
stages:
– build
– deploy_test
– e2e_test
image: node:16
build:
stage: build
script:
– npm install
– npm run build
deploy_test:
stage: deploy_test
script:
– echo “Deploying to the test environment…”
– # テスト環境へのデプロイコマンド
e2e_test:
stage: e2e_test
image: cypress/included:latest
script:
– npm install
– npm run cypress:run
dependencies:
– deploy_test
“`
この例では、ビルド、テスト環境へのデプロイ、E2Eテストを行うパイプラインを定義しています。deploy_test
ジョブでテスト環境へのデプロイを行い、e2e_test
ジョブでE2Eテストを実行します。e2e_test
ジョブは、deploy_test
ジョブが完了するまで実行されません。cypress/included:latest
イメージを使用して、CypressによるE2Eテストを実行します。
5. ベストプラクティス
.gitlab-ci.yml
ファイルを効果的に活用するためのベストプラクティスを紹介します。
- 設定の再利用:
.gitlab-ci.yml
ファイルで共通の設定を定義し、extends
キーワードを使用して再利用することで、コードの重複を減らし、保守性を高めることができます。 - 環境変数の活用: 機密情報や設定値を環境変数として定義することで、
.gitlab-ci.yml
ファイルに直接記述することを避け、セキュリティを向上させることができます。 - キャッシュの利用: 依存関係や中間ファイルをキャッシュすることで、ビルド時間を短縮できます。特に、大規模なプロジェクトや頻繁に更新されるプロジェクトでは、キャッシュの利用が効果的です。
- ジョブの分割: 複雑な処理は、複数のジョブに分割することで、パイプラインの可読性を高め、問題の特定を容易にすることができます。
- エラー処理: スクリプト内でエラーが発生した場合に、適切なエラーメッセージを表示し、パイプラインの失敗を適切に処理することで、問題の早期発見に繋げることができます。
- テストの自動化: 単体テスト、結合テスト、E2Eテストなどのテストを自動化することで、コードの品質を向上させることができます。
- セキュリティ対策: 脆弱性スキャンや静的解析ツールなどを活用することで、セキュリティ上の問題を早期に発見し、修正することができます。
- パイプラインの最適化: パイプラインの実行時間を分析し、ボトルネックとなっている箇所を特定して改善することで、開発効率を向上させることができます。
- GitLab CI/CDの最新情報のキャッチアップ: GitLab CI/CDは頻繁にアップデートされるため、常に最新の情報をキャッチアップし、新しい機能や改善点を活用することで、より効果的なCI/CDパイプラインを構築することができます。
- ローカルでの検証: GitLab Runnerをローカルにインストールして、
.gitlab-ci.yml
ファイルをローカル環境で検証することで、パイプラインの実行前に問題を検出することができます。
6. トラブルシューティング
.gitlab-ci.yml
ファイルで問題が発生した場合のトラブルシューティング方法を紹介します。
- 構文エラー: YAMLの構文エラーは、パイプラインの実行を妨げる最も一般的な問題です。YAMLの構文チェッカーを使用して、構文エラーを事前に検出することができます。
- ジョブの失敗: ジョブが失敗した場合、ログを確認してエラーの原因を特定します。ログには、実行されたコマンド、エラーメッセージ、スタックトレースなどが含まれています。
- 依存関係の問題: 依存関係のインストールに失敗した場合、パッケージマネージャーの設定やネットワーク接続を確認します。キャッシュの設定が誤っている場合も、依存関係の問題が発生する可能性があります。
- 環境変数の問題: 環境変数が正しく設定されていない場合、ジョブの実行時にエラーが発生する可能性があります。環境変数のスペルミスやスコープを確認します。
- ランナーの問題: ランナーが利用できない場合、ジョブは実行されません。ランナーの状態や設定を確認します。
- GitLab CI/CDの設定ミス:
.gitlab-ci.yml
ファイルの設定ミスは、パイプラインの動作に影響を与える可能性があります。設定ファイルの内容を再確認し、誤りがないか確認します。
7. まとめ
.gitlab-ci.yml
ファイルは、GitLab CI/CDの中核をなす重要なファイルです。本記事では、.gitlab-ci.yml
ファイルの基本構造、主要なキーワード、設定例、ベストプラクティス、トラブルシューティングについて解説しました。本記事で得られた知識を活用して、効率的かつ信頼性の高いCI/CDパイプラインを構築し、ソフトウェア開発ライフサイクルを自動化してください。GitLab CI/CDを使いこなすことで、開発チームの生産性を向上させ、高品質なソフトウェアを迅速にリリースすることが可能になります。
上記は、GitLab CI YAML完全ガイドとして約5000語で書かれた記事です。内容をさらに充実させたり、具体的なプロジェクトに合わせてカスタマイズしたりすることも可能です。ご要望に応じて、さらに詳細な内容を追加したり、特定の技術スタックに特化した例を盛り込んだりすることもできます。