Kubernetesクラスタ(on Raspberry Pi5)にCockroachDBを導入する。DB側がTLS有効かつクライアント側でsslmode=verify-fullで接続しようとした際、ユーザの証明書作成に少し手間取ったので、(正しい方法かはわからないが)その手順も示す。
CockroachDBとは
CockroachDBは、PostgreSQL互換を持つ分散データベースでNewSQLと呼ばれているものの1つ。NewSQLは、スケーラビリティを持ちながらもACIDトランザクションが可能で、RDBのスケーラビリティの低さやNoSQLの一貫性の低さといった欠点を解決したデータベース。CockroachDBの他には、TiDBやGoogleCloud Spanner、YugabyteDBなどがある。 中でもCockroachDBの特徴としては、ノード間での役割の差がなく、どのノードがダウンしても最小の待ち時間で利用し続けることができる。システムデータ含むほぼ全てのデータはRangeと呼ばれるチャンクに分割され、各ノードに配置される。またRangeはノード障害に備えてレプリカがデフォルトで3つ作成、いずれかのノードに配置される。クエリを受けたノードがもしデータを持っていなければ他ノードにクエリがルーティングされる。ただし、場合によってはネットワークホップ数が増えてしまい遅延に繋がる。
Kubernetesクラスタにデプロイする
https://github.com/cockroachdb/cockroach-operator?tab=readme-ov-file#install-the-operator に沿って実施する。デプロイの流れは下記の通り。公式のオペレータはARM64に対応していないため、サードパーティを利用する。
- CRDのApply
- オペレータのApply
- CockroachDBのApply
# CRD kubectl apply -f https://raw.githubusercontent.com/cockroachdb/cockroach-operator/master/install/crds.yaml # Operator ## OperatorのyamlのimageはARM64に対応していないため、サードパーティのimageに変更する curl -fsSL -o cockroach-operator.yaml https://raw.githubusercontent.com/cockroachdb/cockroach-operator/master/install/operator.yaml ## image: cockroachdb/cockroach-operator:v2.14.0をghcr.io/jrcichra/cockroach-operator:v2.12.0に変更する sed -i.old 's/image:.*$/image: ghcr.io\/jrcichra\/cockroach-operator:v2.12.0/' cockroach-operator.yaml kubectl create -f cockroach-operator.yaml kubectl get po -n cockroach-operator-system NAME READY STATUS RESTARTS AGE cockroach-operator-manager-7fcf99bc96-6kvq9 1/1 Running 0 57s
CockroachDBは https://github.com/cockroachdb/cockroach-operator/blob/master/examples/example.yaml を元にマニフェストを作成する。 PersistentVolumeが必要なので同時に作成する。共有ストレージである必要はないため、今回は各ノードにLocalで作成する。下記のマニフェストはホスト名で絞ってボリュームおよびDBを作成しているため、参考にする場合は適宜変更してください。 商用の環境でCockroachDBを利用する場合は、SANを構築してPVを作成するのがいいかもしれない。
cockroach-pv.yaml
apiVersion: v1 kind: Namespace metadata: name: cockroach-sample --- apiVersion: v1 kind: PersistentVolume metadata: name: crdb-pv1 spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /opt/k8s/localpv nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - rs01 # ホスト名は適宜修正する --- apiVersion: v1 kind: PersistentVolume metadata: name: crdb-pv2 spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /opt/k8s/localpv nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - rs02 # ホスト名は適宜修正する --- apiVersion: v1 kind: PersistentVolume metadata: name: crdb-pv3 spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /opt/k8s/localpv nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - rs03 # ホスト名は適宜修正する
cockroach.yaml
apiVersion: crdb.cockroachlabs.com/v1alpha1 kind: CrdbCluster metadata: name: cockroachdb namespace: cockroach-sample spec: dataStore: pvc: spec: accessModes: - ReadWriteOnce resources: requests: storage: "5Gi" volumeMode: Filesystem storageClassName: local-storage resources: requests: cpu: 500m memory: 2Gi limits: cpu: 2 memory: 8Gi tlsEnabled: true image: name: cockroachdb/cockroach:v24.2.0 nodes: 3 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - rs01 # ホスト名は適宜修正する - rs02 # ホスト名は適宜修正する - rs03 # ホスト名は適宜修正する
# PV用のディレクトリ作成は各ノードで実施 sudo mkdir -p /opt/k8s/localpv kubectl create -f cockroach-pv.yaml kubectl create -f cockroach.yaml kubectl get po -n cockroach-sample # NAME READY STATUS RESTARTS AGE # cockroachdb 1/1 Running 0 13h # cockroachdb 1/1 Running 0 13h # cockroachdb 1/1 Running 0 13h
デプロイ時には証明書も作成されている。この証明書を利用してこの後rootでログインする。
kubectl get secret -n cockroach-sample # NAME TYPE DATA AGE # cockroachdb-ca Opaque 1 5s # cockroachdb-node Opaque 3 3s # cockroachdb-root Opaque 3 2s
動作確認
専用のSQLクライアントが入ったPodのマニフェストが用意されているので利用する。 https://github.com/cockroachdb/cockroach-operator?tab=readme-ov-file#access-the-sql-shell に従って進める。
kubectl create -f https://raw.githubusercontent.com/cockroachdb/cockroach-operator/master/examples/client-secure-operator.yaml -n cockroach-sample
kubectl exec -it cockroachdb-client-secure -n cockroach-sample -- ./cockroach sql --certs-dir=/cockroach/cockroach-certs --host=cockroachdb-public
rootでログインできたのでユーザ作成しつつ、pg_database
を見てみる。defaultdb
というDBが作られている。テストや幾つかの内部データベースで利用されると記載があるので、削除しないほうが良さそうである。
CREATE USER roach WITH PASSWORD 'Q7gc8rEdS'; SELECT * FROM pg_database; -- oid | datname | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit | datlastsysoid | datfrozenxid | datminmxid | dattablespace | datacl -- ------+-----------+------------+----------+------------+------------+---------------+--------------+--------------+---------------+--------------+------------+---------------+--------- -- 100 | defaultdb | 1546506610 | 6 | en_US.utf8 | en_US.utf8 | f | t | -1 | 0 | NULL | NULL | 0 | NULL -- 102 | postgres | 1546506610 | 6 | en_US.utf8 | en_US.utf8 | f | t | -1 | 0 | NULL | NULL | 0 | NULL -- 1 | system | 3233629770 | 6 | en_US.utf8 | en_US.utf8 | f | t | -1 | 0 | NULL | NULL | 0 | NULL -- (3 rows) -- SQLコマンドは普通に利用できる。 CREATE DATABASE IF NOT EXISTS bank; USE bank; CREATE TABLE accounts (id INT8 PRIMARY KEY, balance DECIMAL); INSERT INTO accounts (balance, id) VALUES (25000.00, 2); SELECT * FROM accounts; -- id | balance -- -----+----------- -- 2 | 25000.00 -- (1 row) GRANT SELECT ON TABLE bank.accounts TO roach; \q
TLSを無効にしてみる
先ほどのPodを利用してinsecureでログインしようとすると、ノードがsecure modeで起動しているため失敗する。
kubectl exec -it cockroachdb-client-secure -n cockroach-sample -- ./cockroach sql --certs-dir=/cockroach/cockroach-certs --host=cockroachdb-public -- insecure # # # # Welcome to the CockroachDB SQL shell. # # All statements must be terminated by a semicolon. # # To exit, type: \q. # # # ERROR: SSL authentication error while connecting. # failed to connect to `host=cockroachdb-public user=root database=`: server error (ERROR: node is running secure mode, SSL connection required (SQLSTATE 08P01)) # Failed running "sql" # command terminated with exit code 1
ここで一度DBクラスタを削除して、先ほどのcockroach.yaml
のtlsEnabled
をfalse
にしてapplyしてみる。
kubectl delete -f cockroach.yaml sed 's/tlsEnabled: true/tlsEnabled: false/' cockroach.yaml | kubectl apply -f - # crdbcluster.crdb.cockroachlabs.com/cockroachdb created kubectl get crdbclusters.crdb.cockroachlabs.com -n cockroach-sample -o yaml | grep -i tls # {"apiVersion":"crdb.cockroachlabs.com/v1alpha1","kind":"CrdbCluster","metadata":{"annotations":{},"name":"cockroachdb","namespace":"cockroach-sample"},"spec":{"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"kubernetes.io/hostname","operator":"In","values":["rs01","rs02","rs03"]}]}]}}},"dataStore":{"pvc":{"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}},"storageClassName":"local-storage","volumeMode":"Filesystem"}}},"image":{"name":"cockroachdb/cockroach:v24.2.0"},"nodes":3,"resources":{"limits":{"cpu":2,"memory":"8Gi"},"requests":{"cpu":"500m","memory":"2Gi"}},"tlsEnabled":false}} kubectl exec -it cockroachdb-client-secure -n cockroach-sample -- ./cockroach sql --certs-dir=/cockroach/cockroach-certs --host=cockroachdb-public --insecure
USE bank; SELECT * FROM accounts; -- id | balance -- -----+----------- -- 2 | 25000.00 -- (1 row)
insecureでログインでき、データも残っていた。引き続き再度ユーザ作成をしてみる。
-- パスワード有りではユーザ作成できない CREATE USER roach2 WITH PASSWORD 'Q7gc8rEdS'; -- ERROR: setting or updating a password is not supported in insecure mode -- SQLSTATE: 28P01 CREATE USER roach2; -- CREATE ROLE
このように、insecure modeだとパスワードの生成ができない。ドキュメントをよくみると記載がある。他にもできないことがあるかもしれないが、insercure modeでできない一覧は探し当てることができなかった。insecure modeで運用するのであれば、初期構築時にはsecure modeで起動し、ユーザ作成など必要なことが終わったら一度DBクラスタを削除して、insecure modeで再作成するのが良いのだろう。ただしユーザ作成のたびに再作成が必要なため、他に切り替える良い方法があるかは引き続き模索していきたい。
ユーザの証明書作成
secure modeで運用する場合、かつ証明書の検証をする場合(verify-ca/verify-full)は、ログインに必要な証明書を作成する必要がある。証明書の作成には、openssl
かcockroach
CLIを利用できる。(https://www.cockroachlabs.com/docs/stable/cockroach-cert 参照)
ユーザの証明書作成には、root CAが必要だが、DBクラスタと同時に作成されており、secretに格納されている。
今回は、cockroach
CLIを利用する。ローカルにインストールするのではなく、先ほどのPodのマニフェストを修正して利用する。
client-secure-operator.yaml
apiVersion: v1 kind: Pod metadata: name: cockroachdb-client-secure namespace: cockroach-sample spec: serviceAccountName: cockroachdb-sa containers: - name: cockroachdb-client-secure image: cockroachdb/cockroach:v24.2.0 imagePullPolicy: IfNotPresent volumeMounts: - name: client-certs mountPath: /cockroach/cockroach-certs/ command: - sleep - "2147483648" # 2^31 terminationGracePeriodSeconds: 0 volumes: - name: client-certs projected: sources: - secret: name: cockroachdb-ca items: - key: ca.key path: ca.key - secret: name: cockroachdb-node items: - key: ca.crt path: ca.crt - secret: name: cockroachdb-root items: - key: tls.crt path: client.root.crt - key: tls.key path: client.root.key
kubectl delete po -n cockroach-sample cockroachdb-client-secure kubectl create -f client-secure-operator.yaml # secure modeにするため再作成する kubectl delete -f cockroach.yaml kubectl create -f cockroach.yaml kubectl get crdbclusters.crdb.cockroachlabs.com -n cockroach-sample -o yaml | grep -i tls # tlsEnabled: true kubectl exec -it cockroachdb-client-secure -n cockroach-sample -- bash -c 'cp -rp /cockroach/cockroach-certs /cockroach/tmp-certs && chmod -R 400 /cockroach/tmp-certs && cockroach cert create-client roach --certs-dir=/cockroach/tmp-certs --ca-key=/cockroach/tmp-certs/ca.key' kubectl cp -n cockroach-sample cockroachdb-client-secure:tmp-certs/client.roach.key ./client.roach.key kubectl cp -n cockroach-sample cockroachdb-client-secure:tmp-certs/client.roach.crt ./client.roach.crt ls -l client.roach.* # -rw-r--r-- 1 hirano00o hirano00o 1147 8月 29 19:28 client.roach.crt # -rw-r--r-- 1 hirano00o hirano00o 1679 8月 29 19:28 client.roach.key
必要なものはDBクラスタ構築時にsecretにあるため、それらをマウントしている。マウントしたディレクトリはread-onlyなためコピーした上で権限を400に変更している。 cockroach cert create-client
コマンドで証明書を作成している。
作成した証明書が利用できるか試してみる。CockroachDBの待受ポートは26257
なのでport-forwardし、別ターミナルでCAの証明書を出力し、Podから取得したユーザの鍵の権限を変更しておく。
kubectl port-forward -n cockroach-sample services/cockroachdb-public 26257 # another terminal kubectl get secret -n cockroach-sample cockroachdb-root -o='jsonpath={.data.ca\.crt}' | base64 -d > ca.crt chmod 600 client.roach.key
下記の簡単なクエリを発行するプログラムを実行する。インサートしたid値である2
が表示され、正しく証明書が作成されていることがわかる。
package main import ( "database/sql" "fmt" _ "github.com/lib/pq" ) func main() { db, err := sql.Open("postgres", "host=localhost port=26257 user=roach password=Q7gc8rEdS dbname=bank sslmode=verify-full sslrootcert=ca.crt sslcert=client.roach.crt sslkey=client.roach.key") if err != nil { panic(err) } var id int if err := db.QueryRow("select id from accounts").Scan(&id); err != nil { panic(err) } fmt.Println(id) }
go mod init cockroach-sample
go mod tidy
go run main.go
# 2
終わりに
オンプレのKubernetesにCockroachDBを導入し、TLS有無それぞれでの動作を確認した。TLSが有効の場合はパスワードが生成できないことがわかった。DBクラスタでTLS有無を切り替える場合は、現状再作成が必要なように伺える。ユーザ作成毎にDBクラスタを再作成することに抵抗がある場合は、TLS有効のままsslmode=requireで接続すると良い。もしverify-ca/verify-fullで接続したい場合は、cockroach
CLIでユーザ証明書を簡易に作成できる。