正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

Gitaly Cluster (Praefect)を構成する

Gitaly Cluster (Praefect)は、以下のいずれかの方法で構成します:

小規模なGitLabのインストールでは、Gitaly単体で十分な場合があります。

Gitaly Cluster (Praefect)は、まだKubernetes、Amazon ECS、または類似のコンテナ環境ではサポートされていません。詳細については、エピック6127を参照してください。

要件

Gitaly Cluster (Praefect) の最小推奨設定には以下が必要です:

ディスク要件はGitalyノードに適用されます。

GitalyノードのいずれかがミューティングRPC呼び出しで失敗した場合にタイブレーカーとなるよう、奇数個のGitalyノードを設定する必要があります。

実装の詳細については、デザインドキュメントを参照してください。

GitLabで機能フラグが設定されていない場合、コンソールからはfalseとして読み取られ、Praefectはそれらのデフォルト値を使用します。デフォルト値はGitLabのバージョンによって異なります。

ネットワークレイテンシーと接続

Gitaly Cluster (Praefect)のネットワークレイテンシーは、理想的には1桁のミリ秒で測定できるべきです。レイテンシーは、特に以下の点で重要です:

  • Gitalyノードのヘルスチェック。ノードは1秒以内に応答できなければなりません。
  • 強い整合性を強制する参照トランザクション。レイテンシーが低いほど、Gitalyノードは変更に早く合意できます。

Gitalyノード間の許容可能なレイテンシーを達成するには:

  • 物理ネットワークでは、一般に高帯域幅の単一ロケーション接続を意味します。
  • クラウドでは、一般に同じリージョン内を意味し、クロスアベイラビリティゾーンレプリケーションを許可することを含みます。これらのリンクは、この種の同期のために設計されています。2ミリ秒未満のレイテンシーは、Gitaly Cluster (Praefect) に十分であるべきです。

レプリケーションのために低いネットワークレイテンシーを提供できない場合 (例えば、遠隔地間) は、Geoを検討してください。詳細については、Geoとの比較を参照してください。

Gitaly Cluster (Praefect) のコンポーネントは、多くのルートを介して相互に通信します。Gitaly Cluster (Praefect)が適切に機能するためには、ファイアウォールルールで以下を許可する必要があります:

送信元宛先デフォルトポートTLSポート
GitLabPraefectロードバランサー23053305
PraefectロードバランサーPraefect23053305
PraefectGitaly80759999
PraefectGitLab (内部API)80443
GitalyGitLab (内部API)80443
GitalyPraefectロードバランサー23053305
GitalyPraefect23053305
GitalyGitaly80759999

GitalyはPraefectに直接接続しません。ただし、Praefectノード上のファイアウォールがGitalyノードからのトラフィックを許可しない限り、GitalyからPraefectロードバランサーへのリクエストはブロックされる可能性があります。

Praefectデータベースのストレージ

データベースには以下のメタデータのみが含まれるため、要件は比較的低いです:

  • リポジトリがどこにあるか。
  • キューに入れられた作業の一部。

リポジトリの数によって異なりますが、主要なGitLabアプリケーションデータベースと同様に、適切な最小値は5~10 GBです。

セットアップ手順

GitLabをLinuxパッケージを使用してインストールした場合 (強く推奨)、以下の手順に従ってください:

  1. 準備
  2. Praefectデータベースの設定
  3. Praefectプロキシ/ルーターの設定
  4. 各Gitalyノードの設定 (Gitalyノードごとに1回)
  5. ロードバランサーの設定
  6. GitLabサーバー設定の更新
  7. Grafanaを設定する

準備

始める前に、動作中のGitLabインスタンスがあることを確認してください。GitLabのインストール方法を学ぶ

PostgreSQLサーバーをプロビジョニングする。Linuxパッケージに同梱されているPostgreSQLを使用して、PostgreSQLデータベースを設定する必要があります。外部PostgreSQLサーバーを使用できますが、手動でセットアップする必要があります。

すべての新しいノードをGitLabをインストールして準備します。以下が必要です:

  • 1つのPostgreSQLノード
  • 1つのPgBouncerノード (オプション)
  • 少なくとも1つのPraefectノード (最小限のストレージが必要)
  • 3つのGitalyノード (高CPU、高メモリ、高速ストレージ)
  • 1つのGitLabサーバー

各ノードのIP/ホストアドレスも必要です:

  1. PRAEFECT_LOADBALANCER_HOST: PraefectロードバランサーのIP/ホストアドレス
  2. POSTGRESQL_HOST: PostgreSQLサーバーのIP/ホストアドレス
  3. PGBOUNCER_HOST: PostgreSQLサーバーのIP/ホストアドレス
  4. PRAEFECT_HOST: PraefectサーバーのIP/ホストアドレス
  5. GITALY_HOST_*: 各GitalyサーバーのIPまたはホストアドレス
  6. GITLAB_HOST: GitLabサーバーのIP/ホストアドレス

Google Cloud Platform、SoftLayer、またはVPC (仮想プライベートクラウド) を提供するその他のベンダーを使用している場合、各クラウドインスタンスのプライベートアドレス (Google Cloud Platformの「内部アドレス」に対応) をPRAEFECT_HOSTGITALY_HOST_*、およびGITLAB_HOSTに使用できます。

シークレット

コンポーネント間の通信は、以下に説明するさまざまなシークレットで保護されています。開始する前に、それぞれに一意のシークレットを生成し、メモしておいてください。これにより、セットアッププロセスが完了すると、これらのプレースホルダートークンを安全なトークンに置き換えることができます。

  1. GITLAB_SHELL_SECRET_TOKEN: これは、Gitフックによって、Gitプッシュを受け入れる際にGitLabへのHTTPコールバックAPIリクエストを行うために使用されます。このシークレットは、レガシー上の理由によりGitLab Shellと共有されます。
  2. PRAEFECT_EXTERNAL_TOKEN: Praefectクラスターでホストされているリポジトリは、このトークンを持つGitalyクライアントのみがアクセスできます。
  3. PRAEFECT_INTERNAL_TOKEN: このトークンは、Praefectクラスター内のレプリケーショントラフィックに使用されます。このトークンはPRAEFECT_EXTERNAL_TOKENとは異なります。GitalyクライアントはPraefectクラスターの内部ノードに直接アクセスできてはならないためです。これによりデータ損失につながる可能性があります。
  4. PRAEFECT_SQL_PASSWORD: このパスワードは、PraefectがPostgreSQLに接続するために使用されます。
  5. PRAEFECT_SQL_PASSWORD_HASH: Praefectユーザーのパスワードのハッシュ。gitlab-ctl pg-password-md5 praefectを使用してハッシュを生成します。このコマンドは、praefectユーザーのパスワードを要求します。PRAEFECT_SQL_PASSWORDプレーンテキストパスワードを入力します。デフォルトでは、Praefectはpraefectユーザーを使用しますが、変更できます。
  6. PGBOUNCER_SQL_PASSWORD_HASH: PgBouncerユーザーのパスワードのハッシュ。PgBouncerは、このパスワードを使用してPostgreSQLに接続します。詳細については、バンドルされたPgBouncerのドキュメントを参照してください。

これらのシークレットが必要な場所を以下の手順で示します。

Linuxパッケージのインストールでは、GITLAB_SHELL_SECRET_TOKENgitlab-secrets.jsonを使用できます。

タイムサーバー設定のカスタマイズ

デフォルトでは、GitalyとPraefectのノードは、時刻同期チェックにpool.ntp.orgにあるタイムサーバーを使用します。この設定は、各ノードのgitlab.rbに以下を追加することでカスタマイズできます:

  • Gitalyノードの場合、gitaly['env'] = { "NTP_HOST" => "ntp.example.com" }
  • Praefectノードの場合、praefect['env'] = { "NTP_HOST" => "ntp.example.com" }

PostgreSQL

Praefectは、GitLabアプリケーションデータベースとは別のデータベースを使用して、Gitalyリポジトリのレプリケーション状態を管理します。GeoとGitaly Cluster (Praefect)を使用する場合、Praefectのレプリケーション状態は各Geoサイトに固有です。各Geoサイトには、Praefectデータベースを格納するために、独立した読み書き可能なPostgreSQLデータベースインスタンスが必要です。

  • GitLabアプリケーションデータベースとPraefectデータベースを同じPostgreSQLサーバーに保存しないでください。
  • GeoサイトのプライマリにPraefect Postgresデータベースを設定して、Geoセカンダリサイトにレプリケートすることは避けてください。

