LinuxパッケージインストールにおけるPostgreSQLのレプリケーションとフェイルオーバー

GitLab セルフマネジメントのフリーユーザーであれば、クラウドホストソリューションを使うことを検討してください。この文書では、セルフコンパイルによるインストールはカバーしていません。

レプリケーションやフェイルオーバーの設定が求めていたものでない場合は、Linux パッケージのデータベース設定ドキュメントをご覧ください。

PostgreSQLをGitLab用にレプリケーションとフェイルオーバーで設定しようとする前に、このドキュメントを十分に読むことをお勧めします。

アーキテクチャ

Linux pacakageが推奨するレプリケーションフェイルオーバーを持つPostgreSQLクラスタの設定には、以下のものが必要です:

  • 最低3つのPostgreSQLノード。
  • 最低3台のConsulサーバーノード
  • プライマリデータベースの読み取りと書き込みを追跡し、処理する最低3台のPgBouncerノード。
    • 内部ロードバランサー(TCP) 、PgBouncerノード間のリクエストのバランスを取ります。
  • データベースのロードバランシングが有効です。
    • 各PostgreSQLノードに設定されたローカルPgBouncerサービス。これはプライマリを追跡するメインのPgBouncerクラスターとは別です。

また、ネットワークが単一障害点にならないように、すべてのデータベースとGitLabインスタンス間の冗長接続を確認し、基盤となるネットワークトポロジーを考慮する必要があります。

note
GitLab 13.3の時点で、PostgreSQL 12はLinuxパッケージのインストールで出荷されています。PostgreSQL 12のクラスターはPatroniでのみサポートされています。詳細はPatroniのセクションを参照してください。GitLab 14.0からはPostgreSQL 12のみがLinuxパッケージインストールで出荷されるため、レプリケーションとフェイルオーバーにはPatroniが必須となります。

データベースノード

各データベースノードは4つのサービスを実行します:

  • PostgreSQL:データベース自体
  • Patroni:クラスター内の他のPatroniサービスと通信を行い、リーダーサーバにイシューが発生した場合のフェイルオーバーを行います。フェイルオーバーの手順は以下の通りです:
    • クラスターの新しいリーダーを選択します。
    • 新しいノードをリーダーに昇格させます。
    • 残りのサーバーに新しいリーダーノードに従うように指示します。
  • PgBouncer:ノードのローカル・プーラ。データベースのロードバランシングの一部として_読み取り_クエリに使用されます。
  • Consul エージェント:現在のPatroniの状態を保存するConsulクラスタと通信します。エージェントはデータベースクラスタの各ノードの状態を監視し、Consulクラスタ上のサービス定義でその状態を追跡します。

Consulサーバノード

ConsulサーバノードはConsulサーバサービスを実行します。これらのノードはPatroniクラスタが起動する_前に_クォーラムに達し、リーダーを選出する必要があります。

PgBouncerノード

各PgBouncerノードは2つのサービスを実行します:

  • PgBouncer:データベース接続プーラー
  • Consul エージェント:Consulクラスタ上のPostgreSQLサービス定義の状態を監視します。ステータスが変更された場合、ConsulはPgBouncerの設定を更新して新しいPostgreSQLリーダーノードを指すようにし、PgBouncerサービスをリロードするスクリプトを実行します。

接続フロー

パッケージ内の各サービスには、デフォルトのポートセットが付属しています。以下に挙げる接続については、特定のファイアウォールルールを作成する必要があるかもしれません:

このセットアップにはいくつかの接続フローがあります:

プライマリー

  • アプリケーションサーバーはデフォルトのポートを経由して直接PgBouncerに接続するか、設定された内部ロードバランサー((TCP) )を経由して複数のPgBouncerに接続します。
  • PgBouncerはプライマリデータベースサーバのPostgreSQLデフォルトポートに接続します。

データベースの負荷分散

最近変更されておらず、すべてのデータベースノードで最新のデータに対する読み取りクエリ:

  • アプリケーションサーバは、ラウンドロビン方式で各データベースノードのデフォルトポートを経由してローカルのPgBouncerサービスに接続します。
  • ローカルのPgBouncerはローカルのデータベースサーバーのPostgreSQLのデフォルトポートに接続します。

レプリケーション

セットアップ

必要な情報

設定を進める前に、必要な情報をすべて収集する必要があります。

ネットワーク情報

PostgreSQLはデフォルトではどのネットワークインターフェースも待ち受けません。他のサービスからアクセスするためには、どのIPアドレスをリッスンするかを知る必要があります。同様に、PostgreSQLへのアクセスはネットワーク接続元に基づいて制御されます。

これが必要な理由です:

  • 各ノードのネットワーク・インターフェースのIPアドレス。これは、すべてのインターフェイスでリッスンするために0.0.0.0 に設定できます。ループバックアドレス127.0.0.1には設定できません。
  • ネットワーク・アドレス。これは、サブネット(つまり、192.168.0.0/255.255.255.0 )またはクラスレス・ドメイン間ルーティング(CIDR) (192.168.0.0/24) 形式にすることができます。

領事情報

デフォルト設定を使用する場合、最小限の設定が必要です:

  • CONSUL_USERNAME.Linuxパッケージ・インストールのデフォルト・ユーザーは次のとおりです。gitlab-consul
  • CONSUL_DATABASE_PASSWORD.データベース・ユーザーのパスワード。
  • CONSUL_PASSWORD_HASH.これはConsulのユーザー名とパスワードのペアから生成されたハッシュです。これは

     sudo gitlab-ctl pg-password-md5 CONSUL_USERNAME
    
  • CONSUL_SERVER_NODES.ConsulサーバーノードのIPアドレスまたはDNSレコード。

サービスに関する注意事項

  • デフォルトではgitlab-consul です。
  • 別のユーザー名を使用する場合は、CONSUL_USERNAME 変数で指定する必要があります。
  • パスワードは以下の場所に保存されます:
    • /etc/gitlab/gitlab.rbハッシュ
    • /var/opt/gitlab/pgbouncer/pg_authハッシュ
    • /var/opt/gitlab/consul/.pgpass: 平文

PostgreSQL 情報

PostgreSQLを設定する際には、以下のようにします:

  • max_replication_slots をデータベースノード数の2倍に設定します。Patroniはレプリケーションを開始する際に、1ノードあたり1スロット余分に使用します。
  • max_wal_senders 、クラスターに割り当てられたレプリケーション・スロット数より1つ多く設定してください。これにより、レプリケーションが利用可能なデータベース接続をすべて使い切ってしまうことを防ぎます。

このドキュメントでは、3つのデータベース・ノードを想定しています:

patroni['postgresql']['max_replication_slots'] = 6
patroni['postgresql']['max_wal_senders'] = 7

前述のように、データベースとの認証権限が必要なネットワークサブネットを準備します。また、ConsulサーバーノードのIPアドレスまたはDNSレコードを用意しておく必要があります。

アプリケーションのデータベースユーザーには以下のパスワード情報が必要です:

  • POSTGRESQL_USERNAME.Linuxパッケージ・インストールのデフォルト・ユーザーは次のとおりです。gitlab
  • POSTGRESQL_USER_PASSWORD.データベース・ユーザーのパスワードは
  • POSTGRESQL_PASSWORD_HASH.これはユーザ名とパスワードのペアから生成されるハッシュです。これは

     sudo gitlab-ctl pg-password-md5 POSTGRESQL_USERNAME
    

パトロニ情報

Patroni APIを利用するためには、以下のパスワード情報が必要です:

  • PATRONI_API_USERNAME.APIへの基本認証のためのユーザー名
  • PATRONI_API_PASSWORD.APIへの基本認証用パスワード

PgBouncer情報

デフォルトの設定を使用する場合、最小設定に必要なのは

  • PGBOUNCER_USERNAME.Linuxパッケージ・インストールのデフォルト・ユーザーは次のとおりです。pgbouncer
  • PGBOUNCER_PASSWORD.これはPgBouncerサービスのパスワードです。
  • PGBOUNCER_PASSWORD_HASH.これはPgBouncerのユーザー名/パスワードのペアから生成されたハッシュです。これは

     sudo gitlab-ctl pg-password-md5 PGBOUNCER_USERNAME
    
  • PGBOUNCER_NODEはPgBouncerが動作しているノードのIPアドレスまたはFQDNです。

