関連
概要
Prometheusでの、PostgreSQLのメトリクス収集用のPostgres ExporterのDocker環境構築手順。
前提条件
以下の手順でPrometheus環境を構築していることを前提とする。
https://qiita.com/Esfahan/items/0feaedfd771f49ac7ee4
Postgres exporter
こちらを利用する。
https://github.com/prometheus-community/postgres_exporter
環境
- postgres_exporter v0.9.0
- PostgreSQL 9.6
監視対象のPostgresの設定
pg_stat_statementsの有効化
以下を参考にpg_stat_statementsを有効化する。
参考:https://qiita.com/Esfahan/items/2f0c5ad85671d435f209
もしpg_stat_statementsを有効化しない場合は、次項の「メトリクス収集用ユーザーの作成」で、CREATE OR REPLACE VIEW postgres_exporter.pg_stat_statements
の箇所を実行せずにskipする。
メトリクス収集用ユーザーの作成
defaultでは like pg_stat_statements や pg_stat_activity はsuperuser以外では参照できない。もしsuperuser以外でメトリクス収集する場合は、以下を実行する。
以下の例ではpostgres_exporter
という名前のメトリクス収集用のユーザーを作成する。
パスワードは、ALTER USER postgres_exporter WITH PASSWORD 'password';
で設定しているので、パスワード値を適宜変更する。
参考:https://github.com/prometheus-community/postgres_exporter#running-as-non-superuser
-- To use IF statements, hence to be able to check if the user exists before
-- attempting creation, we need to switch to procedural SQL (PL/pgSQL)
-- instead of standard SQL.
-- More: https://www.postgresql.org/docs/9.3/plpgsql-overview.html
-- To preserve compatibility with <9.0, DO blocks are not used; instead,
-- a function is created and dropped.
CREATE OR REPLACE FUNCTION __tmp_create_user() returns void as $$
BEGIN
IF NOT EXISTS (
SELECT -- SELECT list can stay empty for this
FROM pg_catalog.pg_user
WHERE usename = 'postgres_exporter') THEN
CREATE USER postgres_exporter;
END IF;
END;
$$ language plpgsql;
SELECT __tmp_create_user();
DROP FUNCTION __tmp_create_user();
-- passwordを適宜変更
ALTER USER postgres_exporter WITH PASSWORD 'password';
ALTER USER postgres_exporter SET SEARCH_PATH TO postgres_exporter,pg_catalog;
-- If deploying as non-superuser (for example in AWS RDS), uncomment the GRANT
-- line below and replace <MASTER_USER> with your root user.
-- GRANT postgres_exporter TO <MASTER_USER>;
CREATE SCHEMA IF NOT EXISTS postgres_exporter;
GRANT USAGE ON SCHEMA postgres_exporter TO postgres_exporter;
GRANT CONNECT ON DATABASE postgres TO postgres_exporter;
CREATE OR REPLACE FUNCTION get_pg_stat_activity() RETURNS SETOF pg_stat_activity AS
$$ SELECT * FROM pg_catalog.pg_stat_activity; $$
LANGUAGE sql
VOLATILE
SECURITY DEFINER;
CREATE OR REPLACE VIEW postgres_exporter.pg_stat_activity
AS
SELECT * from get_pg_stat_activity();
GRANT SELECT ON postgres_exporter.pg_stat_activity TO postgres_exporter;
CREATE OR REPLACE FUNCTION get_pg_stat_replication() RETURNS SETOF pg_stat_replication AS
$$ SELECT * FROM pg_catalog.pg_stat_replication; $$
LANGUAGE sql
VOLATILE
SECURITY DEFINER;
CREATE OR REPLACE VIEW postgres_exporter.pg_stat_replication
AS
SELECT * FROM get_pg_stat_replication();
GRANT SELECT ON postgres_exporter.pg_stat_replication TO postgres_exporter;
CREATE OR REPLACE FUNCTION get_pg_stat_statements() RETURNS SETOF pg_stat_statements AS
$$ SELECT * FROM public.pg_stat_statements; $$
LANGUAGE sql
VOLATILE
SECURITY DEFINER;
-- pg_stat_statementsを利用しない場合は以降は実行しない
CREATE OR REPLACE VIEW postgres_exporter.pg_stat_statements
AS
SELECT * FROM get_pg_stat_statements();
GRANT SELECT ON postgres_exporter.pg_stat_statements TO postgres_exporter;
作成されたものなど確認
psql -U postgres_exporter -W -d postgres
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+------------------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/postgres +
| | | | | postgres=CTc/postgres +
| | | | | postgres_exporter=c/postgres
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
(3 rows)
postgres=# \dn
List of schemas
Name | Owner
-------------------+----------
postgres_exporter | postgres
public | postgres
(2 rows)
postgres=# \du
List of roles
Role name | Attributes | Member of
-------------------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
postgres_exporter | | {}
postgres=> \d
List of relations
Schema | Name | Type | Owner
-------------------+---------------------+------+----------
postgres_exporter | pg_stat_activity | view | postgres
postgres_exporter | pg_stat_replication | view | postgres
postgres_exporter | pg_stat_statements | view | postgres
(3 rows)
Postgres Exporterの環境構築
version: '3'
services:
postgres-exporter:
container_name: postgres-exporter
image: quay.io/prometheuscommunity/postgres-exporter
hostname: postgres-exporter
env_file:
- .env
ports:
- 9187:9187
networks:
- sample-network
networks:
sample-network:
external: true
DATA_SOURCE_NAME=postgresql://postgres_exporter:password@sample-postgres:5432/postgres?sslmode=disable
DATA_SOURCE_NAMEは、"
や'
などクォーテーションを付けるとpostgres-exporterでパースされなかったので付けないこと。
$ docker-compose up -d --build
Prometheusの設定
こちらの記事で構築したPrometheus環境の設定ファイルを編集する。
監視対象を追加
prometheus.yamlに以下を追記。
# 前略
scrape_configs:
+ - job_name: postgres
+ metrics_path: /postgres_exporter/metrics
+ static_configs:
+ - targets:
+ - your-postgres-exporter-hostname:9187
+ labels:
+ env: development
設定を反映
$ sudo docker-compose restart prometheus
ルールを追加
groups:
- name: sample001
rules:
# Postgres用のルールを追記
- alert: Postgres_down
# Postgresが起動しているかのPromQL。
expr: pg_up == 0
# 5分間応答がなければアラートを飛ばす
for: 5m
labels:
severity: critical
# エラー文言
annotations:
firing_text: "[{{ $labels.env }}] {{ $labels.instance }} PostgreSQL has been down for more than 5 minutes."
resolved_text: "[{{ $labels.env }}] {{ $labels.instance }} PostgreSQL has recoverd."
UI確認
http://your_prometeus.com:9090/graph
pg_up == 1
であればpostgresが正常に起動しているということ。0
が異常状態。
その他
Error: function pg_current_wal_lsn() does not exist
pg_current_wal_lsn()
はpostgres 10以降に実装された関数なので、9系ではエラーが出る。
$ docker logs -f postgres-exporter
time="2021-06-07T17:51:16Z" level=info msg="Error running query on database \"sample-postgres:5432\": pg_replication_slots pq: function pg_current_wal_lsn() does not exist" source="postgres_exporter.go:1503"
2021/03/04にIssueが上がっており、対応してくれそうなので待ち。
https://github.com/prometheus-community/postgres_exporter/issues/495
DockerのexporterからホストOSのpostgresにアクセスする場合
ホストOSのpostgresがpg_hba.confでアクセス制限を厳密にやっている時の対策方法。
docker-compose.yaml
以下の様にnetworksの設定でコンテナのIPアドレスを固定する。
version: '3'
services:
postgres-exporter:
container_name: postgres-exporter
image: quay.io/prometheuscommunity/postgres-exporter
hostname: postgres-exporter
extra_hosts:
# コンテナ内からホストOSのlocalhostへアクセスするための設定
# ホストOSのdocker0のIPアドレスが渡される
- "host.docker.internal:host-gateway"
env_file:
- ./postgres-exporter/.env
ports:
- 127.0.0.1:9187:9187
restart: always
networks:
exporter-network:
# このコンテナのIPアドレスを以下に固定
ipv4_address: 192.168.200.1
networks:
exporter-network:
ipam:
driver: default
config:
# 16個確保
- subnet: 192.168.200.0/28
pg_hba.conf
pg_hba.confで、先程固定したexporterのコンテナIPアドレスからの接続許可設定をする。
host dbname postgres_exporter 192.168.200.1/32 md5
postgresql.conf
postgresql.confのlistenを書き換える
-listen_addresses = '127.0.0.1'
+listen_addresses = '*'
接続確認
exporterからではなくホストOS上からコマンドで接続確認する方法。これで接続確認できれば、おそらくDockerコンテナからも接続できる。
docker0のIPアドレスを確認
以下のコマンドでdocker0のIPアドレスを確認。
ここでは、192.168.249.1だったとする
$ /sbin/ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.249.1 netmask 255.255.255.0 broadcast 192.168.249.255
psqlで確認
docker0のIPアドレスをホストに指定して接続。
$ psql dbname -p 5432 -U postgres_exporter -h 192.168.249.1 -W