kubernetesでPython+MySQL8を使う時にハマった点！

# 概要
現在、ローカルにvue+djangoの開発環境をkubernetesで構築しようとしているのですが、
mysqlのコンテナを立てる際にハマったことがあったので、情報を共有します。

# MySQL8をPythonで使う場合について
MySQLをPythonで使う場合、パッケージに`mysqlclient`を選択することがあると思います。

ここでMySQL8で`mysqlclient`を使う場合に注意する点があります。
MySQL8.0.4以降、デフォルトの認証方式が変更され、`mysql_native_password`から`caching_sha2_password`になりました。しかし、`mysqlclient`はこの`caching_sha2_password`に対応していません。
そのため、以下のように、my.cnfを変更するか、もしくは`mysqld`の実行時に`--default-authentication-plugin=mysql_native_password`オプションをつけて、認証方式を`mysql_native_password`に戻す必要があります。

```:my.cnf
[mysqld]
default-authentication-plugin = mysql_native_password
```

```
mysqld --default-authentication-plugin=mysql_native_password
```

# kubernetesでMySQLをデプロイ
私は、docker-composeにてMySQL8系のコンテナを利用していたこともあり、その際にdocker-compose.ymlからコマンドを上書きして、後者のコマンドにオプションをつけて実行する方法で実行していたため、kubernetesでの実行時も同様の方法を選択しました。

一部抜粋した設定定義ファイルでは以下のように指定していました。

**注:ここではローカル環境用の設定定義のため、パスワード等をConfigMapで設定していますが、実際の運用ではSecretを推奨です**

```yaml:mysql-sts.yaml
...
    spec:
      containers:
      - name: mysql
        image: mysql:8.0.15
        # この部分
        command:
          - mysqld
          - --user=root --default-authentication-plugin=mysql_native_password
        env:
          - name: MYSQL_USER
            valueFrom:
              configMapKeyRef:
                name: mysql-cm
                key: MYSQL_USER
          - name: MYSQL_PASSWORD
            valueFrom:
              configMapKeyRef:
                name: mysql-cm
                key: MYSQL_PASSWORD
          - name: MYSQL_DATABASE
            valueFrom:
              configMapKeyRef:
                name: mysql-cm
                key: MYSQL_DATABASE
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
...
```

しかし、これを用いてリソースを作成するとなぜか初期化の段階でうまくいきません。
これはkubernetesのcommandの仕様が、少し特殊だったことが原因でした。

# kubernetesのcommandとENTRYPOINT
結論から言いますと、kubernetesのcommandは`CMD`だけではなく、`ENTRYPOINT`も上書きしてしまうことが問題点となっていました。
[kubernetes学習番外編 コンテナ起動時のコマンド実行 - そんな今日この頃の技術ネタ](https://blue1st-tech.hateblo.jp/entry/2017/08/06/073415)

このリソースでは公式のMySQLイメージを利用していますが、公式イメージはイメージ内でENTRYPOINTを利用して初期化をするスクリプトが走っています。
そのため、上記のようにkubernetesのcommandを利用してしまうと、`ENTRYPOINT`が上書きされてしまい、公式イメージによって自動化されていた初期化のプロセスを実行しなくてはいけないんですが、それをうまく実行できていなかったために、エラーとなっていたようです。

そのため、以下のようにmy.cnfを変更する方法で、認証方式を`mysql_native_password`に戻すことで、エラーを回避することができました。

```yaml:mysql-sts.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: django-mysql-cm
  labels:
    project: django-vue
    app: mysql
data:
  MYSQL_USER: timer
  MYSQL_PASSWORD: timer
  MYSQL_DATABASE: timer
  MYSQL_HOST: django-mysql-svc
  my.cnf: |-
    [mysqld]
    default-authentication-plugin = mysql_native_password
---
...
      containers:
      - name: mysql
        image: mysql:8.0.15
        env:
          - name: MYSQL_USER
            valueFrom:
              configMapKeyRef:
                name: django-mysql-cm
                key: MYSQL_USER
          - name: MYSQL_PASSWORD
            valueFrom:
              configMapKeyRef:
                name: django-mysql-cm
                key: MYSQL_PASSWORD
          - name: MYSQL_DATABASE
            valueFrom:
              configMapKeyRef:
                name: django-mysql-cm
                key: MYSQL_DATABASE
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: my-cnf
          mountPath: /etc/my.cnf
          subPath: my.cnf
          readOnly: true
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
      volumes:
      - name: my-cnf
        configMap:
          name: django-mysql-cm
          items:
          - key: my.cnf
            path: my.cnf
...
```

# あとがき
今回は思ってもみなかったkubernetesの仕様でかなりの時間対応させられることになってしまいました。
初期化で失敗している時点で、公式イメージの初期化処理が通ってないと気づくのが、もう少し早かったならばと悔やまれます。

現在まだ環境を構築中ですが、開発環境が完成したら、後日公開したいなと思っています。