サービス自体について覚えておくべきことがいくつかあります:

  • サービスはデータベースと同じシステムアカウントで実行されます。パッケージではデフォルトでgitlab-psql
  • PgBouncerサービスにデフォルト以外のユーザーアカウント(デフォルトはpgbouncer )を使用する場合、このユーザー名を指定する必要があります。
  • パスワードは以下の場所に保存されます:
    • /etc/gitlab/gitlab.rbハッシュ化されたプレーンテキスト
    • /var/opt/gitlab/pgbouncer/pg_authハッシュ

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

まず、各ノードにLinuxパッケージをダウンロードしてインストールしてください。

ステップ1から必要な依存関係をインストールし、ステップ2からGitLabパッケージリポジトリを追加してください。GitLabパッケージをインストールする時、EXTERNAL_URL

データベースノードの設定

  1. Consulノードの設定を確認してください。
  2. 次のステップを実行する前に、CONSUL_SERVER_NODES,PGBOUNCER_PASSWORD_HASH,POSTGRESQL_PASSWORD_HASH,dbノードの数ネットワークアドレスを必ず収集してください。

Patroniクラスターの設定

Patroniを使うには明示的に有効にする必要があります(patroni['enable'] = true)。

レプリケーションを制御するPostgreSQLの設定項目、例えばwal_levelmax_wal_senders 、その他はPatroniによって厳密に制御されます。これらの設定は、postgresql[...] コンフィギュレーションキーで行った元の設定を上書きします。したがって、これらはすべて分離され、patroni['postgresql'][...]の下に置かれます。この動作はレプリケーションに限定されます。Patroniはpostgresql[...] 設定キーで行った他のPostgreSQL設定を尊重します。例えば、デフォルトではmax_wal_senders5に設定されています。 これを変更したい場合はpatroni['postgresql']['max_wal_senders'] 設定キーで設定しなければなりません。

note
Patroniノードの設定はrepmgrと非常に似ていますが、より短いものです。Patroniが有効な場合、まずPostgreSQLのレプリケーション設定を無視することができます(上書きされます)。そして、repmgr[...] 、repmgr固有の設定も削除してください。特に、postgresql['shared_preload_libraries'] = 'repmgr_funcs' を削除してください。

以下に例を示します:

# Disable all components except Patroni, PgBouncer and Consul
roles(['patroni_role', 'pgbouncer_role'])

# PostgreSQL configuration
postgresql['listen_address'] = '0.0.0.0'

# Disable automatic database migrations
gitlab_rails['auto_migrate'] = false

# Configure the Consul agent
consul['services'] = %w(postgresql)

# START user configuration
# Please set the real values as explained in Required Information section
#
# Replace PGBOUNCER_PASSWORD_HASH with a generated md5 value
postgresql['pgbouncer_user_password'] = 'PGBOUNCER_PASSWORD_HASH'
# Replace POSTGRESQL_REPLICATION_PASSWORD_HASH with a generated md5 value
postgresql['sql_replication_password'] = 'POSTGRESQL_REPLICATION_PASSWORD_HASH'
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'

# Replace PATRONI_API_USERNAME with a username for Patroni Rest API calls (use the same username in all nodes)
patroni['username'] = 'PATRONI_API_USERNAME'
# Replace PATRONI_API_PASSWORD with a password for Patroni Rest API calls (use the same password in all nodes)
patroni['password'] = 'PATRONI_API_PASSWORD'

# Sets `max_replication_slots` to double the number of database nodes.
# Patroni uses one extra slot per node when initiating the replication.
patroni['postgresql']['max_replication_slots'] = X

# Set `max_wal_senders` to one more than the number of replication slots in the cluster.
# This is used to prevent replication from using up all of the
# available database connections.
patroni['postgresql']['max_wal_senders'] = X+1

# Replace XXX.XXX.XXX.XXX/YY with Network Addresses for your other patroni nodes
patroni['allowlist'] = %w(XXX.XXX.XXX.XXX/YY 127.0.0.1/32)

# Replace XXX.XXX.XXX.XXX/YY with Network Address
postgresql['trust_auth_cidr_addresses'] = %w(XXX.XXX.XXX.XXX/YY 127.0.0.1/32)

# Local PgBouncer service for Database Load Balancing
pgbouncer['databases'] = {
  gitlabhq_production: {
    host: "127.0.0.1",
    user: "PGBOUNCER_USERNAME",
    password: 'PGBOUNCER_PASSWORD_HASH'
  }
}

# Replace placeholders:
#
# Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
# with the addresses gathered for CONSUL_SERVER_NODES
consul['configuration'] = {
  retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
}
#
# END user configuration

すべてのデータベースノードが同じ設定を使用します。リーダノードは設定で決定されず、リーダノードとレプリカノードのどちらにも追加設定や異なる設定はありません。

ノードの設定が完了したら、変更を有効にするために各ノードでGitLabを再設定する必要があります。

通常、Consulクラスターの準備ができたら、最初に再設定を行ったノードがリーダーになります。ノードの再設定を順番に行う必要はありません。並列に実行しても、任意の順番で実行してもかまいません。任意の順序を選択した場合、あらかじめ決められたリーダーは存在しません。

モニタリングの有効化

GitLab 12.0から導入されました

モニタリングを有効にする場合、全てのデータベースサーバーで有効にする必要があります。

  1. /etc/gitlab/gitlab.rb を作成/編集し、以下の設定を追加します:

    # Enable service discovery for Prometheus
    consul['monitoring_service_discovery'] = true
       
    # Set the network addresses that the exporters must listen on
    node_exporter['listen_address'] = '0.0.0.0:9100'
    postgres_exporter['listen_address'] = '0.0.0.0:9187'
    
  2. sudo gitlab-ctl reconfigure を実行して設定をコンパイルします。

Patroni APIのTLSサポートを有効にします。

デフォルトではPatroniREST APIはHTTPで提供されます。TLSを有効にして、同じポートでHTTPSを使用するオプションがあります。

TLSを有効にするには、PEM形式の証明書と秘密鍵ファイルが必要です。どちらのファイルもPostgreSQLユーザー(gitlab-psql がデフォルト、もしくはpostgresql['username'] で設定されたユーザー)が読めるものでなければなりません:

patroni['tls_certificate_file'] = '/path/to/server/certificate.pem'
patroni['tls_key_file'] = '/path/to/server/key.pem'

サーバの秘密鍵が暗号化されている場合、それを復号するためのパスワードを指定してください:

patroni['tls_key_password'] = 'private-key-password' # This is the plain-text password.

自己署名証明書や内部CAを使用している場合は、TLS検証を無効にするか、内部CAの証明書を渡す必要があります。そうしないとgitlab-ctl patroni .... コマンドを使うときに予期せぬエラーに遭遇する可能性があります。LinuxパッケージはPatroni APIクライアントがこの設定に従うことを保証します。

TLS証明書検証はデフォルトで有効になっています。無効にするには

patroni['tls_verify'] = false

あるいは、内部CAのPEM形式の証明書を渡すこともできます。この場合も、ファイルはPostgreSQLユーザが読めるものでなければなりません:

patroni['tls_ca_file'] = '/path/to/ca.pem'

TLSが有効な場合、全てのエンドポイントにおいてAPIサーバとクライアントの相互認証が可能で、その範囲はpatroni['tls_client_mode'] 属性に依存します:

  • none (デフォルト):APIはクライアントの証明書をチェックしません。
  • optional:クライアント証明書は、すべての安全でないAPI 呼び出しに必要です。
  • required:すべてのAPIコールにクライアント証明書が必要です。

クライアント証明書は、patroni['tls_ca_file'] 属性で指定された CA 証明書と照合して検証されます。したがって、この属性は相互TLS認証に必要です。また、PEM 形式のクライアント証明書ファイルと秘密鍵ファイルを指定する必要があります。どちらのファイルもPostgreSQLユーザが読めるものでなければなりません:

patroni['tls_client_mode'] = 'required'
patroni['tls_ca_file'] = '/path/to/ca.pem'

patroni['tls_client_certificate_file'] = '/path/to/client/certificate.pem'
patroni['tls_client_key_file'] = '/path/to/client/key.pem'

異なるPatroniノード上のAPIサーバとクライアントで、検証可能であれば異なる証明書と鍵を使用することができます。ただし、CA証明書(patroni['tls_ca_file'])、TLS証明書検証(patroni['tls_verify'])、クライアントTLS認証モード(patroni['tls_client_mode'])は全ノードで同じ値である必要があります。

