2021/06/30
GKEでZalando Postgres Operator On Rook Cephを試す
概要
弊社では、弊社で運用しているwebアプリのほとんどをk8s上で運上しています。(GKEかEKSを使っています。)
今回は、k8s上で動く高可用性のPostgresqlクラスターが必要になってきたので調査の一環でデプロイまで試してみました。
今回試したのは、Zalando Postgres Operatorです。
ざっと調べた感じ、評判が良さそうだったのと、生のkubectlで操作ができるのが魅力的で、こちらを採用しました。
また、データの永続化のための仕組みとして、RookのCeph Block Storateを利用しました。
以下手順を備忘録も兼ねて記載します。
導入手順
以下の手順で作成しました。
- GKEクラスターの作成
- Rook Cephのクラスター(PVCベース)をデプロイ
- Zalando Postgres OperatorとPostgresql Cluster(最小構成main+replica+config)をデプロイ
GKEクラスターの作成
注意事項
- ノードの数は3としました。(rook cephのcluster sizeにも依存しそう?な気がします。一旦k8sのデフォルトでよくある3を選択しています。)
- k8sのバージョンは
1.20.7-gke.1800を選択しました。(rook cephをインストールするのに、一定のversionより上のものを選択する必要がありそうでした。) - 各ノードのimageタイプをUbuntuベースのものを利用する必要がありました。(COSを使ったら、rdbモジュールがなくて、エラーになり、node poolの再作成が必要になってしまいました。)
Rook requires a Linux Kernal built with the RBD module. Many distributions of Linux have this module but some don’t,
e.g. the GKE Container-Optimised OS (COS) does not have RBD. You can test your Kuberetes nodes by running
modprobe rbd. If it says ‘not found’, you may have to
rebuild your kernel
or choose a different Linux distribution.
Rook Cephのクラスターをデプロイ
- operatorをデプロイします。
# まずは、operatorをデプロイします。
% git clone --single-branch --branch v1.6.6 https://github.com/rook/rook.git
% cd rook/cluster/examples/kubernetes/ceph
% kubectl create -f crds.yaml -f common.yaml -f operator.yaml
# operatorがデプロイされるまで待ちます。(RunningになればOK)
% kubectl get pods -n rook-ceph -w
NAME READY STATUS RESTARTS AGE
rook-ceph-operator-6b986cf46d-bzxh9 1/1 Running 0 34s
- rook cephクラスターで使うpvc用のstorage classを定義します
storageclass-pd-ssd.yamlという名前で保存して、kubectl apply -f storageclass-pd-ssd.yamlします。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: pd-ssd
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
fstype: ext4
replication-type: none
- rook cephクラウスターをデプロイします
cluster-on-pvc.yamlのstorageClassName: gp2の箇所をstorageClassName: pd-ssdに編集後、kubectl apply -f cluster-on-pvc.yamlします。
volumeClaimTemplate:
spec:
storageClassName: pd-ssd # gp2となっている箇所を先程定義したpd-ssdに変更します。(変更箇所は2箇所)
resources:
requests:
storage: 10Gi
以上でRook CephクラスターがGKEにデプロイされました。(以下のような感じで確認できました。)
# check pods of cephcluster
% kubectl get pods -n rook-ceph -w
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-8w5cd 3/3 Running 0 4m41s
csi-cephfsplugin-fdmmf 3/3 Running 0 4m41s
csi-cephfsplugin-provisioner-78d66674d8-nb4st 6/6 Running 0 4m40s
csi-cephfsplugin-provisioner-78d66674d8-xvvvm 6/6 Running 0 4m40s
csi-cephfsplugin-zg8tc 3/3 Running 0 4m41s
csi-rbdplugin-5c7nw 3/3 Running 0 4m42s
csi-rbdplugin-bfrkh 3/3 Running 0 4m42s
csi-rbdplugin-provisioner-687cf777ff-4p9zm 6/6 Running 0 4m41s
csi-rbdplugin-provisioner-687cf777ff-4zg2c 6/6 Running 0 4m41s
csi-rbdplugin-tsdvf 3/3 Running 0 4m42s
rook-ceph-crashcollector-0e6a05b0707cc85c81519b8465f005a0-sj2qb 1/1 Running 0 2m6s
rook-ceph-crashcollector-3ef81d5c1764fc7afc02e7c3cdd9a96a-87x2d 1/1 Running 0 111s
rook-ceph-crashcollector-405f94fd9e0c8f4cf6b22739d5fe11f9-9f95m 1/1 Running 0 2m1s
rook-ceph-mgr-a-7d9b46fdb4-5mdrc 1/1 Running 0 2m7s
rook-ceph-mon-a-6bbdfff466-28747 1/1 Running 0 4m56s
rook-ceph-mon-b-57c4d78d5f-q68j6 1/1 Running 0 3m18s
rook-ceph-mon-c-cc896555d-5m4h6 1/1 Running 0 2m29s
rook-ceph-operator-6b986cf46d-xkf5b 1/1 Running 0 10m
rook-ceph-osd-0-59d68c8894-bq296 1/1 Running 0 90s
rook-ceph-osd-1-69d4756cc-kvt4f 1/1 Running 0 90s
rook-ceph-osd-2-67f5fd8bfb-r8gdp 1/1 Running 0 62s
rook-ceph-osd-prepare-set1-data-0q872c-ccbxl 0/1 Completed 0 2m3s
rook-ceph-osd-prepare-set1-data-1h4hrj-xj2rs 0/1 Completed 0 2m3s
rook-ceph-osd-prepare-set1-data-2w7kbn-b9d68 0/1 Completed 0 2m3s
# check if cephcluster is healthy
% kubectl -n rook-ceph get cephcluster
NAME DATADIRHOSTPATH MONCOUNT AGE PHASE MESSAGE HEALTH EXTERNAL
rook-ceph /var/lib/rook 3 5m52s Ready Cluster created successfully HEALTH_OK
Zalando Postgres OperatorとPostgresql Cluster(最小構成main+replica+config)をデプロイ
- postgres operatorのデプロイ
% git clone https://github.com/zalando/postgres-operator.git
% cd postgres-operator
kubectl create -f manifests/configmap.yaml
kubectl create -f manifests/operator-service-account-rbac.yaml
kubectl create -f manifests/postgres-operator.yaml
kubectl create -f manifests/api-service.yaml
# check postgres-operator pod's status
% kubectl get pod -l name=postgres-operator -w
NAME READY STATUS RESTARTS AGE
postgres-operator-55b8549cff-hvqfm 1/1 Running 0 12s
- postgres clusterのデプロイ
先程定義したrook ceph block storageを利用するように、minimal-postgres-manifest.yamlのspec.volumeのプロパティに、storageClassを追加して、kubectl apply -f minimal-postgres-manifest.yamlします。
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: acid-minimal-cluster
namespace: default
spec:
teamId: "acid"
volume:
size: 1Gi
storageClass: rook-ceph-block # この行を追加
numberOfInstances: 2
users:
zalando:
- superuser
- createdb
foo_user: []
databases:
foo: zalando
preparedDatabases:
bar: {}
postgresql:
version: "13"
# postgresql serverのpodが立ち上がっていることが確認できます。(デフォルトでは0がmainで1がreplica)
% kubectl get pods
NAME READY STATUS RESTARTS AGE
acid-minimal-cluster-0 1/1 Running 0 139m
acid-minimal-cluster-1 1/1 Running 0 138m
# postgresql clusterのserviceも立ち上がっていることが確認できました。
% kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
acid-minimal-cluster ClusterIP 172.17.166.182 <none> 5432/TCP 141m
acid-minimal-cluster-config ClusterIP None <none> <none> 140m
acid-minimal-cluster-repl ClusterIP 172.17.189.111 <none> 5432/TCP 141m
postgres-operator ClusterIP 172.17.191.19 <none> 8080/TCP 141m
接続確認
- mainにログインして、データベースとテーブルを作成して、データをインサートしました。
- replicaにログインしてデータを参照した後、インサートではエラーになることを確認しました。
# login to main pod
% kubectl exec -it acid-minimal-cluster-0 -- bash
# 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
# select * from users;
id | name
----+--------
1 | user_a
(1 row)
# login to replica pod
% kubectl exec -it acid-minimal-cluster-1 -- psql -U postgres -d zalando_test
psql (13.3 (Ubuntu 13.3-1.pgdg18.04+1))
Type "help" for help.
zalando_test=# \dt
List of relations
Schema | Name | Type | Owner
--------+-------+-------+----------
public | users | table | postgres
(1 row)
zalando_test=# select * from users;
id | name
----+--------
1 | user_a
(1 row)
# insert into users (name) values ('user_a');
ERROR: cannot execute INSERT in a read-only transaction
感想
今回はまだpodを無理矢理落としたり(kubectl delete pods acid-minimal-cluster-0)、
GCSへのバックアップなどはためせてないですが、近いうちに最小構成ではない構成を組んでみて試してみようと思います。
基本的にはgithubのドキュメントをみながらなんとか作業できるなという感じだったんですが、ちょっと変わったことをやろうとすると
かなり深くまでみないと制御できなそうだなという感じを受けました。
とはいえ、今後大量データを扱うアプリケーションの実装が控えてたりするので、早めにRookベースのアプリになれておかないとなという感じです。
関連する記事
[小〜中規模向け]GKEにTiDBをデプロイする
MySQL互換のNewSQLであるTiDBをGKEにデプロイしてみました。
NATS JetStream Controllerを使ってNATSをGKEにデプロイする
helm chartのnackを使って、NATS JetStreamサーバーをデプロイして、Stream/Consumerをk8sリソースとして管理する
GKEにDragonflydbをデプロイする
redis互換のdragonflydbをGKEにデプロイしました
[GKE]Kafka Strimziをアップグレードする
GKEにデプロイしているKafka Strimzi 0.26.0を0.30.0にアップグレードする
