DockerのMySQLで日本語入力ができなかった話

ローカル環境を汚さずにMySQLの動作検証をサクッとしたかったので、Dockerを使うことにしました。

やりたい検証は単純なものだったので「わざわざDockerfileを準備しなくても、ベースイメージから直接コンテナを起動すればいいか」と思い、以下のコマンドを実行しコンテナを起動→MySQLに接続しました。

```bash
$ docker run --name mysql_container -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mysql:8.0.36
$ docker exec -it mysql_container bash
bash-4.4# mysql
mysql> 
```

ここまでは、何の問題もありませんでしたが、日本語を含んだSELECT文を実行する際に、問題が発生しました。

以下のように「あ」を入力中、確定するためにEnterを押すと「あ」が消えてしまうのです。

```bash
mysql> SELECT 'あ
```

今回は、これを解決するまでの過程を記事にします。

# いきなり解決方法

解決さえすれば、それでいいんだという方のためにまずは解決方法から

以下のDockerfileを使えば、MySQLで日本語を入力することができるようになります。

```dockerfile:Dockerfile
FROM mysql:8.0.36-debian

RUN apt-get update && apt-get install -y locales
RUN sed -i 's/# ja_JP.UTF-8 UTF-8/ja_JP.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
ENV LANG ja_JP.UTF-8
```

実行コマンド

```bash
$ docker build . -t mysql_image
$ docker run --name mysql_container -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mysql_image
$ docker exec -it mysql_container bash
root@d7a83e3b721c:/$ mysql
mysql> SELECT 'あ' = 'ア' as test;
+------+
| test |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
```

# 原因

**OSのロケール設定**ができていないことが原因でした。

# 解決するまでの道のり

あれこれ調べてみると、OSのロケール設定についての情報がいくつか見つかったので、これが原因だと仮定して、解決を試みることにしました。

手順は次のとおりです。

- ベースイメージだけのコンテナ（冒頭のコンテナ）を作成し接続する
- コマンドを入力して解決方法を探る
- 実行したコマンドをDockerfileに反映させる
- Dockerfileから作成したイメージで起動したコンテナを使って確認する

## ベースイメージだけのコンテナを作成し接続する

冒頭の繰り返しになりますが、以下のとおりです。

```bash
$ docker run --name mysql_container -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mysql:8.0.36
$ docker exec -it mysql_container bash
bash-4.4#
```

## コマンドを入力して解決方法を探る

### 必要なパッケージのインストール

まずはロケール設定に必要なパッケージをインストールします。

```bash
bash-4.4# apt-get update
bash: apt-get: command not found
```

`apt-get`コマンドがないだと…

[無印のmysql:8.0.36](https://hub.docker.com/layers/library/mysql/8.0.36/images/sha256-65ce0889751900d2dd5fc5aa5a5fb59073d401fc43df2eae6bd6afb18e7626dd?context=explore)ではoraclelinuxが使われていることが原因のようです。

`yum`なら使えそうですが、今回の目的は「MySQLの動作検証をサクッとしたい」であり、Linuxのディストリビューションにこだわりはありません。

すでに`apt-get`を使う前提で調べ始めていたので、ベースイメージを`mysql:8.0.36-debian`で進めることにします。

では、気を取り直して

```bash
$ docker run --name mysql_container -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mysql:8.0.36-debian
$ docker exec -it mysql_container bash
root@f73d6f614309:/$ apt-get update
```

今度は無事、パッケージリストを更新できました。

次はロケール設定を行うためのパッケージ「locales」をインストールしていきます。

```bash
root@f73d6f614309:/$ apt-get install -y locales
```

無事、インストールが完了しました。

### 日本語を使うための設定

まずは`locale-gen`コマンドで日本語のロケールを生成します。

生成されるロケールは/etc/locale.genで定義されており、今回使用したい日本語は`ja_JP.UTF-8`です。

実際に/etc/locale.genを確認してみます。

```bash
root@f73d6f614309:/$ cat /etc/locale.gen | grep ja_JP.UTF-8    
# ja_JP.UTF-8 UTF-8
```

コメントアウトされた行は`locale-gen`を実行しても、ローケルが生成されません。

最終的にDockerfileに反映させたいので、エディタを起動して手修正するのではなく、コマンドでコメントアウトを外します。

```bash
root@f73d6f614309:/$ sed -i 's/# ja_JP.UTF-8 UTF-8/ja_JP.UTF-8 UTF-8/' /etc/locale.gen
root@f73d6f614309:/$ cat /etc/locale.gen | grep ja_JP.UTF-8
ja_JP.UTF-8 UTF-8
```

これで日本語のロケールを生成する準備はOK。`locale-gen`を実行します。

```bash
root@f73d6f614309:/$ locale-gen
Generating locales (this might take a while)...
  ja_JP.UTF-8... done
Generation complete.
```

生成した`ja_JP.UTF-8`を使うように`LANG`に設定します。

```bash
root@f73d6f614309:/$ export LANG=ja_JP.UTF-8
```

### 再びMySQLに接続して動作確認

日本語設定が完了したので、冒頭と同じように日本語が入力できるか試してみます。

今度は「あ」を入力して、Enterで確定しても「あ」が消えないため最後まで入力できました！

```bash
root@f73d6f614309:/$ mysql
mysql> SELECT 'あ' = 'ア' as test;
+------+
| test |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
```

### 実行したコマンドをDockerfileに反映させる

これで何をすれば日本語が使えるようになるかわかったので、ここまで実行してきたコマンドをDockerfileに反映させます。（冒頭で示したファイルと同じです。）

```dockerfile:Dockerfile
FROM mysql:8.0.36-debian

RUN apt-get update && apt-get install -y locales
RUN sed -i 's/# ja_JP.UTF-8 UTF-8/ja_JP.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
ENV LANG ja_JP.UTF-8
```

### Dockerfileから作成したイメージで起動したコンテナを使って確認する
以下のとおり、日本語が使用できています！
```bash
$ docker build . -t mysql_image
$ docker run --name mysql_container -e MYSQL_ALLOW_EMPTY_PASSWORD=true -d mysql_image
$ docker exec -it mysql_container bash
root@d7a83e3b721c:/$ mysql
mysql> SELECT 'あ' = 'ア' as test;
+------+
| test |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
```

# まとめ

MySQLに問題がありそうなタイトルを付けていますが、実際にはLinuxのローケル設定の問題でした。（同じような問題にぶつかった人が、この記事に辿り着いてくれればという思いを込めたタイトルです。）

また、今回は情報収集の結果「Linuxのロケール設定が原因である」と仮定して、それを解決するための方法を調査・検証し、目的を果たすことができました。

もしかしたら他にも解決方法があるかもしれませんが、**自分なりの仮説を持つことで調査・検証が進めやすくなる**ということを、あらためて実感しました。