PgBouncerノードの設定

  1. 次のステップを実行する前に、CONSUL_SERVER_NODESCONSUL_PASSWORD_HASHPGBOUNCER_PASSWORD_HASH

  2. 各ノードで、/etc/gitlab/gitlab.rb 設定ファイルを編集し、# START user configuration セクションに記載されている値を以下のように置き換えます:

    # Disable all components except PgBouncer and Consul agent
    roles(['pgbouncer_role'])
       
    # Configure PgBouncer
    pgbouncer['admin_users'] = %w(pgbouncer gitlab-consul)
       
    # Configure Consul agent
    consul['watchers'] = %w(postgresql)
       
    # START user configuration
    # Please set the real values as explained in Required Information section
    # Replace CONSUL_PASSWORD_HASH with with a generated md5 value
    # Replace PGBOUNCER_PASSWORD_HASH with with a generated md5 value
    pgbouncer['users'] = {
      'gitlab-consul': {
        password: 'CONSUL_PASSWORD_HASH'
      },
      'pgbouncer': {
        password: 'PGBOUNCER_PASSWORD_HASH'
      }
    }
    # Replace placeholders:
    #
    # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
    # with the addresses gathered for CONSUL_SERVER_NODES
    consul['configuration'] = {
      retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
    }
    #
    # END user configuration
    
    note
    pgbouncer_role はGitLab 10.3で導入されました。
  3. 走るgitlab-ctl reconfigure

  4. ConsulがPgBouncerをリロードできるように.pgpass 。と聞かれたら、PGBOUNCER_PASSWORD を2回入力してください:

    gitlab-ctl write-pgpass --host 127.0.0.1 --database pgbouncer --user pgbouncer --hostuser gitlab-consul
    
  5. モニタリングの有効化

PgBouncerチェックポイント

  1. 各ノードが現在のノードリーダーと話していることを確認します:

    gitlab-ctl pgb-console # Supply PGBOUNCER_PASSWORD when prompted
    

    パスワードを入力した後にエラー(psql: ERROR: Auth failed )が発生した場合は、以前に正しいフォーマットでMD5パスワード・ハッシュを生成していることを確認してください。正しいフォーマットは、パスワードとユーザー名を連結したものです:PASSWORDUSERNAME 。たとえば、Sup3rS3cr3tpgbouncer は、pgbouncer ユーザーの MD5 パスワードハッシュを生成するために必要なテキストです。

  2. コンソールプロンプトが使用可能になったら、以下のクエリを実行します:

    show databases ; show clients ;
    

    出力は以下のようになるはずです:

            name         |  host       | port |      database       | force_user | pool_size | reserve_pool | pool_mode | max_connections | current_connections
    ---------------------+-------------+------+---------------------+------------+-----------+--------------+-----------+-----------------+---------------------
     gitlabhq_production | MASTER_HOST | 5432 | gitlabhq_production |            |        20 |            0 |           |               0 |                   0
     pgbouncer           |             | 6432 | pgbouncer           | pgbouncer  |         2 |            0 | statement |               0 |                   0
    (2 rows)
       
     type |   user    |      database       |  state  |   addr         | port  | local_addr | local_port |    connect_time     |    request_time     |    ptr    | link | remote_pid | tls
    ------+-----------+---------------------+---------+----------------+-------+------------+------------+---------------------+---------------------+-----------+------+------------+-----
     C    | pgbouncer | pgbouncer           | active  | 127.0.0.1      | 56846 | 127.0.0.1  |       6432 | 2017-08-21 18:09:59 | 2017-08-21 18:10:48 | 0x22b3880 |      |          0 |
    (2 rows)
    

内部ロードバランサーの設定

推奨されているように複数のPgBouncerノードを実行している場合、TCP内部ロードバランサーを設定する必要があります。これは評判の良いTCPロードバランサーで実現できます。

例として、HAProxyを使った方法を紹介します:

global
    log /dev/log local0
    log localhost local1 notice
    log stdout format raw local0

defaults
    log global
    default-server inter 10s fall 3 rise 2
    balance leastconn

frontend internal-pgbouncer-tcp-in
    bind *:6432
    mode tcp
    option tcplog

    default_backend pgbouncer

backend pgbouncer
    mode tcp
    option tcp-check

    server pgbouncer1 <ip>:6432 check
    server pgbouncer2 <ip>:6432 check
    server pgbouncer3 <ip>:6432 check

ロードバランサのドキュメントを参照してください。

アプリケーションノードの設定

アプリケーションノードはgitlab-rails サービスを実行します。他の属性を設定することもできますが、以下の属性を設定する必要があります。

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

    # Disable PostgreSQL on the application node
    postgresql['enable'] = false
       
    gitlab_rails['db_host'] = 'PGBOUNCER_NODE' or 'INTERNAL_LOAD_BALANCER'
    gitlab_rails['db_port'] = 6432
    gitlab_rails['db_password'] = 'POSTGRESQL_USER_PASSWORD'
    gitlab_rails['auto_migrate'] = false
    gitlab_rails['db_load_balancing'] = { 'hosts' => ['POSTGRESQL_NODE_1', 'POSTGRESQL_NODE_2', 'POSTGRESQL_NODE_3'] }
    
  2. 変更を有効にするには、GitLabを再設定してください。

アプリケーションノードの設定後

すべてのマイグレーションが実行されたことを確認します:

gitlab-rake gitlab:db:configure

注意: PgBouncerがPostgreSQLに接続できないというrake aborted! エラーが発生した場合、PgBouncerノードのIPアドレスがデータベースノードのgitlab.rb 、PostgreSQLのtrust_auth_cidr_addressesPgBouncerエラーERROR: pgbouncer cannot connect to server トラブルシューティングを参照ください。

バックアップ

PgBouncer接続を通してGitLabのバックアップやリストアをしないでください:GitLabが停止してしまいます。

バックアップの再設定方法についてはこちらをご覧ください。

GitLabが稼働していることを確認します。

この時点で、GitLab インスタンスが稼働しているはずです。サインインし、イシューやマージリクエストを作成できることを確認しましょう。問題が発生した場合は、トラブルシューティングのセクションを参照してください。

設定例

このセクションでは、完全に拡張されたいくつかの設定例について説明します。

この例では、3台のConsulサーバ、3台のPgBouncerサーバ(関連する内部ロードバランサ付き)、3台のPostgreSQLサーバ、1台のアプリケーションノードを使用しています。

全てのサーバは同じ10.6.0.0/16の非公開ネットワークにあり、これらのアドレスで自由に接続できます。

各マシンと割り当てられたIPのリストと説明は以下の通りです:

  • 10.6.0.11:領事1
  • 10.6.0.12:領事2
  • 10.6.0.13:領事3
  • 10.6.0.20:内部ロードバランサー
  • 10.6.0.21:PgBouncer 1
  • 10.6.0.22:用心棒2
  • 10.6.0.23:用心棒3
  • 10.6.0.31:PostgreSQL 1
  • 10.6.0.32:PostgreSQL 2
  • 10.6.0.33:PostgreSQL 3
  • 10.6.0.41:GitLabアプリケーション

すべてのパスワードはtoomanysecrets に設定されています。このパスワードや派生ハッシュは使用しないでください。GitLabのexternal_urlhttp://gitlab.example.com

初期設定の後、フェイルオーバーが発生すると、PostgreSQLリーダーノードはフェイルバックされるまで利用可能なセカンダリノードの1つに変更されます。

各サーバーで/etc/gitlab/gitlab.rb を編集します:

# Disable all components except Consul
roles(['consul_role'])

