MySQL InnoDB ClusterSet の、複数の Kubernetes クラスターへのデプロイは骨の折れるタスクです。MySQL Operator for Kubernetes は、単一の Kubernetes クラスター内では MySQL InnoDB Cluster を効率的に管理できますが、複数のクラスターにまたがる InnoDB ClusterSet のデプロイには、現在の MySQL Operator リリースではまだサポートされていない、クラスター間通信が必要となります。
ここで Cilium が役立ちます。Cilium とは、高度なネットワーク機能を活用し、安全で効率的なクラスター間通信を可能にする強力なソリューションです。Cilium の統合によって、ネイティブな Kubernetes のサポート、簡素化された管理、そして MySQL のようにステートフルアプリケーションでの、パフォーマンス向上の恩恵を受けることができます。
複数クラスターの Kubernetes 環境にまたがって MySQL InnoDB ClusterSet デプロイを行うと、スケーラビリティの向上、ダウンタイムの最小化、データ一貫性の確保、そしてプライマリクラスター障害時のビジネス継続性が得られます。加えて、MySQL Operator によって管理される InnoDB Cluster デプロイメントの回復力も強化します。下図は、Cilium によってクラスター間通信が強化された 2 つの Kubernetes クラスターが、それぞれプライマリクラスターとレプリカクラスターとして MySQL InnoDB ClusterSet をデプロイ構成されている状態を示しています。
複数の Kubernetes クラスターにまたがる InnoDB ClusterSet のセットアップは、現在のところは以下に示すように手動でのプロセスです。このセットアップ手順は、オンプレミスの Kubernetes クラスター、あるいは公共クラウド上のフルマネージド Kubernetes サービスで実行されている、MySQL コンテナイメージを用いた MySQL InnoDB ClusterSet に対して実施できます。CI/CD ツールを用いることで、この手順はスクリプト化、自動化できます。
Cilium クラスターメッシュのデプロイ
すでに Cilium がインストールされている場合はこの章をスキップしてください。PROD クラスターと DR クラスターを区別するためのコンテキストを取得します。
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
context-cabqjcrx6nq cluster-cabqjcrx6nq user-cabqjcrx6nq
* context-che34bk2roa cluster-che34bk2roa user-che34bk2roa
使われている環境に対応するコンテキスト名で、context-cabqjcrx6nq と context-che34bk2roa の値を置き換えてください。手順内での参照を容易にするために、PROD クラスターのkubeconfigコンテキストを CONTEXT1 に、DR クラスターを CONTEXT2 に保存しましょう。
$ export CONTEXT2=context-cabqjcrx6nq
Helm を使用して Cilium をインストールするため、Cilium helm リポジトリを追加し、編集用のマニフェストをローカルに設定します:
$ helm show values cilium/cilium > prod-cilium.yaml
$ helm show values cilium/cilium > dr-cilium.yaml
prod-cilium.yaml を編集し、デフォルト値を以下のように変更します。
name: prod
id: 1
hubble:
tls:
enabled: false
hubble:
relay:
enabled: true
hubble:
ui:
enabled: true
ipam:
mode: “kubernetes”
その後、Helm を用いて PROD Kubernetes クラスターに適用します:
dr-cilium.yaml ファイルを prod-cilium.yaml の設定と一致するように設定しますが、クラスター名を「dr」に、クラスターIDを「2」とする点だけ変更します。そして、それを Helm を用いて DR Kubernetes クラスターに適用します。
続いて各クラスターで、Cilium が管理していないすべてのポッドを削除します。
kubectl delete pod –namespace kube-system -l k8s-app=kube-dns
kubectl delete pod –namespace kube-system -l k8s-app=hubble-relay
kubectl delete pod –namespace kube-system -l k8s-app=hubble-ui
kubectl delete pod –namespace kube-system -l k8s-app=kube-dns-autoscaler
kubectl config use-context $CONTEXT2
kubectl delete pod –namespace kube-system -l k8s-app=kube-dns
kubectl delete pod –namespace kube-system -l k8s-app=hubble-relay
kubectl delete pod –namespace kube-system -l k8s-app=hubble-ui
kubectl delete pod –namespace kube-system -l k8s-app=kube-dns-autoscaler
各クラスターで「cilium status」を実行して、Cilium のデプロイを確認します。Cilium デプロイメントが成功すると、PROD クラスターでは次のようになります:

DR クラスターでは次のようになります:

この状態では、PRODクラスターでクラスターメッシュは無効になっています。有効にするには、prod-cilium.yamlファイルを以下のように変更します:
useAPIServer: true
ciliumEndpointSlice:
enabled: true
そして、Helm を用いて Cilium を再デプロイします。
ここで PROD クラスターでクラスターメッシュのステータスを確認すると、有効になっています。
⚠️ Service type NodePort detected! Service may fail when nodes are removed from the cluster!
✅ Service “clustermesh-apiserver” of type “NodePort” found
✅ Cluster access information is available:
– 158.178.237.122:32379
✅ Deployment clustermesh-apiserver is ready
ℹ️ KVStoreMesh is enabled
🔌 No cluster connected
🔀 Global services: [ min:0 / avg:0.0 / max:0 ]
同じ手順を DR クラスターでも繰り返します。クラスターメッシュを有効にするため、dr-cilium.yaml ファイルを prod-cilium.yaml と同様に変更し、続けて以下を実行します:
$ cilium clustermesh status –context $CONTEXT2
クラスター間通信を有効にするため、次のコマンドを実行し、PROD クラスターと DR クラスターを接続します:
PROD クラスターからクラスターメッシュのステータスを確認します。成功したクラスターメッシュは次のように見えます。
⚠️ Service type NodePort detected! Service may fail when nodes are removed from the cluster!
✅ Service “clustermesh-apiserver” of type “NodePort” found
✅ Cluster access information is available:
– 158.178.237.122:32379
✅ Deployment clustermesh-apiserver is ready
ℹ️ KVStoreMesh is enabled
✅ All 3 nodes are connected to all clusters [min:1 / avg:1.0 / max:1]
✅ All 1 KVStoreMesh replicas are connected to all clusters [min:1 / avg:1.0 / max:1]
🔌 Cluster Connections:
– dr: 3/3 configured, 3/3 connected – KVStoreMesh: 1/1 configured, 1/1 connected
同様に、DR クラスター側からクラスターメッシュのステータスを確認します。
⚠️ Service type NodePort detected! Service may fail when nodes are removed from the cluster!
✅ Service “clustermesh-apiserver” of type “NodePort” found
✅ Cluster access information is available:
– 134.185.86.75:32379
✅ Deployment clustermesh-apiserver is ready
ℹ️ KVStoreMesh is enabled
✅ All 3 nodes are connected to all clusters [min:1 / avg:1.0 / max:1]
✅ All 1 KVStoreMesh replicas are connected to all clusters [min:1 / avg:1.0 / max:1]
🔌 Cluster Connections:
– prod: 3/3 configured, 3/3 connected – KVStoreMesh: 1/1 configured, 1/1 connected
🔀 Global services: [ min:0 / avg:0.0 / max:0 ]
MySQL InnoDB ClusterSet では、各ポッドの FQDN が各クラスターに認識される必要があります。kubectl を用いて以下のマニフェストを PROD クラスターと DR クラスターに適用し、coreDNS を NodePort として公開します。
kind: Service
metadata:
labels:
k8s-app: core-dns-nodeport
kubernetes.io/name: CoreDNS
name: core-dns-nodeport
namespace: kube-system
spec:
ports:
– name: dns
port: 53
protocol: UDP
targetPort: 53
nodePort: 30053
– name: dns-tcp
port: 53
protocol: TCP
targetPort: 53
nodePort: 30053
selector:
k8s-app: kube-dns
sessionAffinity: None
type: NodePort
上記のマニフェストが coreDNS_nodeport.yaml として保存されたと仮定して、以下のコマンドを用いてそれを両方のクラスターに適用します:
$ kubectl apply -f coreDNS_nodeport.yaml –context=$CONTEXT2
PROD と DR で InnoDB Clusters を実行するための環境準備
もしすでに完了している場合、この章をスキップしてください。
PROD クラスターに InnoDB Cluster 用の名前空間とシークレットを作成します。ClusterSet 内の InnoDB Cluster には各々一意な名前空間名が必要です。以下では、PROD InnoDB Cluster(「PRD」クラスターと命名)の名前空間として mysql-prod を使用し、MySQL の root パスワードを root に設定しています。
$ kubectl -n mysql-prod create secret generic mypwds –from-literal=rootUser=root –from-literal=rootHost=% –from-literal=rootPassword=”root” –context=$CONTEXT1
DR InnoDB Cluster(「DR」クラスターと命名)の名前空間として mysql-dr を使用し、MySQL の root パスワードを PROD InnoDB Cluster と同じ root に設定しています。
$ kubectl -n mysql-dr create secret generic mypwds –from-literal=rootUser=root –from-literal=rootHost=% –from-literal=rootPassword=”root” –context=$CONTEXT2
PROD クラスターで、kube-system 名前空間の coreDNS 設定を編集して、ターゲット DNS が mysql-dr.svc.cluster.local の場合に接続トラフィックをすべての DR クラスターワーカーノードの IP アドレスとポート 30053 に転送します。

同様に DR クラスターで、kube-system 名前空間の coreDNS 設定を編集して、ターゲット DNS が mysql-prd.svc.cluster.local の場合に接続トラフィックをすべての PROD クラスターワーカーノードの IP アドレスとポート 30053 に転送します。

MySQL Operator のデプロイ
すでにインストールされている場合、この章をスキップしてください。両方のクラスターにオペレーターが使用する CRD をインストールします。
$ kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy-crds.yaml –context=$CONTEXT2
wgetを使用してマニフェストファイル: deploy-operator.yamlをダウンロードします。
デフォルトの Cilium クラスタードメインに設定するために、MYSQL_OPERATOR_K8S_CLUSTER_DOMAIN 環境変数を追加し、deploy-operator.yaml を更新します。以下を参照してください。
– name: MYSQLSH_USER_CONFIG_HOME
value: /mysqlsh
– name: MYSQLSH_CREDENTIAL_STORE_SAVE_PASSWORDS
value: never
– name: MYSQL_OPERATOR_K8S_CLUSTER_DOMAIN
value: cluster.local
deploy-operator.yaml を各クラスターに適用します:
$ kubectl apply -f deploy-operator.yaml –context=$CONTEXT2
PROD クラスターでの、MySQL Operator のデプロイを確認します:
NAME READY STATUS RESTARTS AGE
mysql-operator-7f84cb7784-x2cjg 1/1 Running 0 41s
DR クラスターでの、MySQL Operator のデプロイを確認します:
NAME READY STATUS RESTARTS AGE
mysql-operator-79bccbddcd-wj96l 1/1 Running 0 51s
MySQL Operator での MySQL InnoDB Cluster のデプロイ
以下のように、PROD クラスターに InnoDB Cluster をデプロイするためのマニフェストファイル(PRD_cluster.yaml)を用意し、名前空間として mysql-prod を用います:
kind: InnoDBCluster
metadata:
name: prd
namespace: mysql-prod
spec:
secretName: mypwds
baseServerId: 100
tlsUseSelfSigned: true
instances: 3
router:
instances: 1
同様に、DR クラスターに InnoDB Cluster をデプロイするための別のマニフェストファイル(DR_cluster.yaml)を用意し、名前空間として mysql-dr を用います:
kind: InnoDBCluster
metadata:
name: dr
namespace: mysql-dr
spec:
secretName: mypwds
baseServerId: 200
tlsUseSelfSigned: true
instances: 3
router:
instances: 1
InnoDB ClusterSet では、各インスタンスに一意な server_id が必要です。したがって、YAML 設定内の baseServerId パラメータは各クラスターで異なる必要があります。以下のコマンドを使用して、双方の YAML を各クラスターに適用します:
$ kubectl apply -f DR_cluster.yaml –context=$CONTEXT2
約 2~3 分待ち、以下のコマンドを用いて PROD クラスターでの InnoDB Cluster のデプロイ状態を確認します。
NAME STATUS ONLINE INSTANCES ROUTERS AGE
prd ONLINE 3 3 1 3m40s
以下のコマンドを用いて、DR クラスターでの InnoDB Cluster のデプロイ状態を確認します。
NAME STATUS ONLINE INSTANCES ROUTERS AGE
dr ONLINE 3 3 1 3m40s
双方の InnoDB Cluster は、MySQL インスタンス用に 3 つのポッドと、MySQL Router 用に 1 つのポッドで実行されています。以下のコマンドを用いて、MySQL Shell で InnoDB Cluster のステータスを確認してみます:


