継続的デプロイは、チームがより迅速かつ高い信頼性で価値を生み出せる画期的な手法です。しかし、GitOpsやKubernetesを用いたコンテナオーケストレーション、動的環境などの高度なデプロイワークフローに取り組むのは、継続的デプロイの導入を始めたばかりのチームにとってはハードルが高いと感じられるかもしれません。
GitLabでは、シームレスかつスケーラブルなデリバリーを実現することに注力しています。チームが基本に集中できるようにすることで、時間をかけてより複雑な戦略へと発展できる、強固な基盤を構築できます。このガイドでは、GitLabを活用した継続的デプロイの導入に必要な基本的なステップを紹介し、長期的な成功のための土台作りをサポートします。
まずはワークフローの計画から
技術的な実装に入る前に、デプロイワークフローをしっかりと設計する時間を取りましょう。成功の鍵は、慎重な計画と体系的なアプローチにあります。
アーティファクト管理戦略
継続的デプロイにおいて、アーティファクトとは、ビルドプロセスによって生成されるパッケージ化された成果物を指し、保存、バージョン管理、デプロイが必要です。アーティファクトには、次のようなものが含まれます。
- アプリケーション用のコンテナイメージ
- パッケージ
- コンパイル済みのバイナリや実行ファイル
- ライブラリ
- 設定ファイル
- ドキュメントパッケージ
- その他のアーティファクト
各アーティファクトは、デプロイプロセスにおいて特定の役割を果たします。たとえば、一般的なWebアプリケーションでは、次のようなアーティファクトが生成されることがあります。
- バックエンドサービス用のコンテナイメージ
- コンパイル済みフロントエンドアセットのZIPアーカイブ
- データベース変更用のSQLファイル
- 環境ごとの設定ファイル
アーティファクトの適切な管理はデプロイを成功させる鍵となります。ここからは、アーティファクト管理のアプローチについて詳しく見ていきましょう。
アーティファクトとリリースのバージョニング戦略
クリーンで整理された構造を保つためのベストプラクティスとして、アーティファクトの明確なバージョニング戦略を確立することが重要です。リリース作成時のポイントは以下のとおりです。
- リリースタグにセマンティックバージョニング(major.minor.patch)を使用する
- 例:安定版リリースが
myapp:1.2.3
の場合 - 破壊的な変更がある場合は、メジャーバージョン変更(2.0.0)
- 新機能を追加する場合は、マイナーバージョン変更(1.3.0)
- バグ修正を行う場合は、パッチバージョン変更(1.2.4)
- 例:安定版リリースが
- 最新の安定版を示す「latest」タグを維持する
- 例:
myapp:latest
(自動デプロイ用)
- 例:
- コミットSHAを含めることで、正確なバージョン追跡を行う
- 例:
myapp:1.2.3-abc123f
(デバッグ用)
- 例:
- 開発環境向けにブランチベースのタグを使用する
- 例:
myapp:feature-user-auth
(新機能テスト用)
- 例:
ビルドアーティファクトの保持
明確な保持ルールを実装しましょう。
- 一時的なアーティファクトの明確な有効期限を設定する
- 永続的に保持する必要があるアーティファクトを定義する
- ストレージ管理のためのクリーンアップポリシーを設定する
レジストリアクセスと認証
適切なアクセス制御でアーティファクトのセキュリティを確保しましょう。
- デベロッパーのアクセス用にパーソナルアクセストークンを実装する
- パイプラインの認証にCI/CD変数を設定する
- 適切なアクセススコープを設定する
環境戦略
環境設計はデプロイパイプライン全体の構成に影響を与えるため、早い段階で検討しましょう。
- 開発、ステージング環境、本番環境の設定
- 環境ごとの変数とシークレットの管理
- アクセス制御と保護ルールの設定
- デプロイの追跡とモニタリングのアプローチ
デプロイターゲット
どこに、どのようにデプロイするのかを慎重に検討しましょう。これらの決定は重要であり、それぞれのメリットとデメリットを考慮する必要があります。
- インフラ要件(仮想マシン、コンテナ、クラウドサービス)
- ネットワークアクセスとセキュリティ設定
- 認証メカニズム(SSH鍵、アクセストークン)
- リソースの割り当てとスケーリングの考慮
これで戦略が定まり、基盤となる決定が完了したので、これらの計画を実際に動作するパイプラインに落とし込んでいきます。それでは、実際に機能する例を作ることで概念を深掘りしていきましょう。まずはシンプルなアプリケーションから始め、徐々にデプロイの機能を追加していきます。
CDパイプラインの実装
具体的な手順
Webアプリケーション向けの基本的な継続的デプロイ(CD)パイプラインの実装手順を順を追って説明します。例としてシンプルなHTMLアプリケーションを使用しますが、ここで紹介する原則はどのタイプのアプリケーションにも応用できます。今回は、アプリケーションをDockerイメージとしてパッケージ化し、シンプルな仮想マシン上にデプロイします。これにより、最小限の依存関係を持つ厳選されたイメージを活用し、環境依存の要件が意図せず混入するのを防ぐことができます。また、仮想マシン上で動作させることで、GitLabのネイティブなインテグレーション機能を活用しない設定となります。複雑で本格的な環境ではなく、理解しやすい簡易的な環境から始めてみましょう。
前提条件
この例では、クラウドプロバイダーの仮想マシン上で実行するアプリケーションをコンテナ化することを目指します。また、ローカル環境でもこのアプリケーションをテストします。以下の前提条件は、このシナリオにおいてのみ必要なものです。
仮想マシン(VM)のセットアップ
- お好みのクラウドプロバイダーでVMをプロビジョニングします(例:GCP、AWS、Azure)
- ネットワークルールを設定し、ポート22、80、443へのアクセスを許可します
- デプロイ用にマシンのパブリックIPアドレスを記録します
SSH認証のセットアップ:
- マシン用の公開鍵と秘密鍵のペアを生成します
- GitLabで設定 > CI/CD > 変数を開きます
GITLAB_KEY
という変数を作成します- タイプを「ファイル」に設定します(SSH認証に必須)
- 秘密鍵を「値」フィールドに貼り付けます
- 「ユーザー」変数を定義します(VMにログインしてスクリプトを実行するユーザー)
デプロイ変数の設定
- デプロイターゲット用の変数を作成します
STAGING_TARGET
:ステージング環境のサーバーIPまたはドメインPRODUCTION_TARGET
:本番環境のサーバーIPまたはドメイン
ローカル開発環境のセットアップ
- デプロイのテスト用に、ローカルマシンにDockerをインストールします
GitLabコンテナレジストリへのアクセス
- レジストリパスを確認します:
- デプロイ > コンテナレジストリを開きます
- レジストリパスをコピーします(例:registry.gitlab.com/group/project)
- 認証の設定:
- 設定 > アクセストークンを開きます
- レジストリアクセス権を持つ新しいトークンを作成します
- トークンの有効期限を最大1年に設定します
- トークンを安全に保存します
- ローカルレジストリのアクセス設定:
docker login registry.gitlab.com
# パーソナルアクセストークンを使用する場合のユーザー名はgitlab-ci-tokenです
# Password:(ここにアクセストークンを入力)
1. アプリケーションを作成する
基本的なWebアプリケーションから始めましょう。今回の例では、シンプルなHTMLページを使用します。
<!|||UNTRANSLATED_CONTENT_START|||-- index.html -->
<html>
<head>
<style>
body {
background-color: #171321; /* GitLab dark */
}
</style>
</head>
<body>
<!|||UNTRANSLATED_CONTENT_END|||-- ここにコンテンツを追加 -->
</body>
</html>
2. アプリケーションをコンテナ化する
アプリケーションをパッケージ化するために、Dockerfileを作成します:
FROM nginx:1.26.2
COPY index.html /usr/share/nginx/html/index.html
このDockerfileは
- nginxをベースイメージとして使用し、Webコンテンツを配信できるようにします
- 作成したindex.htmlをnginxのディレクトリ構造内の適切な場所にコピーします
3. CI/CDパイプラインを設定する
GitLabのパイプラインステージを定義するために、.gitlab-ci.yml
ファイル を作成します:
variables:
TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHA
stages:
- publish
- deploy
解説:
TAG_LATEST
は、次の3つの要素で構成されています:
$CI_REGISTRY_IMAGE
:GitLabのプロジェクトのコンテナレジストリのパス
例:registry.gitlab.com/your-group/your-project
$CI_COMMIT_REF_NAME
:ブランチ名またはタグ名
例:ブランチの場合は/main
、フィーチャーブランチの場合は/feature-login
:latest
:固定のサフィックス
これにより、mainブランチのTAG_LATEST
は次のようになります:registry.gitlab.com/your-group/your-project/main:latest
TAG_COMMIT
はTAG_LATEST
とほぼ同じですが、:latest
の代わりにコミット識別子の$CI_COMMIT_SHA
を使います。例::abc123def456
したがって、同じmainブランチでのTAG_COMMIT
は次のようになります:registry.gitlab.com/your-group/your-project/main:abc123def456
両方のタグを使用する理由は、TAG_LATEST
が常に最新バージョンを取得しやすくするのに対し、TAG_COMMIT
は必要に応じて特定のバージョンに戻れるようにするためです。
4. コンテナレジストリに公開する
パイプラインに公開ジョブを追加します:
publish:
stage: publish
image: docker:latest
services:
- docker:dind
script:
- docker build -t $TAG_LATEST -t $TAG_COMMIT .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $TAG_LATEST
- docker push $TAG_COMMIT
このジョブは
- Docker-in-Dockerを使用してイメージをビルドします
- 2つのタグを付けたイメージを作成します
- GitLabレジストリへの認証を行います
- 両方のイメージをレジストリにプッシュします
これで、コンテナイメージが安全にレジストリに保存されました。次は、ターゲット環境へのデプロイを進めていきます。本番環境へ移行する前に、まずローカル環境でテストを行い、設定が正しく機能していることを確認しましょう。
5. 環境へデプロイする
本番環境にデプロイする前に、ローカル環境でテストできます。先ほどGitLabレジストリにイメージを公開したので、それをローカル環境でプルしてテストします。コンテナイメージのパスが分からない場合は、GitLabのデプロイ > コンテナレジストリに移動し、該当のコンテナイメージの行末にあるアイコンをクリックすると、パスをコピーできます。
docker login registry.gitlab.com
docker run -p 80:80 registry.gitlab.com/your-project-path/main:latest
これにより、Webブラウザからlocalhostにアクセスし、ローカル環境でアプリケーションを確認できるようになります。
それでは、パイプラインにデプロイジョブを追加しましょう:
deploy:
stage: deploy
image: alpine:latest
script:
- chmod 400 $GITLAB_KEY
- apk add openssh-client
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- ssh -i $GITLAB_KEY -o StrictHostKeyChecking=no $USER@$TARGET_SERVER
docker pull $TAG_COMMIT &&
docker rm -f myapp || true &&
docker run -d -p 80:80 --name myapp $TAG_COMMIT
このジョブは
- デプロイ先のサーバーへのSSHアクセスを確立します
- 最新のコンテナイメージをプルします
- 既存のコンテナを削除します
- 新しいバージョンのコンテナをデプロイします
6. デプロイを追跡する
環境設定を追加してデプロイの追跡を有効にします:
deploy:
environment:
name: production
url: https://your-application-url.com
これにより、GitLabのオペレーション > 環境セクションに環境オブジェクトが作成され、以下の情報が提供されます:
- デプロイ履歴
- 現在のデプロイ状況
- アプリケーションへのクイックアクセス
単一の環境向けのパイプラインは、最初のステップとしては有効ですが、ほとんどのチームでは適切なテストやステージングを行うために複数の環境を管理する必要があります。このより実践的なシナリオに対応するために、パイプラインを拡張していきましょう。
7. 複数環境をセットアップする
より堅牢なパイプラインを構築するために、ステージング環境と本番環境のデプロイを設定します:
stages:
- publish
- staging
- release
- version
- production
staging:
stage: staging
rules:
- if: $CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG == null
environment:
name: staging
url: https://staging.your-app.com
# デプロイスクリプトを記述
production:
stage: production
rules:
- if: $CI_COMMIT_TAG
environment:
name: production
url: https://your-app.com
# デプロイスクリプトを記述
この設定は
- mainブランチからステージ環境へデプロイします
- GitLabのタグを利用して本番環境へのデプロイをトリガーします
- 環境ごとに分けてデプロイの状況を管理できるようにします
このステップと次のステップでは、GitLabの非常に便利な機能であるタグを活用しています。GitLabのコード > タグセクションで手動でタグを作成すると、'$ CI_COMMMIT_TAG `変数が設定され、本番環境へのデプロイジョブが適切にトリガーされるようになります。
8. 自動リリースノートを作成する
CI/CDパイプラインを通じてGitLabのリリース機能を使用します。まず、.gitlab-ci.yml
のstagesを更新 します:
stages:
- publish
- staging
- release # New stage for releases
- version
- production
次に、リリースジョブを追加します:
release_job:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG # タグが作成された場合のみ実行する
script:
- echo "Creating release for $CI_COMMIT_TAG"
release: # リリース設定
name: 'Release $CI_COMMIT_TAG'
description: 'Release created from $CI_COMMIT_TAG'
tag_name: '$CI_COMMIT_TAG' # タグを作成する
ref: '$CI_COMMIT_TAG' # リリースのベースとなるタグ
コンテナイメージのリンクを追加することで、さらに内容を充実させることができます:
release:
name: 'Release $CI_COMMIT_TAG'
description: 'Release created from $CI_COMMIT_TAG'
tag_name: '$CI_COMMIT_TAG'
ref: '$CI_COMMIT_TAG'
assets:
links:
- name: 'Container Image'
url: '$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG'
link_type: 'image'
コミットメッセージに基づいて自動リリースノートを生成する場合は次のようにします:
release:
name: 'Release $CI_COMMIT_TAG'
description: 'Release notes for version $CI_COMMIT_TAG'
tag_name: '$CI_COMMIT_TAG'
ref: '$CI_COMMIT_TAG'
auto_generate_release_notes: true # Enables automatic notes
自動リリースノートを充実させるには
- 規則的なコミットメッセージを使用する(例:feat:, fix:)
- イシュー番号を含める(例:#123)
- 件名と本文の間に空行を入れる
デプロイ時の情報をリリースノートに記載したい場合は、以下のように設定できます:
release_job:
script:
- |
DEPLOY_TIME=$(date '+%Y-%m-%d %H:%M:%S')
CHANGES=$(git log $(git describe --tags --abbrev=0 @^)..@ --pretty=format:"- %s")
cat > release_notes.md << EOF
## デプロイ情報
- デプロイ日時: $DEPLOY_TIME
- 環境: 本番環境
- バージョン: $CI_COMMIT_TAG
## 変更内容
$CHANGES
## アーティファクト
- コンテナイメージ: \`$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\`
EOF
release:
description: './release_notes.md'
この設定を行うと、Gitタグの作成時に自動でリリースが作成されるようになります。作成されたリリースは、GitLabのデプロイ > リリースで確認できます。
9. すべてをまとめる
最終的なYAMLファイルは以下のようになります:
variables:
TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHA
STAGING_TARGET: $STAGING_TARGET # CI/CD変数で設定
PRODUCTION_TARGET: $PRODUCTION_TARGET # CI/CD変数で設定
stages:
- publish
- staging
- release
- version
- production
# ビルドとレジストリへの公開
publish:
stage: publish
image: docker:latest
services:
- docker:dind
rules:
- if: $CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG == null
script:
- docker build -t $TAG_LATEST -t $TAG_COMMIT .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $TAG_LATEST
- docker push $TAG_COMMIT
# stagingへデプロイ
staging:
stage: staging
image: alpine:latest
rules:
- if: $CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG == null
script:
- chmod 400 $GITLAB_KEY
- apk add openssh-client
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- ssh -i $GITLAB_KEY -o StrictHostKeyChecking=no $USER@$STAGING_TARGET "
docker pull $TAG_COMMIT &&
docker rm -f myapp || true &&
docker run -d -p 80:80 --name myapp $TAG_COMMIT"
environment:
name: staging
url: http://$STAGING_TARGET
# リリースの作成
release_job:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG
script:
- |
DEPLOY_TIME=$(date '+%Y-%m-%d %H:%M:%S')
CHANGES=$(git log $(git describe --tags --abbrev=0 @^)..@ --pretty=format:"- %s")
cat > release_notes.md << EOF
## デプロイ情報
- デプロイ日時:$DEPLOY_TIME
- 環境:本番環境
- バージョン:$CI_COMMIT_TAG
## 変更内容
$CHANGES
## アーティファクト
- コンテナイメージ:\`$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG\`
EOF
release:
name: 'Release $CI_COMMIT_TAG'
description: './release_notes.md'
tag_name: '$CI_COMMIT_TAG'
ref: '$CI_COMMIT_TAG'
assets:
links:
- name: 'コンテナイメージ'
url: '$CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG'
link_type: 'image'
# リリースタグ付きのバージョンを作成
version_job:
stage: version
image: docker:latest
services:
- docker:dind
rules:
- if: $CI_COMMIT_TAG
script:
- docker pull $TAG_COMMIT
- docker tag $TAG_COMMIT $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG
# 本番環境へデプロイ
production:
stage: production
image: alpine:latest
rules:
- if: $CI_COMMIT_TAG
script:
- chmod 400 $GITLAB_KEY
- apk add openssh-client
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- ssh -i $GITLAB_KEY -o StrictHostKeyChecking=no $USER@$PRODUCTION_TARGET "
docker pull $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG &&
docker rm -f myapp || true &&
docker run -d -p 80:80 --name myapp $CI_REGISTRY_IMAGE/main:$CI_COMMIT_TAG"
environment:
name: production
url: http://$PRODUCTION_TARGET
完成したパイプラインは
- mainブランチでの変更をレジストリに公開します
- mainブランチでの変更をstagingへデプロイします
- タグが作成された際にリリースを作成します
- リリースタグを付けたイメージを作成します
- タグを基に本番環境へデプロイします
主なメリット:
- クリーンで再現性のあるローカル開発およびテスト環境が完成します
- 構造化された本番環境へのデプロイフローにより、信頼性の高いデプロイを実現できます
- 予期しない障害からの復旧パターンを確立します
- より複雑なデプロイ戦略への拡張/導入に対応できます
ベストプラクティス
実装の際は、以下の原則を守りましょう:
- 変数の使用方法からデプロイ手順まで、すべてを文書化する
- GitLabのビルトイン機能(環境管理、リリース、レジストリ)を活用する
- 適切なアクセス制御とセキュリティ対策を実施する
- 強固なロールバック手順を計画し、障害に備える
- パイプラインの設定はDRY(Don't Repeat Yourself:重複を避ける)を意識する
デプロイ戦略をスケールさせる
次は何をすべきでしょうか?ここでは、継続的デプロイ戦略をさらに成熟させるために、検討すべきポイントを紹介します。
高度なセキュリティ対策
以下の方法でセキュリティを強化しましょう:
- アクセスを制限した保護環境を設定する
- 本番環境へのデプロイに承認を必須とする
- セキュリティスキャンをパイプラインに統合する
- 自動脆弱性評価を導入する
- デプロイ関連の変更に対するブランチ保護ルールを適用する
段階的なデリバリー戦略
以下のような高度なデプロイ戦略を実装しましょう。
- 機能フラグを活用して制御されたロールアウトを行う
- リスクを軽減するためにカナリアデプロイを実施する
- ブルーグリーンデプロイ戦略を導入する
- A/Bテストを実施する
- 動的環境管理を行う
モニタリングと最適化
強固なモニタリング体制を確立しましょう:
- デプロイ指標を追跡する
- パフォーマンスモニタリングをセットアップする
- デプロイアラートを設定する
- デプロイのサービスレベル目標(SLO)を確立する
- 定期的にパイプラインを最適化する
GitLabが選ばれる理由
GitLabの継続的デプロイ機能は、現代のデプロイワークフローに最適です。GitLabは、コンテナレジストリ、環境管理、デプロイ追跡などの機能が1つのインターフェースに集約されており、コードから本番環境へのプロセスを効率化します。また、環境ごとの変数、デプロイ承認ゲート、ロールバック機能を備えており、本番環境へのデプロイ時に求められるセキュリティと管理を実現します。さらに、Review Apps(レビューアプリ)や機能フラグを活用することで、段階的なデリバリー(プログレッシブデリバリー)戦略も可能です。GitLabのDevSecOpsプラットフォームの一部として、これらのCD機能はソフトウェアライフサイクル全体とシームレスに連携します。
無料トライアルで今すぐスタート!
継続的デプロイへの道のりは、革命ではなく進化のプロセスです。まずは基本を押さえ、しっかりとした基盤を築き、チームの成長に応じて徐々に高度な機能を取り入れていきましょう。GitLabは、最初の自動デプロイから、複数環境にまたがる複雑なデリバリーパイプラインまで、あらゆる段階でサポートするためのツールと柔軟性を提供します。
GitLab Ultimateの60日間無料トライアルで、今日から継続的デプロイメントを始めましょう。
監修:川瀬 洋平 @ykawase
(GitLab合同会社 カスタマーサクセス本部 シニアカスタマーサクセスマネージャー)