Kubernetesでもデータベースを本格運用――「PostgreSQL Operator PGO」を使い倒す:Cloud Nativeチートシート(19)
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、Operatorを利用して、Kubernetes上でデータベースを動作させる方法とその利点を紹介します。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。連載第8回では、「Operator」を利用してKubernetesを拡張する方法を紹介しました。
今回はそのOperatorを利用して、Kubernetes上で「PostgreSQL」を動作させる方法とその利点を紹介します。
目次
なぜDBをKubernetes上で動かすのか
DBマスター:え、Kubernetesでデータベース(DB)を動かしたことないの?
DB初心者:Kubernetes上でDBを動かしていいんですか? じっちゃんは「Kubernetes上でDBは絶対動かすな」って言ってましたよ。
DBマスター:それは、おじいちゃんだけに情報が古いね。今は、Operatorっていう便利なもんがあって、安心安全にDBを運用できるんだよ。
さて、そもそもなぜDBをKubernetes上で動かすのでしょうか?
いろいろなモチベーションがあるとは思いますが、オンプレミスでKubernetesを利用している場合、「Amazon Relational Database Service」(RDS)のようなクラウドベンダーが提供するDBサービスを利用できないので、自分でPostgreSQLのようなオープンソースソフトウェア(OSS)のDBを構築したいというケースがあるでしょう。
もちろんPostgreSQLのPodを起動するだけなら、DBのコンテナイメージを利用できますが、耐障害性やスケーラビリティ、バックアップやモニタリングまで考えると、PostgreSQL本体以外にもさまざまなプロダクトや、その設計と管理が必要になります。
また、アプリケーションのマイクロサービス化が進むにつれて、単一の巨大なDBではなく、サービスごとに小分けにしたDBを作成する構成も取られるようになります。この場合、多数のDBを管理する必要がありますが、従来の運用ではDBの数が増加するにつれて運用コストも増加しがちです。
このような背景の下、多数のDBを効率的に管理するために、DBも「Deployment」「StatefulSet」などのようにKubernetesのリソースとして扱いたいというのも耳にするケースです。
この点、「PostgreSQL Operator」を利用すれば、運用に必要なものが一通りそろったPostgreSQLクラスタを簡単に構築でき、他のアプリケーション同様Kubernetes上のリソースとして運用できます。
PostgreSQL Operatorにもいろいろある
本記事では、PostgreSQL Operatorを動かして例示しながら、その手軽さやKubernetes上でDBを動かす利点を見ていきます。
2022年7月現在、PostgreSQL Operatorは、PostgreSQL開発コミュニティーが公式に開発、提供しているものはありません。さまざまな企業やコミュニティーがそれぞれ開発したPostgreSQL Operatorを提供している状況です(※1)。
※1:PostgreSQL Operatorの比較については、NTTデータが公開しているスライドがあるので、PostgreSQL Operatorごとの機能の違いや、PGO以外のOperatorに興味のある方はこちらもご参照ください。
今回は数あるPostgreSQL Operatorの中でも、PostgreSQLコア開発者が複数在籍する企業Crunchy Dataが開発を主導している「PGO」を取り上げます。
PGOが作成するPostgreSQL環境のアーキテクチャ
今回利用する機能の範囲で、PGOが作成するPostgreSQLクラスタの概要を図示します。
PostgreSQLのインスタンスには、参照/更新両方のリクエストが処理可能なプライマリと、参照のみ処理可能なリードレプリカ(PostgreSQLでは通常「ホットスタンバイ」といいます)がありますが、上の図では、プライマリとリードレプリカ用のPodがそれぞれ1インスタンスずつ起動している状態を示しています。後ほど解説するように、PGOでは2台以上のリードレプリカを追加することも可能です。
PostgreSQLが動作するPod内には、PostgreSQLのdatabaseコンテナの他、設定ファイルや証明書を更新するコンテナ、バックアップサーバと通信するサイドカーコンテナが起動します。オプションでモニタリング用の情報をエクスポートするサイドカーコンテナも起動できます。
PostgreSQLのPodはStatefulSetから管理されます。リードレプリカを追加した場合、新しいStatefulSetを作成します。通常1つのStatefulSetのレプリカ数を増やすところですが、PGOではそれぞれ独立したStatefulSetを作成します。これも後ほど見るように、PGOが各StatefulSetを管理することで、StatefulSet組み込みのローリングアップデートよりも、PostgreSQLの状態を踏まえた柔軟なアップデートになります。
プライマリとリードレプリカそれぞれにアクセスするServiceが作成されます。ユーザーはこれらのServiceにアクセスすることで、系切り替えなどPostgreSQLクラスタ内部の状態が変化しても、それを意識することなくPostgreSQLにアクセスできます。
バックアップサーバ用のStatefulSetも作成されます。バックアップにはPostgreSQL用のバックアップソフトウェア「pgBackRest」が組み込まれています。
PGOを使ってオールインワンのPostgreSQL環境を作る
Kubernetesクラスタの準備
動作確認用のKubernetesクラスタを準備します。
PGOはKubernetes、OpenShift、Rancher、Google Kubernetes Engine(GKE)、Amazon Elastic Kubernetes Service(EKS)といったプラットフォーム上で動作確認されています。Kubernetesは、1.20以上のバージョンがサポート対象となっています。サポートされている各プラットフォームのバージョンは公式サイトを参照してください。
これらのプラットフォームの他、「minikube」「kind」などでも利用可能です。
用意した環境でデフォルトの「Storage Class」が存在することを確認します。これは、PostgreSQLクラスタを作成するときなど、ボリュームを動的に払い出すために利用されます。なお、カスタムリソースのマニフェストで指定すれば、デフォルト以外のStorage Classを利用することもできます。
こちらはminikubeを利用した場合の例です。
$ kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE standard (default) k8s.io/minikube-hostpath Delete Immediate false 54s
PGOのインストール
PGOは執筆時点の最新バージョン、5.1.1を利用します。Crunchy DataがPGOのインストール資材や、PostgreSQLクラスタを作成する「Kustomize」のサンプルなどをGitHub上に公開しているので、こちらをクローンします。
$ git clone https://github.com/CrunchyData/postgres-operator-examples.git
クローンしたディレクトリに移動します。以降の作業は本ディレクトリ内で実施します。
$ cd postgres-operator-examples
本記事を執筆した時点のコミットIDを指定してブランチを作成、チェックアウトします。
HEADを利用する場合、本記事とは動作が変わる可能性があるので、公式ドキュメントも参照してください。
$ git checkout -b pgotest 12085b73c85f3c30f0a0b1d3f5fe17b22c3eede3
KustomizeによってOperatorのインストールやPostgreSQLクラスタの構成がテンプレート化されているので、これを利用します。次の通り実行することで、PGO用のNamespace「postgres-operator」が作成され、PGOがインストールされます。
$ kubectl apply -k kustomize/install/namespace $ kubectl apply --server-side -k kustomize/install/default
コラム 「--server-side」オプションについて
「kubectl apply」コマンドを実行すると、内部ではマニフェストとKubernetesクラスタの差分を確認し、差分がある場合その部分を変更しますが、この処理は従来kubectlでのみ可能でした。
このため、自分の知らないところで別の人がKubernetesを変更した場合、その変更に気付くことなくkubectl applyで上書きしてしまったり、kubectl以外のクライアントからこの仕組みを利用しようとしたりすると、kubectlのコードを利用するといった対応が必要となる問題がありました。
本問題の対応として、この処理をkubectlではなくKubernetesで実施する仕組みが開発されました。それを有効化するオプションが--server-sideです。
OperatorのPodの「STATUS」が「Running」になるまで待ちます。
$ kubectl -n postgres-operator get pods \ --selector=postgres-operator.crunchydata.com/control-plane=postgres-operator \ --field-selector=status.phase=Running NAME READY STATUS RESTARTS AGE pgo-548fdd84bd-8hkhw 1/1 Running 0 12m
PostgreSQLクラスタの作成
PGOが動作を開始したら、PostgreSQLクラスタを作成できます。具体的には、カスタムリソースとして「PostgresCluster」を利用できるようになります。これを利用することで、PostgreSQLのクラスタを作成します。
サンプルとして幾つかのPostgreSQLクラスタの構成が用意されていますが、今回は最もシンプルなPostgreSQL1台構成のKustomize「kustomize/postgres」を利用します。
マニフェストを適用する前に、中身を確認してみましょう。以下「kustomize/postgres/postgres.yaml」に簡単な説明を追記していますが、詳細やその他に設定可能な項目については、PGOのCRD Referenceを参照してください。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster # カスタムリソース名 3 metadata: 4 name: hippo # PostgreSQLクラスタの名前 5 spec: 6 image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.3-0 # PostgreSQLのコンテナイメージ 7 postgresVersion: 14 # PostgreSQLのバージョン 8 instances: # PostgreSQL Podの設定 9 - name: instance1 10 dataVolumeClaimSpec: # PostgreSQLのデータを保存するPVC(Persistent Volume Claim)の設定。本記述の場合、defaultのStorage Classを利用してPVCを動的に作成 11 accessModes: 12 - "ReadWriteOnce" 13 resources: 14 requests: 15 storage: 1Gi 16 backups: 17 pgbackrest: # PostgreSQLのバックアップソフトウェア、pgBackRestの設定 18 image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.38-1 # pgBackRestのコンテナイメージ 19 repos: # バックアップの保存先を指定 20 - name: repo1 21 volume: 22 volumeClaimSpec: # バックアップを保存するPVCの設定。本記述の場合、defaultのStorage Classを利用してPVCを動的に作成 23 accessModes: 24 - "ReadWriteOnce" 25 resources: 26 requests: 27 storage: 1Gi
PostgresClusterリソースをKubernetes上に作成します。KustomizeでYAMLが定義されているので、次のように「-k」オプションを利用して適用します。
$ kubectl apply -k kustomize/postgres
PostgreSQLのPodのSTATUSがRunningになるまで待ちます。YAMLファイルで確認したコンテナイメージのサイズが1GB程度とそれなりに大きいので、初回はPod起動までに時間がかかることもあります(※2)が、気長に待ちましょう。
※2:筆者の環境では1時間ほどかかることもありました。
PostgreSQLのサービスを提供するコンテナの他、先述した設定ファイルや証明書の更新、バックアップサーバと通信するコンテナが起動し、合計4つのコンテナが起動します。
次のコマンドでは、「hippo」という名前のPostgreSQLクラスタについて、PostgreSQLインスタンスの情報を取得しています。
$ kubectl -n postgres-operator get pods \ --selector=postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/instance NAME READY STATUS RESTARTS AGE hippo-instance1-w7sc-0 4/4 Running 0 85m $ kubectl -n postgres-operator get pod hippo-instance1-w7sc-0 \ -o jsonpath="{.spec.containers[*].name}" database replication-cert-copy pgbackrest pgbackrest-config
PostgreSQLのデータ保存用、およびバックアップデータ保存用のPVCが払い出されていることを確認できます。
$ kubectl -n postgres-operator get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE hippo-instance1-w7sc-pgdata Bound pvc-d56cff2f-da29-4e0f-b317-0632c49d8731 1Gi RWO standard 47s hippo-repo1 Bound pvc-94850c1e-ab9f-4f5e-aa22-d7cda2b60266 1Gi RWO standard 47s
これでPostgreSQLのサービスが利用可能になりました。
PostgreSQLへの接続確認
作成したPostgreSQLに接続して、サービスが利用できることを確認します。接続時にパスワード認証が必要になるので、「Secret」からパスワードを確認します。次の例パスワードを環境変数「HIPPO_CLIENT_PGPASSWORD」に保存しています。
$ HIPPO_CLIENT_PGPASSWORD=`kubectl -n postgres-operator get secret hippo-pguser-hippo -o json | jq -r .data.password | base64 --decode`
クライアントとしてDocker公式イメージの「postgresコンテナ」を利用して、テスト用にテーブル「t1」を作成して、1件データを投入してみます。接続先は、「hippo-ha」というServiceが払い出されているので、これを利用します。
$ kubectl -n postgres-operator run --image=postgres:14 --restart=Never --rm -it client --env="PGPASSWORD=${HIPPO_CLIENT_PGPASSWORD}" --command -- bash If you don't see a command prompt, try pressing enter. root@client:/# psql -h hippo-ha -U hippo -d postgres psql (14.4 (Debian 14.4-1.pgdg110+1)) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) Type "help" for help. postgres=> CREATE TABLE t1(t TEXT); CREATE TABLE postgres=> INSERT INTO t1 VALUES ('test'); INSERT 0 1 postgres=> \q root@client:/# exit exit
無事PostgreSQLに接続し、サービスを利用できることを確認できました。
Kubernetes上で動かしたPostgreSQLの運用性を確認する
機能的にPostgreSQLの動作を確認できましたが、これだけだと、PGOを利用せず、普通にPostgreSQLのコンテナを立ち上げたの大きな違いはありません。
ここからはモニタリングやリードレプリカの追加、バージョンアップなどPGOで提供される運用機能を見ていきましょう。
いずれもマニフェストを編集して適用することで、PostgreSQLクラスタの構成変更や運用操作を実現できます。
モニタリング機能の追加と確認
kustomize/postgres/postgres.yamlを編集します。28〜31行目を新規に追加しています。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster 3 metadata: 4 name: hippo 5 spec: ...(略)... 16 backups: ...(略)... 28 monitoring: 29 pgmonitor: 30 exporter: 31 image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres-exporter:ubi8-5.1.1-0
変更を適用します。
$ kubectl apply -k kustomize/postgres
先ほどまでは「4/4」だった「READY」が、「5/5」になり、コンテナが1つ追加されたことを確認します。追加されたコンテナは、Prometheusサーバからのリクエストに応じてPostgreSQLのメトリクスを返す「Exporter」です。
$ kubectl -n postgres-operator get pods --selector=postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/instance NAME READY STATUS RESTARTS AGE hippo-instance1-w7sc-0 5/5 Running 0 28m
メトリクスを取得、表示するには、モニタリングツールが必要です。PGOには、組み込みのモニタリングツールが用意されているので、ここでは、PGO組み込みのモニタリングツール(「Prometheus」「Grafana」「Alertmanager」)をインストールします。
$ kubectl apply -k kustomize/monitoring
こちらも各PodのSTATUSがRunningになるまで待ちます。
$ kubectl -n postgres-operator get pods --selector=app.kubernetes.io/name=postgres-operator-monitoring NAME READY STATUS RESTARTS AGE crunchy-alertmanager-5fdb768b96-zf46n 1/1 Running 0 10m crunchy-grafana-85799958b8-cbw8q 1/1 Running 0 10m crunchy-prometheus-67b84d64b9-b29c6 1/1 Running 0 10m
これでPrometheus、Grafana、Alertmanagerが利用可能になりました。試しにポートフォワードを利用してローカル端末のブラウザからGrafanaにアクセスしてみます。
下記のコマンドをローカル端末上で実行し、ローカルの3000番ポートをGrafanaが起動しているPodの3000番ポートにポートフォワードします。
$ GRAFANA=$(kubectl -n postgres-operator get pods -o name --selector=name=crunchy-grafana) $ kubectl -n postgres-operator port-forward ${GRAFANA} 3000:3000
ブラウザで「http://localhost:3000」にアクセスすると、ログイン画面が表示されます。初期ユーザー名とパスワードは、いずれも「admin」ですが、初回ログイン後パスワードの変更を促されるので変更しておきます。
※Webブラウザから利用しているクラウドコンソール上でkubectlコマンドを実行している場合は、ポートフォワードしてローカルのWebブラウザで画面を表示できません。ローカルの端末にkubectlを入れてコマンドを実行してください。
ダッシュボードを幾つか見てみましょう。
「PostgreSQLDetails」ダッシュボードでは、PostgreSQLの内部の状況が確認できます。例えば、PostgreSQLへの接続の状況(Active Connections、Idle In Transactionなど)、キャッシュヒット率(Cache Hit Ratio)、DBサイズ(database size)、ロックの取得状況(Locks)などが確認可能です。
「Query Statistics」ダッシュボードでは、PostgreSQLが実行したクエリの情報を確認できます。例えば、DBクラスタ全体のクエリ総実行回数(Queries Executed)や実行時間(Query Runtime)などのマクロな情報の他、SQLクエリごとの平均/最大/総実行時間(Query Mean Runtime、Query Max Runtime、Query Total Runtime)を確認できます。
この他にも幾つかダッシュボードが用意されており、バックアップの状況やPodのリソース利用状況などが確認可能です。
リードレプリカの追加
ここまでPostgreSQLは1台だけでしたが、リードレプリカを追加し、参照性能をスケールアウトしてみましょう。
先ほど確認した通り、現在PostgreSQLインスタンスのPodは1つだけです。これはプライマリが1台だけ動作していることを意味します。
$ kubectl -n postgres-operator get pods \ --selector=postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/instance NAME READY STATUS RESTARTS AGE hippo-instance1-w7sc-0 5/5 Running 0 15m
kustomize/postgres/postgres.yamlを編集し、プライマリ1台、リードレプリカ1台の合計2台構成に変更してみます。10行目を新規に追加しています。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster 3 metadata: 4 name: hippo 5 spec: 6 image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.3-0 7 postgresVersion: 14 8 instances: 9 - name: instance1 10 replicas: 2 11 dataVolumeClaimSpec: ...(略)...
変更を適用します。
$ kubectl apply -k kustomize/postgres
しばらくするとリードレプリカが起動し、Podも2つ起動します。
$ kubectl -n postgres-operator get pods \ --selector=postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/instance NAME READY STATUS RESTARTS AGE hippo-instance1-w7sc-0 5/5 Running 0 16m hippo-instance1-f8m4-0 5/5 Running 0 22s
起動したリードレプリカにSQLクエリを発行してみます。リードレプリカ接続用に、「hippo-replicas」というServiceが用意されているので、これを利用します。
$ kubectl -n postgres-operator run --image=postgres:14 --restart=Never \ --rm -i client --env="PGPASSWORD=${HIPPO_CLIENT_PGPASSWORD}" \ --command -- psql -h hippo-replicas -U hippo -d postgres -c "SELECT * FROM t1" t ------ test (1 row)
リードレプリカはその名の通り、読み込み専用インスタンスなので、参照リクエストのスケールアウトには有効ですが、更新系のクエリを実行できません。下記の例ではテーブルを新規作成しようとしていますが、失敗しています。
$ kubectl -n postgres-operator run --image=postgres:14 --restart=Never \ --rm -i client --env="PGPASSWORD=${HIPPO_CLIENT_PGPASSWORD}" \ --command -- psql -h hippo-replicas -U hippo -d postgres \ -c "CREATE TABLE t2(t TEXT)" ERROR: cannot execute CREATE TABLE in a read-only transaction
リードレプリカの台数を2台以上に増やしたり、任意の台数に減らしたりすることも、マニフェストを変更することで簡単に実現できます。例えば、先ほどマニフェストに追加した「replicas」を「3」に変更して(下記コードの10行目)マニフェストを適用すると、プライマリ1台、リードレプリカ2台の合計3台のPostgreSQLクラスタに拡張されます。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster 3 metadata: 4 name: hippo 5 spec: 6 image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.3-0 7 postgresVersion: 14 8 instances: 9 - name: instance1 10 replicas: 3 11 dataVolumeClaimSpec: ...(略)...
リードレプリカを作成するには、一般的には次のような作業が必要になります。
- リードレプリカ用のノードを作成
- PostgreSQLをインストール
- プライマリのデータを取得
- レプリケーションを開始
KubernetesとOperatorを利用することで、マニフェストを編集、適用するだけで簡単にリードレプリカを追加、削除できました。
自己修復の確認
障害などによって、宣言した状態と実際の状態が乖離(かいり)した場合、KubernetesとOperatorが宣言した状態に修復してくれます。この自己修復の様子を、何らかの障害が発生したと想定し、プライマリのPostgreSQLを停止して確認してみます。
「pg_ctl stop -m immediate」コマンドを実行し、PostgreSQLを即時停止します。
$ PG_CLUSTER_PRIMARY_POD=`kubectl get pod -n postgres-operator -o name \ -l postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/role=master` $ kubectl -n postgres-operator exec ${PG_CLUSTER_PRIMARY_POD} -- /usr/pgsql-14/bin/pg_ctl stop -m immediate waiting for server to shut down.... done server stopped
停止直後にプライマリに接続すると、エラーになります。
$ kubectl -n postgres-operator run --image=postgres:14 --restart=Never \ --rm -i client --env="PGPASSWORD=${HIPPO_CLIENT_PGPASSWORD}" \ --command -- psql -h hippo-ha -U hippo -d postgres -c "select 1" psql: error: connection to server at "hippo-ha" (10.96.72.178), port 5432 failed: Connection refused Is the server running on that host and accepting TCP/IP connections?
しばらくすると通常通り接続可能になり、自己修復されていることを確認できます。
$ kubectl -n postgres-operator run --image=postgres:14 --restart=Never \ --rm -i client --env="PGPASSWORD=${HIPPO_CLIENT_PGPASSWORD}" \ --command -- psql -h hippo-ha -U hippo -d postgres -c "select 1" ?column? ---------- 1 (1 row)
このような自己修復は、Kubernetesだけでも可能なようにも思えますが、HA(ハイアベイラビリティ)ソフトウェア「Patroni」も活躍しています。興味のある方は下記コラムをご覧ください。
コラム HAソフトウェア「Patroni」って何?
Patroniは、OSSのPostgreSQL向けHAソフトウェアです。
3ノード以上のPostgreSQLクラスタも容易に作成可能で、オンプレミスやKubernetes上でも動作することから、「StackGres」などPGO以外のPostgreSQL Operatorでも利用されています。
Patroniの大まかな仕組みは、次の通りです。
- PostgreSQLの台数分Patroniデーモンが動作し、各PostgreSQLの稼働状況をモニタリング
- モニタリング結果を「etcd」「Zookeeper」など高い一貫性を持つデータストアに保存。このデータストアを参照することで、各Patroniは、PostgreSQLクラスタ全体の状態を把握
- 把握した状態に応じてPostgreSQLを操作
Kubernetesも自己修復能力があることから、Patroniまで必要かどうか疑問に感じる方もいるかもしれません。しかし、DBの可用性を高めるには、DBMS内部の情報も踏まえた上で、正常性や系切り替えを判断する必要があるので、Kubernetesだけでは十分な対応が難しいのです。
例えば、プライマリのダウン後、複数台存在するリードレプリカから新プライマリを選出する場合、他の条件が同じならば、各リードレプリカのうち最もレプリケーションの遅延が小さいものを新プライマリとして選出すべきでしょう。このような判断がPatroniによって実現されます。
PostgreSQLのバージョンアップ
PostgreSQLは年に一度のメジャーバージョンアップで新機能が追加される他、マイナーバージョンを少なくとも3カ月に一度リリースします。バージョンの表記は、X.Yの形式をとり、Xがメジャーバージョン番号、Yがマイナーバージョンです。「14.3」の場合、メジャーバージョンは14、マイナーバージョンは3です。
マイナーバージョンはバグやセキュリティ上の問題を修正するリリースなので、基本的に利用しているメジャーバージョン内の最新のマイナーバージョンにアップデートしておくことが望ましいです。
このマイナーバージョンアップ対応もマニフェストから簡単にできます(※3)。具体的には、マニフェスト上のPostgreSQLのコンテナイメージを変更すれば、PGOがローリングアップデートをしてくれます。ローリングアップデート中は系切り替えが発生するので、PostgreSQLのサービスが一時的に停止します。
※3:メジャーバージョンアップもPGO 5.1からサポートされています。マイナーバージョンアップに比べると手順が増えますが、興味のある方はCrunchy Dataのブログを参照してください。
PGOが利用可能なコンテナイメージはCrunchy Dataが公開しています。ここまで、2022年7月の執筆時点でメジャー、マイナーともにコンテナイメージが存在する最新バージョン14.3を利用しているので、いったん14.2に変更した後、14.3にアップデートします。
kustomize/postgres/postgres.yamlの6行目を編集し、コンテナイメージを「ubi8-14.3-0」から「ubi8-14.2-1」に変更します(※4)。
※4:2022年7月の執筆時点では、14.2-1コンテナイメージが利用可能なことを確認していますが、イメージのダウンロードに失敗するなどした場合、Crunchy Data社が公開している最新のPostgreSQL14のコンテナイメージを公式サイトから確認し、適宜利用可能なイメージを選択してください。
ハイフンより前はPostgreSQLのバージョン、ハイフンの後の数字はPGOのコンテナイメージのバージョンです。6行目を変更しています。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster 3 metadata: 4 name: hippo 5 spec: 6 image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.2-1 ...(略)...
変更を適用します。
$ kubectl apply -k kustomize/postgres
下記コマンドを実行し、コンテナイメージがubi8-14.2-1に変更されたことを確認します。
$ kubectl -n postgres-operator get pods \ --selector=postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/instance \ -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.postgres-operator\.crunchydata\.com/role}{"\t"}{.status.phase}{"\t"}{.spec.containers[].image}{"\n"}{end}' hippo-instance1-w7sc-0 replica Running registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.2-1 hippo-instance1-f8m4-0 master Running registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.2-1
クラスタ初期構築時同様コンテナイメージのサイズがそれなりに大きいので、Pod起動までに時間がかかることもありますが、やはり気長に待ちましょう。
さて、先ほど変更したkustomize/postgres/postgres.yamlの6行目のコンテナイメージをubi8-14.3-0に戻し、マニフェストを適用してみましょう。今度はコンテナイメージが既にダウンロード済みなので、短時間で完了するはずです。
ローリングアップデートは、まずレプリカから実施されます。その後スイッチオーバし、旧プライマリがアップデートされ完了となります。アップデートが完了すると、以下のようにコンテナイメージのバージョンがubi8-14.3-0に更新されます。
$ kubectl -n postgres-operator get pods \ --selector=postgres-operator.crunchydata.com/cluster=hippo,postgres-operator.crunchydata.com/instance \ -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.postgres-operator\.crunchydata\.com/role}{"\t"}{.status.phase}{"\t"}{.spec.containers[].image}{"\n"}{end}' hippo-instance1-w7sc-0 master Running registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.3-0 hippo-instance1-f8m4-0 replica Running registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.3-0
ローリングアップデートによってプライマリ(master)とリードレプリカ(replica)が入れ替わっていることを確認できます。
自動バックアップとリストア
PostgreSQLに格納したデータのバックアップの運用も、マニフェスト上に宣言することで実現できます。例えば、開始時刻を指定した自動バックアップの定義や、取得したバックアップデータを利用して新規にPostgreSQLクラスタを作成できます。
今回は自動バックアップの設定とリストアの手順を確認してみます。バックアップの保存先は、Amazon S3やS3互換のオブジェクトストレージなどが選択可能です(※5)。今回はdefaultのStorage Classが新規に作成するPVCを利用します。
※5:その他対応しているストレージは、公式ドキュメントを参照してください。
kustomize/postgres/postgres.yamlを編集し、毎時5分にフルバックアップを取得するように設定します(※6)。
※6:1時間に1回という高頻度でのフルバックアップを取得することになりますが、今回は動作を確認するための設定です。利用する際は、バックアップ要件を踏まえて設定してください。
実行時刻の指定様式はcronと同様です。22〜23行目を新規に追加しています。手元の環境で確認する際は、数分後にバックアップが開始するように設定するとよいでしょう。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster ..(略).. 17 backups: 18 pgbackrest: 19 image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.38-1 20 repos: 21 - name: repo1 22 schedules: 23 full: "5 * * * *"
変更を適用すると、対応するcronjobが追加されます。
$ kubectl apply -k kustomize/postgres $ kubectl -n postgres-operator get cronjobs NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE hippo-repo1-full 5 * * * * False 0 <none> 8s
指定した時刻になるとバックアップを実行するPodが起動します。しばらくするとバックアップが完了し、STATUSがCompletedに変化します。
$ kubectl -n postgres-operator get pods --selector=postgres-operator.crunchydata.com/pgbackrest-cronjob=full NAME READY STATUS RESTARTS AGE hippo-repo1-full-27617165-kl87w 0/1 Completed 0 9m16s
これでバックアップが取得できました。続いてリストアしましょう。バックアップデータを利用して、新しいPostgreSQLクラスタを構築するために、下記の「restore.yaml」というマニフェストを新規に作成します。4〜10行目で、「elephant」というPostgreSQLクラスタを作成し、データとして先ほど取得したバックアップを利用するよう定義しています。
1 apiVersion: postgres-operator.crunchydata.com/v1beta1 2 kind: PostgresCluster 3 metadata: 4 name: elephant # PostgreSQLクラスタの名前 5 namespace: postgres-operator 6 spec: 7 dataSource: 8 postgresCluster: 9 clusterName: hippo 10 repoName: repo1 11 image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:ubi8-14.3-0 12 postgresVersion: 14 13 instances: 14 - dataVolumeClaimSpec: 15 accessModes: 16 - "ReadWriteOnce" 17 resources: 18 requests: 19 storage: 1Gi 20 backups: 21 pgbackrest: 22 image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.38-1 23 repos: 24 - name: repo1 25 volume: 26 volumeClaimSpec: 27 accessModes: 28 - "ReadWriteOnce" 29 resources: 30 requests: 31 storage: 1Gi
マニフェストを適用します。
$ kubectl apply -f restore.yaml
しばらくするとリストアが完了し、新しいPostgreSQLクラスタが起動します。下記のselectorで指定したPodのSTATUSがRunningになるまで待ちましょう。
$ kubectl -n postgres-operator get pods --selector=postgres-operator.crunchydata.com/cluster=elephant,postgres-operator.crunchydata.com/instance NAME READY STATUS RESTARTS AGE elephant-00-79cc-0 4/4 Running 0 2m16s
リストアしたPostgreSQLクラスタ用のServiceである「elephant-ha」に接続すると、バックアップを取得したPostgreSQLクラスタに投入したデータが存在することを確認できます。
$ kubectl -n postgres-operator run --image=postgres:14 --restart=Never \ --rm -i client --env="PGPASSWORD=${HIPPO_CLIENT_PGPASSWORD}" \ --command -- psql -h elephant-ha -U hippo -d postgres \ -c 'select * FROM t1' t ------ test (1 row)
バックアップ/リストアについては、今回紹介した内容以外にも次のような機能もサポートされています。
- 差分/増分バックアップ
- 保存するバックアップ世代数の管理
- 任意のタイミングでの手動バックアップ
- リカバリーポイントを指定したリストア(PITR)
- バックアップを取得したPostgreSQLクラスタへのリストア
興味のある方はこちらも公式ドキュメントの「バックアップ」「リストア」を参照してください。
PGOを利用する際の注意点
以下、幾つかPGOを利用する際の注意点を記載します。
書き込み可能なプライマリはスケールアウトしない
リードレプリカは簡単に追加できましたが、先ほど確認した通り、これはあくまで参照リクエストのみ可能なインスタンスです。更新リクエストが処理できるプライマリは1台のままなので、書き込み性能をスケールアウトさせることはできません。
マニフェストから実施できない操作もある
Kubernetesのマニフェストを編集、適用することでさまざまな運用ができることを見てきましたが、マニフェストからは実施できない操作もあります。例えば、取得したバックアップの一覧を確認する操作は、マニフェスト経由ではできません。下記のようにコンテナ上で直接バックアップツールのコマンドで実行するなどが必要です。
$ kubectl -n postgres-operator exec hippo-repo-host-0 -c pgbackrest -- pgbackrest info stanza: db status: ok cipher: none db (current) wal archive min/max (14): 000000010000000000000001/00000003000000000000005D full backup: 20220705-115307F timestamp start/stop: 2022-07-07 11:53:07 / 2022-07-07 11:53:51 wal start/stop: 000000010000000000000004 / 000000010000000000000004 database size: 33.9MB, database backup size: 33.9MB repo1: backup set size: 4.3MB, backup size: 4.3MB ..(略) full backup: 20220705-120802F timestamp start/stop: 2022-07-07 12:08:02 / 2022-07-05 12:08:10
ストレージソフトウェアは同梱されていない
監視/HAなどさまざまな周辺ソフトウェアや機能が同梱(どうこん)されているPGOですが、ストレージについては特に用意されていません。DBが利用するストレージの性能や信頼性は、サービス品質に直結します。今回defaultのstorage classを利用しましたが、PGOでは任意のstorage classを指定できるので、DBの用途や利用する環境に応じて適切なストレージを選択しましょう。
まとめ
今回は、PostgreSQL OperatorとしてPGOを紹介し、幾つか主要な機能を解説しました。Kubernetes上でPostgreSQLを動作させることで、宣言的にPostgreSQLクラスタを管理可能になり、運用性が向上することを実感できたのではないでしょうか。
注意点も踏まえた上で、オンプレミスのKubernetesでのDB構築や、KubernetesのリソースとしてDBを運用する手段として、PostgreSQL Operatorの利用を検討してみではいかがでしょうか。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- データ永続化と構築運用の自動化を実現する「PostgreSQL on Kubernetes」の仕組み
クラウドネイティブ時代のデータベース設計で考慮すべきポイントを検討する本連載。第2回はKubernetesでPostgreSQLを扱う「PostgreSQL on Kubernetes」の仕組みを解説する。 - プロが教える、クラウドインフラのトラブルシューティング「4つの原則」とは
クラウドインフラはオンプレミス環境と比べて複雑になりがちで、トラブルの原因特定に時間がかかることが多い。では、どういった点に注意してトラブルに対応していけばいいのか。 - 「スケールアウトできる『PostgreSQL』」――Yugabyte Japanに聞く「分散SQLDB」のメリット
なぜ「分散SQLDB」が注目を集めているのか。日本国内における分散SQLDBの普及に注力しているYugabyte Japanに「分散SQLDB」とその利点を伺いました。記事後半では2022年3月に開催されたアジア圏向けイベント「Distributed SQL Summit Asia」の内容を紹介します。