以前「コンテナ上のMariaDBに外部から接続する方法まとめ」というタイトルで、アプリやSQLクライアントから、DockerのMariaDBコンテナにアクセスすべく悪戦苦闘した時の備忘録を記事にしていました。
コンテナ上のMariaDBに外部から接続する方法まとめ - Qiita
ですが、Macに移ってきたのを機に改めてやってみたら こんな面倒なことをする必要は全く無かった ので、改めて備忘録を残しておきます。
※2018/05/27 コメント頂いた内容を適宜反映致しました。
- IPではなく、コンテナ名でそのままアクセス出来ること
-
MYSQL_DATABASE
に記載したスキーマを文字コードを指定しながら作成出来ること
試行環境
- macOS 10.13 High Sierra
- Docker for Mac
アプリコンテナとDBコンテナが別になっている環境を想定しています。
なお、今回はMariaDBではなく、MySQL5.7なので、そこだけ前提が違うことをご了承ください。
Docker立ち上げるまで
docker-compose.yml
※2018/05/27 内容を更新しました。
version: '2'
services:
db:
build: ./db/
environment:
MYSQL_ROOT_PASSWORD: your_password
MYSQL_DATABASE: your_schema
ports:
- "3306:3306"
app:
build: ./app/
ports:
- "8080:80"
links:
- db
volumes:
- ./src:/var/www/html
stdin_open: true
tty: true
db/Dockerfile
FROM mysql:5.7
COPY ./mysql.conf.d /etc/mysql/mysql.conf.d
db/mysql.conf.d/mysqld.cnf
[mysqld]
〜中略〜
character-set-server=utf8mb4 // mysqldの最後に追加
[client]
default-character-set=utf8mb4 // clientのセクションそのものを追加
ポイントは、
-
environment
として最低限MYSQL_ROOT_PASSWORD
とMYSQL_DATABASE
を設定しておく- 文字コードは
mysqld.cnf
の中で定義すれば、MYSQL_DATABASE
で作成されるスキーマに反映される
- 文字コードは
- コンテナ側の
3306
番ポートに繋がるようにする(ローカル側は何番でも良いが、同じく3306
にするのが吉)-
expose
ではなく、ports
で。
-
※appコンテナ側は今回の話題と直接は関係しないので、説明を省きます。
立ち上げ
何も難しいことはありません。普通に立ち上げます。
$ docker-compose up -d
※2018/05/27 必ずしもコンテナの中に入る必要はなくなりました。入り方のメモとして残しておきます。
立ち上がったら、docker exec
してコンテナの中に一度入ります。
入る前には、docker ps
でidを調べておきましょう。
コンテナが特定出来れば良いので、 上3桁ぐらいで十分 です。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
97c4d1095fab dirname_app "/bin/bash" 14 minutes ago Up 14 minutes 0.0.0.0:8080->80/tcp dirname_app_1
d47f748e436c dirname_db "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 0.0.0.0:3306->3306/tcp dirname_db_1
DBコンテナd47f748e436c
にdocker exec
します。
$ docker exec -it d47 /bin/bash
ホストを調べる
実は、アプリコンテナからDBコンテナにはlocalhost
ではアクセス出来ません(当たり前)
じゃあどうするかというと、DBコンテナのIPが分かっている必要があります。(※)
※2018/05/27追記
kazuyoshikitahara様、otolab様からのご指摘コメントの内容を反映してなかったので追記。
IP分かっている必要はありません。 docker-compose.yml
に記載したコンテナ名でアクセス出来ます。
/etc/hosts
に記載されている、ということは、 そもそもそのホスト名でアクセス出来る ということ。
なので、下記の様に /etc/hosts
をわざわざ見る必要はありません。
Dockerの場合はホストを調べれば分かるので、先程docker exec
したDBコンテナの中の/etc/hosts
を調べます。
※ifconfig
を使わないのは、コンテナの中にifconfig
コマンドがインストールされていないため。
root@d47f748e436c:/# ifconfig
bash: ifconfig: command not found
/etc/hosts
をcat
します。
root@d47f748e436c:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.2 d47f748e436c
先程調べたDBコンテナのidd47f748e436c
が、172.18.0.2
のホスト名になっています。
ここから172.18.0.2
がこのDBコンテナのIPアドレスである、と判断することが出来ます。
これで準備完了です。
SQLクライアントからのアクセス
MacならSequel Pro、WindowsならA5:SQL mk2などのSQLクライアントからアクセスするのは、以下のように設定すればOKです。
- Host:
127.0.0.1
- User:
root
- Password: your_password
- Port:
3306
- ローカル側のポートを変更した方は、ここをその番号に
Sequel Proの場合は「標準」接続でOKです。
先に調べたIPアドレスではなく、127.0.0.1
であるというのがミソです。
localhost
でもありません。
127.0.0.1
にしないといけない理由(推測)
-
172.18.0.2
というのはDockerのネットワーク上でのローカルIPであるため、その外にあるSQLクライアントからは参照出来ない- おそらくではありますが、あながち間違いでも無いかと思ってます。
-
localhost
の場合、ソケットの指定が必要になり、どれ使ったら良いのか分からない。 -
docker-compose.yml
でports
の設定をしており、ローカルの3306
番ポートがコンテナの3306
番ポートとリンクしているため、127.0.0.1
を指定した時、そのままコンテナの中までリンク出来る。
アプリからのアクセス
アプリからアクセスするには、先程調べたDBコンテナのIPを使用します。 docker-compose.yml
に記載したコンテナ名でアクセスします。
- Host:
172.18.0.2
db
上記方法で調べたIPを使用してください。今回はこれ。- 2018/05/27 上述追記の通り、
docker-compose.yml
に記載のコンテナ名で。今回はdb
という名前を付けていたので、それを使います。
- User:
root
- Password: your_password
- Port:
3306
先述の通り、SQLクライアントの時とは逆で、127.0.0.1
やlocalhost
ではNGです。
当然ながら、アプリコンテナの中にMySQLがあるわけではありませんからね。
例えばPHPで、PDO使って接続するなら、こんな感じで書けばOKです。
$pdo = new PDO('mysql:dbname=your_schema;host=db;', 'root', 'your_password');
TODO
現状試せていないものを一応控えておきます。
root以外のユーザーでも同様に出来るようにする
実はここまでのやり方では、root
以外のユーザーでうまくいきません。
docker-compose.yml
のenvironment
で、MYSQL_USER
を指定した時、などです。
理由は、mysql.user
テーブルを覗いてみると、Select_priv
すら与えられてないため。
MYSQL_USER
でapp
というユーザーを追加した時の、mysql.user
を見るとこうなってます。
mysql> select host, user, Select_priv from mysql.user;
+-----------+---------------+-------------+
| host | user | Select_priv |
+-----------+---------------+-------------+
| localhost | root | Y |
| localhost | mysql.session | N |
| localhost | mysql.sys | N |
| % | root | Y |
| % | app | N |
+-----------+---------------+-------------+
5 rows in set (0.00 sec)
どこかで、MYSQL_USER
に対しても権限を与えないといけません。
これはTODOとして、改めて調べないといけませんね。。
文字コードを指定しながらスキーマを作成する
2018/05/27追記。
docker-compose.yml
にて、MYSQL_DATABASE
を定義するとコンテナ作成時にスキーマを作成してくれます。
ただ問題は、設定をしてあげないと文字コードがlatin1
になってしまうこと。
utf8mb4
などにするには、コンテナ内/etc/mysql/mysql.conf.d
に下記の内容を含んだmysqld.cnf
を配置すればOKです。
[mysqld]
〜中略〜
character-set-server=utf8mb4 // mysqldの最後に追加
[client]
default-character-set=utf8mb4 // clientのセクションそのものを追加
おわりに
以前Docker for Windowsでやっていた時にはドハマリしていたところが、なぜか楽に出来ていたのは謎ですが。。。
Sequel ProなどのSQLクライアントからアクセス出来ないのは地味にダルいので、あまり手間掛けずアクセス出来るようになってよかったです。