これらの手順は、単一障害点となる単一のPostgreSQLデータベースをセットアップするのに役立ちます。これを避けるために、独自のクラスター化されたPostgreSQLを設定できます。他のデータベース (例えば、PraefectやGeoデータベース) のためのクラスター化されたデータベースサポートは、イシュー7292で提案されています。

以下のオプションが利用可能です:

PostgreSQLをセットアップすると、空のPraefectテーブルが作成されます。詳細については、関連するトラブルシューティングセクションを参照してください。

GitLabとPraefectデータベースを同じサーバーで実行する

GitLabアプリケーションデータベースとPraefectデータベースは、同じサーバーで実行できます。ただし、LinuxパッケージのPostgreSQLを使用する場合、Praefectは独自のデータベースサーバーを持つべきです。フェイルオーバーが発生した場合、Praefectはそれを認識せず、使用しようとしているデータベースが以下のいずれかの状態になるため、失敗し始めます:

  • 利用できない。
  • 読み取り専用モード。

手動データベースセットアップ

このセクションを完了するには、以下が必要です:

  • 1つのPraefectノード
  • 1つのPostgreSQLノード
    • データベースサーバーを管理する権限を持つPostgreSQLユーザー

このセクションでは、PostgreSQLデータベースを設定します。これは、外部およびLinuxパッケージが提供するPostgreSQLサーバーの両方に使用できます。

以下の手順を実行するには、Linuxパッケージ (/opt/gitlab/embedded/bin/psql) によってpsqlがインストールされているPraefectノードを使用できます。Linuxパッケージが提供するPostgreSQLを使用している場合は、代わりにPostgreSQLノードでgitlab-psqlを使用できます:

  1. Praefectが使用する新しいユーザーpraefectを作成します:

    CREATE ROLE praefect WITH LOGIN PASSWORD 'PRAEFECT_SQL_PASSWORD';

    PRAEFECT_SQL_PASSWORDを、準備手順で生成した強力なパスワードに置き換えます。

  2. praefectユーザーが所有する新しいデータベースpraefect_productionを作成します。

    CREATE DATABASE praefect_production WITH OWNER praefect ENCODING UTF8;

Linuxパッケージが提供するPgBouncerを使用する場合は、以下の追加手順を実行する必要があります。バックエンドとして、Linuxパッケージに同梱されているPostgreSQLを使用することを強く推奨します。以下の手順は、Linuxパッケージが提供するPostgreSQLでのみ機能します:

  1. Linuxパッケージが提供するPgBouncerの場合、実際のパスワードの代わりにpraefectパスワードのハッシュを使用する必要があります:

    ALTER ROLE praefect WITH PASSWORD 'md5<PRAEFECT_SQL_PASSWORD_HASH>';

    <PRAEFECT_SQL_PASSWORD_HASH>を、準備手順で生成したパスワードのハッシュに置き換えます。md5リテラルがプレフィックスとして付けられます。

  2. PgBouncerが使用する新しいユーザーpgbouncerを作成します:

    CREATE ROLE pgbouncer WITH LOGIN;
    ALTER USER pgbouncer WITH password 'md5<PGBOUNCER_SQL_PASSWORD_HASH>';

    PGBOUNCER_SQL_PASSWORD_HASHを、準備手順で生成した強力なパスワードハッシュに置き換えます。

  3. Linuxパッケージに同梱されているPgBouncerは、auth_queryを使用するように設定されており、pg_shadow_lookup関数を使用します。praefect_productionデータベースにこの関数を作成する必要があります:

    CREATE OR REPLACE FUNCTION public.pg_shadow_lookup(in i_username text, out username text, out password text) RETURNS record AS $$
    BEGIN
        SELECT usename, passwd FROM pg_catalog.pg_shadow
        WHERE usename = i_username INTO username, password;
        RETURN;
    END;
    $$ LANGUAGE plpgsql SECURITY DEFINER;
    
    REVOKE ALL ON FUNCTION public.pg_shadow_lookup(text) FROM public, pgbouncer;
    GRANT EXECUTE ON FUNCTION public.pg_shadow_lookup(text) TO pgbouncer;

Praefectが使用するデータベースが設定されました。

これで、Praefectがデータベースを使用するように設定できます:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: POSTGRESQL_HOST,
      user: 'praefect',
      port: 5432,
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
   }
}

PostgreSQLの設定後にPraefectデータベースエラーが発生した場合は、トラブルシューティング手順を参照してください。

読み取り分散キャッシュ

session_pooled設定を追加で設定することで、Praefectのパフォーマンスを向上させることができます:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      session_pooled: {
         # ...
         host: POSTGRESQL_HOST,
         port: 5432

         # Use the following to override parameters of direct database connection.
         # Comment out where the parameters are the same for both connections.
         user: 'praefect',
         password: PRAEFECT_SQL_PASSWORD,
         dbname: 'praefect_production',
         # sslmode: '...',
         # sslcert: '...',
         # sslkey: '...',
         # sslrootcert: '...',
      }
   }
}

設定すると、この接続はSQL LISTEN機能に自動的に使用され、PraefectがPostgreSQLからキャッシュの無効化に関する通知を受け取れるようになります。

この機能が動作していることを確認するには、Praefectログで以下のログエントリを探してください:

reads distribution caching is enabled by configuration

PgBouncerを使用する

PostgreSQLのリソース消費を削減するため、PostgreSQLインスタンスの前にPgBouncerをセットアップし、設定する必要があります。ただし、Praefectが行う接続数が少ないため、PgBouncerは必須ではありません。PgBouncerを使用することを選択した場合、GitLabアプリケーションデータベースとPraefectデータベースの両方に同じPgBouncerインスタンスを使用できます。

PostgreSQLインスタンスの前にPgBouncerを設定するには、Praefectの設定でデータベースパラメータを設定することで、PraefectをPgBouncerにポイントする必要があります:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: PGBOUNCER_HOST,
      port: 6432,
      user: 'praefect',
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
      # sslmode: '...',
      # sslcert: '...',
      # sslkey: '...',
      # sslrootcert: '...',
   }
}

Praefectは、LISTEN機能をサポートするPostgreSQLへの追加接続が必要です。PgBouncerでは、この機能はsessionプールモード (pool_mode = session) でのみ利用可能です。transactionプールモード (pool_mode = transaction) ではサポートされていません。

追加接続を設定するには、以下のいずれかの方法で行う必要があります:

  • 同じPostgreSQLデータベースエンドポイントを使用する新しいPgBouncerデータベースを設定しますが、プールモードは異なります (pool_mode = session)。
  • PraefectをPostgreSQLに直接接続し、PgBouncerをバイパスする。
pool_mode = sessionで新しいPgBouncerデータベースを設定する

PgBouncerはsessionプールモードで使用する必要があります。バンドルされたPgBouncerを使用するか、外部のPgBouncerを使用して手動で設定できます。

以下の例では、バンドルされたPgBouncerを使用し、PostgreSQLホスト上に2つの独立した接続プールをセットアップしています。1つはsessionプールモード、もう1つはtransactionプールモードです。この例が機能するためには、セットアップ手順に記載されているようにPostgreSQLサーバーを準備する必要があります。

次に、PgBouncerホスト上で個別の接続プールを設定します:

pgbouncer['databases'] = {
  # Other database configuration including gitlabhq_production
  ...

  praefect_production: {
    host: POSTGRESQL_HOST,
    # Use `pgbouncer` user to connect to database backend.
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    pool_mode: 'transaction'
  },
  praefect_production_direct: {
    host: POSTGRESQL_HOST,
    # Use `pgbouncer` user to connect to database backend.
    user: 'pgbouncer',
    password: PGBOUNCER_SQL_PASSWORD_HASH,
    dbname: 'praefect_production',
    pool_mode: 'session'
  },

  ...
}

# Allow the praefect user to connect to PgBouncer
pgbouncer['users'] = {
  'praefect': {
    'password': PRAEFECT_SQL_PASSWORD_HASH,
  }
}

praefect_productionpraefect_production_directは両方とも同じデータベースエンドポイント (praefect_production) を使用しますが、プールモードは異なります。これは、PgBouncerの以下のdatabasesセクションに変換されます:

