Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Patroni: pg_rewind “password authentication failed” and the PGPASSWORD trap

2026年10月03日に「Dev.to」が公開したITニュース「Patroni: pg_rewind “password authentication failed” and the PGPASSWORD trap」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

PatroniでPostgreSQLのリーダー障害後、旧リーダーがPGPASSWORD環境変数の影響で認証失敗し復旧できない問題が発生する。これはpg_rewindがパスワード認証に失敗するためだ。PatroniをPGPASSWORDがないクリーンな環境で起動すれば解決する。テストでは見落とされやすい。

ITニュース解説

Patroniは、PostgreSQLデータベースの高可用性(HA)を実現するための強力なツールである。HAとは、システムが停止することなく常に利用できる状態を保つことを指し、Patroniはデータベースの障害発生時に、自動的に新しいリーダーを選出し、サービスを継続させる役割を果たす。しかし、この自動復旧プロセスが予期せぬ状況で失敗することがある。今回の問題は、リーダーとなるデータベースがクラッシュした後、残りのデータベースの中から新しいリーダーが選ばれ、サービスが継続するものの、クラッシュした古いリーダーがいつまで経っても復旧せず、「start failed」という状態に陥ってしまうケースについてである。

この現象が発生すると、まずpatronictl listというコマンドでデータベースの状態を確認すると、クラッシュしたノードが「start failed」と表示されているのがわかる。そして、そのノードのPostgreSQLログを見てみると、「FATAL: requested timeline 3 is not a child of this server's history」というエラーメッセージが繰り返し出力されていることが確認できる。このメッセージは、データベースの変更履歴(WALと呼ばれる、データベースに加えられた変更の記録)が、新しいリーダーの履歴と一致しておらず、古いリーダーが新しいリーダーの履歴に追従できない状態であることを示している。Patroniは、このような変更履歴の不一致を解決するために、pg_rewindというツールを使用するはずだ。pg_rewindは、古いリーダーのデータベースを新しいリーダーの履歴に合わせて「巻き戻す」ことで、再びレプリカ(コピー)として参加できるようにするツールである。

しかし、Patroniのログを詳しく見ると、pg_rewindが実行されなかった理由が明らかになる。ログには、「connection to server at "10.0.0.13", port 5432 failed: FATAL: password authentication failed for user "rewind_user"」というエラーが記録されている。つまり、pg_rewindが新しいリーダーに接続しようとした際に、「rewind_user」というユーザーのパスワード認証に失敗してしまったのだ。これが、古いリーダーが復旧できない根本的な原因である。

このパスワード認証失敗の背後にあるのは、PostgreSQLクライアントがパスワードを探す優先順位に関する罠である。PostgreSQLクライアントがデータベースに接続する際、パスワードを探す場所にはいくつかの候補があり、それぞれ優先順位が定められている。具体的には、以下の順序でパスワードが検索される。

  1. 接続文字列そのものにパスワードが含まれている場合
  2. PGPASSWORDという名前の環境変数にパスワードが設定されている場合
  3. .pgpassというパスワードファイルにパスワードが記述されている場合

Patroniは、セキュリティ上の理由から、パスワードをコマンドラインで直接渡すことはしない。代わりに、専用の.pgpassファイルを作成し、pg_rewindやpg_basebackupといったPostgreSQLツールにそのファイルを参照するように指示する。しかし、もしPatroniが起動されたシェル環境にPGPASSWORDという環境変数が設定されていた場合、Patroniプロセスはこの環境変数を受け継いでしまう。その結果、pg_rewindは、Patroniが用意した.pgpassファイルではなく、PGPASSWORD環境変数に設定されていた誤ったパスワードを使って認証を試みてしまう。これが認証失敗の原因であり、pg_rewindが実行されないため、古いリーダーノードは復旧できなくなるのだ。

なぜこのような問題が、通常のシステム切り替えテストでは検出されなかったのだろうか。それは、PGPASSWORD環境変数がPatroniプロセスに引き継がれる状況が限定的だからである。通常、systemdなどのサービスマネージャーによってクリーンな環境でPatroniが起動されている場合、この環境変数は設定されていないため、問題は発生しない。しかし、インシデント(障害)が発生した際に、データベース管理者が手動でpsqlコマンドを実行するためにPGPASSWORDをエクスポートしたシェル環境から、Patroniを再起動したり、復旧スクリプトを実行したりすると、その環境変数がPatroniプロセスに引き継がれてしまうのだ。この場合、pg_rewindだけでなく、レプリケーション自体も認証失敗により機能しなくなる可能性があり、手動での再構築後も問題が続くことがある。

PGPASSWORD環境変数がPatroniプロセスに紛れ込む主な経路はいくつか考えられる。一つは、インシデント後に管理者が手動でPatroniを起動する際に、PGPASSWORDをエクスポートしたシェルからnohup patroni patroni.yml &のように実行してしまうケースである。次に、デプロイや復旧のためのラッパースクリプトが、set -aのようなコマンドを使って、スクリプト内で定義された全ての変数を環境変数としてエクスポートし、その後にPatroniサービスを起動してしまう場合もある。また、systemdのユニットファイル自体にEnvironment=PGPASSWORD=...やEnvironmentFile=といった設定が含まれている場合や、コンテナイメージが利便性を考慮してPGPASSWORDを設定している場合も、同様の問題が発生する可能性がある。

この問題が発生していないかをチェックするには、実行中のPatroniプロセスの環境変数を調べるのが最も手っ取り早い方法である。具体的には、以下のコマンドを実行することで確認できる。 sudo tr '\0' '\n' < /proc/$(pgrep -f 'bin/patroni' | head -1)/environ | grep -E '^PG|^PATRONI_' このコマンドの実行結果に、PGPASSWORD、PGUSER、PGHOST、PGSERVICEといったPGで始まる環境変数が表示された場合、それが問題の原因となる可能性がある。また、PATRONI_で始まる環境変数も、Patroniの設定ファイル(patroni.yml)を上書きする可能性があり、予期せぬ動作を引き起こすことがあるため、注意が必要である。

この問題を解決するための最も確実な方法は、Patroniを常にsystemdなどのサービスマネージャーを通じて、クリーンな環境で起動することである。systemdのユニットファイルにおいて、[Service]セクションにEnvironment=やEnvironmentFile=のような行でPGPASSWORDが設定されていないことを確認し、もし存在すればそれらを削除する。Patroniの起動に必要なPATHなどの最小限の環境変数のみを設定するようにすべきだ。 例:

[Service]
User=postgres
Environment=PATH=/opt/patroni/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/opt/patroni/bin/patroni /etc/patroni/patroni.yml
KillMode=process

このような設定を適用した後、systemctl daemon-reload && systemctl restart patroniコマンドを実行して、設定を反映し、Patroniサービスを再起動する。Patroniの再起動中もPostgreSQLは動作を続けるため、サービスへの影響は最小限に抑えられる。スタックしたノードでは、Patroniを再起動するだけで、pg_rewindが正しいパスワードで再試行され、多くの場合、正常に復旧する。もしpg_rewindに必要なデータベースの変更履歴(WAL)が既に削除されてしまっているなど、再試行でも復旧できない場合は、patronictl reinit <cluster> <node>コマンドを使って、そのノードを完全に再初期化する必要がある。

この修正が本当に有効であったかを証明するには、通常の計画的なスイッチオーバーテストでは不十分である。なぜなら、そのテストではPGPASSWORD環境変数が引き継がれるような状況が発生しないため、問題が表面化しないからだ。本当に修正されたことを確認するためには、テスト環境でクラッシュテストを実施する必要がある。具体的には、リーダーノードのPatroniとPostgreSQLプロセスを、データベースへの書き込み中に強制終了(SIGKILL)させ、新しいリーダーが選出されたことを確認した後、古いリーダーノードを再起動する。そして、古いリーダーノードが新しいリーダーのレプリカとして、自動的に復旧し、データストリーミングを開始することを確認する。このような「クラッシュドリル」と呼ばれるテストこそが、本番環境で問題が発生しないことを保証する唯一の方法である。

関連コンテンツ

関連IT用語