2021/07/05

GKE上のZalando Postgres OperatorでGCSへのバックアップ&リストアを試す

gkepostgresqlk8s

概要

こちらの記事の作業の続きです。

今回は、以下の作業ログになります。

  • Zalando Postgres OperatorのGCSへのバックアップ及びリストアなどを試してみました・・
  • また、podの削除なども試してみました。

少しはまりポイントなどもありましたが、割とスムーズに(数時間程度で)検証できました。

参考にした資料

作業内容

GCS Bucketの作成

まずは以下のようにGCSバケットを作成しました。

  • Bucket名: test-postgres-operator
  • ロケーション タイプ: Dual-region
  • ロケーション: asia1
  • ストレージクラス: Nearline

Service Accountの作成

次に、クラスターのpodがGCSにアクセスできるようなサービスアカウントを準備します。

  • ストレージ管理者のロールを付与
  • json形式の鍵情報を作成してダウンロードしておきます

k8s設定ファイルの修正

secrets.yamlを追加

key.jsonの中身は先程作ったサービスアカウントの鍵のjsonファイルを指定しておきます。

apiVersion: v1
kind: Secret
metadata:
  name: psql-wale-creds
  namespace: default
type: Opaque
stringData:
  key.json: |-
    {
      "type": "service_account",
      "project_id": "your-project-id",
      "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "private_key": "",
      "client_email": "[email protected]",
      "client_id": "XXXXXXXXXXXXXXXXXXXXX",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/your-sa-name%40your-project-id.iam.gserviceaccount.com"
    }


configmap-pod-env-overrides.yamlを追加

  • 検証のため、5分おきに物理バックアップを取る設定にしています。(本番ではBACKUP_SCHEDULEはちゃんとした値に変更します。)
apiVersion: v1
kind: ConfigMap
metadata:
  name: pod-env-overrides
  namespace: default
data:
  # Any env variable used by spilo can be added
  BACKUP_NUM_TO_RETAIN: "5"  # 5 backups will be retained
  BACKUP_SCHEDULE: "*/5 * * * *"  # every 5 minutes for test
  USE_WALG_BACKUP: "true"
  USE_WALG_RESTORE: "true"
  CLONE_USE_WALG_RESTORE: "true"

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-operator
data:
  # 以下の5項目の設定を追加(物理バックアップ用)
  additional_secret_mount: "psql-wale-creds"
  additional_secret_mount_path: "/var/secrets/google"
  gcp_credentials: "/var/secrets/google/key.json"
  pod_environment_configmap: "default/pod-env-overrides"
  wal_gs_bucket: "test-postgres-operator"
  # 以下の4項目の設定を追加(論理バックアップ用)
  logical_backup_google_application_credentials: "/var/secrets/google/key.json"
  logical_backup_provider: "gcs"
  logical_backup_s3_bucket: "test-postgres-operator"  # gcsなんですが、logical_backup_s3_bucketを指定します。(shellファイルの中身をみたら分かりました。)
  # 検証のため5分おきに論理バックアップを取る設定にしています。(商用では論理バックアップ使わないかもしれません)
  logical_backup_schedule: "*/5 * * * *"

minimal-postgres-manifest.yaml

apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: acid-minimal-cluster
  namespace: default
spec:
  # 以下の行を追加すると、cronjobで論理バックアップをとってくれるようになります。
  enableLogicalBackup: true

minimal clusterの削除

以前作成したクラスターを削除します。

% kubectl delete postgresql acid-minimal-cluster

削除したときに、キレイに削除できない場合があると、同名のclusterを作成し直すときにエラーになりました。

通常は関連リソースも削除されるのですが、手順を間違えると関連リソースが削除されない場合があるようです。(私はここではまりました。)

以下のリソースをチェックして、clusterを削除したのに、リリースが残っている場合は、kubectl deleteコマンドを使って手動で削除してから、クラスターの再作成をおこなう必要があるようでした。

% kubectl get svc acid-minimal-cluster
% kubectl get svc acid-minimal-cluster-repl
% kubectl get svc acid-minimal-cluster-config
% kubectl get poddisruptionbudget postgres-acid-minimal-cluster-pdb
% kubectl get statefulset acid-minimal-cluster
% kubectl get pvc pgdata-acid-minimal-cluster-0
% kubectl get pvc pgdata-acid-minimal-cluster-1

クラスターの再作成

上記のSTEPで修正したk8s設定ファイルをデプロイすると、クラスターが再作成されます。
クラスターのデータは(当たり前ですが)初期状態で立ち上がります。