[databases]
praefect_production = host=POSTGRESQL_HOST auth_user=pgbouncer pool_mode=transaction
praefect_production_direct = host=POSTGRESQL_HOST auth_user=pgbouncer dbname=praefect_production pool_mode=session

これで、Praefectが両方の接続にPgBouncerを使用するように設定できます:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      host: PGBOUNCER_HOST,
      port: 6432,
      user: 'praefect',
      # `PRAEFECT_SQL_PASSWORD` is the plain-text password of
      # Praefect user. Not to be confused with `PRAEFECT_SQL_PASSWORD_HASH`.
      password: PRAEFECT_SQL_PASSWORD,
      dbname: 'praefect_production',
      session_pooled: {
         # ...
         dbname: 'praefect_production_direct',
         # There is no need to repeat the following. Parameters of direct
         # database connection will fall back to the values specified in the
         # database block.
         #
         # host: PGBOUNCER_HOST,
         # port: 6432,
         # user: 'praefect',
         # password: PRAEFECT_SQL_PASSWORD,
      },
   },
}

この設定により、Praefectは両方の接続タイプにPgBouncerを使用します。

Linuxパッケージのインストールでは認証要件 (auth_queryを使用) を処理しますが、データベースを手動で準備し、外部PgBouncerを設定する場合は、PgBouncerが使用するファイルにpraefectユーザーとそのパスワードを含める必要があります。例えば、auth_file設定オプションが設定されている場合はuserlist.txt。詳細については、PgBouncerのドキュメントを参照してください。

PraefectがPostgreSQLに直接接続するように設定する

sessionプールモードでPgBouncerを設定する代わりに、Praefectを設定して、PostgreSQLへの直接アクセスに異なる接続パラメータを使用できます。この接続はLISTEN機能をサポートします。

PgBouncerをバイパスするPraefectの設定の例で、PostgreSQLに直接接続します:

praefect['configuration'] = {
   # ...
   database: {
      # ...
      session_pooled: {
         # ...
         host: POSTGRESQL_HOST,
         port: 5432,

         # Use the following to override parameters of direct database connection.
         # Comment out where the parameters are the same for both connections.
         #
         user: 'praefect',
         password: PRAEFECT_SQL_PASSWORD,
         dbname: 'praefect_production',
         # sslmode: '...',
         # sslcert: '...',
         # sslkey: '...',
         # sslrootcert: '...',
      },
   },
}

Praefect

Praefectを設定する前に、Praefectの設定ファイルの例を参照して慣れてください。Linuxパッケージを使用してGitLabをインストールした場合、例のファイルにある設定はRubyに変換する必要があります。

複数のPraefectノードがある場合:

  1. 1つのノードをデプロイノードとして指定し、以下の手順を使用して設定します。
  2. 追加の各ノードについて、以下の手順を完了してください。

このセクションを完了するには、設定済みのPostgreSQLサーバーが必要です。以下を含みます:

Praefectは専用のノードで実行する必要があります。PraefectをアプリケーションサーバーまたはGitalyノード上で実行しないでください。

Praefectノード上で:

  1. /etc/gitlab/gitlab.rbを編集して、他のすべてのサービスを無効にします:
# Avoid running unnecessary services on the Praefect server
gitaly['enable'] = false
postgresql['enable'] = false
redis['enable'] = false
nginx['enable'] = false
puma['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
prometheus['enable'] = false
alertmanager['enable'] = false
gitlab_exporter['enable'] = false
gitlab_kas['enable'] = false

# Enable only the Praefect service
praefect['enable'] = true

# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
gitlab_rails['auto_migrate'] = false
  1. /etc/gitlab/gitlab.rbを編集して、Praefectがネットワークインターフェースでリッスンするように設定します:

    praefect['configuration'] = {
       # ...
       listen_addr: '0.0.0.0:2305',
    }
  2. /etc/gitlab/gitlab.rbを編集して、Prometheusメトリクスを設定します:

    praefect['configuration'] = {
       # ...
       #
       # Enable Prometheus metrics access to Praefect. You must use firewalls
       # to restrict access to this address/port.
       # The default metrics endpoint is /metrics
       prometheus_listen_addr: '0.0.0.0:9652',
       # Some metrics run queries against the database. Enabling separate database metrics allows
       # these metrics to be collected when the metrics are
       # scraped on a separate /db_metrics endpoint.
       prometheus_exclude_database_from_default_metrics: true,
    }
  3. /etc/gitlab/gitlab.rbを編集して、Praefect用の強力な認証トークンを設定します。これは、クラスター外のクライアント (GitLab Shellなど) がPraefectクラスターと通信するために必要です:

    praefect['configuration'] = {
       # ...
       auth: {
          # ...
          token: 'PRAEFECT_EXTERNAL_TOKEN',
       },
    }
  4. PraefectがPostgreSQLデータベースに接続するように設定します。PgBouncerも使用することを強く推奨します。

    TLSクライアント証明書を使用したい場合は、以下のオプションを使用できます:

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          #
          # Connect to PostgreSQL using a TLS client certificate
          # sslcert: '/path/to/client-cert',
          # sslkey: '/path/to/client-key',
          #
          # Trust a custom certificate authority
          # sslrootcert: '/path/to/rootcert',
       },
    }

    デフォルトでは、PraefectはオポチュニスティックTLSを使用してPostgreSQLに接続します。これは、Praefectがsslmodepreferに設定されたPostgreSQLへの接続を試みることを意味します。以下の行のコメントを解除することで、これをオーバーライドできます:

    praefect['configuration'] = {
       # ...
       database: {
          # ...
          # sslmode: 'disable',
       },
    }
  5. /etc/gitlab/gitlab.rbを編集して、Praefectクラスターがクラスター内の各Gitalyノードに接続するように設定します。

    仮想ストレージの名前は、GitLab設定で設定されたストレージ名と一致している必要があります。以降の手順でストレージ名をdefaultとして設定するため、ここでもdefaultを使用します。このクラスターには、相互にレプリカとなる3つのGitalyノードgitaly-1gitaly-2gitaly-3があります。

    すでにdefaultという名前の既存ストレージにデータがある場合は、仮想ストレージを別の名前で設定し、その後データをGitaly Cluster (Praefect) ストレージに移行する必要があります。

    PRAEFECT_INTERNAL_TOKENを、Praefectがクラスター内のGitalyノードと通信する際に使用される強力なシークレットに置き換えます。このトークンはPRAEFECT_EXTERNAL_TOKENとは異なります。

    GITALY_HOST_*を、各GitalyノードのIPまたはホストアドレスに置き換えます。

    レプリカの数を増やすために、より多くのGitalyノードをクラスターに追加できます。非常に大規模なGitLabインスタンスの場合、さらに多くのクラスターを追加することもできます。

    仮想ストレージにGitalyノードを追加する場合、その仮想ストレージ内のすべてのストレージ名は一意である必要があります。さらに、Praefectの設定で参照されているすべてのGitalyノードアドレスは一意である必要があります。

    # Name of storage hash must match storage name in gitlab_rails['repositories_storages'] on GitLab
    # server ('default') and in gitaly['configuration'][:storage][INDEX][:name] on Gitaly nodes ('gitaly-1')
    praefect['configuration'] = {
       # ...
       virtual_storage: [
          {
             # ...
             name: 'default',
             node: [
                {
                   storage: 'gitaly-1',
                   address: 'tcp://GITALY_HOST_1:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-2',
                   address: 'tcp://GITALY_HOST_2:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-3',
                   address: 'tcp://GITALY_HOST_3:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
             ],
          },
       ],
    }
  6. /etc/gitlab/gitlab.rbへの変更を保存し、Praefectを再設定します:

    gitlab-ctl reconfigure
  7. 下記のとおりです:

    • 「デプロイノード」:

      1. /etc/gitlab/gitlab.rbpraefect['auto_migrate'] = trueを設定して、Praefectデータベースの自動移行を再度有効にします。

      2. データベースの移行が再設定中にのみ実行され、アップグレード時に自動的に実行されないようにするには、以下を実行します。

        sudo touch /etc/gitlab/skip-auto-reconfigure
    • 他のノードについては、設定をそのままにしておくことができます。/etc/gitlab/skip-auto-reconfigureは必須ではありませんが、apt-get updateのようなコマンドを実行したときにGitLabが自動的に再設定を実行するのを防ぐために、これを設定したい場合があります。これにより、追加の設定変更を行った後、手動で再設定を実行できます。

  8. /etc/gitlab/gitlab.rbへの変更を保存し、Praefectを再設定します:

    gitlab-ctl reconfigure
  9. PraefectがそのPrometheusリスナーアドレスを更新したことを確認するために、Praefectを再起動します:

    gitlab-ctl restart praefect
  10. PraefectがPostgreSQLに到達できることを確認します:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-ping

    チェックが失敗した場合は、手順が正しく実行されていることを確認してください。/etc/gitlab/gitlab.rbを編集した場合は、sql-pingコマンドを試す前に、sudo gitlab-ctl reconfigureを再度実行することを忘れないでください。

TLSサポートの有効化

PraefectはTLS暗号化をサポートしています。セキュアな接続をリッスンするPraefectインスタンスと通信するには、次のことを行う必要があります。

  • GitalyがTLS用に設定されていることを確認し、GitLab設定の対応するストレージエントリのgitaly_addresstls:// URLスキームを使用します。
  • 証明書は自動的に提供されないため、独自の証明書を用意してください。各Praefectサーバーに対応する証明書を、そのPraefectサーバーにインストールする必要があります。

さらに、証明書またはその認証局は、GitLabカスタム証明書の設定で説明されている手順(以下にも繰り返します)に従って、すべてのGitalyサーバー、およびこのサーバーと通信するすべてのPraefectクライアントにインストールする必要があります。

次の点に注意してください。

  • 証明書は、Praefectサーバーへのアクセスに使用するアドレスを指定する必要があります。ホスト名またはIPアドレスをサブジェクトの別名(SAN)として証明書に追加する必要があります。

  • Gitaly TLSが有効なコマンドラインからdial-nodeslist-untracked-repositoriesのようなPraefectサブコマンドを実行する場合、Gitaly証明書が信頼されるようにSSL_CERT_DIRまたはSSL_CERT_FILE環境変数を設定する必要があります。例:

    SSL_CERT_DIR=/etc/gitlab/trusted-certs sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes
  • Praefectサーバーは、暗号化されていないリスニングアドレスlisten_addrと暗号化されたリスニングアドレスtls_listen_addrの両方で同時に設定できます。これにより、必要に応じて、暗号化されていないトラフィックから暗号化されたトラフィックへの段階的な移行を行うことができます。

    暗号化されていないリスナーを無効にするには、以下を設定します:

    praefect['configuration'] = {
      # ...
      listen_addr: nil,
    }

PraefectをTLSで設定します。

Linuxパッケージインストールの場合:

  1. Praefectサーバーの証明書を作成します。

  2. Praefectサーバーで、/etc/gitlab/sslディレクトリを作成し、キーと証明書をそこにコピーします。

    sudo mkdir -p /etc/gitlab/ssl
    sudo chmod 755 /etc/gitlab/ssl
    sudo cp key.pem cert.pem /etc/gitlab/ssl/
    sudo chmod 644 key.pem cert.pem
  3. /etc/gitlab/gitlab.rbを編集して、以下を追加します。

    praefect['configuration'] = {
       # ...
       tls_listen_addr: '0.0.0.0:3305',
       tls: {
          # ...
          certificate_path: '/etc/gitlab/ssl/cert.pem',
          key_path: '/etc/gitlab/ssl/key.pem',
       },
    }
  4. ファイルを保存し、再設定します。

  5. Praefectクライアント(各Gitalyサーバーを含む)で、証明書またはその認証局を/etc/gitlab/trusted-certsにコピーします。

    sudo cp cert.pem /etc/gitlab/trusted-certs/
  6. Praefectクライアント(Gitalyサーバーを除く)で、/etc/gitlab/gitlab.rbgitlab_rails['repositories_storages']を次のように編集します。

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'tls://PRAEFECT_LOADBALANCER_HOST:3305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  7. ファイルを保存し、GitLabを再設定します。

セルフコンパイルインストールの場合:

  1. Praefectサーバーの証明書を作成します。

  2. Praefectサーバーで、/etc/gitlab/sslディレクトリを作成し、キーと証明書をそこにコピーします。

    sudo mkdir -p /etc/gitlab/ssl
    sudo chmod 755 /etc/gitlab/ssl
    sudo cp key.pem cert.pem /etc/gitlab/ssl/
    sudo chmod 644 key.pem cert.pem
  3. Praefectクライアント (各Gitalyサーバーを含む) で、証明書またはその認証局をシステム信頼済み証明書にコピーします:

    sudo cp cert.pem /usr/local/share/ca-certificates/praefect.crt
    sudo update-ca-certificates
  4. Praefectクライアント(Gitalyサーバーを除く)で、/home/git/gitlab/config/gitlab.ymlstoragesを次のように編集します。

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: tls://PRAEFECT_LOADBALANCER_HOST:3305
  5. ファイルを保存し、GitLabを再起動します。

  6. すべてのPraefectサーバー証明書、またはそれらの認証局を各Gitalyサーバーのシステム信頼済み証明書にコピーします。これにより、Gitalyサーバーから呼び出しされたときにPraefectサーバーが証明書を信頼するようになります:

    sudo cp cert.pem /usr/local/share/ca-certificates/praefect.crt
    sudo update-ca-certificates
  7. /home/git/praefect/config.tomlを編集して、以下を追加します。

    tls_listen_addr = '0.0.0.0:3305'
    
    [tls]
    certificate_path = '/etc/gitlab/ssl/cert.pem'
    key_path = '/etc/gitlab/ssl/key.pem'
  8. ファイルを保存し、GitLabを再起動します。

サービスディスカバリ

前提条件:

  • DNSサーバー。

GitLabは、Praefectホストのリストを取得するためにサービスディスカバリを使用します。サービスディスカバリは、DNS AまたはAAAAレコードの定期的なチェックを伴い、レコードから取得するされたIPがターゲットノードのアドレスとして機能します。PraefectはSRVレコードによるサービスディスカバリをサポートしていません。

デフォルトでは、チェック間の最小時間は5分で、レコードのTTLに関係なくです。Praefectはこの間隔のカスタマイズをサポートしていません。クライアントが更新を受信すると、以下のようになります:

  • 新しいIPアドレスへの新しい接続を確立します。
  • 既存の接続は、変更されていないIPアドレスに維持します。
  • 削除されたIPアドレスへの接続を破棄します。

削除予定の接続における処理中のリクエストは、完了するまで処理されます。Workhorseには10分間のタイムアウトがありますが、他のクライアントはグレースフルタイムアウトを指定していません。

DNSサーバーは、それ自体でロードバランシングを行うのではなく、すべてのIPアドレスを返す必要があります。クライアントは、ラウンドロビン方式でIPアドレスにリクエストを分散できます。

クライアント設定を更新する前に、DNSサービスディスカバリが正しく機能することを確認してください。IPアドレスのリストを正しく返す必要があります。digは検証に役立つツールです。

❯ dig A praefect.service.consul @127.0.0.1

; <<>> DiG 9.10.6 <<>> A praefect.service.consul @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29210
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;praefect.service.consul.                     IN      A

;; ANSWER SECTION:
praefect.service.consul.              0       IN      A       10.0.0.3
praefect.service.consul.              0       IN      A       10.0.0.2
praefect.service.consul.              0       IN      A       10.0.0.1

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Wed Dec 14 12:53:58 +07 2022
;; MSG SIZE  rcvd: 86
サービスディスカバリを設定する

デフォルトでは、PraefectはDNS解決をオペレーティングシステムに委任します。このような場合、Gitalyアドレスは以下のいずれかの形式で設定できます:

  • dns:[host]:[port]
  • dns:///[host]:[port] (3つのスラッシュに注意)

この形式で設定することで、権威あるネームサーバーを指定することもできます:

  • dns://[authority_host]:[authority_port]/[host]:[port]

TLS暗号化でサービスディスカバリを使用するには、dns+tlsスキームを使用します:

  • dns+tls:[host]:[port] (短縮形)
  • dns+tls:///[host]:[port] (3つのスラッシュに注意)
  • dns+tls://[authority_host]:[authority_port]/[host]:[port]

dns+tls://スキームは、DNSベースのサービスディスカバリとTLS暗号化を組み合わせたものです。このスキームを使用する前に、PraefectサーバーでTLSを設定する必要があります。詳細については、TLSの有効化を参照してください。

各PraefectエンドポイントのTLS証明書には、以下のPRAEFECT_SERVICE_DISCOVERY_ADDRESSで使用されているホスト名と一致するSubject Alternative Name (SAN) が含まれている必要があります。例えば、アドレスがdns+tls:///praefect.service.consul:3305の場合、各Praefectノードの証明書にはSANエントリとしてpraefect.service.consulが含まれている必要があります。SANが一致しない場合、接続は失敗します。

  1. 各PraefectノードのIPアドレスをDNSサービスディスカバリアドレスに追加します。

  2. Praefectクライアント (ただしGitalyサーバーを除く) では、/etc/gitlab/gitlab.rbgitlab_rails['repositories_storages']を次のように編集します。PRAEFECT_SERVICE_DISCOVERY_ADDRESSを、praefect.service.consulなどのPraefectサービスディスカバリアドレスに置き換えます。

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }

    TLSを使用するには、スキームをdns+tls://に変更します:

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns+tls://DNS_SERVER_ADDRESS:53/PRAEFECT_SERVICE_DISCOVERY_ADDRESS:3305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  3. ファイルを保存し、GitLabを再設定します。

  1. DNSサービスディスカバリサービスをインストールします。すべてのPraefectノードをサービスに登録します。

  2. Praefectクライアント(Gitalyサーバーを除く)で、/home/git/gitlab/config/gitlab.ymlstoragesを次のように編集します。

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: dns:PRAEFECT_SERVICE_DISCOVERY_ADDRESS:2305

    TLSを使用するには、スキームをdns+tls://に変更します:

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: dns+tls://DNS_SERVER_ADDRESS:53/PRAEFECT_SERVICE_DISCOVERY_ADDRESS:3305
  3. ファイルを保存し、GitLabを再起動します。

