毎日、GitLabは世界最大のGitLabインスタンスであるGitLab.comにコード変更を最大12回、ダウンタイムなしでデプロイしています。これらのデプロイ管理には、GitLab独自のCI/CDプラットフォームを使用しており、世界中の数百万人のデベロッパーに影響を与えています。このデプロイ頻度は、私たちの主要な品質基準とストレステストとして機能しています。また、お客様は数週間や数か月待つことなく、開発から数時間以内で新機能にアクセスできるようになります。組織がDevOpsワークフローにGitLabを利用する場合、私たち自身のインフラストラクチャで大規模に実証されたプラットフォームを使用していることになります。この記事では、このデプロイの複雑さを処理するために、GitLab CI/CDのコア機能を使用して自動化されたデプロイパイプラインを構築した方法をご紹介します。
デプロイ速度がもたらすビジネスケース
当社の実践から見えるもの:私たちのデプロイ頻度は単なるエンジニアリング指標ではなく、ビジネス上の必須要件です。迅速なデプロイサイクルにより、お客様からのフィードバックに数時間以内に対応し、セキュリティパッチを即座に提供し、新機能を本番環境で検証してからスケールすることができます。
お客様が得られる価値:GitLab.comへのすべてのデプロイは、ユーザーに推奨するデプロイプラクティスを検証しています。GitLabのデプロイ機能を使用する場合、数百万のgit操作、CI/CDパイプライン、ユーザーインタラクションを日々処理する実証済みのアプローチを使用していることになります。以下のメリットがあります:
- 最新機能が即座に利用可能:新しい機能は四半期ごとのリリースサイクルではなく、完成してから数時間以内に提供されます
- 大規模環境で実証された信頼性:機能がGitLab.comで動作すれば、お客様の環境でも信頼できます
- GitLabの完全な価値:ゼロダウンタイムデプロイにより、更新中でもDevOpsプラットフォームへのアクセスが失われることはありません
- 実環境でテストされたプラクティス:当社のデプロイドキュメントは理論ではなく、世界最大のGitLabインスタンスを実際に運用する方法そのものです
コードフローアーキテクチャ
デプロイパイプラインは、複数のステージを経て構造化された進行に従います。各ステージは、コード提案から本番環境へのデプロイまでの過程におけるチェックポイントとして機能します。
graph TD
A[コード提案] --> B[マージリクエスト作成]
B --> C[パイプライントリガー]
C --> D[ビルド & テスト]
D --> E{スペック/統合/QAテスト合格?}
E -->|いいえ| F[フィードバックループ]
F --> B
E -->|はい| G[デフォルトブランチへマージ]
G -->|定期的| H[Auto-Deployブランチ]
subgraph "デプロイパイプライン"
H --> I[パッケージ作成]
I --> K[Canary環境]
K --> L[QA検証]
L --> M[main環境]
end
デプロイパイプラインの構成
デプロイアプローチでは、GitLabのネイティブCI/CD機能を使用して、ハイブリッドインフラストラクチャ全体で複雑なデプロイを調整します。 その実装方法をご紹介します。
ビルド
GitLabのビルドは、それ自体が複雑なトピックであるため、ここでは概要レベルで説明します。
OmnibusパッケージとCloud Native GitLab(CNG)イメージの両方をビルドします。OmnibusパッケージはGitalyフリート(Gitストレージレイヤー)にデプロイされ、CNGイメージは他のすべてのコンポーネントをコンテナ化されたワークロードとして実行します。PostgresやRedisなどの他のステートフルサービスは非常に大規模になったため、専任チームが個別に管理しています。GitLab.comの場合、これらのシステムはAuto-Deploy手順中にはデプロイされません。
gitlab-org/gitlabを定期的に確認し、デフォルトブランチで成功した(「グリーン」)パイプラインを持つ最新のコミットを検索するスケジュールされたパイプラインがあります。グリーンパイプラインは、GitLabのすべてのコンポーネントが包括的なテスト群に成功したことを示します。次に、そのコミットからauto-deployブランチを作成します。
これにより一連のイベントがトリガーされます。主に、このパッケージとモノリスの一部であるすべてのコンポーネントをビルドする必要があります。 別のスケジュールされたパイプラインが、最新のビルドされたパッケージを選択し、デプロイパイプラインを開始します。手順としては、このようにシンプルに見えます:
graph LR
A[ブランチ作成] --> B[ビルド]
B --> C[ビルドされたパッケージを選択]
C --> D[デプロイパイプラインを開始]
ビルドには時間がかかり、さまざまな状況によりデプロイが変動する可能性があるため、最新のビルドをデプロイするように選択しています。技術的には、実際にデプロイされるよりも多くのGitLabのバージョンを.com用にビルドしています。これにより、常に準備が整ったパッケージが用意され、.comに対して完全に継続的にデリバリーされる製品に最も近い状態を実現できます。
環境ベースの検証とCanary戦略
品質保証(QA)は単なる後付けではなく、開発からデプロイまでのすべてのレイヤーに組み込まれています。QAプロセスでは、ユニットテスト、統合テスト、GitLabの機能との実際のユーザーインタラクションをシミュレートするエンドツーエンドテストを含む自動化されたテスト群を活用しています。しかし、デプロイパイプラインにとってさらに重要なのは、QAプロセスが環境ベースの検証を通じてCanary戦略と密接に連携していることです。
検証アプローチの一環として、GitLabのネイティブCanaryデプロイを活用し、完全な本番環境へのデプロイ前に、限定されたトラフィックで変更を制御しながら検証できるようにしています。すべてのトラフィックの約5%をCanaryステージに送信しています。このアプローチはデータベースマイグレーションの複雑性を高めますが、Canaryデプロイを成功させることで、信頼性の高い製品をシームレスにデプロイすることができます。
GitLabで使用するCanaryデプロイ機能は、本番環境における最も複雑なデプロイメントシナリオの管理を通じて改良されたものです。アプリケーション用にCanaryデプロイを実装する場合、大規模環境で実証済みのパターンを使用していることになります。
当社のデプロイプロセスは、段階的ロールアウト戦略に従います:
- ステージング環境 Canary: 初期検証環境
- 本番環境 Canary: 限定された本番トラフィック
- ステージング環境 main: ステージング環境への完全デプロイ
- 本番環境 main: 本番環境への完全ロールアウト
graph TD
C[ステージング環境 Canaryデプロイ]
C --> D[QA スモーク main Testステージ]
C --> E[QA スモーク Canary Testステージ]
D --> F
E --> F{テスト合格?}
F -->|はい| G[本番環境 Canary デプロイ]
G --> S[QA スモーク main Testステージ]
G --> T[QA スモーク Canary Testステージ]
F -->|いいえ| H[イシュー作成]
H --> K[修正&バックポート]
K --> C
S --> M[Canary トラフィック監視]
T --> M[Canary トラフィック監視ベイク期間]
M --> U[本番環境安全性チェック]
U --> N[ステージング環境 main]
N --> V[本番環境 main]
QA検証は、この段階的デプロイプロセス全体の複数のチェックポイントで行われます。各Canaryデプロイ後、そしてデプロイ後のマイグレーション実施後に再度検証を行います。この多層的なアプローチにより、デプロイ戦略の各フェーズに独自のセーフティーネットが確保されます。GitLabの包括的なテスト手法については、ハンドブックで詳しく説明しています。
デプロイパイプライン
デプロイパイプライン全体で対処している課題についてご紹介します。
技術アーキテクチャに関する考慮事項
GitLab.comは、大規模な実環境でのデプロイの複雑性を体現しています。既知の最大規模のGitLabインスタンスとして、デプロイには公式のGitLab HelmチャートとLinuxパッケージを使用しており、これらはお客様が使用するものと同じアーティファクトです。GitLab.comアーキテクチャについては、ハンドブックで詳しく説明しています。このハイブリッドアプローチにより、デプロイパイプラインは同一のデプロイサイクルでコンテナ化されたサービスと従来のLinuxサービスの両方をインテリジェントに処理する必要があります。
大規模なドッグフーディング: ゼロダウンタイムのアップグレード用にドキュメント化したものと同じ手順を使用してデプロイしています。もし私たちにとってスムーズに機能しないものがあれば、お客様にも推奨しません。この自己規律により、デプロイツールの継続的な改善が促進されています。
すべての環境とステージのアップグレードで、以下のステージが実行されます:
graph LR
a[Prep] --> c[通常 Migrations - Canaryステージのみ]
a --> f[Assets - Canaryステージのみ]
c --> d[Gitaly]
d --> k8s
subgraph subGraph0["VMワークロード"]
d["Gitaly"]
end
subgraph subGraph1["Kubernetesワークロード"]
k8s["k8s"]
end
subgraph fleet["フリート"]
subGraph0
subGraph1
end
ステージの詳細:
- Prep: デプロイの準備状況を検証し、デプロイ前のチェックを実行します
- Migrations: データベースの通常マイグレーションを実行します。これはCanaryステージでのみ実行されます。Canaryステージとmainステージは同じデータベースを共有しているため、mainステージのデプロイ時にはこれらの変更がすでに利用可能であり、タスクを繰り返す必要はありません。
- Assets: すべての静的アセットにGCSバケットを活用しています。新しいアセットが作成された場合、バケットにアップロードし、Canaryステージですぐに利用できるようにします。アセットにWebPackを活用し、アセットの命名にSHAを適切に活用しているため、古いアセットを上書きする心配はありません。したがって、古いアセットは古いデプロイで引き続き利用可能であり、新しいアセットはCanaryがデプロイを開始するとすぐに利用可能になります。これはCanaryステージのデプロイ中にのみ実行されます。Canaryステージとmainステージは同じアセットストレージを共有しているため、mainステージのデプロイ時にはこれらの変更はすでに利用可能です。
- Gitaly: 各GitalyノードでOmnibus LinuxパッケージによりGitaly仮想マシンスのトレージレイヤーを更新します。このサービスは
gitとバンドルされているため、特殊です。したがって、このサービスがアトミックアップグレードを実行可能かを確認する必要があります。Gitalyのラッパーを活用し、新しいバージョンのGitalyをインストールし、ライブラリtableflipを使用しすることで、実行中のGitalyをクリーンにローテーションし、各インスタンスでこのサービスの高可用性を確保しています。 - Kubernetes: Helmチャートを使用してコンテナ化されたGitLabコンポーネントをデプロイします。冗長性のために複数のゾーンにまたがる多数のクラスターにデプロイするため、通常これらは被害を最小限に抑えるために個別のステージに分割され、重大な問題が検出された場合はデプロイを途中で停止できるようにしています。
マルチバージョン互換性:隠れた課題
プロセスを読むと、データベーススキーマがmainステージが認識しているコードより先行している期間があることに気付くでしょう。これは、Canaryステージが既に新しいコードをデプロイし、通常のデータベースマイグレーションを実行しているが、mainステージはまだこれらの新しいデータベース変更を認識していない以前のバージョンのコードを実行しているために発生します。
実際の例: マージリクエストに新しいmerge_readinessフィールドを追加するとします。デプロイ中、一部のサーバーはこのフィールドを期待するコードを実行していますが、他のサーバーはまだその存在を認識していません。これを適切に処理しないと、数百万人のユーザーが使用するGitLab.comが壊れてしまいます。適切に処理すれば、誰も何が起こったか気付きません。
これは他のほとんどのサービスでも発生します。たとえば、クライアントが複数のリクエストを送信する場合、そのうちの1つがCanaryステージに到達する可能性があります。他のリクエストはmainステージに向けられる可能性があります。これはデプロイとそれほど変わりません。サービスを実行している数千のPodを通過するのにかなりの時間がかかるためです。
いくつかの例外を除いて、サービスの大部分は、Canaryでそのコンポーネントのわずかに新しいバージョンを一定期間実行します。ある意味では、これらのシナリオはすべて一時的な状態です。しかし、ライブの本番環境では数時間または数日間持続することがよくあります。したがって、永続的な状態と同じように注意を払って扱う必要があります。どのデプロイ中も、複数のバージョンのGitLabが同時に実行されており、それらすべてが適切に連携する必要があります。
データベース操作
データベースマイグレーションは、Canaryデプロイモデルにおいて独特の課題を提示します。新機能をサポートするためのスキーマ変更が必要な一方で、問題が発生した場合のロールバック機能を維持する必要があります。当社のソリューションでは、懸念を慎重に分離しています:
- 通常マイグレーション: Canaryステージ中に実行され、後方互換性を持つように設計され、可逆的な変更のみで構成されます
- デプロイ後マイグレーション: 複数の成功したデプロイ後にのみ実行される「ポイント・オブ・ノーリターン」マイグレーション
データベース変更は、正確さと広範な検証手順により処理されます:
graph LR
A[通常マイグレーション] --> B[Canaryステージデプロイ]
B --> C[mainステージデプロイ]
C --> D[デプロイ後マイグレーション]
デプロイ後マイグレーション
GitLabのデプロイには多くのコンポーネントが関与します。GitLabの更新はアトミックではないため、多くのコンポーネントが後方互換性を持つ必要があります。
デプロイ後マイグレーションには、簡単にロールバックできない変更(データ変換、カラムの削除、または古いコードバージョンを壊す構造的変更など)が含まれることがよくあります。複数の成功したデプロイを通じて信頼を得た_後_にそれらを実行することで、次を保証します:
- 新しいコードが安定しているため、ロールバックが必要になる可能性が低い
- パフォーマンス特性が本番環境で十分に理解されている
- エッジケースが発見され対処されている
- 問題が発生した場合に影響範囲が最小限に抑えられる
このアプローチは最適なバランスを提供します。Canaryリリースによる迅速な機能デプロイを可能にしながら、デプロイの安定性に高い信頼を得るまでロールバック機能を維持します。
拡張-移行-縮小パターン: データベース、フロントエンド、アプリケーション互換性の変更は、慎重に調整された3段階のアプローチに従います。
- 拡張: 古い構造を機能させたまま、新しい構造(カラム、インデックス)を追加
- 移行: 新しい構造を使用する新しいアプリケーションコードをデプロイ
- 縮小: すべてが安定した後、デプロイ後マイグレーションで古い構造を削除
実際の例: マージリクエストに新しいmerge_readinessカラムを追加する場合:
- 拡張: デフォルト値を持つ新しいカラムを追加。既存のコードはそれを無視
- 移行: 古いアプローチをサポートしながら、新しいカラムの読み書きを行うコードをデプロイ
3 縮小: 複数の成功したデプロイの後、デプロイ後マイグレーションで古いカラムを削除
すべてのデータベース操作、アプリケーションコード、フロントエンドコードなどは、エンジニアリングが遵守する必要がある一連のガイドラインの対象となります。これらはマルチバージョン互換性ドキュメントで確認できます。
結果と影響
デプロイインフラストラクチャは測定可能なメリットを提供します:
GitLabにとって
- GitLab.comへの1日最大12回のデプロイ
- 数百万人のデベロッパーにサービスを提供するダウンタイムゼロのデプロイ
- セキュリティパッチを数日ではなく数時間以内で本番環境に提供可能
- 一般公開前に大規模な本番環境で検証された新機能
お客様にとって
- 独自のアプリケーションに採用できる実証済みのデプロイパターン
- お客様の環境に到達する前に、世界最大のGitLabインスタンスで実証された機能
- 理論的なベストプラクティスではなく、実際の本番環境のプラクティスを反映したドキュメント
- GitLabの推奨アップグレード手順が、あらゆる規模で機能するという確信
エンジニアリングチームへの重要なポイント
GitLabのデプロイパイプラインは、デプロイ速度と運用の信頼性のバランスをとる洗練されたシステムを表しています。段階的デプロイモデル、包括的なテスト統合、堅牢なロールバック機能により、大規模な信頼性の高いソフトウェア配信の基盤を提供します。
同様のシステムを実装するエンジニアリングチームにとって、次のような重要な考慮事項があります:
- 自動テスト: デプロイパイプライン全体にわたる包括的なテストカバレッジ
- 段階的ロールアウト: リスクを最小限に抑え、迅速な復旧を可能にする段階的デプロイ
- 監視統合: すべてのデプロイステージにわたる包括的な可観測性
- インシデント対応: デプロイ問題の迅速な検出と解決能力
GitLabのアーキテクチャは、最新のCI/CDシステムが競争力のあるソフトウェア開発に必要な速度を維持しながら、大規模デプロイの複雑性を管理する方法を実証しています。
対象範囲に関する重要な注意事項
この記事では、特にGitLab OmnibusパッケージとHelmチャートの一部であるサービス(基本的にコアGitLabモノリスとその緊密に統合されたコンポーネント)のデプロイパイプラインについて具体的に説明しています。
ただし、GitLabのインフラストラクチャの範囲は、ここで説明されている内容を超えて広がっています。他のサービス、特にAIサービスや概念実証段階にあるサービスは、Runwayと呼ばれる内部プラットフォームを使用した異なるデプロイアプローチに従っています。
これらの他のサービスで作業している場合、または興味がある場合は、Runwayドキュメントで詳細情報を確認できます。
GitLab Dedicatedなどの他のサービスは、お客様がGitLab Environment Toolkitを使用して、お客様自身で実行できることを期待する内容により沿った形でデプロイされます。詳細については、GitLab Environment Toolkitプロジェクトをご覧ください。
この記事で概説されているデプロイ戦略、アーキテクチャに関する考慮事項、パイプラインの複雑性は、コアプラットフォームで使用している実証済みのアプローチを表していますが、大規模なエンジニアリング組織と同様に、さまざまなサービスタイプと成熟度レベルに合わせた複数のデプロイ戦略があります。
Auto-Deployと手順に関する詳細なドキュメントは、以下のリンクで確認できます:




