MySQLの高可用性ツールである Orchestratorは、これまでGitHub本家リポジトリはアーカイブ状態となっており、Percona版フォークでは、Percona製品のPercona Operatorなどに組み込む形で保守・活用が続けられていました。
しかし、2026年4月に ProxySQLから発表があり、ProxySQLがOrchestratorを正式に引き継ぎ、今後の保守・開発を担うことになりました。
Announcing the future of Orchestrator: ProxySQL takes takes the helm — ProxySQL Blog
既にGitHubにリポジトリも確認でき、利用できる段階にあります。
すなわち、ここまでの開発体制を表にまとめると以下の通りとなります。
|
開発元 |
リポジトリ |
開発状態 |
|---|---|---|
|
openark |
× アーカイブ済み |
|
|
Percona |
△ Percona Operator用に限りメンテナンス下 |
|
|
ProxySQL |
〇 メンテナンス下 |
ProxySQLが引き継ぐことで、データベースプロキシ製品としてのProxySQLとの機能連携の強化も期待されています。
目玉機能の紹介
ProxySQL発表のブログ記事では、主に以下の3点が挙げられています。
-
ProxySQLネイティブ連携
-
Kubernetes/クラウドネイティブ対応
-
PostgreSQL ストリーミングレプリケーション対応
ProxySQLネイティブ連携
MySQLユーザーにとって特に注目したいのが、ProxySQLとのネイティブ連携機能です。従来はフェイルオーバー後にProxySQLのHostgroupを書き換えるため、PostFailoverProcessesにスクリプトを独自に実装するケースが一般的でした。
一方、ProxySQL版Orchestratorバージョンv4.30.0からは、Orchestrator側の設定ファイルに項目を追加するだけでProxySQLとの連携が可能となり、フェイルオーバー時にHostgroupが自動更新されるようになりました。
これにより、
-
自作スクリプトが不要
-
保守コスト削減
-
人為的な設定ミス防止
が期待できます。
Kubernetes/クラウドネイティブ対応
追加されたKubernetes用エンドポイント
-
/health/live -
/health/ready -
/health/leader
は、KubernetesのLiveness ProbeやReadiness Probeに利用できるAPIであり、クラウドネイティブ環境で運用しやすくなっています。
PostgreSQL ストリーミングレプリケーション対応
本ブログ記事では扱いませんが、PostgreSQLユーザーにとっては、HA製品の選択肢が増える、非常に大きなトピックになるはずです。
検証環境
早速Orchestrator v4.30を使用して、実機検証をやってみました。
Kubernetes上に以下のリソースをデプロイしました。
|
ソフトウェア |
台数 |
バージョン |
|---|---|---|
|
ProxySQL |
2台の冗長構成 |
3.0.7-debian |
|
Orchestrator |
3台のRaft構成 |
v4.30.2 |
|
MySQL |
Source1台、Replica2台のレプリケーション構成 |
8.4.6-6.1 |
検証のために、手軽に簡単にKubernetes上にProxySQL版Orchestratorを構築するHelmチャートを探しましたが見当たりませんでしたので、代替案として、以下を用いて構築しています。
-
Percona Operator for MySQL Serverを使用して、OrchestratorのimageをProxySQL版に差し替えました。
-
ProxySQLの公式Helmチャートは、6年前(2020年)からGitHubにコミットが見られず長期放置の状態でした。大部分は拝借しつつ、imageのバージョンを最新版に差し替えるなどの対策を行いました。
尚、本ブログ記事ではPercona Operatorのインストール手順は簡易的なものに留まります。 具体的なステップバイステップについては公式マニュアルや、前回の記事「KubernetesでMySQL自動フェイルオーバーを検証する(Percona Operator+Orchestrator)」を参照していただけますと幸いです。
Orchestratorイメージのビルド
ここはあまり重要ではないので、説明は簡易的なものに留まります。
Dockerイメージをビルドします。
|
1 2 3 |
git clone https://github.com/ProxySQL/orchestrator.git cd orchestrator ./script/dock hub |
作成されたDockerイメージを確認します。
|
1 2 3 |
$ docker images openarkcode/orchestrator:v4.30.2 IMAGE ID DISK USAGE CONTENT SIZE EXTRA openarkcode/orchestrator:v4.30.2 0e2c5a7a756f 71.9MB 23.6MB |
これをコンテナレジストリにプッシュして使います。
今回はOCI環境で検証しているため、OCIRを指定します。リージョンや個別の値は適宜読み替えてください。
|
1 2 3 |
docker login -u '<your_namespace>/<your_email>' nrt.ocir.io docker tag openarkcode/orchestrator:v4.30.2 nrt.ocir.io/<your_namespace>/openarkcode/orchestrator:v4.30.2 docker push nrt.ocir.io/<your_namespace>/openarkcode/orchestrator:v4.30.2 |
docker-registry Secretを作成します。
|
1 2 3 4 5 |
kubectl create secret docker-registry ocir-secret \ --docker-server=nrt.ocir.io \ --docker-username='<your_namespace>/<your_email>' \ --docker-password='<your_password>' \ --docker-email='<your_email>' |
Helmチャートのvalues.yamlのimagePullSecretsにSecret名を指定します。
|
1 2 3 4 5 6 7 8 |
orchestrator: enabled: true image: repository: nrt.ocir.io/<your_namespace>/openarkcode/orchestrator tag: v4.30.2 imagePullPolicy: IfNotPresent imagePullSecrets: - name: ocir-secret |
ProxySQLネイティブ連携のための設定
Orchestrator側
特に重要な設定は、ProxySQLネイティブ連携のためのパラメータをOrchestratorの設定ファイルに追加することです。
ユーザーマニュアルの設定例を参考に、以下を追記します。 https://github.com/ProxySQL/orchestrator/blob/master/docs/user-manual.md#setting-up-proxysql-hooks
orchestrator.conf.json
|
1 2 3 4 5 6 7 8 9 |
{ "ProxySQLAdminAddress": "proxysql", "ProxySQLAdminPort": 6032, "ProxySQLAdminUser": "radmin", "ProxySQLAdminPassword": "radmin", "ProxySQLWriterHostgroup": 10, "ProxySQLReaderHostgroup": 20, "ProxySQLPreFailoverAction": "offline_soft" } |
上記設定をConfigMapに保存し、OrchestratorのPodでマウントするように指定してあります。
ConfigMap
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
apiVersion: v1 data: orchestrator.conf.json: | { "RaftEnabledSingleNode":false, "RaftNodes":["my-db-ps-db-orc-0.percona.svc:10008","my-db-ps-db-orc-1.percona.svc:10008","my-db-ps-db-orc-2.percona.svc:10008"], "ProxySQLAdminAddress": "proxysql", "ProxySQLAdminPort": 6032, "ProxySQLAdminUser": "radmin", "ProxySQLAdminPassword": "radmin", "ProxySQLWriterHostgroup": 10, "ProxySQLReaderHostgroup": 20, "ProxySQLPreFailoverAction": "offline_soft" } kind: ConfigMap |
OrchestratorのPod側
|
1 2 3 4 5 6 7 8 9 |
volumeMounts: - mountPath: /etc/orchestrator/custom name: custom ... volumes: - configMap: defaultMode: 420 name: my-db-ps-db-orc name: custom |
Hostgroup
ProxySQLでは接続先サーバをHostgroupという単位で管理します。 Writer hostgroupは書き込み対象、Reader hostgroupは読み取り対象として利用され、フェイルオーバー時にはWriter hostgroupのメンバーが入れ替わるのが基本です。
今回の構成で、以下の固定値を指定しています。
-
WriterHostgroup:10
-
ReaderHostgroup:20
マニュアルに記載のあるように、WriterHostgroupは1以上である必要があります。
Writer hostgroup ID. Must be > 0 to enable hooks.
Writer HostgroupにはSourceのみが登録され、Reader HostgroupにはSourceとReplicaの両方が登録されます。
AdminUser
ProxySQLのadminはローカル接続前提の構成で使われることが多いため、Podを跨ぐ Orchestratorからの接続では利用できません。そのため、外部からのリモート接続を想定したradminを用意し、OrchestratorからはこのアカウントでProxySQL管理APIにアクセスするようにしています。
ProxySQL側でradminユーザは以下のように定義してあります proxysql.cnf
|
1 2 3 4 5 |
admin_variables= { admin_credentials="admin:admin;radmin:radmin" mysql_ifaces="0.0.0.0:6032" } |
ProxySQL側
OrchestratorとProxySQLの設定ファイルで Writer hostgroupとReader hostgroupの数値が合うようにProxySQL設定ファイルを構成します。
file/proxysql.cnf
|
1 2 3 4 5 6 7 8 9 10 |
... mysql_replication_hostgroups= ( { writer_hostgroup=10 reader_hostgroup=20 comment="RHG1" } ) |
上記設定をConfigMapに保存し、ProxySQLのPodでマウントするように指定してあります。
|
1 2 3 4 5 6 7 8 9 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-proxysqlcm data: proxysql.cnf: | {{ tpl (.Files.Get "files/proxysql.cnf") . | indent 4 }} probe-proxysql.bash: | {{ tpl (.Files.Get "files/probe-proxysql.bash") . | indent 4 }} |
|
1 2 3 4 5 6 7 8 9 10 |
volumeMounts: - mountPath: /etc/proxysql.cnf name: proxysql-config subPath: proxysql.cnf ... volumes: - configMap: defaultMode: 420 name: proxysql-proxysqlcm name: proxysql-config |
proxysqlのServiceにradmin用の6032ポートを追加する。
|
1 2 3 4 5 |
ports: - name: radmin port: 6032 protocol: TCP targetPort: 6032 |
Hostgroupの確認方法
ここまで設定が完了したら、ProxySQLのAPIを実際に叩いて、トポロジーの状態を確認してみます。 /api/proxysql/serversでは、現在Orchestratorが認識しているProxySQL上のHostgroup構成を取得できます。
|
1 2 |
kubectl exec -it my-db-ps-db-orc-0 \ -- sh -c 'curl -sS http://localhost:3000/api/proxysql/servers | jq' |
結果例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
{ "Code": "OK", "Message": "Found 4 servers", "Details": [ { "hostgroup_id": 10, "hostname": "my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona.svc.cluster.local", "port": 3306, "status": "ONLINE", "weight": 1, "max_connections": 5000, "comment": "" }, { "hostgroup_id": 20, "hostname": "my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona.svc.cluster.local", "port": 3306, "status": "ONLINE", "weight": 1, "max_connections": 5000, "comment": "" }, { "hostgroup_id": 20, "hostname": "my-db-ps-db-mysql-1.my-db-ps-db-mysql.percona.svc.cluster.local", "port": 3306, "status": "ONLINE", "weight": 1, "max_connections": 5000, "comment": "" }, { "hostgroup_id": 20, "hostname": "my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona.svc.cluster.local", "port": 3306, "status": "ONLINE", "weight": 1, "max_connections": 5000, "comment": "" } ] } |
mysql-0 Podのhostgroup_idが10なのでWriterであることが確認できます。
新しいヘルスチェック用エンドポイントの指定
-
/health/live:LivenessProbe用のエンドポイント -
/health/ready:ReadinessProbe用のエンドポイント -
/health/leader:現在のPodがRaftリーダーかどうかを確認するためのエンドポイント
OrchestratorのPodに新しいエンドポイントでのヘルスチェックを行うように設定しました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
livenessProbe: failureThreshold: 3 httpGet: path: /health/live port: 3000 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3 readinessProbe: failureThreshold: 3 httpGet: path: /health/ready port: 3000 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3 |
/health/leaderエンドポイントについては、APIを直打ちした結果例を以下に示しておきます。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# Raftリーダー $ kubectl exec -it my-db-ps-db-orc-0 -- curl http://localhost:3000/health/leader Defaulted container "orchestrator" out of: orchestrator, mysql-monit, orchestrator-init (init) {"status":"leader"} # Raftフォロワー $ kubectl exec -it my-db-ps-db-orc-2 -- curl http://localhost:3000/health/leader Defaulted container "orchestrator" out of: orchestrator, mysql-monit, orchestrator-init (init) {"status":"not leader"} $ kubectl exec -it my-db-ps-db-orc-1 -- curl http://localhost:3000/health/leader Defaulted container "orchestrator" out of: orchestrator, mysql-monit, orchestrator-init (init) {"status":"not leader"} |
現在のトポロジーを確認する(初期状態)
ここからは、フェイルオーバー挙動を確認します。 フェイルオーバー前後でHostgroupの割り当てがどのように変化するかを確認してみましょう。
観察ポイント
-
Orchestratorで SourceとReplicaの関係が正しく表示されているか
-
ProxySQLの
/api/proxysql/serversでWriter=10 / Reader=20が正しく割り当てられているか -
特にWriter hostgroupにSourceが1台だけ入っているかが重要
実行例
ProxySQLの/api/proxysql/serversから確認しても良いのですが、JSON形式より、表形式の方が少し視認性が良いので、直接ProxySQLのPodからSQLを実行して確認しました。
|
1 2 3 4 5 6 7 8 9 10 |
$ export PROXYSQL_POD=$(kubectl get po -l app.kubernetes.io/instance=proxysql -ojsonpath="{.items[0].metadata.name}") $ kubectl exec -it $PROXYSQL_POD -- mysql -h127.0.0.1 -uadmin -padmin -P6032 -e"select hostgroup_id, hostname, status from runtime_mysql_servers" +--------------+-----------------------------------------------------------------+--------+ | hostgroup_id | hostname | status | +--------------+-----------------------------------------------------------------+--------+ | 10 | my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-1.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | +--------------+-----------------------------------------------------------------+--------+ |
OrchestratorのPodから確認
|
1 2 3 4 5 |
$ kubectl exec -it my-db-ps-db-orc-0 -- orchestrator-client -c topology -i my-db-ps-db.percona Defaulted container "orchestrator" out of: orchestrator, mysql-monit, orchestrator-init (init) my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona:3306 (my-db-ps-db-mysql-2) [0s,ok,8.4.6-6,rw,ROW,>>,GTID] + my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona:3306 (my-db-ps-db-mysql-0) [0s,ok,8.4.6-6,ro,ROW,>>,GTID] + my-db-ps-db-mysql-1.my-db-ps-db-mysql.percona:3306 (my-db-ps-db-mysql-1) [0s,ok,8.4.6-6,ro,ROW,>>,GTID] |
期待される状態
-
ProxySQL側
-
mysql-0が hostgroup_id=10(Writer) -
mysql-0,mysql-1,mysql-2が hostgroup_id=20(Reader)
-
-
Orchestrator側
-
mysql-0が Source(rw) -
mysql-1,mysql-2が Replica(ro)
-
Sourceを強制ダウンさせる(フェイルオーバー発火)
方法例
SourceのPodを削除
|
1 |
kubectl delete pod my-db-ps-db-mysql-0 |
フェイルオーバー後のトポロジー変動を確認する
観察ポイント
-
Orchestratorで新しいSourceが正しく昇格しているか
-
ProxySQLのWriter hostgroupが新Sourceに切り替わっているか
-
Reader hostgroupが自動的に再構成されているか
実行例
ProxySQLのPodから確認する
|
1 2 3 4 5 6 7 8 9 |
$ kubectl exec -it $PROXYSQL_POD -- mysql -h127.0.0.1 -uadmin -padmin -P6032 -e"select hostgroup_id, hostname, status from runtime_mysql_servers" +--------------+-----------------------------------------------------------------+---------+ | hostgroup_id | hostname | status | +--------------+-----------------------------------------------------------------+---------+ | 10 | my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona.svc.cluster.local | SHUNNED | | 20 | my-db-ps-db-mysql-1.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | +--------------+-----------------------------------------------------------------+---------+ |
OrchestratorのPodから確認する
|
1 2 3 4 5 |
$ kubectl exec -it my-db-ps-db-orc-0 -- orchestrator-client -c topology -i my-db-ps-db.percona Defaulted container "orchestrator" out of: orchestrator, mysql-monit, orchestrator-init (init) my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona:3306 (my-db-ps-db-mysql-2) [0s,ok,8.4.6-6,rw,ROW,>>,GTID] + my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona:3306 (my-db-ps-db-mysql-0) [0s,ok,8.4.6-6,ro,ROW,>>,GTID] + my-db-ps-db-mysql-1.my-db-ps-db-mysql.percona:3306 (my-db-ps-db-mysql-1) [0s,ok,8.4.6-6,ro,ROW,>>,GTID] |
期待される状態
-
ProxySQL側
-
旧Source(
mysql-0)のstatusがSHUNNEDになり、hostgroupから除外される -
新Source(例:
mysql-2)がhostgroup_id=10に入る -
残りReplicaがhostgroup_id=20のまま
-
-
Orchestrator側
-
旧Source(
mysql-0)は Replica(ro)に入る -
新Source(例:
mysql-2)がrwになる -
残りReplicaはroのまま
-
本検証環境では旧SourceはReplicaとして再参加しました。
なお、この挙動はPercona OperatorやMySQLレプリケーション構成、再参加設定などによって異なる場合があります。
旧Source が復帰したときの挙動(リカバリ)
観察ポイント
-
ProxySQLのhostgroup に自動で戻るか
実行例
SHUNNEDから復帰させる
|
1 |
kubectl exec -it $PROXYSQL_POD -- mysql -uadmin -padmin -h127.0.0.1 -P6032 |
|
1 |
LOAD MYSQL SERVERS TO RUNTIME; |
ProxySQLのPodから確認する
|
1 2 3 4 5 6 7 8 9 |
$ kubectl exec -it $PROXYSQL_POD -- mysql -h127.0.0.1 -uadmin -padmin -P6032 -e"select hostgroup_id, hostname, status from runtime_mysql_servers" +--------------+-----------------------------------------------------------------+---------+ | hostgroup_id | hostname | status | +--------------+-----------------------------------------------------------------+---------+ | 10 | my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-0.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-1.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | | 20 | my-db-ps-db-mysql-2.my-db-ps-db-mysql.percona.svc.cluster.local | ONLINE | +--------------+-----------------------------------------------------------------+---------+ |
期待される状態
-
SHUNNEDがONLINEに戻る
-
他はそのまま
まとめ
今回の検証で特に大きいと感じたのは、フェイルオーバー時の後処理がシンプルになった点です。 ProxySQLネイティブ連携により従来必要だったPostFailoverProcessesのカスタム自作スクリプトを利用せず、Hostgroupが自動更新されることを確認できました。
設定も数項目追加するだけで済み、運用負荷を大きく下げられる点は大きなメリットと言えます。
一方で、Helmチャートの整備状況やOperatorとの組み合わせなど、導入時に考慮すべき点も残っています。
今後、クラウドネイティブ環境での利用が進めば、MySQL高可用性構成における有力な選択肢の一つになる可能性があります。


