Omnibus-GitLabアーキテクチャとコンポーネント
Omnibus-GitLabは、ChefのOmnibusプロジェクトをカスタマイズしてフォークしたもので、CookbookやレシピのようなChefコンポーネントを使用して、ユーザのマシンでGitLabを設定するタスクを実行します。GitLab.com上のOmnibus-GitLabリポジトリは、Omnibus-GitLabに必要なすべてのコンポーネントをホストしています。 これには、設定やプロジェクトメタデータのようなパッケージをビルドするために必要なOmnibusの部分と、インストール後にユーザのマシンで使用されるChef関連のコンポーネントが含まれます。
これらのコンポーネントの詳細なビデオ・ウォークスルーはYouTubeでご覧いただけます。
ソフトウェアの定義
GitLab プロジェクト定義ファイル
オムニバス・アーキテクチャの主要なコンポーネントは、プロジェクトの詳細と外部ソフトウェアやライブラリとの依存関係をリスト化したプロジェクト定義ファイルです。
このプロジェクト定義ファイルの主な構成要素は以下の通りです:
- プロジェクトのメタデータ - 名前、説明など。
- プロジェクトのライセンス詳細。
- 依存関係リスト - GitLabをビルド/実行するために必要な外部ツールやソフトウェアのリストと、そのメタデータ。
- GitLabのインストールに使用されるグローバル設定変数 - インストールディレクトリ、システムユーザー、システムグループなど。
config/projects/gitlab.rb
.個別のソフトウェア定義
Omnibus-GitLabはバッテリーインクルードスタイルのディストリビューションに従っています。 GitLabインスタンスを適切に機能させるために必要なすべてのソフトウェア、ライブラリ、バイナリは、パッケージの一部として組み込み形式で提供されます。
オムニバス・アーキテクチャのもう一つの主要な構成要素は、ソフトウェアの定義とコンフィギュレーションです。 典型的なソフトウェア・コンフィギュレーションは4つの部分で構成されています:
- 必要なソフトウェアのバージョン
- ソフトウェアのライセンス
- ビルド/実行するソフトウェアの依存関係。
- ソフトウェアをビルドし、パッケージに組み込むために必要なコマンド。
セキュリティ脆弱性の修正、GitLabに必要な機能の追加、GitLabの他のコンポーネントとの連携など、GitLabで使用するためにソフトウェアのソースコードにパッチを適用する必要がある場合があります。 この目的のために、Omnibus-GitLabにはパッチディレクトリがあり、さまざまなソフトウェアのパッチが格納されています。
より広範な変更については、ミラー上のブランチで必要な変更を追跡する方が便利な場合があります。 この場合、上流のタグからブランチを作成するか、ブランチ名でそのブランチポイントを参照する sha を使用します。 Omnibus コードベースの例として、gitlab-omnibus-v5.6.10
は上流プロジェクトのv5.6.10
タグに基づいています。これにより、https://gitlab.com/gitlab-org/omnibus/compare/v5.6.10...gitlab-omnibus-v5.6.10
のような比較リンクを生成して、ローカルでの変更を特定することができます。
GitLab グローバル設定テンプレート
Omnibus-GitLabには、ユーザーのマシンにインストールされるGitLabインスタンスの各部分を設定するために使用できる単一の設定ファイルが同梱されています。 この設定ファイルは、GitLabインスタンスに適用されるすべての設定設定の標準的なソースとして機能します。 このファイルには、GitLabインスタンスの一般的な設定だけでなく、さまざまなコンポーネントのさまざまなオプションが記載されています。 このファイルの一般的な構造は、<component>['<setting>'] = <value>
の形式で指定された設定で構成されています。 利用可能なオプションはすべてテンプレートに記載されていますが、GitLabの基本的な動作に必要なもの以外はデフォルトでコメントアウトされています。 ユーザーは必要に応じてコメントを解除し、対応する値を指定することができます。
files/gitlab-config-template/gitlab.rb.template
.GitLab クックブック
前述したように、Omnibus-GitLabはCookbook、アトリビュート、リソースなどのChefコンポーネントの多くを使用しています。 GitLab EEは、GitLab CEが使用しているCookbookを拡張し、EE専用のコンポーネントを追加した別のCookbookを使用しています。 Omnibus-GitLabのChef関連部分の主なプレイヤーは以下のとおりです:
デフォルト属性
デフォルト属性は、その名前が示すように、設定ファイルで提供されるさまざまな設定に対するデフォルト値を指定します。 これらの値はフェイルセーフとして機能し、ユーザーが設定に値を提供しなかった場合に使用されます。したがって、必要最小限のユーザーによる微調整で GitLab インスタンスを動作させることができます。
files/gitlab-cookbooks/gitlab/attributes/default.rb
.レシピ
Omnibusパッケージを使ってGitLabをインストールする際に、レシピはGitLabエコシステムの各コンポーネントをユーザーのマシンにセットアップする役割を担っています。 必要なファイル、ディレクトリ、リンクを対応する場所に作成し、権限とオーナーを設定し、必要なサービスを設定、起動、停止し、対応するファイルが変更されたときにこれらのサービスに通知するなどです。default
というマスターレシピがエントリポイントとして機能し、様々なコンポーネントやサービスに必要な他のすべてのレシピを呼び出します。
files/gitlab-cookbooks/gitlab/recipes
フォルダにあります。定義
定義は、レシピ間で利用可能なグローバルレベルのマクロと考えることができます。 定義の一般的な用途としては、共通のサービスに使用されるポートの定義、異なるレシピで使用される可能性のある重要なディレクトリのリストなどがあります。
files/gitlab-cookbooks/gitlab/definitions
フォルダにあります。コンポーネントの設定用テンプレート
前述したように、Omnibus-GitLabはGitLabインスタンスのすべてのコンポーネントを調整するための単一の設定ファイルを提供します。 しかし、異なるコンポーネントのアーキテクチャ設計では、特定の場所に個別の設定ファイルを置く必要がある場合があります。 これらの設定ファイルは、一般的な設定ファイルでユーザーが指定した値、または指定されたデフォルト値のいずれかから生成する必要があります。 したがって、Omnibus-GitLabは、デフォルト値またはユーザーからの値で埋めることができるプレースホルダを持つ、そのような設定ファイルのテンプレートを同梱しています。 レシピは、それらを埋めて必要な場所に配置することによって、これらのテンプレートを完成させるジョブを行います。
files/gitlab-cookbooks/gitlab/templates
フォルダにあります。一般的なライブラリのメソッド
Omnibus-GitLabには、主にコードの再利用を目的としたライブラリメソッドもいくつか同梱されています。 これには、サービスが稼働しているかどうかをチェックするメソッド、ファイルが存在するかどうかをチェックするメソッド、異なるコンポーネントとやりとりするためのヘルパーメソッドなどが含まれ、これらはChefレシピでよく使われます。
Omnibus-GitLabで使われるライブラリの中で、いくつか特別なものがあります:プライマリGitLabモジュールと、それが呼び出すすべてのコンポーネント固有のライブラリです。 コンポーネント固有のライブラリには、対応するコンポーネントに定義された設定のために設定ファイルをパースする仕事をするメソッドが含まれています。 プライマリGitLabモジュールには、これを調整するメソッドが含まれています。 デフォルト値の識別、コンポーネント固有のライブラリの呼び出し、デフォルト値とユーザー指定値のマージ、それらの検証、初期値に基づく追加の設定の生成などを担当します。Omnibus-GitLabパッケージによって出荷されるすべてのトップレベルのコンポーネントはこのモジュールに追加され、設定ファイルやデフォルト属性に記載され、正しくパースされるようになります。
files/gitlab-cookbooks/gitlab/libraries
フォルダにあります。ランイット
GitLabはサービス管理と監視の目的でrunitレシピを使用しています。runitレシピはOSによって使用されるinitシステムを特定するジョブを行い、GitLabに必要なサービスファイルの作成、サービスの有効化、サービスのリロードなどの基本的なサービス管理タスクを実行します。runitは、他のレシピがサービスと相互作用するために使用できるrunit_service
定義を提供します。 (/files/gitlab-cookbook/runit
)
サービス
サービスとは、runitプロセスのinit/supervisorを使用して実行するソフトウェアプロセスです。gitlab-ctl
コマンドを使用して、それらのステータスを確認し、起動、停止、再起動することができます。レシピは、プロセスグループとGitLabのインスタンスに設定された設定/ロールに基づいて、これらのサービスを無効にしたり有効にしたりすることもできます。サービスのリストとそれらに関連するサービスグループは、files/gitlab-cookbooks/package/libraries/config/services.rb
にあります。
gitlab-ctl
その他のコマンド
Omnibusにはデフォルトで、GitLabインスタンスを管理するためのgitlab-ctl reconfigure
、gitlab-ctl restart
などのラッパーコマンドが用意されています。Omnibus-GitLabリポジトリで定義されている特定のユースケースをターゲットにした追加のラッパーコマンドがいくつかあります。これらのコマンドは、データベースの移行や休止アカウントの削除など、あまり一般的ではないタスクを実行するために、一般的なgitlab-ctl
コマンドと一緒に使用されます。
files/gitlab-ctl-commands
フォルダにあります。テスト
Omnibus-GitLabリポジトリはChefSpecを使用して、出荷するクックブックとレシピをテストします。 通常の戦略は、レシピが2つ(またはそれ以上)の条件で正しく動作するかどうかをチェックすることです: ユーザが対応する設定を何も指定しない場合(すなわちデフォルトが使用される場合)と、ユーザが指定した設定が使用される場合です。 テストには、ファイルが正しい場所に生成されるかどうか、サービスが開始/停止/通知されるかどうか、正しいバイナリが呼び出されるかどうか、メソッド呼び出しに正しいパラメータが渡されるかどうか、などをチェックすることが含まれます。 Omnibus-GitLabはまた、テストプロセスを支援するためにいくつかのサポートメソッドやマクロを使用します。 テストは、可能な限り並列化に対応して定義され、テストスイート全体を実行するのに必要な時間を短縮します。
ですから、上記のコンポーネントのうち、いくつか(ソフトウェア定義、プロジェクトメタデータ、テストなど)はパッケージのビルド中、ビルド環境で使われ、いくつか(Chefクックブックとレシピ、GitLab設定ファイル、runit、gitlab-ctl
コマンドなど)はユーザのインストールしたインスタンスを設定するために使われます。
Omnibus-GitLabのワークライフサイクル
パッケージ構築中に起こること
ビルドされるパッケージの種類は、ビルドプロセスが実行される OS によって異なります。 Debian 環境でビルドが行われる場合、.deb
パッケージが作成されます。 パッケージのビルド中に行われることは、以下のステップにまとめることができます。
- 依存関係ソフトウェアのソースを取得します:
- ソフトウェアの定義を解析し、対応するバージョンを調べます。
- リモートやキャッシュからのソースコードの取得。
- 個々のソフトウェアコンポーネントの構築
- 必要な環境変数とフラグの設定。
- 該当する場合は、パッチを適用します。
- コンポーネントのビルドとインストールを行い、適切な場所(
/opt/gitlab
内部)にインストールします。
- 外部ソフトウェア、Ruby gems、JSモジュールなどを含む、バンドルされているすべてのコンポーネントのライセンス情報を生成します。これには、コンポーネントによって提供される追加のライセンス文書(GitLab Railsによって提供される
licenses.csv
ファイルのような)と同様に、各依存関係の定義を分析する必要があります。 - コンポーネントのライセンスをチェックし、互換性のないライセンスでコンポーネントを出荷していないことを確認します。
- パッケージのヘルスチェックを実行し、バイナリが利用可能なライブラリに対してリンクされていることを確認します。 バンドルされているライブラリの場合、バイナリはグローバルに利用可能なライブラリではなく、それらのライブラリに対してリンクする必要があります。
-
/opt/gitlab
の内容でパッケージをビルドします。 これはgitlab.rb
ファイルの内部で指定されたメタデータを利用します。 メタデータにはパッケージ名、バージョン、メンテナー、ホームページ、他のパッケージとの競合に関する情報などが含まれます。
キャッシュ
Omnibus は、ビルドプロセスを最適化するために 2 種類のキャッシュを使用します。1 つはソフトウェアアーティファクト (依存するソフトウェアのソース) を保存するためのもので、もう 1 つは各ソフトウェアコンポーネントがビルドされた後のプロジェクトツリーを保存するためのものです。
ソフトウェアアーティファクトキャッシュ(GitLab Incビルド用)
ソフトウェアアーティファクトキャッシュは、依存するソフトウェアのソースを格納するためにAmazon S3バケットを使用します。ビルドプロセスでは、このキャッシュはコマンドbin/omnibus cache populate
を使用して入力されます。 これは、Amazonバケットから必要なすべてのソフトウェアソースを取り込み、必要な場所に格納します。 ソフトウェアのバージョン要件に変更があった場合、omnibusは元のアップストリームからそれを取得し、アーティファクトキャッシュに追加します。 このプロセスはomnibus内部で行われ、リポジトリのルートにあるomnibus.rbファイルを使用するようにAmazonバケットを設定します。 このキャッシュは、元のアップストリームリモートがダウンしても、依存するソフトウェアの可用性を保証します。
キャッシュの構築
A second type of cache that plays an important role in our build process is the build cache. Build cache can be described in simple words as snapshots of the project tree (where the project actually gets built -/opt/gitlab
) after each dependent software is built. To understand it easily, consider a project with 5 dependent softwares - A, B, C, D and E, built in that order. For simplicity, we are not considering the dependencies of these individual softwares. Build cache makes use of Git tags to make snapshots. After each software is built, a Git tag is computed and committed. Now, consider we made some change to the definition of software D. A, B, C and E remains the same. When we try to build again, omnibus can reuse the snapshot that was made before D was built in the previous build. Thus, the time taken to build A, B and C can be saved as it can simply checkout the snapshot that was made after C was built. Omnibus uses the snapshot just before the software which “dirtied” the cache (dirtyi
このキャッシュが意味を持つのは、ビルドをまたいで保持される場合だけです。 そのために、GitLab CI のキャッシュ機構を使います。私たちは、内部キャッシュを Amazon バケットに保存するように設定された専用のランナーを持っています。 各ビルドの前に、このキャッシュを取り込み ( Makefile 内のrestore_cache_bundle
target)、適切な場所に移動してビルドを開始します。 ダーティになるまで Omnibus によって使用されます。 ビルドの後、新しいキャッシュをパックし、それを Amazon バケットにバックアップするように CI に指示します ( Makefile 内のpack_cache_bundle
)。
どちらのキャッシュもGitLabの全体的なビルド時間を短縮し、外部要因への依存を減らします。
キャッシュの仕組みは次のように要約できます:
- 各ソフトウェアの依存関係
- バージョンとSHA256を理解するために定義を解析します。
- AmazonバケットのアーティファクトキャッシュにあるソースファイルのtarballがバージョンとSHA256に一致する場合、それを使用します。
- そうでない場合は、アップストリームリモートから正しいtarボールをダウンロードしてください。
- CIキャッシュからビルドキャッシュを取得します。
- 各ソフトウェアの依存関係
- キャッシュが汚れている場合は、ループを解除します。
- そうでなければ、スナップショットをチェックしてください。
- 依存関係が残っている場合
- 残りの依存関係について
- 依存関係を構築します。
- スナップショットを作成し、コミットします。
- 残りの依存関係について
- 新しいビルドキャッシュをCIキャッシュにプッシュバックします。
何が起こっているのかgitlab-ctl reconfigure
GitLabインスタンスを管理する際によく使われるコマンドの一つに、gitlab-ctl reconfigure
があります。このコマンドは、簡単に言うと、設定ファイルを解析し、そこから供給された値でレシピを実行します。実行されるレシピは、インストールディレクトリ内のembedded
フォルダに存在するdna.json
というファイルで定義されます(このファイルは、ソフトウェア定義で定義されるgitlab-cookbooks
というソフトウェアの依存関係によって生成されます)。 GitLab CEの場合、gitlab
というクックブックがマスターレシピとして選択され、runitを含む他のすべての必要なレシピが呼び出されます。 要するに、reconfigureは基本的に、設定テンプレートで提供された値でさまざまなファイルやサービスを設定するchef-clientの実行です。