MySQLコンテナの文字コードをutf8mb4に設定する

背景

実践Djangoのサンプルアプリケーションを実装していて、フォームからマルチバイト文字を保存しようとしたところ、エラーが発生しました。

MySQLのオフィシャルコンテナは、そのままだとデフォルトの文字コードがutf8になっていないようなので、その設定方法をまとめておきます。

クライアント側の設定

クライアント側はDjangoなので、Djangoの設定になります。
プロジェクト/settings.pyのデータベース設定に、OPTIONSに文字コードを指定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'djangosnippets',
'USER': 'django',
'PASSWORD': 'django',
'HOST': 'db',
'PORT': 3306,
'OPTIONS': {
'charset': 'utf8mb4'
}
}
}

以上でクライアント側の設定は完了です。

サーバー側の設定

MySQLのオフィシャルコンテナのページを見ると、以下のように記載があります。

1
2
3
4
5
Configuration without a cnf file

Many configuration options can be passed as flags to mysqld. This will give you the flexibility to customize the container without needing a cnf file. For example, if you want to change the default encoding and collation for all tables to use UTF-8 (utf8mb4) just run the following:

$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

設定ファイルをカスタマイズして読み込ませてもいいと思いますが、そうしなくていい方法を選ぼうと思います。コマンドのオプションで指定できるようなので、docker-compose.ymlにそのように記載します。

1
2
3
4
5
6
7
8
9
10
11
12
db:
image: mysql:5.7
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: 'django'
MYSQL_PASSWORD: 'django'
MYSQL_DATABASE: 'djangosnippets'
ports:
- 33060:3306
volumes:
- mysql:/var/lib/mysql

commandを記述して、起動コマンドを上書きします。

これでサーバー側の設定は完了です。

動作確認

では動作確認を行います。Djangoのコマンドでデータベースに接続します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ docker-compose run --rm web python manage.py dbshell
Creating djangosnippets_web_run ... done
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 24
Server version: 5.7.36 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [djangosnippets]>

文字コードを確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MySQL [djangosnippets]> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.011 sec)

ちゃんとutf8mb4になっていました。

まとめ

MySQLコンテナの文字コードの設定方法を記述しました。

utf8mb4にしておくことで、絵文字も保存できるようになります。

開発環境を作る際に忘れてしまったらこのページを参照しようと思います。

参考図書