開発ガイドラインのアップロード
アップロードはGitLabの多くの機能にインテグレーションされています。GitLabがどのようにアップロードを扱うかを理解するために、このページではファイルをストレージに転送する主な仕組みの概要を説明します。
GitLabのアップロードは機能ごとに設定されます。アップロードに関わる全ての機能は同じ設定オプションを提供しますが、互いに独立して設定することができます。例えば、Git LFSアップロードはCI/CDビルドアーティファクトアップロードとは独立して設定できますが、どちらも同じ設定キーのセットを提供します。これらの設定は、アップロードがどのように処理されるかを管理し、パフォーマンスやスケーラビリティに劇的な影響を与えます。
このページでは、このようなファイルの処理方法を決定する上で重要なアップロード設定を要約します。その後に続くセクションでは、これらのメカニズムそれぞれについて詳しく説明します。
アップロード設定がアップロードフローを駆動する方法
個々のアップロード戦略を詳しく検討する前に、どのアップロード設定がこれらの各戦略に対応するのか、ハイレベルな内訳を検討しましょう。
アップロードの設定そのものはUploads administrator で説明されています。ここでは、これらの設定が GitLab のアップロードロジックの内部をどのように動かすかに焦点を当てます。トップレベルでは、アップロードされたファイルの行き先を2つに分けています:
- ローカルストレージ - ファイルはウェブサーバノードに接続されたボリュームに保存されます。
- オブジェクトストレージ - ファイルはリモートのオブジェクトストアバケットに保存されます。
この表で、x.y.z
はgitlab.yml
を経由するパスを指定します:
設定 | 値 | 動作 |
---|---|---|
<feature>.object_store.enabled | false | ファイルは<feature>.storage_path
|
<feature>.object_store.enabled | true | ファイルはリモートで<feature>.object_store.remote_directory
|
オブジェクトストレージを使用する場合、管理者はこれらのファイルをそれぞれのバケットに移動する方法を制御することができます。この移動は、以下のいずれかの方法で行われます:
個々のSidekiqワーカーはオブジェクトストレージにファイルを保存することもできます。
最後に、Workhorseはアップロードバッファリングメカニズムを使用してユーザーによるアップロードのほとんどを支援し、Railsコントローラから遅い作業を排除します。このメカニズムについては、Workhorseによるアップロード支援で説明します。
次に、それぞれのケースを詳しく見ていきます。
ローカル・ストレージ
ローカルストレージは、アップロードが取ることができる最も単純な経路です。GitLabが初期にアップロードを扱っていた方法です。Rails アプリケーションからstorage_path
にアクセスできるストレージボリューム (ディスクやネットワーク接続ストレージなど) を想定しています。このファイルパスはRailsのルートディレクトリからの相対パスで、他のアップロード設定と同様に機能ごとに設定可能です。
クライアントがファイルアップロードを送信すると、Workhorseはまずファイルをディスクにバッファリングします。リクエストがRailsアプリケーションに到達したとき、ファイルはすでにローカルストレージに存在しているので、Railsはそれを指定されたディレクトリに移動してトランザクションを完了させるだけです。
ローカルストレージはクラウドネイティブのGitLab(CNG) インストールでは使用できません。そのため、GitLab SaaSでも使用されません。
オブジェクトストレージ
水平方向にスケーラブルなストレージを提供するには、次のようなオブジェクトストア・プロバイダを使用する必要があります:
- Amazon AWS。
- Google Cloud Storage(GCS).
- Azure Cloud Storage。
オブジェクトストレージを使用すると、主に2つの利点があります:
- ストレージ容量の追加が容易:クラウドプロバイダーが自動的に行ってくれます。
- GitLabインストールの水平スケーリングが可能:複数のGitLabアプリケーションサーバーがオブジェクトストレージに保存された同じデータにアクセスできます。
GitLab SaaSを含むCNGインストールは常にオブジェクトストレージ(GitLab SaaSの場合はGCS。)
リモートオブジェクトストアへのアップロードの課題は、GitLabからオブジェクトストア・プロバイダへのHTTPリクエストの送信です。上述したように、このHTTPリクエストの送信方法には3つの異なる戦略があります。
Railsコントローラのアップロード
直接アップロードできない場合、Railsはコントローラcreate
アクションの一部としてファイルをオブジェクトストレージにアップロードします。どのコントローラが担当するかは、アップロードされるファイルの種類によって異なります。
Railsコントローラのアップロードは、ローカルストレージへのアップロードとよく似ています。主な違いはRailsはオブジェクトストアにHTTPリクエストを送信する必要があります。これはCarrierWave Fogアップローダを介して行われます。
ローカルストレージの場合と同様に、この戦略ではWorkhorseの支援により、コストのかかるI/O作業の一部をRubyやRailsから排除することができます。ダイレクトアップロードは、オブジェクトストレージへのHTTP PUTリクエストをPumaの外部に保持するため、より優れたジョブです。
この戦略は、Pumaの60秒のリクエストタイムアウトが適用されるため、小さなファイルのアップロードにのみ適しています。
直接アップロード
GitLab SaaSのようなCNGインストールで、大きなファイルをオブジェクトストレージに移動するにはダイレクトアップロードが推奨されています。
ダイレクトアップロードを有効にすると、Workhorse:
- でリクエストの作成者を認証します。
- オブジェクトストア自身との接続を確立し、ファイルを一時的な場所に転送します。
- 転送が完了すると、WorkhorseはRailsとのリクエストを確定します。Railsはオブジェクトストアのコピーオペレーションをイシューして、ファイルを最終的な場所に置きます。
- オブジェクトストレージ内の一時ファイルを削除してアップロードを完了します。
この戦略は、Workhorse アシスタンスとは異なる形式です。WorkhorseとPumaの両方がアクセスできる共有ストレージには依存しません。
既存のすべてのアップロード戦略の中で、直接アップロードは大規模(ギガバイト)なアップロードを処理するのに最も適しています。しかし、Pumaは依然としてオブジェクトストレージのコピーオペレーションを行い、アップロードのサイズに比例して時間がかかるため、Pumaのタイムアウトにぶつかる可能性が残っています。
Workhorseアシストアップロード
ほとんどのアップロードは何らかの形でWorkhorseの支援を受けています。
- 多くの場合、Workhorseはアップロードを一時ファイルにバッファリングします。Workhorseはリクエストにメタデータを追加して、一時ファイルの名前と場所をPumaに伝えます。そのため、WorkhorseとPumaの間で一時ストレージを共有する必要があります。すべてのGitLabインストール(CNGを含む)にはこの共有テンポラリストレージがあります。
- Workhorseはファイルを前処理することがあります。例えば、CIアーティファクトのアップロードでは、WorkhorseはZIPファイルの中身のインデックスを別に作成します。Workhorseでこれを行うことで、Pumaリクエストのタイムアウトを回避します。Sidekiqのバックグラウンド処理と比べると、GitLabがファイルを受け取ったもののまだ処理していないという中間状態をユーザーに見せないという利点があります。
- 直接アップロードでは、Workhorseはファイルの前処理とオブジェクトストレージへのアップロードの両方を行うことができます。大きなファイルをオブジェクトストレージにアップロードするには時間がかかります。Workhorseでこれを行うことで、Pumaリクエストのタイムアウトを避けることができます。