PostgresqlのMultiple Primariesを検知してアラートする
はじめに
PostgresqlをKubernetesにデプロイして利用しているのですが、一つやっかいな問題があります。それは、複数レプリカ存在するPostgresqlにおいて、通常ではPostgresqlが何らかの不具合でKubernetesのヘルスチェックに失敗したときに、Primaryのノードの場合はクラスターから切り離され、スタンバイのノードがプライマリーに昇格します。このフェイルオーバーが正しく動かず、複数のPrimaryがクラスター内に存在し、データの整合性が取れなかったりする原因になります。
これは、使用しているPostgresqlのHelmチャートのレポジトリでも複数回問題が報告されていますが、現在でも修正されてはいません。
上記問題の対処法としては、本来スタンバイであるはずがPrimaryとして動作しているPodを削除する。というのが挙げられます。が、しかしこの現象がいつ起こるのかは不明のため、Prometheusのメトリクスなどを利用して発生した段階でわかるようなアラートが必要になってきます。今回そのダッシュボードとアラートを作成したので、紹介しようと思います。
全体のソースコードは以下レポジトリに格納しています。
環境
- WSL2: Ubuntu 20.04
- Docker: 4.10.1
- kind: kind v0.11.1 go1.16.4 linux/amd64
Postgresqlのインストール
PostgresqlのインストールにはHelmチャートを利用します。
ローカルのKindにインストールするために必要な設定をvalues.yamlとして保存します。
---
global:
storageClass: 'local-path'
postgresql:
postgresqlPassword: postgres
postgresql:
priorityClassName: ''
username: test
password: test
repmgrUsername: repmgr
repmgrPassword: repmgr!
repmgrDatabase: repmgr
pgpool:
adminUsername: admin
adminPassword: admin
configuration: |
failover_on_backend_error = 'on'
failover_command = '/opt/bitnami/pgpool/etc/failover.sh %d %P %H %R'
volumePermissions:
enabled: true
metrics:
enabled: true
customMetrics:
pg_replication:
master: true
query: |
SELECT
CASE
WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0
ELSE EXTRACT (EPOCH FROM now() - pg_last_xact_replay_timestamp())::INTEGER
END
AS lag,
CASE WHEN pg_is_in_recovery() THEN 1 ELSE 0 END as is_replica;
metrics:
- lag:
usage: "GAUGE"
- is_replica:
usage: "GAUGE"
persistance:
enabled: true
size: 100Mi
その次に実際に、Postgresqlをインストールしていきます。
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update bitnami
kubectl create namespace database
helm upgrade postgres bitnami/postgresql-ha \
--install \
--namespace database \
--values=./values.yaml
カスタムメトリクスの作成
values.yamlに以下の項目を記載することでpostgres-exporterにはない独自メトリクスを追加することができます。
metrics:
customMetrics:
pg_replication:
master: true
query: |
SELECT
CASE
WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0
ELSE EXTRACT (EPOCH FROM now() - pg_last_xact_replay_timestamp())::INTEGER
END
AS lag,
CASE WHEN pg_is_in_recovery() THEN 1 ELSE 0 END as is_replica;
metrics:
- lag:
usage: "GAUGE"
- is_replica:
usage: "GAUGE"
作成されたメトリクス名としては、pg_replication_is_replica
にて検索することが可能です。
Grafanaのダッシュボードを作成する
今回使用するpostgres-exporterには、複数GrafanaのダッシュボードがGrafanaのサイトに登録されているので、基本的なメトリクスについてはそれを使うことにします。ただ、今回追加したカスタムメトリクスについてはダッシュボードが提供されているわけではないので、Grafanaで作成していきます。
Multiple Primariesを検知してアラートを出すダッシュボードを作成する
pg_replication_is_replica
で検索すると、各PodごとのReplicaのステータスが確認できます。
この情報をもとに、ダッシュボードを作っていきます。といっても、複雑なことは特にせず、値が0(Primary)のメトリクスの数を数えるだけです。
保存した後に、アラートを作成していきます。こちらもシンプルで、ダッシュボードで表示している値が5分以上連続して2以上の時に通知するものを作成します。
最後に
PrometheusのメトリクスとGrafanaのダッシュボードを使うことで、当初の問題であったPostgresqlの複数のPrimaryを検知し、アラート通知することができました。本来であれば、自動的に検知して修復まで出来れば運用の負荷としては減るのでそこまで作れればよかったのですが、現状だと通知までの実装になっています。PostgresqlのOperatorを導入できれば、そこまで実現できそうな気がするので、次回はそちらに挑戦してみようと思います。
認識違いや不正確な点などあれば、コメント等で指摘してもらえると非常に助かります。
それでは、今回はここまで。
Discussion