consul['configuration'] = {
  server: true,
  retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
consul['monitoring_service_discovery'] =  true

変更を有効にするには、GitLabを再設定してください。

各サーバで/etc/gitlab/gitlab.rbを編集します:

# Disable all components except Pgbouncer and Consul agent
roles(['pgbouncer_role'])

# Configure PgBouncer
pgbouncer['admin_users'] = %w(pgbouncer gitlab-consul)

pgbouncer['users'] = {
  'gitlab-consul': {
    password: '5e0e3263571e3704ad655076301d6ebe'
  },
  'pgbouncer': {
    password: '771a8625958a529132abe6f1a4acb19c'
  }
}

consul['watchers'] = %w(postgresql)
consul['configuration'] = {
  retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
consul['monitoring_service_discovery'] =  true

変更を有効にするには、GitLabを再設定してください。

内部ロードバランサーの設定

内部ロードバランサー(TCP) は各PgBouncerノード(この例では10.6.0.20 のIP)に提供するために設定する必要があります。設定方法はPgBouncer Configure Internal Load Balancerを参照してください。

データベースノードで/etc/gitlab/gitlab.rb を編集します:

# Disable all components except Patroni, PgBouncer and Consul
roles(['patroni_role', 'pgbouncer_role'])

# PostgreSQL configuration
postgresql['listen_address'] = '0.0.0.0'
postgresql['hot_standby'] = 'on'
postgresql['wal_level'] = 'replica'

# Disable automatic database migrations
gitlab_rails['auto_migrate'] = false

postgresql['pgbouncer_user_password'] = '771a8625958a529132abe6f1a4acb19c'
postgresql['sql_user_password'] = '450409b85a0223a214b5fb1484f34d0f'
patroni['username'] = 'PATRONI_API_USERNAME'
patroni['password'] = 'PATRONI_API_PASSWORD'
patroni['postgresql']['max_replication_slots'] = 6
patroni['postgresql']['max_wal_senders'] = 7

patroni['allowlist'] = = %w(10.6.0.0/16 127.0.0.1/32)
postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/16 127.0.0.1/32)

# Local PgBouncer service for Database Load Balancing
pgbouncer['databases'] = {
  gitlabhq_production: {
    host: "127.0.0.1",
    user: "pgbouncer",
    password: '771a8625958a529132abe6f1a4acb19c'
  }
}

# Configure the Consul agent
consul['services'] = %w(postgresql)
consul['configuration'] = {
  retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
consul['monitoring_service_discovery'] =  true

変更を有効にするには、GitLabを再設定してください。

設定をデプロイしたら、以下の手順に従ってください:

  1. プライマリデータベースノードを見つけます:

    gitlab-ctl get-postgresql-primary
    
  2. アプリケーション・サーバーの10.6.0.41

    gitlab-consul ユーザーの PgBouncer パスワードをtoomanysecrets に設定します:

    gitlab-ctl write-pgpass --host 127.0.0.1 --database pgbouncer --user pgbouncer --hostuser gitlab-consul
    

    データベースのマイグレーションを実行します:

    gitlab-rake gitlab:db:configure
    

パトロニ

note
Repmgrの代わりにPatroniを使用することはPostgreSQL 11でサポートされており、PostgreSQL 12では必須です。GitLab 14.0からはPostgreSQL 12のみが利用可能で、フェイルオーバーとレプリケーションを実現するためにPatroniは必須です。

PatroniはPostgreSQLの高可用性を実現するソリューションです。PostgreSQLを制御し、設定を上書きし、ライフサイクル(起動、停止、再起動)を管理します。PatroniはPostgreSQL 12のクラスタリングとデプロイ用のカスケードレプリケーションのための唯一のオプションです。

基本的なアーキテクチャ(上記)はPatroniでも変わりません。データベースノードをプロビジョニングする際に、Patroniを特別に考慮する必要はありません。Patroniはクラスターの状態を保存し、リーダーを選出するためにConsulに大きく依存しています。Consulクラスタとそのリーダー選出に障害が発生すると、Patroniクラスタにも同様に伝搬します。

Patroniはクラスターを監視し、フェイルオーバーを処理します。プライマリノードに障害が発生すると、Consulと連携してPgBouncerに通知します。障害が発生すると、Patroniは古いプライマリのレプリカへの移行を処理し、自動的にクラスタに再参加させます。

Patroniの場合、接続フローは少し異なります。各ノードのPatroniはConsulエージェントに接続してクラスターに参加します。この時点で初めて、そのノードがプライマリかレプリカかを判断します。この決定に基づいて、PostgreSQLを設定し、起動します。PostgreSQLはUnixソケットで直接通信します。つまり、Consulクラスタが機能していなかったり、リーダがいなかったりすると、Patroni、ひいてはPostgreSQLは起動しません。PatroniはREST APIも公開しており、各ノードのデフォルトポートからアクセスすることができます。

レプリケーション状況の確認

gitlab-ctl patroni members を実行して Patroni にクラスタステータスの概要をクエリします:

+ Cluster: postgresql-ha (6970678148837286213) ------+---------+---------+----+-----------+
| Member                              | Host         | Role    | State   | TL | Lag in MB |
+-------------------------------------+--------------+---------+---------+----+-----------+
| gitlab-database-1.example.com       | 172.18.0.111 | Replica | running |  5 |         0 |
| gitlab-database-2.example.com       | 172.18.0.112 | Replica | running |  5 |       100 |
| gitlab-database-3.example.com       | 172.18.0.113 | Leader  | running |  5 |           |
+-------------------------------------+--------------+---------+---------+----+-----------+

レプリケーションの状態を確認するには

echo -e 'select * from pg_stat_wal_receiver\x\g\x \n select * from pg_stat_replication\x\g\x' | gitlab-psql

同じコマンドを3台すべてのデータベースサーバで実行できます。サーバーが実行しているロールに応じて、レプリケーションに関するあらゆる情報が返されます。

リーダーはレプリカ1つにつき1つのレコードを返す必要があります:

-[ RECORD 1 ]----+------------------------------
pid              | 371
usesysid         | 16384
usename          | gitlab_replicator
application_name | gitlab-database-1.example.com
client_addr      | 172.18.0.111
client_hostname  |
client_port      | 42900
backend_start    | 2021-06-14 08:01:59.580341+00
backend_xmin     |
state            | streaming
sent_lsn         | 0/EA13220
write_lsn        | 0/EA13220
flush_lsn        | 0/EA13220
replay_lsn       | 0/EA13220
write_lag        |
flush_lag        |
replay_lag       |
sync_priority    | 0
sync_state       | async
reply_time       | 2021-06-18 19:17:14.915419+00

もしそうなら、さらに調査してください:

  • 記録漏れや余分な記録がある場合
  • reply_time は最新ではありません。

lsn フィールドは、どのライトアヘッドログセグメントがレプリケートされたかに関連します。現在のログシーケンス番号(LSN)を調べるには、リーダー上で以下を実行してください:

echo 'SELECT pg_current_wal_lsn();' | gitlab-psql

レプリカが同期していない場合、gitlab-ctl patroni members は欠落しているデータ量を示し、lag フィールドは経過時間を示します。

leaderが返すデータについては、state フィールドの他の値を含め、PostgreSQLのドキュメントを参照してください。

レプリカは

-[ RECORD 1 ]---------+-------------------------------------------------------------------------------------------------
pid                   | 391
status                | streaming
receive_start_lsn     | 0/D000000
receive_start_tli     | 5
received_lsn          | 0/EA13220
received_tli          | 5
last_msg_send_time    | 2021-06-18 19:16:54.807375+00
last_msg_receipt_time | 2021-06-18 19:16:54.807512+00
latest_end_lsn        | 0/EA13220
latest_end_time       | 2021-06-18 19:07:23.844879+00
slot_name             | gitlab-database-1.example.com
sender_host           | 172.18.0.113
sender_port           | 5432
conninfo              | user=gitlab_replicator host=172.18.0.113 port=5432 application_name=gitlab-database-1.example.com

レプリカが返すデータについての詳細はPostgreSQLのドキュメントを参照してください。

適切なPatroniレプリケーションメソッドの選択

変更する前にPatroniのドキュメントをよくレビューしてください。 いくつかのオプションは完全に理解されていない場合、潜在的なデータ損失のリスクを伴います。.設定されたレプリケーションモードにより、許容されるデータ損失の量が決まります。

caution
レプリケーションはバックアップ戦略ではありません!十分に検討されテストされたバックアップソリューションに代わるものはありません。

Linuxパッケージのインストールはデフォルトでsynchronous_commiton

postgresql['synchronous_commit'] = 'on'
gitlab['geo-postgresql']['synchronous_commit'] = 'on'

Patroni フェイルオーバー動作のカスタマイズ

Linuxパッケージのインストールでは、Patroniのリストアプロセスをコントロールするためのいくつかのオプションが用意されています。

各オプションのデフォルト値を/etc/gitlab/gitlab.rb に示します。

patroni['use_pg_rewind'] = true
patroni['remove_data_directory_on_rewind_failure'] = false
patroni['remove_data_directory_on_diverged_timelines'] = false

アップストリームのドキュメントは常に最新ですが、以下の表は機能の最低限の概要を提供するものです。

設定概要--use_pg_rewind |データベースクラスタに再参加する前に、以前のクラスタリーダ上でpg_rewind 。|remove_data_directory_on_rewind_failurepg_rewind |失敗した場合、ローカルのPostgreSQLデータディレクトリを削除し、現在のクラスタリーダから再複製してください。|remove_data_directory_on_diverged_timelinespg_rewind |使用できず、以前のリーダのタイムラインが現在のタイムラインから乖離している場合、ローカルのデータディレクトリを削除し、現在のクラスタリーダから再複製してください。| |失敗した場合、ローカルのPostgreSQLデータディレクトリを削除し、現在のクラスタリーダから再複製してください。

Patroniのデータベース作成者

PatroniはPostgreSQLインスタンスを管理するためにUnixソケットを使用します。そのため、local ソケットからの接続は信頼されなければなりません。

また、レプリカはリーダーとの通信にレプリケーションユーザー( デフォルトではgitlab_replicator )を使用します。このユーザーには、trustmd5 のどちらかの認証を選択できます。postgresql['sql_replication_password'] を設定した場合、Patroniはmd5 認証を使用し、それ以外の場合はtrustにフォールバックします。 クラスタのCIDRはそれぞれpostgresql['md5_auth_cidr_addresses'] またはpostgresql['trust_auth_cidr_addresses'] で指定する必要があります。

クラスターとのやりとり

gitlab-ctl patroni members を使ってクラスタメンバーの状態を確認することができます。各ノードのステータスを確認するためにgitlab-ctl patroni にはcheck-leadercheck-replica という2つのサブコマンドがあり、ノードがプライマリかレプリカかを示します。

Patroniが有効な場合、PostgreSQLの起動、シャットダウン、再起動を排他的に制御します。つまり、あるノードのPostgreSQLをシャットダウンするには、同じノードのPatroniをシャットダウンしなければなりません:

sudo gitlab-ctl stop patroni

リーダーノードでPatroniサービスを停止または再起動すると、自動的にフェイルオーバーが発生します。フェイルオーバーを発生させずにPatroniの設定をリロードしたり、PostgreSQLプロセスを再起動する必要がある場合は、gitlab-ctl patroni のサブコマンドreload またはrestart を使用してください。これら2つのサブコマンドは同じpatronictl コマンドのラッパーです。

Patroniの手動フェイルオーバー手順

Patroniは自動フェイルオーバーをサポートしていますが、手動フェイルオーバーも可能です:

  • フェイルオーバー: 健全なノードがない場合に手動でフェイルオーバーを行うことができます。このアクションはどのPostgreSQLノードでも実行できます:

     sudo gitlab-ctl patroni failover
    
  • Switchover:クラスターが健全な時にのみ動作し、切り替えをスケジュールすることができます(すぐに実行することもできます)。どのPostgreSQLノードでもこのアクションを実行できます:

     sudo gitlab-ctl patroni switchover
    

この件に関する詳細はPatroniのドキュメントを参照してください。

Geoセカンダリーサイトの考察

GeoセカンダリサイトがPatroniPgBouncer を使用するプライマリサイトからレプリケートする場合、PgBouncerを介したレプリケーションはサポートされません。セカンダリノードはクラスターのリーダーノードから直接レプリケートする必要がありますPatroniPatroniクラスターPatroni 内で自動または手動でフェイルオーバーが Patroni発生した場合、セカンダリサイトを手動で再指定して、新しいリーダーノードからレプリケートすることができます:

sudo gitlab-ctl replicate-geo-database --host=<new_leader_ip> --replication-slot=<slot_name>

そうしないと、元のノードがフォロワーノードとして再追加されても、レプリケーションは行われません。これはセカンダリ・サイトのデータベースを再同期するもので、同期するデータ量によっては長い時間がかかる場合があります。再同期後もレプリケーションが機能しない場合は、gitlab-ctl reconfigure

Patroniクラスターのリカバリ

古いプライマリをリカバリしてレプリカとしてクラスターに再参加させるには、Patroniを起動します:

sudo gitlab-ctl start patroni

これ以上の設定や介入は必要ありません。

パトロニのメンテナンス手順

Patroniを有効にすると、ノードに対して計画的なメンテナンスを実行することができます。Patroniを使用していないノードのメンテナンスを行うには、以下の手順でメンテナンスモードにします:

sudo gitlab-ctl patroni pause

Patroniが一時停止モードで動作している場合、PostgreSQLの状態は変化しません。終了後、Patroniを再開することができます:

sudo gitlab-ctl patroni resume

詳細はPatroniのドキュメントを参照してください。

repmgrからPatroniへの切り替え

caution
repmgrからPatroniへの切り替えは簡単です。Patroniからrepmgrへのロールバックは複雑で、データディレクトリの削除を伴うかもしれません。その必要がある場合はGitLabサポートに連絡してください。

以下の手順で、終了したデータベースクラスタをrepmgrの代わりにPatroniを使うように切り替えることができます:

  1. すべてのレプリカノードでrepmgrを停止し、最後にプライマリノードで停止します:

    sudo gitlab-ctl stop repmgrd
    
  2. すべてのレプリカノードでPostgreSQLを停止します:

    sudo gitlab-ctl stop postgresql
    
    note
    プライマリノードでwalsender プロセスが実行されていないことを確認してください。ps aux | grep walsender に実行中のプロセスが表示されていないことを確認してください。
  3. プライマリノードでPatroniを設定します。repmgr 、その他のrepmgr固有の設定を削除します。PostgreSQLレプリケーションに関連する設定もすべて削除してください。
  4. プライマリノードでGitLabを再設定します。これでリーダーノードになります。これで確認できます:

    sudo gitlab-ctl tail patroni
    
  5. 最後の二つのステップをすべてのレプリカノードで繰り返します。gitlab.rb はすべてのノードで同じように見えるはずです。
  6. 存在する場合は、gitlab_repmgr プライマリ上のデータベースとロールを gitlab_repmgr削除してください。データベースをgitlab_repmgr 削除 gitlab_repmgrしないと、PostgreSQL 11から12へのアップグレードは失敗します:

    could not load library "$libdir/repmgr_funcs": ERROR:  could not access file "$libdir/repmgr_funcs": No such file or directory
    

PatroniクラスタでのPostgreSQLメジャーバージョンのアップグレード

GitLab 14.1では、PostgreSQL 12.6と13.3はデフォルトでLinuxパッケージに同梱されています。GitLab 15.0ではPostgreSQL 13がデフォルトです。GitLab 15.0より前のバージョンでPostgreSQL 13にアップグレードしたい場合は、明示的にリクエストする必要があります。

caution
PatroniクラスターでPostgreSQLをアップグレードする手順は、repmgrを使ってアップグレードする場合とは異なります。以下に、PostgreSQLをアップグレードする際の主な違いと重要な考慮点の概要を示します。

PostgreSQLをアップグレードする前に考慮しなければならないいくつかの重要な事実を示します:

  • 最大のポイントは、Patroniクラスターをシャットダウンしなければならないということです。これは、データベースのアップグレードの間、あるいは少なくともリーダーノードがアップグレードされる間、GitLabのデプロイが停止することを意味します。これは、データベースのサイズによってはかなりのダウンタイムになる可能性があります。

  • PostgreSQL をアップグレードすると、新しい制御データを持つ新しいデータディレクトリが作成されます。Petroniから見ると、これは新しいクラスターであり、再度ブートストラップする必要があります。したがって、アップグレード手順の一環として、クラスターの状態(Consulに保存されている)は消去されます。アップグレードが完了すると、Patroniは新しいクラスターをブートストラップします。これにより_クラスターIDが_変更されます。

  • リーダーとレプリカのアップグレード手順は同じではありません。そのため、各ノードで正しい手順を使用することが重要です。

  • レプリカノードをアップグレードすると、データディレクトリが削除され、設定されたレプリケーション方法を使用してリーダーから再同期されます(pg_basebackup が唯一の利用可能なオプションです)。データベースのサイズによっては、レプリカがリーダーに追いつくのに時間がかかる場合があります。

  • アップグレード手順の概要はPatroni のドキュメントにあります。この手順を実装しているgitlab-ctl pg-upgrade を、少し調整して使うこともできます。

これらを考慮した上で、PostgreSQLのアップグレードを慎重に計画してください:

  1. どのノードがリーダで、どのノードがレプリカかを調べてください:

    gitlab-ctl patroni members
    
    note
    Geoセカンダリノードでは、Patroniリーダーノードはstandby leader と呼ばれます。
  2. レプリカ上でのみPatroniを停止します。

    sudo gitlab-ctl stop patroni
    
  3. アプリケーションノードでメンテナンスモードを有効にします:

    sudo gitlab-ctl deploy-page up
    
  4. リーダーノードで PostgreSQL をアップグレードし、アップグレードが正常に完了したことを確認します:

    sudo gitlab-ctl pg-upgrade -V 13
    
    note
    gitlab-ctl pg-upgrade はノードのロールを検出しようとします。何らかの理由で自動検出がうまくいかなかったり、正しくロールを検出できなかったと思われる場合は、--leader--replica 引数を使用して手動で上書きすることができます。
  5. リーダーとクラスターの状態を確認します。リーダが正常である場合にのみ続行できます:

    gitlab-ctl patroni check-leader
       
    # OR
       
    gitlab-ctl patroni members
    
  6. アプリケーションノードのメンテナンスモードを無効にできます:

    sudo gitlab-ctl deploy-page down
    
  7. レプリカのPostgreSQLをアップグレードします(すべてのレプリカで並行して行うことができます):

    sudo gitlab-ctl pg-upgrade -V 13
    

レプリカのアップグレードでイシューが発生した場合、解決策となる可能性のあるトラブルシューティングセクションがあります。

note
gitlab-ctl revert-pg-upgrade 、PostgreSQLのアップグレードを元に戻すには、gitlab-ctl pg-upgrade と同じ考慮事項があります。まずレプリカを停止し、次にリーダを元に戻し、最後にレプリカを元に戻すという同じ手順を踏む必要があります。

PatroniクラスタにおけるPostgreSQLのほぼゼロダウンタイムのアップグレード

PatroniではPostgreSQLのメジャーアップグレードをクラスターをシャットダウンすることなく実行することができます。しかし、アップグレードされたPostgreSQLを持つ新しいPatroniノードをホストするための追加リソースが必要です。実際には、この手順では

  • 新しいバージョンのPostgreSQLで新しいPatroniクラスタを作成します。
  • 既存のクラスターからデータをマイグレーションします。

この手順は非侵襲的で、既存のクラスターをオフにする前に影響を与えることはありません。ただし、時間とリソースの両方がかかります。可用性とのトレードオフを考慮してください。

手順を順に説明します:

  1. 新しいクラスターのリソースをプロビジョニングします。
  2. プリフライトチェック
  3. 新しいクラスターのリーダーを設定します。
  4. 既存のリーダでパブリッシャーを開始します。
  5. 既存のクラスターからデータをコピーします。
  6. 既存のクラスターからデータを複製します。
  7. 新しいクラスターを成長させます。
  8. 新しいクラスターを使用するようにアプリケーションを切り替えます
  9. クリーンアップします。

新しいクラスターにリソースを提供します。

Patroniノード用の新しいリソースが必要です。新しいPatroniクラスタは既存のクラスタと全く同じ数のノードを必要としません。要件に応じて異なるノード数を選択できます。新しいクラスターは既存のConsulクラスター(異なるpatroni['scope'] )とPgBouncerノードを使用します。

少なくとも既存のクラスターのリーダーノードが新しいクラスターのノードからアクセス可能であることを確認してください。

プリフライトチェック

PostgreSQLの論理レプリケーションは、クラスターのダウンタイムがほぼゼロになるようなアップグレードをサポートします。論理レプリケーションの要件を満たす必要があります。特に、wal_levellogical でなければなりません。wal_levelを確認するには、既存のクラスターの任意のノードでgitlab-psql を指定して以下のコマンドを実行してください:

SHOW wal_level;

デフォルトでは、Patroniはwal_levelreplica に設定します。 これをlogical に増やす必要があります。wal_level を変更するにはPostgreSQLを再起動する必要があるため、この手順を実行するとダウンタイムが短くなります(つまりダウンタイムはほぼゼロになります)。Patroniリーダーノードでこれを行うには、以下の手順に従います:

  1. gitlab.rb

    patroni['postgresql']['wal_level'] = 'logical'
    
  2. Rungitlab-ctl reconfigure.これで設定が書き込まれますが、PostgreSQLサービスは再起動されません。
  3. gitlab-ctl patroni restart を実行して PostgreSQL を再起動し、フェイルオーバーをトリガせずに新しいwal_level を適用します。再起動サイクルの間、クラスター・リーダーは利用できません。
  4. gitlab-psqlSHOW wal_level を実行して変更を確認してください。

新しいクラスターのリーダーを設定します。

新しいクラスターの最初のノードを設定します。このノードが新しいクラスタのリーダになります。新しいPostgreSQLのバージョンと互換性があれば、既存のクラスターの設定を使用することができます。Patroniクラスタの設定に関するドキュメントを参照してください。

共通の設定に加えて、gitlab.rb

  1. 新しいPatroniクラスタが異なるスコープを使用していることを確認してください。スコープはConsulのPatroni設定の名前空間として使用され、既存のクラスタと新しいクラスタで同じConsulクラスタを使用することができます。

    patroni['scope'] = 'postgresql_new-ha'
    
  2. Consulエージェントが既存のPatroniクラスタと新しいPatroniクラスタで提供されるPostgreSQLサービスを混在させないようにしてください。このためには、内部属性を使用する必要があります:

    consul['internal']['postgresql_service_name'] = 'postgresql_new'
    

既存のリーダーでパブリッシャーを開始

既存のリーダー上で、論理レプリケーションパブリッシャーを開始するために、gitlab-psql を指定して、この SQL 文を実行してください:

CREATE PUBLICATION patroni_upgrade FOR ALL TABLES;

既存のクラスターからデータをコピーします。

既存のクラスターから現在のデータベースをダンプするには、新しいクラスターのリーダー上で以下のコマンドを実行します:

  1. オプション。グローバル・データベース・オブジェクトをコピーします:

    pg_dumpall -h ${EXISTING_CLUSTER_LEADER} -U gitlab-psql -g | gitlab-psql
    

    ロールなどの既存のデータベース・オブジェクトに関するエラーは無視できます。これらのオブジェクトは、ノードの初回設定時に作成されます。

  2. 現在のデータベースをコピーします:

    pg_dump -h ${EXISTING_CLUSTER_LEADER} -U gitlab-psql -d gitlabhq_production -s | gitlab-psql
    

    データベースのサイズによっては、このコマンドの完了に時間がかかる場合があります。

pg_dump およびpg_dumpall コマンドは/opt/gitlab/embedded/bin にあります。 これらのコマンドでは、EXISTING_CLUSTER_LEADER は既存のクラスターのリーダー・ノードのホスト・アドレスです。

note
gitlab-psql ユーザーは、新しいリーダーノードから既存のリーダーを認証できる必要があります。

既存のクラスターからのデータの複製

最初のデータダンプを取った後、新しいリーダーを既存のクラスターの最新の変更と同期させておく必要があります。新しいリーダー上で、gitlab-psql を指定してこのSQL文を実行し、既存のリーダーの公開を購読します:

CREATE SUBSCRIPTION patroni_upgrade
  CONNECTION 'host=EXISTING_CLUSTER_LEADER dbname=gitlabhq_production user=gitlab-psql'
  PUBLICATION patroni_upgrade;

この文では、EXISTING_CLUSTER_LEADER は既存のクラスターのリーダーノードのホストアドレスです。他のパラメータを使用して接続文字列を変更することもできます。たとえば、認証パスワードを渡すことができます。

レプリケーションの状態を確認するには、以下のクエリを実行します:

  • SELECT * FROM pg_replication_slots WHERE slot_name = 'patroni_upgrade' 既存のリーダー(パブリッシャー)に対して
  • SELECT * FROM pg_stat_subscription 新しいリーダー(購読者)の上で。

新しいクラスターの成長

新しいクラスターの他のノードを、リーダーを設定した方法で設定します。同じpatroni['scope']consul['internal']['postgresql_service_name'] を使用していることを確認してください。

ここで起こること

  • アプリケーションはデータベースのバックエンドとして既存のリーダーを使用します。
  • 論理レプリケーションは、新しいリーダーの同期を保証します。
  • 他のノードが新しいクラスターに追加されると、Patroniはこれらのノードへのレプリケーションを処理します。

新しいクラスターのレプリカノードが初期化され、レプリケーションラグに追いつくまで待つのがよいでしょう。

新しいクラスターを使用するようにアプリケーションを切り替えます。

この時点までは、既存のクラスターのデータを失うことなくアップグレード手順を停止できます。アプリケーションのデータベースバックエンドを切り替えて新しいクラスターに向けると、古いクラスターは新しい更新を受け取りません。新しいクラスターに遅れをとります。この時点以降、リカバリはすべて新しいクラスターのノードから行う必要があります。

すべてのPgBouncerノードで切り替えを行うには:

  1. gitlab.rb

    consul['watchers'] = %w(postgresql_new)
    consul['internal']['postgresql_service_name'] = 'postgresql_new'
    
  2. gitlab-ctl reconfigure を実行してください。

クリーンアップ

以上の手順が完了したら、古いPatroniクラスタのリソースをクリーンアップします。これらはもはや必要ありません。しかし、リソースを削除する前に、DROP SUBSCRIPTION patroni_upgrade を実行して新しいリーダーの論理レプリケーションサブスクリプションを削除してください。gitlab-psql.

トラブルシューティング

ConsulとPostgreSQLの変更が反映されない

潜在的な影響のため、gitlab-ctl reconfigure 、ConsulとPostgreSQLをリロードするだけで、サービスは再起動しません。しかし、すべての変更がリロードによって有効になるわけではありません。

どちらかのサービスを再起動するにはgitlab-ctl restart SERVICE

PostgreSQLの場合、通常はデフォルトでリーダーノードを再起動するのが安全です。自動フェイルオーバーのデフォルトは1分間のタイムアウトです。それまでにデータベースが復帰していれば、他に何もする必要はありません。

Consulサーバーノードでは、Consulサービスを制御された方法で再起動することが重要です。

PgBouncerエラーERROR: pgbouncer cannot connect to server

gitlab-rake gitlab:db:configure 、PgBouncerのログファイルにエラーが表示されます。

PG::ConnectionBad: ERROR:  pgbouncer cannot connect to server

問題はPgBouncerノードのIPアドレスがデータベースノードの/etc/gitlab/gitlab.rbtrust_auth_cidr_addresses の設定に含まれていないことです。

リーダーデータベースノードのPostgreSQLログを確認することでイシューを確認できます。以下のエラーが表示された場合、trust_auth_cidr_addresses が問題です。

2018-03-29_13:59:12.11776 FATAL:  no pg_hba.conf entry for host "123.123.123.123", user "pgbouncer", database "gitlabhq_production", SSL off

この問題を解決するには、IPアドレスを/etc/gitlab/gitlab.rb に追加してください。

postgresql['trust_auth_cidr_addresses'] = %w(123.123.123.123/32 <other_cidrs>)

変更を有効にするには、GitLabを再設定してください。

レプリカの再初期化

レプリカがクラスターを開始できない、あるいは再参加できない場合、あるいは遅れて追いつけない場合、レプリカを再初期化する必要があるかもしれません:

  1. レプリケーション・ステータスを確認して、再初期化が必要なサーバを確認します。たとえば

    + Cluster: postgresql-ha (6970678148837286213) ------+---------+--------------+----+-----------+
    | Member                              | Host         | Role    | State        | TL | Lag in MB |
    +-------------------------------------+--------------+---------+--------------+----+-----------+
    | gitlab-database-1.example.com       | 172.18.0.111 | Replica | running      | 55 |         0 |
    | gitlab-database-2.example.com       | 172.18.0.112 | Replica | start failed |    |   unknown |
    | gitlab-database-3.example.com       | 172.18.0.113 | Leader  | running      | 55 |           |
    +-------------------------------------+--------------+---------+--------------+----+-----------+
    
  2. 壊れたサーバにサインインし、データベースとレプリケーションを再初期化します。PatroniはそのサーバのPostgreSQLをシャットダウンし、データディレクトリを削除し、ゼロから再初期化します:

    sudo gitlab-ctl patroni reinitialize-replica --member gitlab-database-2.example.com
    

    This can be run on any Patroni node, but be aware thatsudo gitlab-ctl patroni reinitialize-replica without--member restarts the server it is run on.これはどのPatroniノードでも実行できますが、、 を実行しない場合、実行されたサーバが再起動されることに注意してください。意図しないデータ損失のリスクを減らすために、壊れたサーバ上でローカルに実行してください。

  3. ログを監視してください:

    sudo gitlab-ctl tail patroni
    

コンシュルでのパトロニ状態のリセット

caution
ConsulでPatroniの状態をリセットすることは潜在的に破壊的なプロセスです。まず健全なデータベースのバックアップがあることを確認してください。

最後の手段として、ConsulのPatroniの状態を完全にリセットすることができます。

これはPatroniクラスタが未知の状態、もしくは悪い状態にあり、どのノードも起動できない場合に必要となります:

+ Cluster: postgresql-ha (6970678148837286213) ------+---------+---------+----+-----------+
| Member                              | Host         | Role    | State   | TL | Lag in MB |
+-------------------------------------+--------------+---------+---------+----+-----------+
| gitlab-database-1.example.com       | 172.18.0.111 | Replica | stopped |    |   unknown |
| gitlab-database-2.example.com       | 172.18.0.112 | Replica | stopped |    |   unknown |
| gitlab-database-3.example.com       | 172.18.0.113 | Replica | stopped |    |   unknown |
+-------------------------------------+--------------+---------+---------+----+-----------+

ConsulでPatroniの状態を削除する前にPatroniノードでgitlab-ctl エラー を解決してみてください。

このプロセスにより、最初のPatroniノードが起動したときにPatroniクラスタが再初期化されます。

ConsulでPatroniの状態をリセットするには:

  1. ConsulでPatroniの状態をリセットするには:リーダーだったPatroniノード、またはアプリケーションが現在のリーダーだと思っているPatroniノードをメモしてください:
    • /var/opt/gitlab/consul/databases.ini 、現在のリーダーのホスト名を含むPgBouncerノードを探します。
    • すべてのデータベースノードのPatroniログ/var/log/gitlab/patroni/current (または、より古いローテートされ圧縮されたログ/var/log/gitlab/patroni/@40000*)を見て、クラスターによって最も最近リーダーとして認識されたサーバを確認します:

       INFO: no action. I am a secondary (database1.local) and following a leader (database2.local)
      
  2. 全てのノードでPatroniを停止します:

    sudo gitlab-ctl stop patroni
    
  3. Consulの状態をリセットします:

    /opt/gitlab/embedded/bin/consul kv delete -recurse /service/postgresql-ha/
    
  4. Patroniクラスタを初期化し、リーダーとして選出します。クラスターの状態が壊れたためにレプリケートされなかったかもしれない既存の書き込みを失わないために、(最初のステップで述べた)前のリーダーを起動することを強く推奨します:

    sudo gitlab-ctl start patroni
    
  5. Patroniクラスターに参加する他のすべてのPatroniノードをレプリカとして起動します:

    sudo gitlab-ctl start patroni
    

それでもイシューが表示される場合は、次のステップとして最後に健全なバックアップをリストアします。

Patroniログにpg_hba.conf のエントリに関するエラーが表示されます。127.0.0.1

Patroniログの以下のログエントリはレプリケーションが機能しておらず、設定変更が必要であることを示しています:

FATAL:  no pg_hba.conf entry for replication connection from host "127.0.0.1", user "gitlab_replicator"

この問題を解決するには、ループバックインターフェースがCIDRアドレスリストに含まれていることを確認してください:

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

    postgresql['trust_auth_cidr_addresses'] = %w(<other_cidrs> 127.0.0.1/32)
    
  2. 変更を有効にするには、GitLabを再設定してください。
  3. 全てのレプリカが同期されていることを確認します。

Patroniログのエラー:要求された開始ポイントがWrite Ahead Log(WAL) のフラッシュ位置より前にあります。

このエラーはデータベースがレプリケートされていないことを示します:

FATAL:  could not receive data from WAL stream: ERROR:  requested starting point 0/5000000 is ahead of the WAL flush position of this server 0/4000388

このエラーの例は、初期設定に誤りがあり、一度もレプリケートされていないレプリカのものです。

レプリカを再初期化することで修正してください。

PatroniがMemoryError

Patroni は起動に失敗し、エラーとスタックトレースを記録します:

MemoryError
Traceback (most recent call last):
  File "/opt/gitlab/embedded/bin/patroni", line 8, in <module>
    sys.exit(main())
[..]
  File "/opt/gitlab/embedded/lib/python3.7/ctypes/__init__.py", line 273, in _reset_cache
    CFUNCTYPE(c_int)(lambda: None)

スタックトレースの末尾がCFUNCTYPE(c_int)(lambda: None) である場合、Linux サーバーがセキュリティのためにハード化されていれば、このコードはMemoryError をトリガーします。

このコードは Python に一時的な実行可能ファイルを書かせます。例えば、noexec/tmp ファイルシステムに設定されている場合、MemoryError で失敗します(詳しくはイシューを読んでください)。

回避策

  • /tmp/var/tmp のようなファイルシステムのマウントオプションからnoexec を削除します。
  • enforcingに設定すると、SELinuxがこれらのオペレーションを阻止することもあります。SELinux を permissive に設定して、イシューが修正されていることを確認してください。

PatroniはPython 3.7のビルドとともにGitLab 13.1のLinuxパッケージで最初に出荷されました。この問題を引き起こすコードは Python 3.8 で削除されました。この修正はGitLab 14.3以降の Linux パッケージで出荷され、回避策の必要性はなくなりました。

実行中のエラーgitlab-ctl

Patroniノードはgitlab-ctl コマンドが失敗し、gitlab-ctl reconfigure ノードを修正できない状態になることがあります。

PostgreSQLのバージョンアップと重なる場合は、別の手順に従ってください。

よくある症状として、データベースサーバが起動に失敗している場合、gitlab-ctl がインストールに必要な情報を判断できないというものがあります:

Malformed configuration JSON file found at /opt/gitlab/embedded/nodes/<HOSTNAME>.json.
This usually happens when your last run of `gitlab-ctl reconfigure` didn't complete successfully.
Error while reinitializing replica on the current node: Attributes not found in
/opt/gitlab/embedded/nodes/<HOSTNAME>.json, has reconfigure been run yet?

同様に、ノードファイル(/opt/gitlab/embedded/nodes/<HOSTNAME>.json)には多くの情報が含まれているはずですが、作成される情報はわずかです:

{
  "name": "<HOSTNAME>"
}

これを修正するための以下のプロセスには、このレプリカの再初期化が含まれます:

  1. Patroniと(存在すれば)PostgreSQLのサービスを停止します:

    sudo gitlab-ctl status
    sudo gitlab-ctl stop patroni
    sudo gitlab-ctl stop postgresql
    
  2. その状態がPostgreSQLの起動を妨げている場合に備えて、/var/opt/gitlab/postgresql/data

    cd /var/opt/gitlab/postgresql
    sudo rm -rf data
    

    データの損失を避けるため、この手順には注意してください。data/プライマリデータベースの新しいコピーのために十分な空きディスクがあることを確認し、レプリカが修正されたら余分なディレクトリを削除してください。

  3. PostgreSQLが稼働していない状態で、ノードファイルが正常に作成されました:

    sudo gitlab-ctl reconfigure
    
  4. Patroniを起動します:

    sudo gitlab-ctl start patroni
    
  5. ログを監視し、クラスターの状態を確認します:

    sudo gitlab-ctl tail patroni
    sudo gitlab-ctl patroni members
    
  6. 再度reconfigure

    sudo gitlab-ctl reconfigure
    
  7. gitlab-ctl patroni members が必要であると示した場合は、レプリカを再初期化します:

    sudo gitlab-ctl patroni reinitialize-replica
    

この手順がうまくいかずクラスターがリーダーを選出できない場合、最後の手段としてのみ使用すべきもう1つの修正があります。

PostgreSQLのメジャーバージョンアップがPatroniレプリカで失敗します。

Patroniレプリカが gitlab-ctl pg-upgrade 、ループにはまり、アップグレードに失敗することがあります。

症状の例を以下に示します:

  1. 通常Patroniノードには存在しないはずのpostgresql サービスが定義されています。これはgitlab-ctl pg-upgrade 、新しい空のデータベースを作成するために追加されるためです:

    run: patroni: (pid 1972) 1919s; run: log: (pid 1971) 1919s
    down: postgresql: 1s, normally up, want up; run: log: (pid 1973) 1919s
    
  2. PostgreSQLはレプリカの再初期化の一環としてPatroniが/var/opt/gitlab/postgresql/data を削除する際に、/var/log/gitlab/postgresql/currentPANIC ログエントリを生成します:

    DETAIL:  Could not open file "pg_xact/0000": No such file or directory.
    WARNING:  terminating connection because of crash of another server process
    LOG:  all server processes terminated; reinitializing
    PANIC:  could not open file "global/pg_control": No such file or directory
    
  3. /var/log/gitlab/patroni/current で、Patroniは以下のログを記録します。ローカルのPostgreSQLのバージョンがクラスター・リーダーと異なります:

    INFO: trying to bootstrap from leader 'HOSTNAME'
    pg_basebackup: incompatible server version 12.6
    pg_basebackup: removing data directory "/var/opt/gitlab/postgresql/data"
    ERROR: Error when fetching backup: pg_basebackup exited with code=1
    

重要: この回避策はPatroniクラスタが以下の状態のときに適用されます:

この回避策では、PatroniレプリカのPostgreSQLのアップグレードを完了させるために、新しいバージョンのPostgreSQLを使用するようにノードを設定し、リーダーのアップグレード時に作成された新しいクラスターのレプリカとして再初期化します:

  1. すべてのノードでクラスターの状態を確認し、どのノードがリーダーで、レプリカがどのような状態にあるかを確認します。

    sudo gitlab-ctl patroni members
    
  2. レプリカ: どのバージョンのPostgreSQLがアクティブかを確認します:

    sudo ls -al /opt/gitlab/embedded/bin | grep postgres
    
  3. Replica: ノードファイルが正しく、gitlab-ctl が実行できることを確認してください。レプリカにこれらのエラーがある場合、gitlab-ctl](#errors-running-gitlab-ctl) を実行する[のエラーも解決されます:

    sudo gitlab-ctl stop patroni
    sudo gitlab-ctl reconfigure
    
  4. Replica: PostgreSQLバイナリを必要なバージョンに再リンクして、incompatible server version のエラーを修正してください:

    1. /etc/gitlab/gitlab.rb を編集して必要なバージョンを指定してください:

      postgresql['version'] = 13
      
    2. GitLab を再設定します:

      sudo gitlab-ctl reconfigure
      
    3. バイナリが再リンクされているか確認してください。PostgreSQL用に配布されているバイナリはメジャーリリースによって異なるため、誤ったシンボリックリンクが少なからず存在するのが普通です:

      sudo ls -al /opt/gitlab/embedded/bin | grep postgres
      
  5. Replica: PostgreSQLが指定されたバージョンで完全に再初期化されていることを確認してください:

    cd /var/opt/gitlab/postgresql
    sudo rm -rf data
    sudo gitlab-ctl reconfigure
    
  6. Replica: オプションで、さらに2つのターミナルセッションでデータベースを監視します:

    • pg_basebackup を実行するとディスク使用量が増加します。でレプリカの初期化の進捗を追跡します:

       cd /var/opt/gitlab/postgresql
       watch du -sh data
      
    • ログでプロセスを監視します:

       sudo gitlab-ctl tail patroni
      
  7. レプリカPatroni を起動してレプリカを再初期化します:

    sudo gitlab-ctl start patroni
    
  8. レプリカを再初期化します:完了後、/etc/gitlab/gitlab.rb からハードコードされたバージョンを削除します:

    1. /etc/gitlab/gitlab.rb を編集し、postgresql['version'] を削除してください。
    2. GitLab を再設定します:

      sudo gitlab-ctl reconfigure
      
    3. 正しいバイナリがリンクされているか確認してください:

      sudo ls -al /opt/gitlab/embedded/bin | grep postgres
      
  9. すべてのノードでクラスターの状態を確認します:

    sudo gitlab-ctl patroni members
    

必要に応じて、もう一方のレプリカでこの手順を繰り返します。

他のコンポーネントのイシュー

ここに記載されていないコンポーネントでイシューが発生した場合は、そのコンポーネントのドキュメントページのトラブルシューティングセクションを確認してください: