Python
MySQL
Python3
kubernetes
MySQL8.0

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を推奨です


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学習番外編 コンテナ起動時のコマンド実行 - そんな今日この頃の技術ネタ

このリソースでは公式のMySQLイメージを利用していますが、公式イメージはイメージ内でENTRYPOINTを利用して初期化をするスクリプトが走っています。

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

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


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の仕様でかなりの時間対応させられることになってしまいました。

初期化で失敗している時点で、公式イメージの初期化処理が通ってないと気づくのが、もう少し早かったならばと悔やまれます。

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