6月に未経験エンジニアとして入社して早いもので、3ヶ月が経ってしまいました...
日々研修に励んでいます。
まだまだ分からないことばかりですが、初投稿していきたいと思います。お手柔らかにお願いします。
では。本題に入ります。
誰のための記事?
- スッキリわかるSQLやゼロからはじめるデータベース操作などの教材をDockerのMySQLコンテナで使ってみたい方。(そんな方います??)
- MySQLコンテナで日本語入力を使いたい方(時短:本命(Dockerfile)だけ見れば解決できるかと思います。)
MySQLコンテナ内で日本語入力できない⁉
SQLの研修時に、Docker環境を構築して「MySQLをいじるぞー」って意気込んで作ってはみたものの、何故か日本語が入力できない。
「ナゼー???」っという事で調べてみました。
結果、日本語入力できる環境ができたので、いろいろ調べたものをまとめハンズオンっぽい記事を書いてみました。
原因
MySQLの文字コードを日本語(utf8mb4)に設定しても入力できず...
どうやらコンテナ内のLinux カーネルのlocaleを日本語が使えるように設定しないとダメみたいです。
docker-composeでDocker環境をつくってみた。
リポジトリ
ディレクトリ構成図
docker-mysql
├─ mysql
│ ├ Dockerfile // Dockerファイル
│ ├ my.cnf // MySQL設定ファイル
│ └ prefecture.sql // SQLファイル(使いたいSQLファイルに差し替えてください。)
┝ .env // 環境設定ファイル
└ docker-compose.yml
Docker
version: '3.9'
volumes:
sql:
services:
db:
build:
context: .
dockerfile: ./mysql/Dockerfile
ports:
- 3306:3306
volumes:
- sql:/var/lib/mysql
- ./mysql/:/docker-entrypoint-initdb.d
environment:
- MYSQL_DATABASE=${DB_NAME}
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASS}
- MYSQL_ROOT_PASSWORD=${DB_PASS}
- TZ=${TZ)
ファイルについて上から順に説明していきます。
- version: docker-composeで使うバージョン
-
volumes: sql: コンテナを破壊(down)するとデータが消えてしまうので永続化のためのボリューム
永続化って何?って方はこちらに詳しい書いてくれてますね。
- services: 各コンテナを要素ごとにまとめている。今回はdbのみですが
- build: コンテナを作る設定
- context: コマンドを実行した場所
-
dockerfile: Dockerfileの場所
なんでコンテキストが必要なのだろうか?って方はこちらを
-
port: 左側がホストのポート番号で右側がコンテナのポート番号
今回は同じ番号ですが、例えば。3307:3306
の場合。
JavaなどのバックエンドからDB(MySQL)に接続したい時は3307
でアクセス、コンテナ内からDB(MySQL)へ接続するときは3306
でアクセスが必要です。
3306
はMySQLのデフォルトのポート番号です。(ポート番号を変えたい場合はmy.cnfの項目で説明します。) -
volumes: - sql:/var/lib/mysql データを永続化するためさっき用意したvolumes:sqlをバインドします。これでコンテナを破壊(down)してもデータがボリュームに保存されます。
- ./mysql/:/docker-entrypoint-initdb.d エントリーポイントを指定します。
mysqlディレクトリにある.shや.sqlファイルを起動時にdaemonが読み取って初期化を行ってくれます。
つまり、mysqlディレクトリにSQLファイルを入れれば、起動時にテーブルを作ってくれます。(便利!!) -
environment: 環境変数の指定です。.envの値を指定します。TZ(timezone)を指定しないとMySQLで
CURRENT_TIMESTAMP
が取れないので注意です。
DB_NAME=sql
DB_USER=user
DB_PASS=password
TZ=Asia/Tokyo
環境変数を設定するファイルです。
リポジトリには.envはありません。
cp .env.example .env
で.envをコピーして設定してください。
MySQLの設定ファイル エントリーポイントを指定しているので、起動時に読み込んでくれます。
[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
文字コードを日本語が使えるように設定してます。
設定しないとcharacter_set
がlatin1
のままでバックエンドから日本語データを取った時に文字化けしたりします。
[mysqld]にport=3388
を記述するとポート番号が変更できます。
本命
# apt-get出来る様にdebian版を使う。
FROM mysql:8.0.30-debian
# コンテナ内で日本語が打てるようにlocalを変更といらないファイル削除
RUN apt-get update \
&& apt-get install -y locales \
&& sed -i -E 's/# (ja_JP.UTF-8)/\1/' /etc/locale.gen \
&& locale-gen \
&& update-locale LANG=ja_JP.UTF-8 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV LC_ALL ja_JP.UTF-8
表題の解決策はこれです。
mysql imageにlocaleを設定します。
こちらを参考にしました。
-
FROM mysql:8.0.30-debian apt-getするにはdebian版を使う必要があります。
はじめapt-getできなくて「なぜできないの??」ってハマってしまいました。
どうやらデフォルトのosが変わっていたらしくapt-getできなかったようです。
- apt-get update && apt-get install -y locales パッケージを更新してlocalesをインストール
-
sed -i -E 's/# (ja_JP.UTF-8)/\1/' /etc/locale.gen locale.genにある#ja_JP.UTF-8 → ja_JP.UTF-8へ変更
コンテナ内の/etc/locale.genをcatしてみると
# it_IT.UTF-8 UTF-8
# it_IT@euro ISO-8859-15
# iu_CA UTF-8
# ja_JP.EUC-JP EUC-JP
ja_JP.UTF-8 UTF-8
# ka_GE GEORGIAN-PS
# ka_GE.UTF-8 UTF-8
# kab_DZ UTF-8
# kk_KZ PT154
なるほど!
- locale-gen localedefを呼び出すシェルスクリプトみたいです。
- update-locale LANG=ja_JP.UTF-8 ロケールを日本語に設定。
- apt-get clean && rm -rf /var/lib/apt/lists/ apt キャッシュをクリーンにして、/var/lib/apt/lits を削除することで、イメージのサイズを減らせるベストプラクティスみたいです。
作ったdocker-compose環境を使ってみる。
まずはbuildしてMySQLコンテナを作っていきます。
docker-mysqlのディレクトリ内で
docker-compose build
docker-mysql> docker-compose build
Building db
[+] Building 4.4s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 32B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/mysql:8.0.30-debian 4.3s
=> [1/2] FROM docker.io/library/mysql:8.0.30-debian@sha256:6d49fc540dac15528491aed83c7127b0c5874e87b5c81d0e89437 0.0s
=> CACHED [2/2] RUN apt-get update && apt-get install -y locales && sed -i -E 's/# (ja_JP.UTF-8)/\1/' /e 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:967a578ba2ec984ed705d653fe49ae1443b02b0b054d8e5f7182512e318e68e3 0.0s
=> => naming to docker.io/library/docker-mysql_db 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
docker-mysql>
ビルドできました!
次にコンテナを建てます。
docker-compose up -d
docker-mysql> docker-compose up -d
Creating network "docker-mysql_default" with the default driver
Creating docker-mysql_db_1 ... done
docker-mysql>
建ちましたね。
きちんと建ったか確認して見ます。
docker-compose ps
docker-mysql> docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------------
docker-mysql_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp
docker-mysql>
大丈夫ですね。
コンテナがすぐ落ちたり、立ち上がらなくなってしまったら
SQL文が間違っているとエラーをはいてコンテナが数秒立ち上がったのにExit 1
になり落ちてしまうことがあります。
docker-mysql> docker-compose ps
Name Command State Ports
----------------------------------------------------------------
docker-mysql_db_1 docker-entrypoint.sh mysqld Exit 1
docker-mysql>
コンテナが立ち上がるように修正していきたいと思います。
ログ見てエラーを確認します。
docker-compose logs
db_1 | ERROR 1064 (42000) at line 10: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 48
エラーが見えれました。
SQL文が間違っているようです。
SQLファイルを修正するため、まずコンテナを破壊(down)します。
docker-compose down
SQLファイルを修正します。(INSERT文の48項目目にいらない「,」をつけていましたので修正しました。)
このままコンテナを起動しても永続化されたボリュームがエラーの状態を保存しているため一度ボリューム削除する必要があります。
ボリュームを見てみます。
docker volume ls
DRIVER VOLUME NAME
local c58542dcb9f8b981c3daa9cef6e2e07c9bf7807cc04f00318f7d4f149277b15a
local db9fde8114f175621fdc22c7fd9c20697032361c735fbf0e358d451cee530ab2
local docker-mysql_sql
docker-mysql_sqlがありました。(ディレクトリ名:docker-mysql, ボリューム名:sqlになるっぽいですね。)
ボリュームを削除します。
※docker-compose down
していないと使ってる状態なのでボリュームの削除ができません。
docker volume rm docker-mysql_sql
docker-mysql> docker volume rm docker-mysql_sql
docker-mysql_sql
docker-mysql>
docker volume ls
ボリュームが消えました。
コンテナを起動します。
docker-compose up -d
docker-compose ps
docker-mysql> docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------------
docker-mysql_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp
docker-mysql>
これで修正完了です。
コンテナ内のMySQLを使ってみる
docker-compose up -d
コンテナを起動した状態にします。
docker-compose exec db bash
execコマンドでコンテナの中に入れます。
db:コンテナの名前 bash:シェル(bashが使えないコンテナもあったりします。そういう場合はshを使います。)
docker-mysql> docker-compose exec db bash
root@33d333d333c3:/#
dbコンテナの中に入ることができました。
MySQLに接続してみます。
mysql -u$MYSQL_USER -p$MYSQL_PASSWORD
root@33d333d333c3:/# mysql -u$MYSQL_USER -p$MYSQL_PASSWORD
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.30 MySQL Community Server - GPL
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
MySQLに接続できました。
接続に環境変数を使っていますが使わなくても接続できます。
日本語データが使えるか文字コードを確認します。
show variables like '%char%';
mysql> 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 | utf8mb3 |
| character_sets_dir | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.04 sec)
mysql>
文字コードは大丈夫ですね。
データベースを見てみます。
show databases;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| sql |
+--------------------+
3 rows in set (0.01 sec)
mysql>
information_schemaとperformance_schemaはMySQLの機能用のデータベースみたいですね。
MYSQL_DATABASEで設定した名前(sql)が初期化テーブルの詰まったデータベースです。
データベースを選択します。
use sql;
mysql> use sql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql>
データベースを選択できました。
テーブルを見てみます。
show tables;
mysql> show tables;
+---------------+
| Tables_in_sql |
+---------------+
| prefecture |
+---------------+
1 row in set (0.00 sec)
mysql>
初期化したテーブルが見えると思います。
サンプルのprefectureテーブルのデータ一覧を取ります。
mysql> select * from prefecture;
+----+--------------+--------------------+---------------------+---------------------+
| id | 名前 | カナ | create_at | update_at |
+----+--------------+--------------------+---------------------+---------------------+
| 1 | 北海道 | ホッカイドウ | 2022-09-04 21:37:51 | 2022-09-04 21:37:51 |
| 2 | 青森県 | アオモリケン | 2022-09-04 21:37:51 | 2022-09-04 21:37:51 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| 46 | 鹿児島県 | カゴシマケン | 2022-09-04 21:37:51 | 2022-09-04 21:37:51 |
| 47 | 沖縄県 | オキナワケン | 2022-09-04 21:37:51 | 2022-09-04 21:37:51 |
+----+--------------+--------------------+---------------------+---------------------+
47 rows in set (0.00 sec)
日本語表示は大丈夫ですね。
日本語入力も試してみます。
mysql> sselect id, 名前, カナ from prefecture;
+----+--------------+--------------------+
| id | 名前 | カナ |
+----+--------------+--------------------+
| 1 | 北海道 | ホッカイドウ |
| 2 | 青森県 | アオモリケン |
| 3 | 岩手県 | イワテケン |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| 45 | 宮崎県 | ミヤザキケン |
| 46 | 鹿児島県 | カゴシマケン |
| 47 | 沖縄県 | オキナワケン |
+----+--------------+--------------------+
47 rows in set (0.00 sec)
日本語入力もしっかりできました。
後片付け
コンテナの終了作業をします。
exit
(または、Ctrl+D)を2回打ってMySQLとコンテナから抜けます。
mysql> exit
Bye
root@33d333d333c3:/# exit
exit
docker-mysql>
作業が終わったらコンテナを破壊します。
down
しないとコンテナが起動し続けるので必ず破壊します。
docker-compose
にはコンテナを停止するだけのstop
というコマンドもありますがなぜdown
を使うのか?はこちらの記事を
docker-compose down
docker-mysql> docker-compose down
Stopping docker-mysql_db_1 ... done
Removing docker-mysql_db_1 ... done
Removing network docker-mysql_default
docker-mysql>
破壊されたか確認します。
docker-compose ps
docker-mysql> docker-compose ps
Name Command State Ports
------------------------------
docker-mysql>
片付けができました。
以上になります。
後は、好きにいじり倒してください。
終わり
日本語入力できるようになりましたが、入力が確定されるまで文字が表示されないのはちょっと使いづらいですね...
まだまだLinuxやコンテナ周り知識が全然足りなそうです。今回はとても勉強になりました。
これからDockerの研修を受けるのでしっかり勉強していきたいなと感じました。おしまい。