ortの灰ログ

人狼のことや技術のことや日々雑感

自前で構築したkubernetesクラスタにmysql構築したメモ

この記事は

oritone.hatenablog.com

の続きで、
構築したkubernetesクラスタにとりあえずmysqlを構築した際のメモです。

やりたいこと

  • Oracle Cloud無料枠に構築したkubernetesクラスタmysqlを使えるようにする
  • workerで動作させる
  • podが作り直されてもデータが消えないよう永続化もする

永続化用の設定

こんな感じでPersistentVolumeとPersistentVolumeClaimの設定を書いて反映させる。
20GB確保、/data/mysql に永続化。

mysql-storage.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: db-pv
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /data/mysql
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
$ kubectl apply -f mysql-storage.yml

$ kubectl get pv,pvc

NAME                          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE
persistentvolume/db-pv   20Gi       RWO            Retain           Bound    default/db-pvc   manual                  10h

NAME                                STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/db-pvc   Bound    db-pv   20Gi       RWO            manual         10h

秘匿情報を先に反映

後で必要になるのでrootのパスワードとかをSecretに入れて反映しておく

パスワードにしたい文字をbase64

$ echo -n {パスワードにしたい文字列} | base64

Secretに入れて反映

mysql-secret.yml

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  root_password: aG9nZQ== #ここにbase64化した文字列を入れる
$ kubetcl apply -f mysql-secret.yml

worker nodeで動作させたいのでlabelをつけておく

まずnodeの名前を確認して

$ kubectl get nodes
NAME           STATUS   ROLES                  AGE     VERSION
vm-1   Ready    control-plane,master   3d22h   v1.21.1
vm-2   Ready    <none>                 3d21h   v1.21.1

key=valueで名前をつける。

kubectl label nodes vm-2 nodeName=worker

mysql構築

mysql公式のDocker imageを使う。
mysql 使えば余裕じゃんと思っていたのだが、
今回使用しているVM.Standard.A1.FlexのCPUはarmベースとなっており、
mysql のDocker imageは現状armに対応していないため動作しなかった。
どうやら、mysql-server は対応しているらしいので、そちらを使う。

設定

こんな感じでDeployment, Service, ConfigMap等を書いて反映。
mysql-serverは8.0にした。
my.cnfの設定はお好み。

mysql.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - image: mysql/mysql-server:8.0
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              # 先ほど設定したSecretから取得
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: root_password 
            - name: TZ
              value: Asia/Tokyo
          imagePullPolicy: Always
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: mysql
              mountPath: /var/lib/mysql
            - name: my-cnf
              mountPath: /etc/my.cnf
              subPath: my.cnf
              readOnly: true
      # 先ほど設定したlabelをnodeSelectorで指定する
      nodeSelector:
        nodeName: worker
      volumes:
        - name: mysql
          # 先ほど設定したPVCを指定する
          persistentVolumeClaim:
            claimName: db-pvc
        - name: my-cnf
          configMap:
            name: db-configmap
            items:
              - key: my.cnf
                path: my.cnf
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  selector:
    app: mysql
  type: NodePort
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
    # nodePort: 30000 # 手元のPC等から確認したい場合に設定(当然セキュリティは落ちる)
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: db-configmap
  labels:
    app: mysql
data:
  my.cnf: |-
    [mysqld]
    bind-address=0.0.0.0
    character-set-server=utf8mb4
    collation_server=utf8mb4_unicode_ci
    lower_case_table_names = 1
    transaction-isolation=READ-COMMITTED
    sql_mode = 'TRADITIONAL'
    skip-name-resolve=1
    default_authentication_plugin=mysql_native_password

    [client]
    default-character-set=utf8mb4
kubectl apply -f mysql.yml

containerの外から接続できるようにする

参考記事にも記載されているが、
mysql-serverの場合はこんな感じになっている(rootのhostがlocalhost)のでpodの中からしかDBに接続できない。

mysql> select user,host from mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| healthchecker    | localhost |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+

ので、一度podに入って外から接続できるユーザを作ってあげる必要がある。
(以下はrootを作る例)

$ kubectl get pods

NAME                       READY   STATUS    RESTARTS   AGE
mysql-658d66ff85-nz46j   1/1     Running   0          110m

$ kubectl exec --stdin --tty mysql-658d66ff85-nz46j -- /bin/bash

bash-4.4# mysql -uroot -p
create user root@'10.%';
grant all privileges on *.* to root@'10.%' with grant option;

確認

$ kubectl get services

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
mysql      NodePort    10.X.Y.Z   <none>        3306:30000/TCP   116m

worker側で

$ mysql -uroot -h 10.X.Y.Z

で接続できるところまで確認できた。 root以外でも同じ要領でやれば良さそう。
vmインスタンス外からもアクセスしたい場合は
ServiceのnodePort設定、vmインスタンスiptables穴あけ、OracleCloud上で同じく穴あけが必要なので注意。

(自分はなんとなくrootはpodの中でだけアクセス可能なままで良いやと思ったので消した)