オンプレ、VMからCNPへのレプリケーションによる複製作成(証明書編)

はじめに

説明

Cloud Native PostgreSQL(CNP)とはEDB社の提供しているPostgreSQLのKubernates Operatorになります。

Kubernates Operatorを初耳の方も多いと思いますが、一言で申しますとクラスタ管理・構築ツールになります。

今回は1.50から加わったpg_basebackupを使ってVMからベースバックアップを取得し、CNPを構築させる方法を記載します

構築所要時間

30分程度を想定しております。

前提

CNPの構築や操作は最低限の記載となりますので、詳しくは初回の記事を参考にして下さい。

CNPをインストール

下記を参考にcluster-exampleというクラスタを作成します。

EDB Postgres for Kubernetes v1 - Installation and upgrades
$ kubectl apply -f \
  https://get.enterprisedb.io/cnp/postgresql-operator-1.7.1.yaml
$ cat cluster-example.yaml
apiVersion: postgresql.k8s.enterprisedb.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 2
  primaryUpdateStrategy: unsupervised

  storage:
    size: 1Gi
$ kubectl apply -f cluster-example.yaml

作成されたことを確認します。

$ kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
cluster-example-1   1/1     Running   0          42m
cluster-example-2   1/1     Running   0          42m

テスト用のテーブルを作成し、データを入れます。

$ kubectl exec -it cluster-example-1 -- /binb/ash
$ psql
pqsl# create table japan ( id serial primary key, pref text, city text );
pqsl# INSERT INTO japan
  ( pref , city ) 
VALUES
  ( '東京都', '八王子市' ),
  ( '東京都', '立川市' ),
  ( '東京都', '武蔵野市' ),
  ( '東京都', '三鷹市' ),
  ( '東京都', '青梅市' ),
  ( '東京都', '府中市' ),
  ( '東京都', '昭島市' ),
  ( '東京都', '調布市' ),
  ( '東京都', '小金井市' ),
  ( '東京都', '小平市' ),
  ( '東京都', '日野市' ),
  ( '東京都', '東村山市' ),
  ( '東京都', '国分寺市' ),
  ( '東京都', '国立市' ),
  ( '東京都', '福生市' ),
  ( '東京都', '狛江市' ),
  ( '東京都', '東大和市' ),
  ( '東京都', '清瀬市' ),
  ( '東京都', '東久留米市' ),
  ( '東京都', '武蔵村山市' ),
  ( '東京都', '多摩市' ),
  ( '東京都', '稲城市' ),
  ( '東京都', '羽村市' ),
  ( '東京都', 'あきる野市' ),
  ( '東京都', '西東京都市' );

接続ユーザを設定します

$ psql# CREATE ROLE streaming_replica LOGIN REPLICATION PASSWORD 'password';
pqsl# \q

今回pg_hba.confを編集しないのは

CNPの場合はデフォルトで設定されているためです。

また、この設定のため証明書が必須となっております。

cat /var/lib/postgresql/data/pgdata/pg_hba.conf
# Grant local access
local all all peer map=local

# Require client certificate authentication for the streaming_replica user
hostssl postgres streaming_replica all cert clientcert=1
hostssl replication streaming_replica all cert clientcert=1

hostssl app app all md5

# Otherwise use md5 authentication
host all all all md5

証明書準備

まずシークレット一覧を確認します。

$ kubectl get secret
NAME                          TYPE                                  DATA   AGE
cluster-example-app           kubernetes.io/basic-auth              3      43m
cluster-example-ca            Opaque                                2      43m
cluster-example-replication   kubernetes.io/tls                     2      43m
cluster-example-server        kubernetes.io/tls                     2      43m
cluster-example-superuser     kubernetes.io/basic-auth              3      43m
cluster-example-token-4mbv7   kubernetes.io/service-account-token   3      43m
default-token-9k729           kubernetes.io/service-account-token   3      4h18m

シークレットの中身を確認し、証明書が設定されていることを確認します。

$ kubectl get secret cluster-example-replication -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJuRENDQVVLZ0F3SUJBZ0lRWHZJcUcydmhJOEdpeDFsRG5WUFdRakFLQmdncWhrak9QUVFEQWpBc01SQXcKRGdZRFZRUUxFd2RrWldaaGRXeDBNUmd3RmdZRFZRUURFdzlqYkhWemRHVnlMV1Y0WVcxd2JHVXdIaGNOTWpFdwpPREUzTVRFeE1USTNXaGNOTWpFeE1URTFNVEV4TVRJM1dqQWNNUm93R0FZRFZRUUREQkZ6ZEhKbFlXMXBibWRmCmNtVndiR2xqWVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkU4cEVtK1dOSk84bTZJRjUxZTUKVEw2azAxOHRmLzRsV3hPclB3KytuT1lSeGNLRVYvUzdBYnVKV1RRa2FrRkZwb2N6MkdLMTl2OWkrSnNoUnFWOApnMG1qVmpCVU1BNEdBMVVkRHdFQi93UUVBd0lEaURBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQU1CZ05WCkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGSlJJZ2dYdlBaVVBWdXVIajRQdUVPWDFoVVBlTUFvR0NDcUcKU000OUJBTUNBMGdBTUVVQ0lGN0J6Z1gvN2VDSHBFRHBqN0FEVk0vczdPVmUxSmJTSXVMRWdwbVdNWlhOQWlFQQpxUlBweksyR0w4QXdiakszNEg2UjUvY3BIdzhMVnBRRnNZZlJiaCtLTFFVPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  tls.key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVLOTBndzM3ajJpb2xBMi9YSmNqYjNPcHdlcWlzaTBrNEZVZ25VeEQvbEZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVHlrU2I1WTBrN3lib2dYblY3bE12cVRUWHkxLy9pVmJFNnMvRDc2YzVoSEZ3b1JYOUxzQgp1NGxaTkNScVFVV21oelBZWXJYMi8yTDRteUZHcFh5RFNRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
kind: Secret
metadata:
  creationTimestamp: "2021-08-17T11:16:27Z"
  name: cluster-example-replication
  namespace: default
  ownerReferences:
  - apiVersion: postgresql.k8s.enterprisedb.io/v1
    controller: true
    kind: Cluster
    name: cluster-example
    uid: c4eced4b-4387-49ec-a74e-5adb0f636faf
  resourceVersion: "37816"
  uid: 134cea5f-fe5f-4a91-b372-2548e4cc6e53
type: kubernetes.io/tls

今回は既存のシークレットを使用しますが

新規で作成する場合は後述のclone.yaml通りですと下記コマンドで設定を行います。

$ kubectl create secret generic cluster-example-replication \
  --from-literal=tls.key=xxxxxxx \
  --from-literal=tls.crt=xxxxxxx

接続用のパスワードを設定します。

$ kubectl create secret generic source-db-replica-user \
  --from-literal=password=password

レプリケーションによる複製作成

設定ファイルを作成します。

$ cat clone.yaml
apiVersion: postgresql.k8s.enterprisedb.io/v1
kind: Cluster
metadata:
  name: cluster-restore
spec:
  instances: 2
  primaryUpdateStrategy: unsupervised

  bootstrap:
    pg_basebackup:
      source: cluster-example

  storage:
    size: 5Gi

  externalClusters:
  - name: cluster-example
    connectionParameters:
      host: cluster-example-rw
      user: streaming_replica
      sslmode: require
    password:
      name: source-db-replica-user
      key: password
    sslKey:
      name: cluster-example-replication
      key: tls.key
    sslCert:
      name: cluster-example-replication
      key: tls.crt

設定を反映し、Podが遷移するのを確認します。

エラーの場合はkubectl logs cluster-restore-1-pgbasebackup-hwllz

のように確認していきます。

$ kubectl apply -f clone.yaml
$ kubectl get pod
NAME                                   READY   STATUS     RESTARTS   AGE
cluster-example-1                      1/1     Running    0          145m
cluster-example-2                      1/1     Running    0          144m
cluster-restore-1-pgbasebackup-hwllz   0/1     Init:0/1   0          7s
$ kubectl get pod
NAME                                   READY   STATUS      RESTARTS   AGE
cluster-example-1                      1/1     Running     0          146m
cluster-example-2                      1/1     Running     0          145m
cluster-restore-1                      0/1     Init:0/1    0          9s
cluster-restore-1-pgbasebackup-hwllz   0/1     Completed   0          35s

無事、通常の起動と同じになれば完了です。

$ kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
cluster-example-1   1/1     Running   0          147m
cluster-example-2   1/1     Running   0          146m
cluster-restore-1   1/1     Running   0          71s
cluster-restore-2   1/1     Running   0          25s

動作確認

DBが複製されていることを確認します。

$ kubectl exec -it cluster-restore-1 -- /bin/bash

$ psql
psql# select * from japan;
 id |   pref    |      city
----+-----------+-----------------
  1 | 東京都 | 八王子市
  2 | 東京都 | 立川市
  3 | 東京都 | 武蔵野市
  4 | 東京都 | 三鷹市
  5 | 東京都 | 青梅市
  6 | 東京都 | 府中市
  7 | 東京都 | 昭島市
  8 | 東京都 | 調布市
  9 | 東京都 | 小金井市
 10 | 東京都 | 小平市
 11 | 東京都 | 日野市
 12 | 東京都 | 東村山市
 13 | 東京都 | 国分寺市
 14 | 東京都 | 国立市
 15 | 東京都 | 福生市
 16 | 東京都 | 狛江市
 17 | 東京都 | 東大和市
 18 | 東京都 | 清瀬市
 19 | 東京都 | 東久留米市
 20 | 東京都 | 武蔵村山市
 21 | 東京都 | 多摩市
 22 | 東京都 | 稲城市
 23 | 東京都 | 羽村市
 24 | 東京都 | あきる野市
 25 | 東京都 | 西東京都市
(25 rows)

あとがき

CNPはPodでPostgreSQLの設定を変更しても戻ってしまうため

pg_basebackupの方法が提供されているのはうれいしいですね。


ここまでお読みいただき、ありがとうございました!