両方の InnoDB Cluster が、正常な状態で実行されています。
クラスター間通信のためには、MySQL ポッドでクラスター間サービスルーティング設定(global service affinity)を有効にする必要があります。PROD クラスターで有効にするには、以下のコマンドを用います。
$ kubectl -n mysql-prod annotate svc prd-instances service.cilium.io/global=”true” –context=$CONTEXT1
$ kubectl -n mysql-prod annotate svc prd-instances service.cilium.io/global-sync-endpoint-slices=”true” –context=$CONTEXT1
$ kubectl -n mysql-prod annotate svc prd-instances service.cilium.io/shared=”true” –context=$CONTEXT1
次に、DR クラスターで実行されている MySQL ポッドでもクラスター間サービスルーティング設定を有効にするには、以下のコマンドを使用します。
$ kubectl -n mysql-dr annotate svc dr-instances service.cilium.io/global=”true” –context=$CONTEXT2
$ kubectl -n mysql-dr annotate svc dr-instances service.cilium.io/global-sync-endpoint-slices=”true” –context=$CONTEXT2
$ kubectl -n mysql-dr annotate svc dr-instances service.cilium.io/shared=”true” –context=$CONTEXT2
FQDN を用いて、PROD クラスターの MySQL ポッドから DR クラスターの MySQL ポッドへのログインをテストしてみましょう:
同様に、FQDN を用いて DR クラスターの MySQL ポッドから PROD クラスターの MySQL ポッドへのログインを試みます:
PROD と DR、双方のクラスターにある InnoDB Cluster は、InnoDB ClusterSet を設定するのに必要な FQDN を通じてリモートの Kubernetes クラスターからアクセスできます。これは、リモート FQDN トラフィックを NodePort として公開されているリモートの coreDNS に転送するために、coreDNS を編集したためです。
PROD クラスターでの InnoDB ClusterSet の設定
以下のコマンドを用いて、PROD クラスターに InnoDB ClusterSet を作成し、「mycs」と名付けます。
クラスター・メタデータの変更を適用するために、PROD クラスターで MySQL Router を再デプロイします:
PROD クラスターで InnoDB ClusterSet の状態を確認すると、メンバーとして表示される InnoDB Cluster は 1 つのみです。

DR クラスターから InnoDB ClusterSet へのレプリカクラスターの追加
まず、DR クラスターの既存の InnoDB Cluster を解散し、DR クラスターのプライマリノードをレプリカクラスターの最初のメンバーとして用いて、「myreplica」という名前のレプリカクラスターを作成します。
DR クラスターを解散します:
レプリカクラスターを作成します:
PROD クラスターで InnoDB ClusterSet の状態を確認すると、今度は ClusterSet には 2 つの InnoDB Cluster が確認できます。

続いて、PROD クラスターの Kubernetes シークレットに保存されているバックアップパスワード、クラスター管理者パスワード、およびルーターパスワードをエクスポートし、それらを DR クラスターに適用します。
PROD クラスターから InnoDB Cluster のユーザーパスワードをエクスポートします:
$ export clusterAdminPassword=`kubectl –context=$CONTEXT1 -n mysql-prod get secret prd-privsecrets -o json | jq -r ‘.data[“clusterAdminPassword”]’`
$ export backupPassword=`kubectl –context=$CONTEXT1 -n mysql-prod get secret prd-backup -o json | jq -r ‘.data[“backupPassword”]’`
InnoDB Cluster のユーザーパスワードを DR クラスターにインポートします:
$ kubectl –context=$CONTEXT2 -n mysql-dr get secret dr-privsecrets -o json | jq –arg x `echo $clusterAdminPassword` ‘.data[“clusterAdminPassword”]=$x’ | kubectl –context=$CONTEXT2 apply -f –
$ kubectl –context=$CONTEXT2 -n mysql-dr get secret dr-router -o json | jq –arg x `echo $routerPassword` ‘.data[“routerPassword”]=$x’ | kubectl –context=$CONTEXT2 apply -f –
第三に、DR クラスターのレプリカクラスターにすべてのセカンダリノードを戻します:
$ kubectl –context=$CONTEXT2 -n mysql-dr exec -it dr-0 — mysqlsh root:root@localhost:3306 — cluster add-instance root:root@dr-2.dr-instances.mysql-dr.svc.cluster.local:3306 –recoveryMethod=clone
クラスター・メタデータの変更を適用するために、DR クラスターで MySQL Router を再デプロイします:
まとめ
おめでとうございます!これで複数の Kubernetes クラスターにまたがる MySQL InnoDB ClusterSet が正常にデプロイされました。Cilium をデプロイすることで、2 つ以上の Kubernetes クラスターをシームレスに接続し、それらを同じ Kubernetes クラスターの一部であるかのように機能させられるようになりました。これにより、ある Kubernetes クラスターで実行されている InnoDB Cluster が、リモートの Kubernetes クラスターにある別の InnoDB Cluster を検出し、接続できるようになります。それにより、複数の Kubernetes クラスターにまたがる 2 つ以上の InnoDB Cluster 間で、データを複製するための InnoDB ClusterSet を設定できるようになりました。
(訳者註: 原記事は2025年3月10日に公開されました。)

