概要
MySQL Operator for Kubernetes(以下MySQL Operator)というKubernetes上にMySQLの環境を手軽に用意できるOperatorを試してみましたのでまとめてみます。
(普段はインメモリのDBやSQLiteのようなファイルベースを使いがち)
本記事の対象
- Kubernetesを触り始めた方
- 簡単にMySQLを構築してみたい方
- MySQL Operatorを使ってみたい方
※本記事ではKubernetesの環境はご自身で準備いただくことを前提としております
MySQL Operatorについて
OperatorというKubernetesの運用自動化に使われる拡張機能を利用して、Oracle社のMySQL開発チームにて開発がされたものとなります。
MySQL OperatorはMySQL InnoDB Clusterの管理に重点を置いております。
参考リンク:KubernetesのOperatorについて
開発元Github:MySQL Operator for Kubernetes
MySQL InnoDB Clusterについて
複数台のMySQLServerでの高可用性やスケーリングなどの機能を提供するものになります。
最低3台のMySQL Serverと、アプリケーションとMySQL Server間のルーティングを提供するMySQL Routerで構成がされます。
引用元
MySQL Operatorのアーキテクチャ図
構築手順
それではここからMySQL Operatorの構築した手順について記載いたします。
基本的には公式ドキュメントを参考にしながら進めております。
公式ドキュメント
今回展開先に使用したKubernetes環境
Kubeadmで構築した1台のMasterと2台のWorkerで成る以下のようなKubernetesクラスタに対して展開を行いました。
一応以下記事に同じ構成を作成する手順をまとめております。
よく使っているkubeadmを使ったKubernetes検証環境の構築
MySQL Operatorデプロイ
CRDのインストール
MySQL Operatorで使用されるカスタム リソース定義 (CRD) をインストールします
kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy-crds.yaml
#出力
customresourcedefinition.apiextensions.k8s.io/innodbclusters.mysql.oracle.com created
customresourcedefinition.apiextensions.k8s.io/mysqlbackups.mysql.oracle.com created
customresourcedefinition.apiextensions.k8s.io/clusterkopfpeerings.zalando.org created
customresourcedefinition.apiextensions.k8s.io/kopfpeerings.zalando.org created
MySQL Operator デプロイ
以下コマンドでMySQL Operatorのデプロイを実施します。
kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy-operator.yaml
#出力
clusterrole.rbac.authorization.k8s.io/mysql-operator created
clusterrole.rbac.authorization.k8s.io/mysql-sidecar created
clusterrolebinding.rbac.authorization.k8s.io/mysql-operator-rolebinding created
clusterkopfpeering.zalando.org/mysql-operator created
namespace/mysql-operator created
serviceaccount/mysql-operator-sa created
deployment.apps/mysql-operator created
名前空間[mysql-operator]が自動で作成されデプロイが行われたため、実行に問題がないか確認。
kubectl get deployment mysql-operator --namespace mysql-operator
#出力
NAME READY UP-TO-DATE AVAILABLE AGE
mysql-operator 1/1 1 1 25h
以上でMySQL Operatorの準備が完了となります。
ここから先はMySQL Operatorで管理するMySQL InnoDB Clusterを展開していきます。
MySQL InnoDB Clusterデプロイ
Secret作成
MySQLのrootユーザー用のSecretを作成しておきます。
※mysqlpwdとtestは任意の値に変更してください
kubectl create secret generic mysqlpwd \
--from-literal=rootUser=root \
--from-literal=rootHost=% \
--from-literal=rootPassword="test"
#出力
secret/mysqlpwd created
MySQL InnoDB Cluster yaml作成
MySQL InnoDB Clusterをデプロイするためのyamlを準備します。
以下ではMySQL Serverインスタンス3台とMySQL Routerインスタンス1台を定義しています。
※sercretNameは前述の手順で作成したSercretをご記載ください
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: mycluster
spec:
secretName: mysqlpwd
tlsUseSelfSigned: true
instances: 3
router:
instances: 1
MySQL InnoDB Cluster デプロイ
作成したyamlでInnoDB Clusterのデプロイを行います。
kubectl apply -f mycluster.yaml
#出力
innodbcluster.mysql.oracle.com/mycluster created
以下コマンドでプロセスがすべてONLINEになるまで待機をします。
(少し時間がかかると聞いたため、ご飯でも食べてきます)
kubectl get innodbcluster --watch
#出力
NAME STATUS ONLINE INSTANCES ROUTERS AGE
mycluster PENDING 0 3 1 15s
MySQL InnoDB Cluster デプロイ失敗
ここでしばらく待つ(ご飯から帰ってくる)とONLINEになっているはずが、、一向にならない。。
そこで生成されているPodのログをのぞいてみます。
kubectl describe pod mycluster-0
#出力抜粋
Warning FailedScheduling 11s default-scheduler 0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.
Error Logging 22s kopf Handler 'on_pod_create' failed temporarily: Sidecar of mycluster-0 is not yet configured
Normal Logging 22s kopf POD CREATED: pod=mycluster-0 ContainersReady=None Ready=None gate[configured]=None
中身を見るとWarningの中にPersistentVolumeClaimsがバインドされていない旨の記載があります。
ここでPersistentVolumeを作成していなかったことに気づきます。
PersistentVolume の作成
MySQL Serverの展開にPersistentVolume(以下PV)が必要になるため、準備を進めます。
今回INSTANCEは3つあるため、小分けに3つのPVを用意していきます。
PV作成用のyaml作成
今回はNFSのサーバーがありましたため、そちらを使用していきます。
※NFS等の外部ストレージの用意が急遽難しい場合はhostPathの指定でローカルのディレクトリで取り合えず試すことはできます。
※hostPathの指定は以下yaml内のコメントアウト部分です。nfsの記載と入れ替えでご利用ください。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0001
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
server: ××.××.××.××
path: /export/nfs/pv0001
#hostPath:
# path: /data/pv0001
PV作成
作成したyamlでPVを作成します。
kubectl apply -f pv0001.yaml
#出力
persistentvolume/pv0001 created
今回はPVを3つ用意してSTATUSがAvailableになっていることを確認します。
kubectl get pv
#出力
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv0001 50Gi RWX Recycle Available 115m
pv0002 50Gi RWX Recycle Available 115m
pv0003 50Gi RWX Recycle Available 115m
これでPVの準備は完了となります。
補足
今回私はNFSを利用しましたが、それにあたりKubernetes Clusterに参加しているMaster及びWorkerに、
nfs-commonのインストールが必要になります。
同じ手順を追っていただきNFSを使ってみた方は各Kubernetes Nodeに以下のような形でインストールが必要な旨ご注意ください。
sudo apt-get install nfs-common
MySQL InnoDB Clusterデプロイ リベンジ
それではPVの準備が出来たため、気を取り直してMySQL InnoDB Clusterのデプロイを行います。
MySQL InnoDB Cluster yaml修正
今回PVの作成の際にaccessModesをReadWriteManyにしています。
そのため、前述で作成したmycluster.yamlでもReadWriteManyを指定する形に修正しておきます。
※datadirVolumeClaimTemplate以下を追記しております。
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: mycluster
spec:
secretName: mysqlpwd
tlsUseSelfSigned: true
instances: 3
router:
instances: 1
datadirVolumeClaimTemplate:
accessModes:
- ReadWriteMany
MySQL InnoDB Cluster 再デプロイ
修正したyamlにて再度デプロイを実施して、ONLINEになるまで待機します。
kubectl apply -f mycluster.yaml
kubectl get innodbcluster --watch
少し待つとONLINEが3になり全プロセスがONLINEになったことが確認できました。
NAME STATUS ONLINE INSTANCES ROUTERS AGE
mycluster ONLINE 3 3 1 112s
pvcも試しに見てみると無事にBoundになっており、それぞれバインドされていることが確認できます。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
datadir-mycluster-0 Bound pv0001 50Gi RWX 8m30s
datadir-mycluster-1 Bound pv0002 50Gi RWX 8m30s
datadir-mycluster-2 Bound pv0003 50Gi RWX 8m30s
構築した環境でMySQLを試してみる
せっかくなので構築した環境でMySQLを少し試してみます。
MySQLへログイン
まずは作成したMySQL Serverへログインをしてみます。
接続先のIPアドレスを確認
MySQLにログインするにあたり、接続先のIPアドレスを確認していきます。
Kubernetesクラスタ内から接続できる入り口としてServiceが展開されているので、そのCLUSTER-IPを確認します。
kubectl get service mycluster
#出力
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mycluster ClusterIP 10.102.215.34 <none> 3306/TCP,33060/TCP,6446/TCP,6448/TCP,6447/TCP,6449/TCP 13m
ログイン実行
前述で確認したCLUSTER-IPを用いてログインを行います。
※mysqlコマンドでログインを試すため、Masterに一旦mysqlクライアントをインストールしております
mysql -h 10.102.215.34 -u root -p
上記コマンド実行後パスワードが求められるので、Sercret作成の際に使ったパスワードを入力すると、
無事にログインが完了してSQLコマンドを実行できるようになります。
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1159
Server version: 8.0.31 MySQL Community Server - GPL
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
お試しで色々SQLを実行
とりあえずINSERTしたデータをSELECTできるところまで実行してみます。
-- DBの作成と指定
create database test_db;
use test_db;
-- テーブルの作成とデータの挿入
create table test_table(test_id int auto_increment not null primary key, test_text text not null);
insert into test_table (test_text) values('Hello MySQL Operator');
-- 挿入したデータの取得
select * from test_table;
-- 出力
+---------+----------------------+
| test_id | test_text |
+---------+----------------------+
| 1 | Hello MySQL Operator |
+---------+----------------------+
1 row in set (0.00 sec)
無事にSQLコマンドが動作していることが確認できました。
以上で、MySQL Serverとして問題なく利用できることが確認できたかと思います。
おまけ:現在のSQL Serverのhostnameについて
最後にhostnameの取得を行ってみます。
MySQLでは以下コマンドでhostnameを取得することができます。
select @@hostname;
-- 出力
+-------------+
| @@hostname |
+-------------+
| mycluster-0 |
+-------------+
1 row in set (0.00 sec)
mycluster-0というhostnameが取得できました。
このhostnameをkubectl get podsの結果と照らし合わせると、現在Workerのubuntu-kube02上のSQL Serverに入っているんだなと確認ができました。
kubectl get pods -o wide
# 出力
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mycluster-0 2/2 Running 0 36m 10.244.2.49 ubuntu-kube02 <none> 2/2
mycluster-1 2/2 Running 0 36m 10.244.1.39 ubuntu-kube03 <none> 2/2
mycluster-2 2/2 Running 0 36m 10.244.2.48 ubuntu-kube02 <none> 2/2
最後に
今回構築していて気になったこと
途中でPVを作ってPVCとバインドをしているのですが、その際にストレージクラスの指定をしていませんでした。
なにかデフォルトのなにかが勝手に使用されるのかなと思いましたが、「kubectl get sc」をうっても特に出力はされませんでした。
問題なく動きはしたものの、ストレージクラスはなくても動くもの?なのかというところが疑問のままになりました。
(他パターン等で試したり、色々調べてみます)
感想
今回はMySQL Operatorについて構築をしてみた内容についてまとめました。
Kubernetesは触り始めて間もないため、実際は記事に書いてあるよりも苦労したところもありました。
Kubernetesは今後も使う機会がありそうなため、もう少し土台はしっかり学んでおければと思います。