Consulでサービスディスカバリを設定する

すでにアーキテクチャにConsulサーバーがある場合は、各PraefectノードにConsulエージェントを追加し、それにpraefectサービスを登録できます。これにより、各ノードのIPアドレスがpraefect.service.consulに登録され、サービスディスカバリによって検出できるようになります。

前提条件:

  • Consulエージェントを追跡するための1つまたは複数のConsulサーバー。
  1. 各Praefectサーバーで、/etc/gitlab/gitlab.rbに以下を追加します:

    consul['enable'] = true
    praefect['consul_service_name'] = 'praefect'
    
    # The following must also be added until this issue is addressed:
    # https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/8321
    consul['monitoring_service_discovery'] = true
    praefect['configuration'] = {
      # ...
      #
      prometheus_listen_addr: '0.0.0.0:9652',
    }
  2. ファイルを保存し、GitLabを再設定します。

  3. サービスディスカバリを使用するために、各Praefectサーバーで前の手順を繰り返します。

  4. Praefectクライアント (ただしGitalyサーバーを除く) では、/etc/gitlab/gitlab.rbgitlab_rails['repositories_storages']を次のように編集します。CONSUL_SERVERをConsulサーバーのIPまたはアドレスに置き換えます。デフォルトのConsul DNSポートは8600です。

    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => 'dns://CONSUL_SERVER:8600/praefect.service.consul:2305',
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  5. Praefectクライアントからdigを使用して、各IPアドレスがpraefect.service.consuldig A praefect.service.consul @CONSUL_SERVER -p 8600で登録されていることを確認します。CONSUL_SERVERを以前に設定した値に置き換えると、すべてのPraefectノードIPアドレスが出力に表示されるはずです。

  6. ファイルを保存し、GitLabを再設定します。

Gitaly

各Gitalyノードについて、これらの手順を完了してください。

このセクションを完了するには、以下が必要です:

  • 設定済みのPraefectノード
  • GitLabがインストールされた3つ (またはそれ以上) のサーバーを、Gitalyノードとして設定します。これらは専用のノードであるべきで、これらのノードで他のサービスを実行しないでください。

Praefectクラスターに割り当てられたすべてのGitalyサーバーを設定する必要があります。設定は標準のスタンドアロンGitalyサーバーと同じですが、以下の点が異なります:

  • ストレージ名はGitLabではなくPraefectに公開されます。
  • シークレットトークンはGitLabではなくPraefectと共有されます。

Praefectクラスター内のすべてのGitalyノードの設定は同じにすることができます。これは、Praefectが操作を正しくルーティングすることに依存しているためです。

特に以下の点に注意してください:

  • このセクションで設定されたgitaly['configuration'][:auth][:token]は、Praefectノード上のpraefect['configuration'][:virtual_storage][<index>][:node][<index>][:token]の下にあるtokenの値と一致している必要があります。この値は、前のセクションで設定されました。このドキュメントでは、常にプレースホルダーPRAEFECT_INTERNAL_TOKENを使用します。
  • このセクションで設定されたgitaly['configuration'][:storage]内の物理ストレージ名は、Praefectノード上のpraefect['configuration'][:virtual_storage]の下にある物理ストレージ名と一致している必要があります。これは前のセクションで設定されました。このドキュメントでは、物理ストレージ名としてgitaly-1gitaly-2、およびgitaly-3を使用します。

Gitalyサーバーの設定の詳細については、当社のGitalyドキュメントを参照してください。

  1. GitalyノードにSSHで接続し、rootとしてログインします:

    sudo -i
  2. /etc/gitlab/gitlab.rbを編集して、他のすべてのサービスを無効にします:

    # Disable all other services on the Gitaly node
    postgresql['enable'] = false
    redis['enable'] = false
    nginx['enable'] = false
    puma['enable'] = false
    sidekiq['enable'] = false
    gitlab_workhorse['enable'] = false
    prometheus_monitoring['enable'] = false
    gitlab_kas['enable'] = false
    
    # Enable only the Gitaly service
    gitaly['enable'] = true
    
    # Enable Prometheus if needed
    prometheus['enable'] = true
    
    # Disable database migrations to prevent database connections during 'gitlab-ctl reconfigure'
    gitlab_rails['auto_migrate'] = false
  3. /etc/gitlab/gitlab.rbを編集して、Gitalyがネットワークインターフェースでリッスンするように設定します:

    gitaly['configuration'] = {
       # ...
       #
       # Make Gitaly accept connections on all network interfaces.
       # Use firewalls to restrict access to this address/port.
       listen_addr: '0.0.0.0:8075',
       # Enable Prometheus metrics access to Gitaly. You must use firewalls
       # to restrict access to this address/port.
       prometheus_listen_addr: '0.0.0.0:9236',
    }
  4. /etc/gitlab/gitlab.rbを編集して、Gitaly用の強力なauth_tokenを設定します。これは、クライアントがこのGitalyノードと通信するために必要です。通常、このトークンはすべてのGitalyノードで同じです。

    gitaly['configuration'] = {
       # ...
       auth: {
          # ...
          token: 'PRAEFECT_INTERNAL_TOKEN',
       },
    }
  5. git push操作に必要なGitLab Shellシークレットトークンを設定します。次のいずれかの操作を行います:

    • 方法1:

      1. /etc/gitlab/gitlab-secrets.jsonをGitalyクライアントからGitalyサーバーおよびその他のGitalyクライアントの同じパスにコピーします。
      2. Gitalyサーバー上でGitLabを再設定します。
    • 方法2:

      1. /etc/gitlab/gitlab.rbを編集します。

      2. GITLAB_SHELL_SECRET_TOKENを実際のシークレットに置き換えます。

        • GitLab 17.5以降:

          gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
        • GitLab 17.4以前:

          gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
  6. git push操作にも必要なinternal_api_urlを設定します:

    # Configure the gitlab-shell API callback URL. Without this, `git push` will
    # fail. This can be your front door GitLab URL or an internal load balancer.
    # Examples: 'https://gitlab.example.com', 'http://10.0.2.2'
    gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
  7. /etc/gitlab/gitlab.rbgitaly['configuration'][:storage]を設定して、Gitデータのストレージロケーションを設定します。各Gitalyノードは一意のストレージ名 (gitaly-1など) を持つ必要があり、他のGitalyノードで重複してはなりません。

    gitaly['configuration'] = {
       # ...
       storage: [
         # Replace with appropriate name for each Gitaly nodes.
         {
           name: 'gitaly-1',
           path: '/var/opt/gitlab/git-data/repositories',
         },
       ],
    }
  8. /etc/gitlab/gitlab.rbへの変更を保存し、Gitalyを再設定します:

    gitlab-ctl reconfigure
  9. GitalyがそのPrometheusリスナーアドレスを更新したことを確認するために、Gitalyを再起動します:

    gitlab-ctl restart gitaly

前の手順は各Gitalyノードで完了する必要があります!

すべてのGitalyノードが設定された後、Praefect接続チェッカーを実行して、PraefectがPraefect設定内のすべてのGitalyサーバーに接続できることを確認します。

  1. 各PraefectノードにSSHで接続し、Praefect接続チェッカーを実行します:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes

ロードバランサー

フォールトトレラントなGitaly設定では、GitLabアプリケーションからPraefectノードへの内部トラフィックをルーティングするために、ロードバランサーが必要です。使用するロードバランサーや正確な設定の詳細は、GitLabドキュメントの範囲外です。

ロードバランサーは、GitLabノードに加えてGitalyノードからのトラフィックを受け入れるように設定する必要があります。

GitLabのようなフォールトトレラントシステムを管理している場合、すでに選択したロードバランサーがあることを期待しています。いくつかの例としては、HAProxy (オープンソース)、Google Internal Load BalancerAWS Elasticロードバランサー、F5 Big-IP LTM、およびCitrix Net Scalerなどがあります。このドキュメントでは、設定する必要があるポートとプロトコルについて概説します。

長時間実行される操作 (例えば、クローン) は一部の接続を長時間開いたままにするため、HAProxyのleastconnロードバランシング戦略に相当するものを使用する必要があります。

LBポートバックエンドポートプロトコル
23052305TCP

TCPロードバランサーを使用する必要があります。HTTP/2またはgRPCロードバランサーをPraefectと共に使用することは、Gitalyサイドチャンネルのため機能しません。この最適化は、gRPCハンドシェイクプロセスを傍受します。これにより、すべての重いGit操作がgRPCよりも効率的な「チャンネル」にリダイレクトされますが、HTTP/2またはgRPCロードバランサーはこのようなリクエストを適切に処理しません。

TLSが有効な場合、Praefectのいくつかのバージョンでは、RFC 7540に従ってApplication-Layer Protocol Negotiation (ALPN) 拡張が使用される必要があります。TCPロードバランサーは、追加の設定なしにALPNを直接渡します:

sequenceDiagram
    autonumber
    participant Client as Client
    participant LB as TCP Load Balancer
    participant Praefect as Praefect

    Client->>LB: Establish TLS Session (w/ ALPN Extension)
    LB->>Praefect: Establish TLS Session (w/ ALPN Extension)
    Client->>LB: Encrypted TCP packets
    LB->>Praefect: Encrypted TCP packets
    Praefect->>LB: Encrypted Response
    LB->>Client: Encrypted Response

一部のTCPロードバランサーは、TLSクライアント接続を受け入れ、新しいTLS接続でPraefectに接続をプロキシするように設定できます。ただし、これはALPNが両方の接続でサポートされている場合にのみ機能します。

このため、proxy_ssl設定オプションが有効な場合、NGINXのngx_stream_proxy_moduleは機能しません:

sequenceDiagram
    autonumber
    participant Client as Client
    participant NGINX as NGINX Stream Proxy
    participant Praefect as Praefect

    Client->>NGINX: Establish TLS Session (w/ ALPN Extension)
    NGINX->>Praefect: Establish New TLS Session
    Praefect->>NGINX: Connection failed: missing selected ALPN property

ステップ2では、NGINXがこれをサポートしていないため、ALPNは使用されません。詳細については、NGINXイシュー406をフォローしてください。

ALPNエンフォースメント

GitLabの一部のバージョンではALPNエンフォースメントが有効になっていました。しかし、ALPNエンフォースメントはデプロイを破損させ、移行するパスを提供するために無効化されています。以下のGitLabのバージョンでは、ALPNエンフォースメントが有効になっています:

  • GitLab 17.7.0
  • GitLab 17.6.0 - 17.6.2
  • GitLab 17.5.0 - 17.5.4
  • GitLab 17.4.x

GitLab 17.5.5、17.6.3、および17.7.1では、ALPNエンフォースメントは再度無効になっています。GitLab 17.4以前では、ALPNエンフォースメントは一度も有効化されていませんでした。

GitLab

このセクションを完了するには、以下が必要です:

Praefectクラスターは、GitLabアプリケーションへのストレージロケーションとして公開する必要があります。これはgitlab_rails['repositories_storages']を更新することで行われます。

特に以下の点に注意してください:

  • このセクションのgitlab_rails['repositories_storages']に追加されたストレージ名は、Praefectノード上のpraefect['configuration'][:virtual_storage]の下にあるストレージ名と一致している必要があります。これは本ガイドのPraefectセクションで設定されました。このドキュメントでは、Praefectストレージ名としてdefaultを使用します。
  1. GitLabノードにSSHで接続し、rootとしてログインします:

    sudo -i
  2. /etc/gitlab/gitlab.rbを編集して、適切なエンドポイントアクセスによりGitLabがファイルを配信できるようにexternal_urlを設定します:

    GITLAB_SERVER_URLを、現在のGitLabインスタンスがサービスを提供している実際の外部公開URLに置き換える必要があります:

    external_url 'GITLAB_SERVER_URL'
  3. GitLabホストで実行されているデフォルトのGitalyサービスを無効にします。GitLabは設定済みのクラスターに接続するため、これは必要ありません。

    デフォルトのGitalyストレージに既存のデータがある場合は、まずGitalyクラスター (Praefect) ストレージにデータを移行する必要があります。

    gitaly['enable'] = false
  4. /etc/gitlab/gitlab.rbを編集して、Praefectクラスターをストレージの場所として追加します。

    以下を置き換える必要があります:

    • PRAEFECT_LOADBALANCER_HOSTをロードバランサーのIPアドレスまたはホスト名に置き換えます。
    • PRAEFECT_EXTERNAL_TOKENを実際のシークレットに置き換えます。

    TLSを使用している場合:

    • gitaly_addressは代わりにtls://で始める必要があります。
    • ポートを3305に変更する必要があります。
    gitlab_rails['repositories_storages'] = {
      "default" => {
        "gitaly_address" => "tcp://PRAEFECT_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  5. git push中のGitalyノードからのコールバックが適切に認証されるように、GitLab Shellシークレットトークンを設定します。次のいずれかの操作を行います:

    • 方法1:

      1. /etc/gitlab/gitlab-secrets.jsonをGitalyクライアントからGitalyサーバーおよびその他のGitalyクライアントの同じパスにコピーします。
      2. Gitalyサーバー上でGitLabを再設定します。
    • 方法2:

      1. /etc/gitlab/gitlab.rbを編集します。

      2. GITLAB_SHELL_SECRET_TOKENを実際のシークレットに置き換えます:

        • GitLab 17.5以降:

          gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
        • GitLab 17.4以前:

          gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
  6. /etc/gitlab/gitlab.rbを編集してPrometheusのモニタリング設定を追加します。Prometheusが別のノードで有効になっている場合は、代わりにそのノードで編集してください。

    以下を置き換える必要があります:

    • PRAEFECT_HOSTをPraefectノードのIPアドレスまたはホスト名に置き換えます。
    • GITALY_HOST_*を各GitalyノードのIPアドレスまたはホスト名に置き換えます。
    prometheus['scrape_configs'] = [
      {
        'job_name' => 'praefect',
        'static_configs' => [
          'targets' => [
            'PRAEFECT_HOST:9652', # praefect-1
            'PRAEFECT_HOST:9652', # praefect-2
            'PRAEFECT_HOST:9652', # praefect-3
          ]
        ]
      },
      {
        'job_name' => 'praefect-gitaly',
        'static_configs' => [
          'targets' => [
            'GITALY_HOST_1:9236', # gitaly-1
            'GITALY_HOST_2:9236', # gitaly-2
            'GITALY_HOST_3:9236', # gitaly-3
          ]
        ]
      }
    ]
  7. /etc/gitlab/gitlab.rbへの変更を保存し、GitLabを再構成します:

    gitlab-ctl reconfigure
  8. 各GitalyノードでGitフックがGitLabに到達できることを確認します。各Gitalyノードで実行します:

    sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
  9. GitLabがPraefectに到達できることを確認します:

    gitlab-rake gitlab:gitaly:check
  10. Praefectストレージが新しいリポジトリを保存するように設定されていることを確認します:

    1. 右上隅で、管理者を選択します。
    2. 左サイドバーで、設定 > リポジトリを選択します。
    3. リポジトリのストレージセクションを展開します。

    このガイドに従うと、defaultストレージはすべての新しいリポジトリを保存するために100のウェイトを持つ必要があります。

  11. 新しいプロジェクトを作成して、すべてが機能していることを確認します。リポジトリに表示されるコンテンツがあるように、「Readmeでリポジトリを初期化」ボックスをチェックします。プロジェクトが作成され、Readmeファイルが表示されたら、機能しています。

既存のGitLabインスタンスにTCPを使用する

既存のGitalyインスタンスにGitalyクラスター (Praefect) を追加する場合、既存のGitalyストレージはTCP/TLSでリッスンしている必要があります。gitaly_addressが指定されていない場合、Unixソケットが使用され、クラスターとの通信が妨げられます。

例:

gitlab_rails['repositories_storages'] = {
  'default' => { 'gitaly_address' => 'tcp://old-gitaly.internal:8075' },
  'cluster' => {
    'gitaly_address' => 'tls://<PRAEFECT_LOADBALANCER_HOST>:3305',
    'gitaly_token' => '<praefect_external_token>'
  }
}

複数のGitalyストレージの実行に関する詳細については、混合設定を参照してください。

複数の仮想ストレージを設定する

複数の仮想ストレージを設定して、リポジトリを個別のGitalyクラスター (Praefect) クラスターに整理できます。各仮想ストレージは、独自のGitalyノードセットとレプリケーション設定で独立して動作します。

複数の仮想ストレージを設定するには:

  1. 各Praefectノードで、/etc/gitlab/gitlab.rbを編集してvirtual_storage配列に複数のエントリを追加します:

    praefect['configuration'] = {
       # ...
       virtual_storage: [
          {
             name: 'storage-1',
             default_replication_factor: 3,
             node: [
                {
                   storage: 'gitaly-1',
                   address: 'tcp://GITALY_HOST_1:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-2',
                   address: 'tcp://GITALY_HOST_2:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-3',
                   address: 'tcp://GITALY_HOST_3:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                }
             ]
          },
          {
             name: 'storage-2',
             default_replication_factor: 2,
             node: [
                {
                   storage: 'gitaly-4',
                   address: 'tcp://GITALY_HOST_4:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-5',
                   address: 'tcp://GITALY_HOST_5:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                },
                {
                   storage: 'gitaly-6',
                   address: 'tcp://GITALY_HOST_6:8075',
                   token: 'PRAEFECT_INTERNAL_TOKEN'
                }
             ]
          }
       ]
    }
  2. 変更を保存し、Praefectを再構成します:

    gitlab-ctl reconfigure
  3. GitLabサーバーで、/etc/gitlab/gitlab.rbを編集して両方の仮想ストレージを設定します:

    gitlab_rails['repositories_storages'] = {
      "storage-1" => {
        "gitaly_address" => "tcp://PRAEFECT_1_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      },
      "storage-2" => {
        "gitaly_address" => "tcp://PRAEFECT_2_LOADBALANCER_HOST:2305",
        "gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  4. 変更を保存し、GitLabを再構成します:

    gitlab-ctl reconfigure
  5. 設定を確認します:

    gitlab-rake gitlab:gitaly:check

設定後、以下を実行できます:

混合スタンドアロンおよびクラスターストレージを設定する

GitLabを設定して、スタンドアロンのGitalyインスタンスとGitalyクラスター (Praefect) 仮想ストレージの両方を同時に使用できます。移行中、または一部のリポジトリのみが高可用性を必要とする場合にこれを行うことがあります。

混合設定を設定するには:

  1. スタンドアロンのGitalyインスタンスがTCPでリッスンするように設定されていることを確認します。スタンドアロンのGitalyノードで、/etc/gitlab/gitlab.rbを編集します:

    gitaly['configuration'] = {
       # ...
       listen_addr: '0.0.0.0:8075'
    }
  2. スタンドアロンGitalyインスタンスの認証を設定します:

    gitaly['configuration'] = {
       # ...
       auth: {
          token: 'GITALY_AUTH_TOKEN',
       },
    }
  3. 保存して再構成します:

    gitlab-ctl reconfigure
  4. GitLabサーバーで、/etc/gitlab/gitlab.rbを編集してスタンドアロンおよびクラスターストレージの両方を設定します:

    gitlab_rails['repositories_storages'] = {
      'default' => {
        'gitaly_address' => 'tcp://STANDALONE_GITALY_HOST:8075',
        'gitaly_token' => 'GITALY_AUTH_TOKEN'
      },
      'cluster' => {
        'gitaly_address' => 'tcp://PRAEFECT_LOADBALANCER_HOST:2305',
        'gitaly_token' => 'PRAEFECT_EXTERNAL_TOKEN'
      }
    }
  5. 変更を保存し、GitLabを再構成します:

    gitlab-ctl reconfigure
  6. 両方のストレージにアクセスできることを確認します:

    gitlab-rake gitlab:gitaly:check

この設定では、次のようになります。

  • defaultストレージはスタンドアロンのGitalyノードに直接接続します。
  • clusterストレージは、ロードバランサーを介してGitalyクラスター (Praefect) に接続します。
  • GitLabは両方のストレージを同等に扱い、どちらのストレージにもリポジトリを保存できます。
  • 新しいリポジトリに対して、一方のストレージを他方よりも優先するようにストレージのウェイトを設定できます。

詳細については、混合設定を参照してください。

Grafana

GrafanaはGitLabに含まれており、Praefectクラスターをモニタリングするために使用できます。詳細なドキュメントについては、Grafanaダッシュボードサービスを参照してください。

簡単に始めるには:

  1. GitLabノード (またはGrafanaが有効になっているいずれかのノード) にSSHで接続し、rootとしてログインします:

    sudo -i
  2. /etc/gitlab/gitlab.rbを編集してGrafanaのログインフォームを有効にします。

    grafana['disable_login_form'] = false
  3. /etc/gitlab/gitlab.rbへの変更を保存し、GitLabを再構成します:

    gitlab-ctl reconfigure
  4. Grafana管理者のパスワードを設定します。このコマンドは、新しいパスワードの入力を求めます:

    gitlab-ctl set-grafana-password
  5. Webブラウザで、GitLabサーバーの/-/grafana (https://gitlab.example.com/-/grafanaなど) を開きます。

    設定したパスワードとユーザー名adminを使用してログインします。

  6. 検索に移動し、gitlab_build_infoをクエリして、すべてのマシンからメトリクスを取得していることを確認します。

おつかれさまでした。監視可能なフォールトトレラントなPraefectクラスターを設定しました。

レプリケーション係数を設定する

Praefectは、特定のストレージノードにリポジトリをホストするよう割り当てることで、リポジトリごとにレプリケーション係数を設定することをサポートしています。

オブジェクトプール、フォークしたリポジトリ、またはフォーク自体のレプリケーション係数を減らさないでください。これにより、フォークネットワーク全体が破損する可能性があります。オブジェクトプールには、@pools/で始まる相対パスがあります。リポジトリがフォークしたかどうかは、GitLab UIを通じて確認できます。

Praefectは実際のレプリケーション係数を保存しませんが、目的のレプリケーション係数が満たされるように、リポジトリをホストするのに十分なストレージを割り当てます。仮想ストレージからストレージノードが後で削除された場合、そのストレージに割り当てられたリポジトリのレプリケーション係数はそれに応じて減少します。

以下を設定できます:

  • 新しく作成されたリポジトリに適用される、各仮想ストレージのデフォルトレプリケーション係数。
  • 既存のリポジトリのレプリケーション係数をset-replication-factorサブコマンドで設定します。

デフォルトレプリケーション係数を設定する

オブジェクトプールがある場合にデフォルトレプリケーションを減らすと、一部のリンクされたリポジトリが破損する可能性があります。オブジェクトプールには、@pools/で始まる相対パスがあります。

If default_replication_factorが設定されていない場合、リポジトリはvirtual_storagesで定義されたすべてのストレージノードに常にレプリケートされます。仮想ストレージに新しいストレージノードが導入されると、新規および既存のリポジトリの両方が自動的にそのノードにレプリケートされます。

多くのストレージノードを持つ大規模なGitalyクラスター (Praefect) デプロイでは、すべてのストレージノードにリポジトリをレプリケートすることは合理的でない場合が多く、問題を引き起こす可能性があります。レプリケーション係数3は通常十分であり、これは利用可能なストレージがそれ以上あっても、3つのストレージにリポジトリをレプリケートすることを意味します。レプリケーション係数が高いほど、プライマリストレージへの負荷が増加します。

デフォルトレプリケーション係数を設定するには、/etc/gitlab/gitlab.rbファイルに設定を追加します:

praefect['configuration'] = {
   # ...
   virtual_storage: [
      {
         # ...
         name: 'default',
         default_replication_factor: 3,
      },
   ],
}

既存のリポジトリのレプリケーション係数を設定する

set-replication-factorサブコマンドは、必要なレプリケーション係数に到達するために、ランダムなストレージノードを自動的に割り当てまたは割り当て解除します。リポジトリのプライマリノードは常に最初に割り当てられ、割り当て解除されることはありません。

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml set-replication-factor -virtual-storage <virtual-storage> -relative-path <relative-path> -replication-factor <replication-factor>
  • -virtual-storageは、リポジトリが配置されている仮想ストレージです。
  • -relative-pathは、ストレージ内のリポジトリの相対パスです。
  • -replication-factorは、リポジトリの目的のレプリケーション係数です。プライマリはリポジトリのコピーを必要とするため、最小値は1です。最大レプリケーション係数は、仮想ストレージ内のストレージの数です。

成功すると、割り当てられたホストストレージが出力されます。例:

$ sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml set-replication-factor -virtual-storage default -relative-path @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git -replication-factor 2

current assignments: gitaly-1, gitaly-2

リポジトリストレージの推奨事項

必要なストレージのサイズはインスタンスによって異なり、設定されたレプリケーション係数に依存します。リポジトリストレージの冗長性の実装を含めることをお勧めします。

レプリケーション係数が次のとおりの場合:

  • 1の場合: GitalyとGitalyクラスター (Praefect) は、ほぼ同じストレージ要件を持っています。
  • 1より多い場合: 必要なストレージの量はused space * replication factorです。used spaceには、計画されている将来の成長を含める必要があります。

リポジトリの検証

Praefectは、リポジトリに関するメタデータをデータベースに保存します。リポジトリがPraefectを介さずにディスク上で変更された場合、メタデータが不正確になる可能性があります。例えば、Gitalyノードが新しいノードに置き換えられるのではなく再構築された場合、リポジトリの検証によってこれが検出されます。

メタデータはレプリケーションとルーティングの決定に使用されるため、不正確な点があると問題が発生する可能性があります。Praefectには、メタデータをディスク上の実際の状態と定期的に照合して検証するバックグラウンドワーカーが含まれています。ワーカーは次のとおりです:

  1. 健全なストレージで検証するレプリカのバッチを選択します。レプリカは未検証であるか、設定された検証間隔を超過しています。未検証のレプリカが優先され、次に最後の成功した検証からの時間が最も長い他のレプリカが続きます。
  2. レプリカがそれぞれのストレージに存在するかどうかを確認します。もし:
    • レプリカが存在する場合、最後の成功した検証時刻を更新します。
    • レプリカが存在しない場合、そのメタデータレコードを削除します。
    • チェックが失敗した場合、次のワーカーがさらに多くの作業をデキューするときに、レプリカは再び検証のために選択されます。

ワーカーは、検証しようとしている各レプリカに対して排他的な検証リースを取得します。これにより、複数のワーカーが同じレプリカを同時に検証するのを防ぎます。ワーカーは、チェックが完了するとリースを解放します。ワーカーが何らかの理由でリースを解放せずに終了した場合、Praefectは期限切れのリースを10秒ごとに解放するバックグラウンドgoroutineを含んでいます。

ワーカーは、メタデータの削除を実行する前にそれぞれをログに記録します。perform_deletionsキーは、無効なメタデータレコードが実際に削除されたかどうかを示します。例:

{
  "level": "info",
  "msg": "removing metadata records of non-existent replicas",
  "perform_deletions": false,
  "replicas": {
    "default": {
      "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b.git": [
        "praefect-internal-0"
      ]
    }
  }
}

検証ワーカーを設定する

ワーカーはデフォルトで有効になっており、7日ごとにメタデータレコードを検証します。検証間隔は、有効なGo期間文字列Go duration stringで設定できます。

3日ごとにメタデータを検証するには:

praefect['configuration'] = {
   # ...
   background_verification: {
      # ...
      verification_interval: '72h',
   },
}

0以下の値はバックグラウンドベリファイアーを無効にします。

praefect['configuration'] = {
   # ...
   background_verification: {
      # ...
      verification_interval: '0',
   },
}

削除を有効にする

リポジトリの名前変更との競合状態により不正確な削除が発生する可能性があるため、GitLab 15.9より前は削除がデフォルトで無効になっていました。これは、Geoを持たないインスタンスよりもGeoインスタンスの方が名前変更を多く実行するため、特に顕著です。GitLab 15.0から15.5では、gitaly_praefect_generated_replica_paths機能フラグが有効になっている場合にのみ、削除を有効にする必要があります。機能フラグはGitLab 15.6で削除され、これにより常に削除を安全に有効にできるようになりました。

デフォルトでは、ワーカーは無効なメタデータレコードを削除します。削除されたレコードをログに記録し、Prometheusメトリクスを出力します。

無効なメタデータレコードの削除は、次で無効にできます:

praefect['configuration'] = {
   # ...
   background_verification: {
      # ...
      delete_invalid_records: false,
   },
}

検証を手動で優先する

一部のレプリカの検証を、次のスケジュールされた検証時刻よりも早く優先させることができます。これは、ディスク障害の後などに必要になる場合があります。たとえば、管理者がディスクの内容が変更された可能性があることを認識している場合です。Praefectはいずれレプリカを再度検証しますが、それまでの間にユーザーはエラーに遭遇する可能性があります。

一部のレプリカの再検証を手動で優先するには、praefect verifyサブコマンドを使用します。サブコマンドはレプリカを未検証としてマークします。未検証のレプリカは、バックグラウンド検証ワーカーによって優先されます。レプリカを検証するには、検証ワーカーを有効にする必要があります。

特定のリポジトリのレプリカの検証を優先する:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml verify -repository-id=<repository-id>

仮想ストレージに保存されているすべてのレプリカの検証を優先する:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml verify -virtual-storage=<virtual-storage>

ストレージに保存されているすべてのレプリカの検証を優先する:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml verify -virtual-storage=<virtual-storage> -storage=<storage>

出力には、未検証としてマークされたレプリカの数が含まれます。

自動フェイルオーバーとプライマリ選出

Praefectは各Gitalyノードの健全性を定期的にヘルスチェックします。これは、現在のプライマリノードが異常であると判断された場合に、新しく選出されたプライマリGitalyノードに自動的にフェイルオーバーするために使用されます。

リポジトリ固有のプライマリノードが、利用可能な唯一の選出戦略です。

リポジトリ固有のプライマリノード

Gitaly Cluster (Praefect) は、各リポジトリごとに個別にプライマリGitalyノードを選出します。設定可能なレプリケーション要素と組み合わせることで、ストレージ容量を水平的にスケールするし、Gitalyノード間で書き込みロードを分散できます。

プライマリ選出は遅延実行されます。Praefectは、現在のプライマリノードが異常な場合、直ちに新しいプライマリノードを選出しません。現在のプライマリが利用できないときにリクエストを処理する必要がある場合、新しいプライマリが選出されます。

有効なプライマリノード候補は、次のGitalyノードです:

  • 健全であること。Gitalyノードは、>=50% Praefectノードが過去10秒間にGitalyノードのヘルスチェックに成功した場合に、健全であるとみなされます。
  • リポジトリの完全に最新のコピーを保持している。

複数のプライマリノード候補がある場合、Praefectは次の処理を行います:

  • ランダムに1つを選択します。
  • リポジトリをホストするように割り当てられたGitalyノードの昇格を優先します。プライマリとして選出する割り当てられたGitalyノードがない場合、Praefectは一時的に割り当てられていないノードを選出することがあります。利用可能な割り当てられたノードができた場合、割り当てられていないプライマリは、割り当てられたプライマリに置き換えられます。

あるリポジトリに有効なプライマリ候補がない場合:

  • 異常なプライマリノードは降格され、リポジトリにはプライマリノードがない状態になります。
  • プライマリノードを必要とする操作は、プライマリが正常に選出されるまで失敗します。