本記事はPostgreSQL on Kubernetes Advent Calendar 2018の14日目です。
昨日は「Recap: PGConf.Asia 2018」ということで、3日間にかけて行われたカンファレンスの振り返りをしました。
12/25までのAdvent Calenderも今日でようやく半分を超えました。
本日からはPostgreSQL on Kubernetesの検証内容の投稿を再開します。
TL;DR
- 公式のpostgresイメージを使って、コンフィグは外から与えるように設定するよ。
 - データとアーカイブログは保存先を分けよう。
 - Probe設定もわすれずに。
 
PostgreSQLのStatefulSet設定
これまで話している通り、今回のPostgreSQL on KubernetesではStatefulSetを使っています。
今回のPostgreSQL on Kubernetesで求められる要件は以下となります。
- postgresql.confを外出しして、設定を自由に変えられること。
 - アーカイブログモードで動くこと。
 - 外部ディスクとして、データとアーカイブログの領域を分けること。
 
実際にどのような設定で使っているかを順に記していきます。YAML全体はこちらをご覧下さい。
imageの指定
まずコンテナイメージですが、Docker Hub上のPostgres公式のものを使っています。
    spec:
      containers:
        - name: pg-rook-sf
          image: postgres:10.4
          imagePullPolicy: "IfNotPresent"
PostgreSQLのバージョンは10.4、OSはDebianベースになります。公式のコンテナイメージとして提供されているのは2018年時点ではDebianとAlpineになっています。
postgresql.confの指定
公式のコンテナイメージでは、今回検証に必要なアーカイブログモードの設定がOFFになっています。さらにログ出力も少しカスタマイズしたかったので、事前にpg-rook-postgresql_conf.yamlを作りました。
archive_mode = on                                   # enables archiving; off, on, or always
                                                    # (change requires restart)
archive_command = 'cp %p /mnt/postgresql/xlog/%f'   # command to use to archive a logfile segment
                                                    # placeholders: %p = path of file to archive
                                                    #               %f = file name only
archive_timeout = 60                                # force a logfile segment switch after this
                                                    # number of seconds; 0 disables
さらに起動時にこのコンフィグをマウントしたConfigMapから与えるために、コンテナにargsを与えています。
          args:
          - -c 
          - config_file=/etc/postgresql/postgresql.conf
上記により、ConfigMapで指定したファイルがドキュメントにある以下の形で与えられ、想定したパラメータでPostgreSQLを起動することができます。
$ docker run -d --name some-postgres -v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf postgres -c 'config_file=/etc/postgresql/postgresql.conf'
PGDATAディレクトリとTimeZoneの設定
公式のコンテナイメージでは環境変数:PGDATAでPostgreSQLのデータディレクトリを指定することができます。これを使うのはドキュメントにあるとおり、データディレクトリがマウントポイントになるケースです。
This optional environment variable can be used to define another location - like a subdirectory - for the database files. The default is /var/lib/postgresql/data, but if the data volume you're using is a fs mountpoint (like with GCE persistent disks), Postgres initdb recommends a subdirectory (for example /var/lib/postgresql/data/pgdata ) be created to contain the data.
(Google翻訳)
このオプションの環境変数を使用して、データベースファイルの別の場所(サブディレクトリなど)を定義することができます。デフォルトは/ var / lib / postgresql / dataですが、使用するデータボリュームがfsマウントポイント(GCE永続ディスクなど)の場合、Postgres initdbはサブディレクトリ(たとえば/ var / lib / postgresql / data / pgdata)を作成してデータを格納することができます。
今回のPostgreSQL on Rook構成でもPVでマウントした箇所が/var/lib/postgresql/dataとなるため、このPGDATAを指定しないと、PostgreSQLが起動できません。
          env:
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
            - name: TZ
              value: Asia/Tokyo
さらに、TimeZoneについては今回検証するまで知らなかったのですが、コンテナの時刻はホストOSのそれを踏襲するのですね。TimeZoneを明示するために環境変数でTZ:Asia/Tokyoを与えています。
ボリュームのマウント
これまでの設定を踏まえて、今回のPostgreSQLコンテナでは3つのボリュームをマウントします。
- PGDATA、PostgreSQLのデータ格納ディレクトリ。Cephのブロックデバイス。
 - アーカイブログの保存先。Cephのブロックデバイス。
 - postgresql.conf。ConfigMap。
 
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: pg-rook-vol
            - mountPath: /mnt/postgresql/xlog
              name: pg-rook-vol-xlog
            - mountPath: /etc/postgresql
              readOnly: true
              name: postgres-conf
データベースの設計としてはデータとアーカイブログの領域を分けて配置するのは当然のことです。後日、バックアップ/リストアのケースで詳細は確認しますが、リストアされるデータ領域と継続的に保管されるだけのアーカイブログ領域はライフサイクルが異なるためです。
今回はデータ、アーカイブログ領域のどちらもCephのブロックデバイスをマウントしていますが、アーカイブログ側は特にブロックデバイスである必要はありません。NFSのようなファイルストレージで十分なケースも多いので、いずれそこは修正できればと思います。
ただ、この構成で問題になってくるのがアーカイブログを出力する/mnt/postgresql/xlogの権限です。コンテナを普通に起動するとPostgreSQLコンテナから権限不足で書き込みができなくなってしまいます。
これを避けるため、今回はpostStartで該当ディレクトリの書き込み権限を付与をしています。
          lifecycle:
            postStart:
              exec:
                command:
                  - sh
                  - -c
                  - chmod a+w /mnt/postgresql/xlog/
これもファイルストレージを事前に用意しておけば、回避することができるはずです。
Probeの設定
最後にliveness/readinessProbeの設定です。
ここではPostgreSQLが使う5432ポートに対して、tcpソケットでヘルスチェックを投げる設定を入れています。
          livenessProbe:
              tcpSocket:
                 port: 5432
              initialDelaySeconds: 10
              periodSeconds: 3
              timeoutSeconds: 3
              failureThreshold: 2
          readinessProbe:
              tcpSocket:
                 port: 5432
              initialDelaySeconds: 5
              periodSeconds: 3
              timeoutSeconds: 1
              successThreshold: 1
ただ、ポッド障害のケースで見たようにPostgreSQLのリカバリを待つケースなどでは上のヘルスチェックでは意味がないため、もう少し修正が必要そうです。
まとめ
とりあえず動く形にはなりましたが、アーカイブログやProbe設定でまだまだ修正が必要な部分は残っています。PostgreSQL on Kubernetesしたいという方もこちらを参考に独自のYAMLを書いてみて下さい。
よろしくお願いします。