MySQL の管理用 GUI ツール Adminer を Kubernetes に設置

MySQL データベースの中身を確認するにあたって、ちょっとした簡単な操作ならば CLI で済ませてしまいますが、いろいろなパターンで操作したい場合には GUI の管理画面を使いたくなります。

phpMyAdmin や Adminer といったツールがあり、目的に対してはどちらでも構わないと思いますが、ここでは Adminer をさっさとセットアップして利用する手順(カンペ)を記載します。

以下の3パターンを説明します。

  1. Adminer だけを Kubernetes 上にデプロイする場合
  2. Adminer を GCP の CloudSQL で使う前提で Kubernetes へデプロイする場合
  3. 【参考】ローカルでの確認用に Docker Compose で起動する場合

Kubernetes デプロイの方針

通常 Kubernetes 上に何かをデプロイしてサービスとして利用可能にするためには Deployment (Pod)、Service、および Ingress あたりを構築することになります。

しかし MySQL 管理画面という性質上、セキュリティ的にはこれらサービスは一般公開したくないので何かしらのアクセス制限をかけるべきでしょう。そうなると、IPアドレスでの制限あるいは認証による制限などを準備するわけですが、IPアドレスが変わったり、パスワードの記録といった面倒くさい運用が発生してしまいます。

となると、一番手っ取り早いのは一般公開しなければいいわけですね。

そこで、「デプロイするのは Pod のみとし、使いたい時に Pod に対して Port-forward して接続する」という運用で済ませることにします。この手法だと kubectl を使えることが前提になるので大人数向けではありませんが、利用者がエンジニアあるいは個人に限られる場合にはセキュリティリスクおよび運用負担を最小限に抑えられます。

ポートフォワードに関するドキュメントはこちら

Use Port Forwarding to Access Applications in a Cluster | Kubernetes ― https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/#forward-a-local-port-to-a-port-on-the-pod

Adminer だけをデプロイする場合

変数も必要ありませんし、非常に楽です。接続先DBの指定は Web 画面上から行えますので、ネットワークの到達性があれば任意の場所に接続可能です。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: adminer
  namespace: my-namespace
spec:
  replicas: 1
  selector:
    matchLabels:
      app: adminer
  template:
    metadata:
      labels:
        app: adminer
    spec:
      containers:
        # CONTAINER: 1
        - name: app
          image: adminer
          ports:
            - containerPort: 8080

Adminer から CloudSQL を使う構成でデプロイする場合

参考に CloudSQL に接続するための SQL Proxy を使った構成も記載します。

変数の準備

  • CLOUDSQL_INSTANCE_NAME
    • SQL Proxy の command で指定している -instances=$(CLOUDSQL_INSTANCE_NAME) のために環境変数を設定します。
    • コンフィグを Git で共有することを前提に固有値を外部化していますが、コマンド内に値をベタ書きするのでも構いません。その場合は環境変数の準備を省略可能です。
    • もちろん ConfigMap あるいは Secret のマニフェストを用意して設定するでも構いません。

さて、環境変数をセットします。

eval "kubectl -n my-namespace create secret generic cloudsql-credentials --from-literal=CLOUDSQL_INSTANCE_NAME=project-name-012345:us-region:mysql-instance=tcp:3306"

ちょっと分解すると、やっていることは以下の通り

  • kubectl -n my-namespace
    • namespace を指定している
  • create secret generic cloudsql-instance-secrets
    • cloudsql-credentials という名前で Secret (秘匿パラメタ)を作成している
  • --from-literal=CLOUDSQL_INSTANCE_NAME=project-name-012345:us-region:mysql-instance=tcp:3306"
    • 今回はコマンドからベタで作成してしまうので、 --from-literal を利用して環境変数を key=value で指定
    • project-name-012345:us-region:mysql-instance=tcp:3306 の部分は、コロン区切りで以下の要素に分解されています。GCP 上の Cloud SQL のダッシュボードにて「接続名」としてコピペ可能になっているはずなのでその値をそのまま当てはめてください
      • GCPプロジェクト名
      • リージョン
      • CloudSQL インスタンス名
      • ポート番号

Deployment の準備

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: adminer
  namespace: my-namespace
spec:
  replicas: 1
  selector:
    matchLabels:
      app: adminer
  template:
    metadata:
      labels:
        app: adminer
    spec:
      containers:
        # CONTAINER: 1
        - name: app
          image: adminer
          ports:
            - containerPort: 8080

        # CONTAINER: 2
        - name: cloudsql
          image: gcr.io/cloudsql-docker/gce-proxy:1.28.1
          imagePullPolicy: IfNotPresent
          command:
            - "/cloud_sql_proxy"
            - "-instances=$(CLOUDSQL_INSTANCE_NAME)"
            - "-credential_file=/credentials/credentials.json"
          securityContext:
            runAsUser: 2 # non-root user
            allowPrivilegeEscalation: false
          envFrom:
            - secretRef:
                name: cloudsql-instance-secrets
          volumeMounts:
            - mountPath: /cloudsql
              name: cloudsql
            - mountPath: /credentials
              name: cloudsql-credentials

      volumes:
        - name: cloudsql
          emptyDir: {}
        - name: cloudsql-credentials
          secret:
            secretName: cloudsql-credentials

CloudSQL Proxy の最新バージョンは以下にて確認してください。

GoogleCloudPlatform/cloudsql-proxy: Cloud SQL proxy client and Go library ― https://github.com/GoogleCloudPlatform/cloudsql-proxy

Port forward での接続方法

ここまで、Kubernetes へのデプロイ方法を2種類説明しました。いずれも Deployment しか利用していませんので、 Pod だけが立ち上がっている状況です。Pod は次のコマンドで確認してみましょう。

kubectl -n my-namespace get pod

---
NAME                       READY   STATUS    RESTARTS   AGE
adminer-79fa8edc8c-6pa7e   2/2     Running   0          1d15h

Pod が見えたらその名前を控えます。( adminer-7xxxxx-6xxxx

# Podの名前を入れること
kubectl -n my-namespace port-forward adminer-7xxxxx-6xxxx 8080:8080


Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

このように Forwarding 状態になれば、あとはブラウザで http://localhost:8080 に接続できるはずです。

ローカルで確認する場合(Docker Compose)

  • Docker で MySQL を起動する
  • その MySQL に対して Adminer で接続して操作したい

これらを実現する構成( docker-compose.yml )は以下の通り。お手軽すぎるので新規に MySQL を利用するプロジェクトはとりあえずコピペで開始できます。

version: "3.3"
services:
  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    volumes:
      - "./tmp/volumes/mysql:/var/lib/mysql"
    environment:
      MYSQL_ROOT_PASSWORD: password

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    depends_on:
      - mysql
  • version を 3.3 としていますが絶対的な理由があるものではありません。適用可能なバージョンは以下のURLを参考にしてください。ただ、この程度の構成であればルーズでも問題ないかと。
  • この例では docker-compose.yml ファイルが配置されている場所の tmp/ ディレクトリにMySQLデータベースのファイル群を配置しています。試して気に入らなければ tmp/volumes を削除すれば改めて再セットアップできるのでお手軽です。

まとめ

MySQL の Web GUI 管理ツールである Adminer をセットアップする方法を3例記載しました。

効率がいいときは素直に GUI を使うといいなと改めて感じました。