なので、再度以下のような感じでデータベースとテストデータを作成し直しました。

% kubectl exec -it acid-minimal-cluster-0 -- psql -U postgres
postgres=#  create database zalando_test;
CREATE DATABASE
postgres=# \c zalando_test;
You are now connected to database "zalando_test" as user "postgres".
# create table users (id SERIAL NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id));
CREATE TABLE
# insert into users (name) values ('user_a');
INSERT 0 1

手動での物理バックアップの実行

以下の手順で、(スケジュールでのバックアップだけではなく)手動で物理バックアップが取れました。

# masterのpodにログインします
% kubectl exec -it acid-minimal-cluster-0 -- bash

# rootでログインしているので、postgresユーザーになった後、postgres_backup.shを実行します。
# su postgres
$ envdir "/run/etc/wal-e.d/env" /scripts/postgres_backup.sh "/home/postgres/pgdata/pgroot/data"
2021-07-05 05:19:33.656 - /scripts/postgres_backup.sh - I was called as: /scripts/postgres_backup.sh /home/postgres/pgdata/pgroot/data
2021-07-05 05:19:34.168 - /scripts/postgres_backup.sh - producing a new backup
INFO: 2021/07/05 05:19:34.261365 Doing full backup.
INFO: 2021/07/05 05:19:34.279203 Calling pg_start_backup()
INFO: 2021/07/05 05:19:35.037738 Walking ...
INFO: 2021/07/05 05:19:35.038758 Starting part 1 ...
INFO: 2021/07/05 05:19:36.059773 Finished writing part 1.
INFO: 2021/07/05 05:19:36.833921 Starting part 2 ...
INFO: 2021/07/05 05:19:36.834079 /global/pg_control
INFO: 2021/07/05 05:19:36.900824 Finished writing part 2.
INFO: 2021/07/05 05:19:36.904008 Calling pg_stop_backup()
INFO: 2021/07/05 05:19:38.316448 Starting part 3 ...
INFO: 2021/07/05 05:19:38.411608 backup_label
INFO: 2021/07/05 05:19:38.411720 tablespace_map
INFO: 2021/07/05 05:19:38.411810 Finished writing part 3.
INFO: 2021/07/05 05:19:39.520783 Wrote backup with name base_000000020000000000000009

以下のようなバックアップファイルがGCSに作成されていることが確認できました。

test-postgres-operator/spilo/acid-minimal-cluster/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/wal/13/basebackups_005/base_000000020000000000000009

物理バックアップデータからリストア

minimal-postgres-manifest.yamlspec.cloneを追加します

apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: acid-minimal-cluster
  namespace: default
spec:
  # 以下の部分
  # uidはGCSにバックアップされるkey名にもついていますし、
  # kubectl describe postgresql acid-minimal-cluster コマンドからも確認できました。
  clone:
    uid: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    cluster: "acid-minimal-cluster"
    timestamp: "2021-07-05T15:35:08+09:00"

この状態で、clusterを再作成すると、バックアップファイルからクラスターが立ち上がります。

論理バックアップデータ

論理データは test-postgres-operator/spilo/acid-minimal-cluster/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/logical_backups/のpathの下に1625466607.sql.gzなどのsqlがgzip形式で格納されていました。

論理バックアップデータは特に復元の仕組みに使えるわけではないようなので、論理データのバックアップは物理バックアップの保険用って感じになるかなと思います。

Logical backups should not be seen as a proper alternative to basebackups and WAL archiving which are described above. At the moment, the operator cannot restore logical backups automatically and you do not get point-in-time recovery but only snapshots of your data. In its current state, see logical backups as a way to quickly create SQL dumps that you can easily restore in an empty test cluster.

pod削除時の挙動

最後に前回試していなかった、mainのpodの削除を試してみました。

acid-minimal-clusterはmain 1pod、replica 1podの状態で起動します。

% kubectl get pods -o name
pod/acid-minimal-cluster-0    # <= main
pod/acid-minimal-cluster-1    # <= replica
pod/postgres-operator-55b8549cff-vckk8

この状態で、mainであるpod/acid-minimal-cluster-0を削除してみました。

すると

pod/acid-minimal-cluster-1がすぐにmainに昇格し、pod/acid-minimal-cluster-0が10秒くらい?で再作成されてreplicaとして起動しました。

ひとまず、main 1pod / replica 2podくらいの構成で開発環境で動かして、問題なさそうなら商用環境に適用していこうと思います。

以上です。