[Kubernetes] Prometheus MySQL Exporter インストール方法
Kubernetes (GKE) へ Prometheus の MySQL Exporter をインストールするための情報を記載します。この記事では以下を対象としています。
- Kubernetes クラスタは Google Kubernetes Engine (GKE)
- Workload Identity を用いて権限付与をセキュアにする
- Prometheus Community の Helm Chart を利用する
- Prometheus Operator を利用している
- 対象となる MySQL は GCP の Cloud SQL である
- Cloud SQL へのアクセスは Cloud SQL Proxy を利用している
上記の条件すべてに当てはまる必要はありませんが、条件が近いほうが役に立つと思います。
Prometheus Operator のインストールは以下の記事を参考にしてください。
この記事を読むことで以下の理解に役立つ可能性があります。
- MySQL Exporter の Helm CHart の設定カスタマイズ方法
- ServiceMonitor による MySQL Exporter の登録
続いて、Prometheus MySQL Exporter のインストール手順の詳細を記載します。
完成品のコンフィグ
GCP のプロジェクトは dummy-project-0123456
とします。
helmfile.yaml
repositories:
- name: prometheus-community
url: https://prometheus-community.github.io/helm-charts
releases:
- name: prometheus-mysql-exporter
namespace: observability
chart: prometheus-community/prometheus-mysql-exporter
values:
- ./values.yaml
values.yaml
serviceMonitor:
enabled: true
interval: 30s
namespace: observability
additionalLabels:
# Changes may be required depending on Prometheus Operator setup conditions
release: prometheus
jobLabel: ""
targetLabels: []
podTargetLabels: []
metricRelabelings: []
relabelings: []
serviceAccount:
create: true
name: prometheus-mysql-exporter
mysql:
existingSecret: "mysql-exporter-cloudsql-secret"
cloudsqlproxy:
enabled: true
image:
repo: "gcr.io/cloudsql-docker/gce-proxy"
tag: "1.33.0-alpine"
pullPolicy: "IfNotPresent"
# ConnectionName 要変更
instanceConnectionName: "dummy-project-0123456:asia-northeast1:mysql-cloudsql"
workloadIdentity:
enabled: true
serviceAccountEmail: "prometheus-mysql-exporter@dummy-project-0123456.iam.gserviceaccount.com"
Helm での構成管理をしやすくするために Helmfile を利用しています。
本記事作成の背景
Prometheus Operator を利用した Exporter のインストールをいくつか試していたところですが、MySQL Exporter の Helm Chart は思いの外インストールに時間がかかったので、悩んだところなどを記録することを目的としています。
チュートリアル的な step by step の記事構成にはなっていないため、ある程度の Prometheus Operator への理解がある方を対象としています。基礎的な内容は関連記事を作成していますので参考にしてください。
Kubernetes タグが設定されている本サイトの記事一覧
手順概要
- Workload Identity を利用するためのサービスアカウントを作成する
- MySQL サーバーに Exporter 用の参照ユーザーを作成する
- MySQL Exporter の設定をしてデプロイする
サービスアカウントの作成
サービスアカウントには Kubernetes Service Account と Google Service Account の2つの概念が登場します。違いについては以下の記事を参考にしてください。
カスタムロールの作成
ロールの定義を YAML ファイルで管理することができます。Git 管理を最大化するためにここではできるだけ YAML を利用するようにします。
カスタムロールの作成と管理 | IAM のドキュメント | Google Cloud
Google Service Account
サービスアカウント名は prometheus-mysql-exporter
とします。(正しくは values.yaml
ファイルの serviceAccount.name
にて設定している文字列と一致させてください)
gcloud iam service-accounts create prometheus-mysql-exporter \
--display-name prometheus-mysql-exporter
ロールの作成
vi role.yaml
ファイルを作成します。ここでは CloudSQL アクセスのための権限を2つ設定します。これによりシークレット情報(JSONキー)が不要になります。
title: Prometheus MySQL Expoter
description: Give permissions to the MySQL Exporter
stage: GA
includedPermissions:
- cloudsql.instances.connect
- cloudsql.instances.get
# 自身のGCPプロジェクトIDを取得する
PROJECT_ID=$(gcloud projects list --filter="$(gcloud config get-value project)" --format="value(PROJECT_ID)"); echo $PROJECT_ID
# ROLEのIDを任意の文字列で設定する
ROLE_ID=prometheusMySQLExporter; echo $ROLE_ID
# YAMLファイルを用いてロールを作成する
gcloud iam roles create $ROLE_ID \
--project=$PROJECT_ID \
--file=role.yaml
続いて、Google Service Account に ロールをマッピングします。
# 次の手順で利用するサービスアカウントの識別子(メールアドレス形式)を取得
SERVICE_ACCOUNT_EMAIL=$(gcloud iam --project=$PROJECT_ID service-accounts list --filter prometheus-mysql-exporter --format 'value([email])'); echo $SERVICE_ACCOUNT_EMAIL
# 作成したロールのID(完全文字列)を取得する
ROLE_FULL_ID=$(gcloud iam --project=$PROJECT_ID roles list --filter ${ROLE_ID} --format 'value([name])'); echo $ROLE_FULL_ID
# サービスアカウントとロールをマッピングする
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member serviceAccount:${SERVICE_ACCOUNT_EMAIL} \
--role $ROLE_FULL_ID
Workload Identity で使えるようにマッピング
上記までは GCP サービス内の概念での操作でしたが、ここで Kubernetes のサービスアカウントが登場します。この時点では MySQL Exporter の Chart をインストールしていないため、 Kubernetes 上のサービスアカウントは存在していませんが、ただの文字列なので先に作業をしてしまいます。
値は以下の通りとします。
- デプロイ先の名前空間 (Namespace) は
observability
とする - 作成する Kubernetes Service Account は
prometheus-mysql-exporter
とする
# 名前空間 と Kubernetes Service Account をスラッシュで連結した文字列を作成
MYSQL_EXPORTER_SA=observability/prometheus-mysql-exporter
#
gcloud iam service-accounts add-iam-policy-binding \\
--role roles/iam.workloadIdentityUser \\
--member "serviceAccount:${PROJECT_ID}.svc.id.goog[${MYSQL_EXPORTER_SA}]" \\
$SERVICE_ACCOUNT_EMAIL
これで、Google Service Account と Kubernetes Service Account の間の IAM バインディングを有効にできます。(Google Service Account に対して、 $PROJECT_ID.svc.id.goog[observation/prometheus-mysql-exporter]
形式のWorkload Identity 権限が設定されます)
roles/iam.workloadIdentityUser
の意味は以下の記事で説明しています。
[GKE] サービスアカウントとサービスアカウントを連携する - Workload Identity
MySQL ユーザーの作成
ユーザー作成は MySQL Exporter の GitHub の説明通りに作成します。
https://github.com/prometheus/mysqld_exporter
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'XXXXXXXX' WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
MySQL Exporter のデプロイ
記事の冒頭に記載した通り、YAMLファイルが2つあります。
helmfile.yaml
values.yaml
最初に完成品を記載しているのですが、コピペだけでは応用がきかないので、以下に説明を補足します。
MySQL ユーザー情報の与え方
重要なのは、最終的には環境変数 DATA_SOURCE_NAME
に何らかの方法で MySQLへの接続情報を与える必要があるということです。
そのための手段がいくつかあります。
values.yaml
に文字列を Plain Text で記載するenv:
から参照するためのkey
を与えるenvFrom:
から参照する形でDATA_SOURCE_NAME
の環境変数を直接与えてしまう
これらの振る舞いを実装しているのは、以下の template が該当します。
ドキュメントにはこれらの全体概要をつかむための情報が記載されておらず少々苦労しました。
- prometheus/mysqld_exporter: Exporter for MySQL server metrics
- helm-charts/charts/prometheus-mysql-exporter at main · prometheus-community/helm-charts
インストールが完了したあとに見つけたのですが、以下のサイトを最初に見ておけば、もう少し手早く作業ができたように思います。
参照サイト
MySQL Exporter - ExporterHub
The MySQL exporter is required to monitor MySQL metrics as databases are a critical resource with downtime causing significant financial and …
MySQL ユーザー情報の作成方法
いくつかの方法があることを説明しましたが、今回は envFrom:
から参照するための手順とします。
values.yaml
は Git で管理することを考えるとパスワードを記載したくないので却下、同様の理由で kind: Secret
リソースを作成するのも却下、そうなると残るのは kubectl
コマンドを用いて引数で Secret を作成することになります。
ここまでくると env
と envFrom
の違いは誤差ではないかと思いますが、個人的にはパスワード情報は特定の(安全な)場所に書き出しておき、そのファイルから Secret を生成する方法が好みです。
Managing Secrets using kubectl | Kubernetes
具体的には以下の通りです。
# SECRET_FILE は各自のワークスペースのセキュアな場所とする(暗号化されたディレクトリなど)
SECRET_FILE=$HOME/credentials/cloudsql/datasource.txt
# テキストファイルに接続情報を書き出す
echo -n 'username:password@(localhost:3306)/' > $SECRET_FILE
# テキストファイルの文字列から DATA_SOURCE_NAME を作成する
kubectl -n observability create secret generic mysql-exporter-cloudsql-secret --from-file=DATA_SOURCE_NAME=$SECRET_FILE
# DATA_SOURCE_NAME が期待した値になっているかを確認する
kubectl -n observability get secret mysql-exporter-cloudsql-secret -ojsonpath='{.data.DATA_SOURCE_NAME}' | base64 -d -
デプロイ
# デプロイされるリリースを確認する
helmfile diff
# デプロイする
helmfile apply
設定のカスタマイズ
設定可能な値は以下を参考にしてください。
Workload Identity の利用
Workload Identity の利用の有無は以下の設定が該当します。
cloudsqlproxy:
enabled: true
# ...
workloadIdentity:
enabled: true
serviceAccountEmail: "xxxx@xxxxx"
Workload Identity を利用しない場合は、CloudSQL の認証ファイルが必要になることが以下の template から読み取れます。
Kubernetes Service Account の作成
Kubernetes ServiceAccount の作成は以下の template で行われます。
workloadIdentity
の設定が有効であれば自動で作成される対象になっています。
ServiceAccount の名前は設定しなくても勝手に生成してくれるのですが、デフォルトだと長い文字列になってしまうので、最初に固定文字を決めておいたほうが Google Service Account の作成作業も効率的に行えるのでよいのではないかと思います。
まとめ
MySQL Exporter を Helm を利用してインストールしました。
インストール手順として最も単純なのは values.yaml
にパスワードを記載する方法ですが、セキュアな構成管理をするうえでは Workload Identity を利用は欠かせないでしょう。結果的にシークレットキーの管理が不要になり、シンプルな構成(デプロイするリソースの削減)が実現できました。
インストールが上手く行かない場合は認証情報の設定に失敗している可能性も考えられるので、ログを利用してひとつひとつ確認して解消していきましょう。
参考情報
いくつかのエラーの説明
msg=“Error parsing my.cnf” file=/home/.my.cnf err=“failed reading ini file: open /home/.my.cnf: no such file or directory”
ts=2022-11-23T08:35:25.987Z caller=mysqld_exporter.go:277 level=info msg="Starting mysqld_exporter" version="(version=0.14.0, branch=HEAD, revision=ca1b9af82a471c849c529eb8aadb1aac73e7b68c)"
ts=2022-11-23T08:35:25.987Z caller=mysqld_exporter.go:278 level=info msg="Build context" (gogo1.17.8,userroot@401d370ca42e,date20220304-16:25:15)=(MISSING)
ts=2022-11-23T08:35:25.988Z caller=mysqld_exporter.go:284 level=info msg="Error parsing my.cnf" file=/home/.my.cnf err="failed reading ini file: open /home/.my.cnf: no such file or directory"
.my.cnf
が登場し、最初は MySQL データベースサーバーの my.cnf かと思って混乱したが、MySQL Exporter における.my.cnf
とはDB接続情報を記載するためのファイルを指しているDATA_SOURCE_NAME
の書式が間違っていた時に遭遇。環境変数にDB接続情報が定義されていないときには.my.cnf
を利用する動きになると思われる
msg=“Error opening connection to database” err=“invalid DSN: missing the slash separating the database name”
prometheus-mysql-exporter-7fbf7bcfc6-cf7ch prometheus-mysql-exporter ts=2022-11-23T08:58:48.896Z caller=exporter.go:136 level=error msg="Error opening connection to database" err="invalid DSN: missing the slash separating the database name"
DATA_SOURCE_NAME
形式の文字列では最後にスラッシュを明示する必要がある
msg=“Error pinging mysqld” err=“Error 1102: Incorrect database name ‘\n’”
prometheus-mysql-exporter-7fbf7bcfc6-mk9wt prometheus-mysql-exporter ts=2022-11-23T09:01:57.634Z caller=exporter.go:149 level=error msg="Error pinging mysqld" err="Error 1102: Incorrect database name '\n'"
- 最終文字に改行が入っていないか注意すること。エディタによっては最後に改行が入ってし待っている可能性があるので、1行になっていることを確認すること
- https://github.com/prometheus/mysqld_exporter/issues/568