dockerに入門してみる(その7)
前回の記事はこちら↓ ren-opdev.hatenablog.com
チュートリアルを超える内容が少しあったので、目次を付けてみますm(__)m
今回は、「MySQLをApplication Stackに加える」ためにアプリケーションのマルチコンテナ化に挑戦します。 ちなみにApplication Stackとは、「ある目的を達成するために用いるソフトウェア群」を指すようです。www.techopedia.com
マルチコンテナ化をするには幾つか理由があります。
- フロントエンドとデータベースの実装を切り離せる。
- コンテナという単位でバージョン管理が出来る。
- development環境ではローカルを使い、production環境ではマネージドサービスを使う、といった変更が容易である。
- そもそも一つのコンテナで複数プロセスを回すことが煩雑さの原因となる。
上記の理由から、今回はToDoアプリとデータベースをそれぞれコンテナにパッケージングして実装していきます。
ちなみに、コンテナはデフォルトでは他のコンテナと独立していてやり取りができないため、コンテナ同士を同じネットワークに配置することで、コンテナ同士の疎通を実現します。 コンテナをネットワーク上に配置するには、1)起動時に配置する方法 と、2)既にあるコンテナを接続する方法 があります。今回は、1)の手法を試していきます。
MySQLコンテナを用意する
まず、ネットワークを作ります。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker network create todo-app
02cbb30fa67ef761135ee9ebe21b21ac649f6ba4b2652c72b6f3fff99fe5ea4a
特にログはなく、ネットワークに固有の値っぽいものが吐き出されました。 次に、下記コマンドでMySQLコンテナを起動し、ネットワークに配置します。ここで、データベース初期化に必要な環境変数も定義します。
docker run -d ` --network todo-app --network-alias mysql ` -v todo-mysql-data:/var/lib/mysql ` -e MYSQL_ROOT_PASSWORD=secret ` -e MYSQL_DATABASE=todos ` mysql:5.7
-v todo-mysql-data:/var/lib/mysql
で、まだ定義していないボリュームをマウントしようとしていますが、このように書くだけでDockerが自動的にボリュームを作り、マウントしてくれるようです。スゴイですね。
データベースが構成され立ち上がったのかどうかを確かめるため、コンテナ内でmysqlコマンドを叩きます。パスワードを求められるので、上記で指定したsecret
を入力します。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker exec -it 18d797997125 mysql -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.32 MySQL Community Server (GPL) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. 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 DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | todos | +--------------------+ 5 rows in set (0.00 sec)
データベースが構成されていることが確認できましたね。
MySQLコンテナと接続する
ネットワーク内のコンテナにアクセスするには、そのコンテナのIPアドレスを知る必要があります。 そのために、nicolaka/netshootコンテナを用います。これは、ネットワーク関連の便利ツールがまとまっているコンテナです。READMEにめちゃくちゃ使い方が書いてあってスゴイですね。
下記の通り、実行してみました。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker run -it --network todo-app nicolaka/netshoot Unable to find image 'nicolaka/netshoot:latest' locally latest: Pulling from nicolaka/netshoot cbdbe7a5bc2a: Already exists fa7edde5704a: Pull complete d142e371ed28: Pull complete db6c3597a95e: Pull complete 468b5d8bd548: Pull complete 1540e3cf45e1: Pull complete 676bb9b891dd: Pull complete bc4557056759: Pull complete Digest: sha256:52dcf922fc8d419c23f677f07cb0f2467f2157b92448f35bda15f471026ad476 Status: Downloaded newer image for nicolaka/netshoot:latest dP dP dP 88 88 88 88d888b. .d8888b. d8888P .d8888b. 88d888b. .d8888b. .d8888b. d8888P 88' `88 88ooood8 88 Y8ooooo. 88' `88 88' `88 88' `88 88 88 88 88. ... 88 88 88 88 88. .88 88. .88 88 dP dP `88888P' dP `88888P' dP dP `88888P' `88888P' dP Welcome to Netshoot! (github.com/nicolaka/netshoot) root @ / [1] 🐳 →
クジラマークのプロンプト! 🐳 こんなこともできるんですね~。
ここで、ネットワーク作成時に--network-alias mysql
と設定していたmysqlエイリアスを用いて、IPアドレスを調べてみます。
root @ / [1] 🐳 → dig mysql ; <<>> DiG 9.14.12 <<>> mysql ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18996 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;mysql. IN A ;; ANSWER SECTION: mysql. 600 IN A 172.18.0.2 ;; Query time: 1 msec ;; SERVER: 127.0.0.11#53(127.0.0.11) ;; WHEN: Tue Dec 29 07:26:37 UTC 2020 ;; MSG SIZE rcvd: 44
ANSWER SECTIONにある172.18.0.2
が、目当てのIPアドレスのようです。
IPアドレスを知ることができましたが、今回は上述の通りmysql
というエイリアスを被せているため、このIPアドレス自体を打ち込むのではなくmysql
というホストネームを使用すればデータベースに接続することが可能です。
MySQLと共にアプリケーションを実行する
では、いよいよToDoアプリコンテナとMySQLコンテナを紐づけていきます。 まず、以下で使用していく環境変数について説明します。
環境変数 | 意味 |
---|---|
MYSQL_HOST | 起動中のMySQLサーバーのホストネーム |
MYSQL_USER | MySQLサーバーへの接続に使うユーザーネーム |
MYSQL_PASSWORD | MySQLサーバーへの接続に使うパスワード |
MYSQL_DB | 接続後に使用するデータベース |
下記コマンドより、コンテナを実行します。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker run -dp 3000:3000 ` >> -w /app -v "$(pwd):/app" ` >> --network todo-app ` >> -e MYSQL_HOST=mysql ` >> -e MYSQL_USER=root ` >> -e MYSQL_PASSWORD=secret ` >> -e MYSQL_DB=todos ` >> node:12-alpine ` >> sh -c "yarn install && yarn run dev" 10c150eded9cd36d707ef2e65d47dcc1909ed805f8a0f24b727311706dc31717
コンテナログを見てみるとConnected to mysql db at host mysql
とあり、実際に接続されたことが分かります。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker logs 10c150eded9c yarn install v1.22.5 [1/4] Resolving packages... success Already up-to-date. Done in 0.46s. yarn run v1.22.5 $ nodemon src/index.js [nodemon] 1.19.2 [nodemon] to restart at any time, enter `rs` [nodemon] watching dir(s): *.* [nodemon] starting `node src/index.js` Waiting for mysql:3306. Connected! Connected to mysql db at host mysql Listening on port 3000
http://localhost:3000/ にアクセスし、データを入れてみます。
そして、先ほどと同様にMySQLコンテナに入り、正しくレコードが登録されたかを確認します。
mysql> select * from todo_items; +--------------------------------------+-----------+-----------+ | id | name | completed | +--------------------------------------+-----------+-----------+ | a7ef25b8-11e3-456d-9770-f329c90a7b4b | sample! | 0 | | 786c96d1-b708-4905-b03f-72527a5fce5e | CHAPTER 7 | 0 | +--------------------------------------+-----------+-----------+ 2 rows in set (0.01 sec)
アプリケーションコンテナからMySQLコンテナに接続し、データを保存できたことを確認できました。
日本語を入力できない問題
チュートリアルの通り進めていくと、MySQLが日本語をIncorrect string valueだ!
と言って受け付けてくれません。実際、MySQLの状態を見てみると
mysql> status -------------- mysql Ver 14.14 Distrib 5.7.32, for Linux (x86_64) using EditLine wrapper Connection id: 8 Current database: todos Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.7.32 MySQL Community Server (GPL) Protocol version: 10 Connection: Localhost via UNIX socket Server characterset: latin1 Db characterset: latin1 Client characterset: latin1 Conn. characterset: latin1 UNIX socket: /var/run/mysqld/mysqld.sock Uptime: 1 hour 16 min 4 sec Threads: 2 Questions: 68 Slow queries: 0 Opens: 109 Flush tables: 1 Open tables: 102 Queries per second avg: 0.014 --------------
Server characterset: latin1
のように、文字コードがlatin1
になっています。
文字コードを変えれば良さそうなのですが、cnfファイルをいじらなきゃいけない…??
と思ったら、Docker公式のMySQLリポジトリ内にConfiguration without a cnf file
というパラグラフが見つかりました。
公式が「cnfファイルを使わなくてもこのオプション使えばUTF-8にできるよ」というオプションを用意してくれているようです。感謝。。 というわけで、新しいコンテナを起動していきます。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker run -d ` >> --network todo-app --network-alias mysql_v2 ` >> -e MYSQL_ROOT_PASSWORD=secret ` >> -e MYSQL_DATABASE=todos_ja ` >> mysql:5.7 ` >> --character-set-server=utf8mb4 ` >> --collation-server=utf8mb4_unicode_ci ff39d7d156c04fdf37d020891b483df44537ba8ae00d8810bd42b276d193a4f2
無事起動できているようなので、細かい確認手順は省いて、アプリケーションコンテナと再度結び付けてみます。
PS C:\Users\530lo\Documents\docker\tutorial\app\app> docker run -dp 3000:3000 ` >> -w /app -v "$(pwd):/app" ` >> --network todo-app ` >> -e MYSQL_HOST=mysql_v2 ` >> -e MYSQL_USER=root ` >> -e MYSQL_PASSWORD=secret ` >> -e MYSQL_DB=todos_ja ` >> node:12-alpine ` >> sh -c "yarn install && yarn run dev" 9e1a01749ef688a05fdf43e30ad7efcb32403c987e76ee94fbd8cce8cb9de88b
無事コンテナを実行できたようです。
データベースの状態↓
mysql> select * from todo_items; +--------------------------------------+------------------------------+-----------+ | id | name | completed | +--------------------------------------+------------------------------+-----------+ | c719ab12-0f2b-4ced-985b-abfd0d3982e0 | ?????????????? | 0 | | f4948b12-3dea-4e34-bc5c-25b9cbef7af3 | ???????? | 0 | | 71b71092-42c5-4d04-88d0-512d280f7891 | Happy New Year! | 0 | | f11a222b-71ce-4438-8648-53e6862eb09f | You can also enter English! | 0 | +--------------------------------------+------------------------------+-----------+ 4 rows in set (0.00 sec)
部分的にutf-8に変更したため、完全に対応できたとは言えませんが、一旦は日本語入力もいけましたね。。! (また違うタイミングでデータベースのことをちゃんと勉強したいです)
データ保持専用のコンテナを作りコンテナ同士を結びつけられたところで、このチャプターは終わりです。
今はまだコンテナごとに立ち上げていますが、次のチャプターではDocker Compose
を勉強して、Application Stackという単位で操作する手段を身に着けられるそうです。
マルチコンテナをググった際に日本語版のページが出てきてビックリしましたが、翻訳が機械っぽいし、このチュートリアルもあともう少しなので、 感想を交えたこの一連のブログが101 Tutorialの日本人向け資料として誰かの役に立つことを信じてやり進めます。。