この記事は Grafana Advent Calendar 2025 の 8 日目になります。
私は GMO GPUクラウドのサービス・インフラストラクチャの開発に従事しており、最近の仕事としては Grafana ダッシュボードを利用できる機能を開発、kubernetes 上にホストして統合しました。
概要
kubernetes 上で Grafana のバックエンドデータベースを InnoDB Cluster に指定してテストした時の備忘録です。
プロダクション想定である以上、各コンポーネントの冗長化は必須であり、Prometheus や TSDB の冗長化はさることながら、Grafana 自身の管理情報を保持するデータベースについても冗長化を検討することになります。
デフォルトでは組み込みの SQLite を使用することになりますが、MySQL Operator を用いた InnoDB Cluster バックエンドに使用できないかな?と思ったものの、意外と情報が無かったので情報を残します。
※なお、サポートされているデータベースでは MySQL 5.7+ は含まれているものの InnoDB Cluster の扱いは不明瞭です。この点はご了承ください。
MySQL Operator とは
MySQL 公式が提供している高可用性ソリューションである InnoDB Cluster を kubernetes 上にデプロイするための Operator です。
もし kubernetes 上に HA 化を実装するとなると Primary/Replica や LB の設計などが大変ですが、InnoDB Cluster という HA ソリューションを簡単にデプロイできるのが魅力です。
また、Operator をプロダクションで利用する場合は品質が気になるところですが、MySQL Operator は Oracle 社が開発を支援しており、定期的なメンテナンス・リリースもあることから、安心して選定しやすいと言えます。
構築手順
基本的には公式の Installation に沿って行きます。
前提
- kubernetes クラスタ
- StorageClass を用意する(今回は Ceph による
SCを作成)
1. MySQL Operator のデプロイ
CRD/Operator の yaml を入手し、apply します。
$ wget https://raw.githubusercontent.com/mysql/mysql-operator/refs/heads/trunk/deploy/deploy-crds.yaml
$ wget https://raw.githubusercontent.com/mysql/mysql-operator/refs/heads/trunk/deploy/deploy-operator.yaml
$ kubectl apply -f path/to/deploy-crds.yaml
$ kubectl apply -f path/to/deploy-operator.yaml
$ kubectl -n mysql-operator get po
NAME READY STATUS RESTARTS AGE
mysql-operator-59b79c9fb4-9qxrk 1/1 Running 0 2m14s
注意点
お使いのクラスタ CNI が Cillium の場合、MYSQL_OPERATOR_K8S_CLUSTER_DOMAIN 変数にクラスタドメインを設定してください。
$ vim deploy-operator.yaml
...
env:
- name: MYSQLSH_USER_CONFIG_HOME
value: /mysqlsh
- name: MYSQLSH_CREDENTIAL_STORE_SAVE_PASSWORDS
value: never
- name: MYSQL_OPERATOR_K8S_CLUSTER_DOMAIN <<<
value: cluster.local <<<
...
2. InnoDB Cluster のデプロイ
デプロイ用の Namespace を作成し、Secret Deployment を設定していきます。
$ kubectl create ns monitoring
$ vim secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: mycluster-sec
namespace: monitoring # NameSpace 名指定
stringData:
rootUser: root
rootHost: '%'
rootPassword: 'p@ssword!'
$ vim deploy.yaml
---
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: mysql # 名称変更
namespace: monitoring # NameSpace 名指定
spec:
secretName: mycluster-sec # Secret 名指定
baseServerId: 100
tlsUseSelfSigned: true
instances: 2
router:
instances: 1
datadirVolumeClaimTemplate:
resources:
requests:
storage: 2Gi
storageClassName: my-sc # StorageClass 指定
デプロイし、すべての Pod が動作することを確認します。
$ kubectl apply -f secret.yaml
$ kubectl apply -f deploy.yaml
$ kubectl -n monitoring get po
NAME READY STATUS RESTARTS AGE
mysql-0 2/2 Running 0 2m10s
mysql-1 2/2 Running 0 2m9s
mysql-router-8674dcd4f5-lcn8c 1/1 Running 0 14s
念のためテスト用のコンテナからアクセスを確認しておきます。
$ kubectl run mysql-client --rm -it --image=mysql:8 --restart=Never -- bash
...
bash-5.1# mysql -h mysql.monitoring.svc.cluster.local -u root -p
Enter password: <<< 'p@ssword!'
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 9.4.0 |
+-----------+
1 row in set (0.00 sec)
3. Grafana のデプロイ
InnoDB Cluster に Grafana 用のデータベースを作成しておきます。
$ mysql -h "${MYSQL_HOST}" -uroot -p"${MYSQL_ROOT_PASSWORD}" -e "
CREATE DATABASE IF NOT EXISTS grafana CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'grafana'@'%' IDENTIFIED BY 'p@ssw0rd!';
GRANT ALL PRIVILEGES ON grafana.* TO 'grafana'@'%';
FLUSH PRIVILEGES;
"
続けて Grafana の Deploy を行いますが、ここでは grafana:latest を pull して StatefulSet を実装します。ポイントとして、Grafana の DB 参照先を作成した InnoDB Cluster の grafana データベースに向けます。
...
containers:
- name: grafana
image: grafana/grafana:latest
imagePullPolicy: Always
env:
- name: GF_DATABASE_TYPE
value: "mysql"
- name: GF_DATABASE_HOST
value: "mysql:3306" # 作成した InnoDB Cluster の SVC
- name: GF_DATABASE_NAME
value: "grafana"
- name: GF_DATABASE_USER # grafana データベースユーザ
valueFrom:
secretKeyRef:
name: grafana-secret
key: db-user
- name: GF_DATABASE_PASSWORD # grafana データベースのパスワードの Secret
valueFrom:
secretKeyRef:
name: grafana-secret
key: db-password
...
正常に Pod が起動すれば OK です。
$ kubectl -n monitoring get po
NAME READY STATUS RESTARTS AGE
grafana-0 1/1 Running 0 1d
grafana-1 1/1 Running 0 1d
mysql-0 2/2 Running 0 1d
mysql-1 2/2 Running 0 1d
mysql-router-8674dcd4f5-lcn8c 1/1 Running 0 1d
Known Issue
InnoDB Cluster をバックエンドに指定すると、なぜか Grafana Pod が正常に起動してくれません。
Error: ✗ migration failed (id = copy alert_rule_tag v1 to v2): Error 3098 (HY000): The table does not comply with the requirements by an external plugin. とのことで、どうやら Grafana -> InnoDB Cluster の接続がうまくいっていないようです。
logger=migrator t=****-**-**T**:**:**.*********Z level=error msg="Executing migration failed" id="copy alert_rule_tag v1 to v2" error="Error 3098 (HY000): The table does not comply with the requirements by an external plugin." duration=1.468343ms
logger=migrator t=****-**-**T**:**:**.*********Z level=error msg="Exec failed" error="Error 3098 (HY000): The table does not comply with the requirements by an external plugin." sql="INSERT INTO `alert_rule_tag` (`tag_id`\n, `alert_id`) SELECT `tag_id`\n, `alert_id` FROM `alert_rule_tag_v1`"
logger=migrator t=****-**-**T**:**:**.********* level=info msg="Unlocking database"
Error: ✗ migration failed (id = copy alert_rule_tag v1 to v2): Error 3098 (HY000): The table does not comply with the requirements by an external plugin.
色々調べると同様の問題があるようで、Grafana が使用する alert_rule_tag_v1 テーブルに PRIMARY_KEY が無いので、InnoDB Cluster 側に怒られる(?)ようですね。。。
mysql> SHOW INDEX FROM alert_rule_tag_v1 WHERE Key_name = 'PRIMARY';
Empty set (0.01 sec)
仕方がないので DB に入ってプライマリキーを設定します。
mysql> use grafana;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> alter table alert_rule_tag_v1
-> add constraint alert_tag_v1_pk
-> primary key (tag_id, alert_id);
Query OK, 0 rows affected (0.28 sec)
しばらくするとマイグレートが進むようになりますが、別のテーブル(annotation_tag_v2)で同様のエラーになるので再度プライマリキーを手動付与します。
mysql> use grafana;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
mysql> alter table annotation_tag_v2
-> add constraint annotation_tag_v2_pk
-> primary key (tag_id, annotation_id);
Query OK, 0 rows affected (0.26 sec)
まとめ
一部すんなりいかない部分もあり難航しましたが、Grafana と InnoDB Cluster を組み合わせて動作させることに成功しました。
kubernetes 上で使用する場合は作りやすく、冗長化も Operator に任せられることから運用性も高いと思いますので、是非参考にしていただければ幸いです。