VMware SQL with MySQL for Kubernetesは以前はTanzu SQLとして展開されていたもので、Kubernetesクラスタ上にMySQLインスタンスを管理するOperatorを展開してくれるものだ。このOperatorがある状態でカスタムリソースであるMySQLの定義(Manifest)をクラスタ上でapplyすると、簡単にDBが構築できる。すなわち、DDB as a Serviceのような感じで簡単にDBを用意することが出来る。
コンポーネントとしては以下が含まれる。
- Percona Server 8.0
- Percona XtraBackup 8.0
Percona ServerはMySQLを拡張させたオープンソースのDBで、こちらで開発が行われている。
無料で完全な互換性があり、パフォーマンス、拡張性、可視性で優れているとのこと。
Percona XtraBackupもオープンソースのバックアップユーティリティで、こちらで開発が行われている。
バックアップ中にロックをせず、DBのパフォーマンスを落とさずにシームレスにバックアップできるとのこと。
今回はVMware SQL with MySQL for Kubernetesの構築からこのバックアップを使うところまでやってみる。
なお、バージョンは1.7.1を利用し、TKG2.2.0上で構築するものとする。
前提条件
こちらによると、以下の条件を揃えておく必要がある。
- kubectlとkubernetesクラスタが利用可能(バージョン指定なし)
- kubectlを
cluster-admin
権限で利用可能 - Kubernetesクラスタ内にcert-managerが構築済み
- Helm CLIが利用可能 (v3.8.0以降)
- registry.tanzu.vmware.comにアクセスするためのユーザ名とパスワードを用意
- Docker daemonが起動している
registry.tanzu.vmware.comにアクセスするアカウント情報はTanzu Networkにアクセスするものと同一になる。
また、バックアップを利用する場合はS3互換ストレージが必要となる。
ここではMinIOを利用する。MinIOの構築手順は過去の記事で書いているためここでは割愛する。
インストール
こちらの手順に従い進めていく。
最初にTanzu Networkのユーザ名とパスワードを設定しておく。
export TANZUNET_USERNAME=xxx@hoge.info
export TANZUNET_PASSWORD=xxxx
レジストリにログインして、Helm Chartを取得する。公式手順だとHelm Chartを/tmpに展開していたが、残しておきたいのでカレントディレクトリに変更している。
echo $TANZUNET_PASSWORD | helm registry login registry.tanzu.vmware.com -u $TANZUNET_USERNAME --password-stdin
helm pull oci://registry.tanzu.vmware.com/tanzu-mysql-for-kubernetes/vmware-sql-with-mysql-operator --version 1.7.1 --untar --untardir ./
Namespaceを作成し、MySQLインスタンスを作る際にイメージをpullするための認証情報を格納したSecretを作成する。
kubectl create namespace vmware-mysql-for-kubernetes-system
kubectl create secret docker-registry tanzu-image-registry \
--docker-server=https://registry.tanzu.vmware.com/ \
--docker-username="${TANZUNET_USERNAME}" \
--docker-password="${TANZUNET_PASSWORD}" \
--namespace=vmware-mysql-for-kubernetes-system
必要に応じてvmware-sql-with-mysql-operator/values.yaml
を編集する。
編集可能な項目とその説明はこちらの中にある表を参照。
今回はデフォルト値を利用するため、特に編集していない。
最後にインストールする。
helm install --wait my-mysql-operator ./vmware-sql-with-mysql-operator/ \
--namespace=vmware-mysql-for-kubernetes-system \
--create-namespace
※追記:values.yaml
を編集しない場合はhelm pull
を飛ばして以下でもOK。
helm install --wait my-mysql-operator oci://registry.tanzu.vmware.com/tanzu-mysql-for-kubernetes/vmware-sql-with-mysql-operator \
--namespace=vmware-mysql-for-kubernetes-system \
--create-namespace
インストールに無事成功すれば、以下のような感じで各種リソースが取得できる。
$ kubectl get all --namespace=vmware-mysql-for-kubernetes-system
NAME READY STATUS RESTARTS AGE
pod/my-mysql-operator-5898d897f6-5854t 1/1 Running 0 92s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/vmware-mysql-webhook-service ClusterIP 100.66.6.61 <none> 443/TCP 92s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/my-mysql-operator 1/1 1 1 92s
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-mysql-operator-5898d897f6 1 1 1 92s
インストールされるカスタムリソースと動作確認
VMware SQL with MySQLでは以下のカスタムリソースがインストールされる。
-
kind: MySQL
:MySQLインスタンス本体 -
kind: MySQLVersion
:利用可能なDBのバージョンの管理 -
kind: MySQLBackup
:バックアップのリクエスト -
kind: MySQLBackupLocation
:バックアップに使うS3のバケットを定義 -
kind: MySQLBackupSchedule
:バックアップのスケジュールの定義 -
kind: MySQLRestore
:リストアのリクエスト
ここではメインとなるkind: MySQL
の挙動だけ確認しておく。
default
Namespaceにkind: MySQL
オブジェクトを作成してみる。
MySQLインスタンスのイメージはregistry.tanzu.vmware.com
にあるため、Pullする際に認証情報が必要となる。
Namespaceごとに認証情報を用意するのが面倒であれば、tanzu secret registry add
で全Namespaceから参照できるようにし、Exportするとよい。
tanzu secret registry add tanzu-image-registry-public --server registry.tanzu.vmware.com --username ${TANZUNET_USERNAME} --password ${TANZUNET_PASSWORD} --export-to-all-namespaces --yes --namespace vmware-mysql-for-kubernetes-system
ImportにはSecretImport
を使う。TKG2.2.0であれば標準で利用できる。
cat << EOF > ./secret-import.yaml
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretImport
metadata:
name: tanzu-image-registry-public
spec:
fromNamespace: vmware-mysql-for-kubernetes-system
EOF
kubectl apply -f ./secret-import.yaml -n default
Secretが取り込まれていることがわかる。
$ kubectl get secret tanzu-image-registry-public
NAME TYPE DATA AGE
tanzu-image-registry-public kubernetes.io/dockerconfigjson 1 2m6s
次に作成したSecretを使ってMySQLインスタンスを作成する。
こちらのManifestを流用し、Secret名だけ変更して実行する。
cat << EOF > ./mysql-sample.yaml
apiVersion: with.sql.tanzu.vmware.com/v1
kind: MySQL
metadata:
name: mysql-sample
spec:
resources:
mysql:
requests:
memory: 1Gi
storageSize: 1Gi
imagePullSecretName: tanzu-image-registry-public
EOF
kubectl apply -f ./mysql-sample.yaml -n default
起動すると、以下のような形でOperatorやDBのバージョンが取得できる。
$ kubectl get mysql
NAME READY STATUS AGE OPERATOR VERSION DB VERSION UPDATE STATUS USER ACTION
mysql-sample true Running 10m 1.7.1 8.0.31 NoUpdateRequired
なお、kubectl tree
で確認すると以下のような構造となる。
NAMESPACE NAME READY REASON AGE
default MySQL/mysql-sample - 112s
default ├─Certificate/mysql-sample-metrics-tls True Ready 111s
default │ └─CertificateRequest/mysql-sample-metrics-tls-9k49n True Issued 111s
default ├─Certificate/mysql-sample-mysql-tls True Ready 112s
default │ └─CertificateRequest/mysql-sample-mysql-tls-w4ngn True Issued 111s
default ├─ConfigMap/mysql-sample-autotune-config - 111s
default ├─RoleBinding/tanzu-mysql-backup-cron-mysqlbackup-creator-rolebinding - 112s
default ├─RoleBinding/tanzu-mysql-sidecar-rolebinding - 112s
default ├─Secret/mysql-sample-app-user-db-secret - 111s
default ├─Secret/mysql-sample-credentials - 111s
default ├─Secret/mysql-sample-metrics-tls - 110s
default ├─Secret/mysql-sample-mysql-tls - 110s
default ├─Service/mysql-sample - 111s
default │ └─EndpointSlice/mysql-sample-l48fx - 111s
default ├─Service/mysql-sample-members - 111s
default │ └─EndpointSlice/mysql-sample-members-kkvs9 - 111s
default ├─ServiceAccount/tanzu-mysql - 112s
default ├─ServiceAccount/tanzu-mysql-backup-cron - 112s
default └─StatefulSet/mysql-sample - 111s
default ├─ControllerRevision/mysql-sample-788c8dc948 - 111s
default └─Pod/mysql-sample-0 True 111s
証明書、RBAC(RoleBinding, SA))や設定周り(ConfigMap,Secret)、Service, StatefulSetあたりで構成されることが分かる。
この後は使わないので消しておく。なお、削除してもPVC、PVが残るので、完全削除するにはPVCも削除する。
kubectl delete mysql mysql-sample
kubectl delete pvc mysql-data-mysql-sample-0
サンプルアプリの起動
公式ドキュメントのConnectiong Applicationに従ってサンプルアプリを立ち上げてデータを格納する。
サンプルアプリ用DBの構築
公式手順はこちらとなる。
先程動作確認用に作成したManifestにmysqlのVersionを追加したものを用意した。
(利用可能なMySQLのバージョンはkubectl get mysqlversions
で取得可能。)
cat << EOF > ./mysql-sample.yaml
apiVersion: with.sql.tanzu.vmware.com/v1
kind: MySQL
metadata:
name: mysql-for-wordpress
spec:
mysqlVersion:
name: mysql-8.0.29
resources:
mysql:
requests:
memory: 1Gi
storageSize: 1Gi
imagePullSecretName: tanzu-image-registry-public
EOF
kubectl apply -f ./mysql-sample.yaml -n default
起動したことを確認する。
$ kubectl get mysql
NAME READY STATUS AGE OPERATOR VERSION DB VERSION UPDATE STATUS USER ACTION
mysql-for-wordpress true Running 4m54s 1.7.1 8.0.29 NoUpdateRequired
ここからは、こちらの記述に従いサンプルアプリ用にDBの中をいじっていく。
MySQLのコンテナ内に入る。
kubectl exec -it mysql-for-wordpress-0 -c mysql -- bash
MySQLに接続する。環境変数やパスワードのファイルはPod内に持っているので特に設定等する必要はない。
mysql -p$(cat $MYSQL_ROOT_PASSWORD_FILE) -u root
以下実行し、bitnami_wordpress
DBとユーザbn_wordpress
を作成する。
CREATE DATABASE bitnami_wordpress;
CREATE USER 'bn_wordpress'@'%' IDENTIFIED BY 'hunter2';
GRANT ALL PRIVILEGES ON bitnami_wordpress.* TO 'bn_wordpress'@'%';
FLUSH PRIVILEGES;
exit;
Podを抜けた後、cert-managerを使って証明書を発行する。
cat << EOF | kubectl apply -f -
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ca-certificate
spec:
isCA: true
issuerRef:
name: selfsigned-issuer
secretName: ca-secret
commonName: ca-cert
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: tls-issuer
spec:
ca:
secretName: ca-secret
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: tls-certificate
spec:
isCA: false
dnsNames:
- mysql-sample.default # See note after the code excerpt
secretName: mysql-tls-secret
issuerRef:
name: tls-issuer
EOF
既存のMySQLインスタンスにTLSの設定を追加する。
kubectl patch mysql mysql-for-wordpress --type merge -p '{"spec":{"tls":{"secret":{"name":"mysql-tls-secret"}}}}'
追加後、ログを確認するとTLSサポートが確認できる。
$ kubectl logs pod/mysql-for-wordpress-0 -c mysql | grep TLS
2023-06-01T01:40:12.245902Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2023-06-01T01:40:12.325310Z 0 [Warning] [MY-000067] [Server] unknown variable 'loose-group-replication-recovery-tls-version=TLSv1.2,TLSv1.3'.
サンプルアプリの用意
bitnami版WordPressを利用するため、最初にbitnamiリポジトリを追加する。
helm repo add bitnami https://charts.bitnami.com/bitnami
WordPressのvalues.yaml
が公式手順に用意されているので、これをコピーして一部修正してデプロイする。
cat << EOF > bitnami-wordpress-values.yaml
mariadb:
enabled: false
externalDatabase:
host: mysql-for-wordpress.default.svc.cluster.local
user: bn_wordpress
password: hunter2
database: bitnami_wordpress
extraEnvVars:
- name: "WORDPRESS_DATABASE_SSL_CA_FILE"
value: "/etc/mysql/tls/ca.crt"
- name: "WORDPRESS_ENABLE_DATABASE_SSL"
value: "yes"
- name: "BITNAMI_DEBUG"
value: "true"
extraVolumes:
- name: mysql-ca
secret:
secretName: "mysql-tls-secret"
items:
- key: ca.crt
path: ca.crt
extraVolumeMounts:
- name: mysql-ca
mountPath: /etc/mysql/tls/
EOF
helm install wp bitnami/wordpress -f ./bitnami-wordpress-values.yaml
なお、extraEnvVars
にWORDPRESS_ENABLE_DATABASE_SSL
をセットしないと動かない。同僚に聞いたところ、WordPress側で同パラメタが設定されていないとMySQLとの接続を有効化してくれないとのこと。
実際、このパラメタなしで実行するとPodが停止するため、必ず付与してデプロイする。
起動後、デフォルトではWordPressはtype:LoadBalancer
で公開しているので、公開先IPにアクセスする。
Hello world!
をクリックするとコメントを残すことが出来るので、適当に入力してPost Comment
をクリックする。
また、<IP address>/admin
にアクセスすると管理画面にアクセスできる。
- ユーザ名:
user
- パスワード:
kubectl get secret --namespace default wp-wordpress -o jsonpath="{.data.wordpress-password}" | base64 -d
でログインすることが出来る。
左サイドバーのPosts
からHello world!をEditし、タイトルを修正して右上のUpdate
で保存する。
変更後の画面は以下のようになっている。
これをバックアップ・リストアして復元できることを確認する。
サンプルアプリのバックアップ・リストア
先ほど作成したサンプルアプリをバックアップする。バックアップにはS3互換ストレージが必要になる。
ここではMinIOを利用する。
バックアップ
最初にバックアップの格納先リソース(kind: MySQLBackupLocation
)を作成する。
以下のbucket
、endpoint
、accessKeyId
、secretAccessKey
は自環境のものにあわせて修正する。また、forcePathStyle: true
がないとendpointのドメインの先頭にバケット名を含めてアクセスしに行くため、MinIOを使う場合は必須となる。
cat << 'EOF' > ./backup-location.yaml
apiVersion: with.sql.tanzu.vmware.com/v1
kind: MySQLBackupLocation
metadata:
name: mysql-location
spec:
storage:
s3:
bucket: "mysql-bucket"
endpoint: "http://10.222.147.222:9000"
forcePathStyle: true
secret:
name: minio-creds
---
apiVersion: v1
kind: Secret
metadata:
name: minio-creds
stringData:
accessKeyId: "minio"
secretAccessKey: "minio123"
EOF
kubectl apply -f ./backup-location.yaml
次にバックアップの要求を行うkind: MySQLBackup
リソースを作成する。
location.name
は先程作成したMySQLBackupLocation
オブジェクトの名前を、instance.name
は起動しているMySQL
オブジェクトの名前を指定する。
cat << EOF > ./backup.yaml
apiVersion: with.sql.tanzu.vmware.com/v1
kind: MySQLBackup
metadata:
name: backup-wp
spec:
location:
name: mysql-location
instance:
name: mysql-for-wordpress
EOF
kubectl apply -f ./backup.yaml
MySQLBackupLocation
に問題がなければ、バックアップが実行(Running)される。
$ kubectl get mysqlbackup
NAME STATUS SOURCE INSTANCE TIME STARTED TIME COMPLETED
backup-wp Running mysql-for-wordpress 2023-06-01T02:46:14Z
成功するとSucceededに変わる。
$ kubectl get mysqlbackup
NAME STATUS SOURCE INSTANCE TIME STARTED TIME COMPLETED
backup-wp Succeeded mysql-for-wordpress 2023-06-01T02:46:14Z 2023-06-01T02:46:23Z
リストア
問題なくMySQLインスタンスが作成されるか確認する。
一旦WordPressとMySQLインスタンスを削除する。
helm delete wp
kubectl delete mysql mysql-for-wordpress
kubectl delete pvc mysql-data-mysql-for-wordpress-0
ここからMySQLRestore
リソースを使って復元する。以下のManifestをapplyする。
なお、backup.name
に作成したMySQLBackup
オブジェクトの名前を、instanceTemplate.metadata.name
にMySQL
インスタンス名(バックアップと一致しなくてOK)を指定する。またimagePullSecretName
はPullが可能なSecretを指定する。
cat << EOF > ./restore.yaml
apiVersion: with.sql.tanzu.vmware.com/v1
kind: MySQLRestore
metadata:
name: restore-wp
spec:
backup:
name: backup-wp
instanceTemplate:
metadata:
name: mysql-for-wordpress-restored
spec:
storageSize: 1Gi
imagePullSecretName: tanzu-image-registry-public
EOF
kubectl apply -f ./restore.yaml
こちらもMySQLBackupLocation
に問題がなければ、リストアが実行(Running)され、完了するとSucceededになる。
$ kubectl get mysqlrestore
NAME STATUS SOURCE BACKUP TARGET INSTANCE TIME STARTED TIME COMPLETED
restore-wp Succeeded backup-wp mysql-for-wordpress-restored 2023-06-01T02:55:07Z 2023-06-01T02:57:28Z
この状態でWordPressを立ち上げる。
MySQLインスタンス名を変更したため、values.yamlのDB参照パスを以下のように変更する。
externalDatabase:
host: mysql-for-wordpress-restored.default.svc.cluster.local
変更が終わったら、helm installで立ち上げる。
helm install wp bitnami/wordpress -f ./bitnami-wordpress-values.yaml