Ubuntu上でビルド・デプロイしたwebappを、今度はDockerコンテナ上でデプロイしてみる。
「Dockerってなにそれおいしいの?」とかの、コンテナを使うメリットとかの話はここにはないですごめんなさい。
アプリケーションのビルドについてもマルチステージビルドを使ってコンテナ上でビルドして、作成したwarをデプロイ用のイメージに組み込む手順もあるけど、とりあえずビルドについてはコンテナの外(VM上)でやります。
※ マルチステージビルドについてはこちら: Dockerのマルチステージビルド機能でコンテナ上のMavenビルド - Qiita
全体の構成図はこんな感じ
Windows 10 homeを使っているからというのも大きいけど、VirtualBox上のVMの中でDockerを動かしているので、Windows上からVMで動いているコンテナへの__直接の__通信(図中windowsからブラウザでwebアクセスとか)はできない。
(接続方法は後述)
ちなみに、Minishift(OpenShift)を使ったオーケストレーション環境でのデプロイはこちら
更新履歴
- 2019.02.11: マルチステージビルドについて記事へのリンク追加
- 2019.02.07: ポートフォワーディング(
-p
)について説明追加 - 2019.02.06: 構成図追加
Dockerのインストール
まずは実行環境としてのDockerをインストール。といってもapt
やyum
で入る。
Ubuntuであればdocker.ioパッケージ。(dockerパッケージもあるけどそっちは違うw)
また、universeリポジトリにあるので、aptlineに追加されていなければ修正する。
root@chaource:~# apt install docker.io
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
bridge-utils cgroupfs-mount libltdl7 pigz ubuntu-fan
Suggested packages:
ifupdown aufs-tools debootstrap docker-doc rinse zfs-fuse | zfsutils
The following NEW packages will be installed:
bridge-utils cgroupfs-mount docker.io libltdl7 pigz ubuntu-fan
0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.
Need to get 40.3 MB of archives.
After this operation, 198 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
...snip...
Adding group `docker' (GID 113) ...
Done.
Created symlink /etc/systemd/system/sockets.target.wants/docker.socket → /lib/systemd/system/docker.socket.
Processing triggers for ureadahead (0.100.0-20) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Processing triggers for systemd (237-3ubuntu10.11) ...
root@chaource:~#
root@chaource:~#
root@chaource:~#
root@chaource:~# docker version
Client:
Version: 18.06.1-ce
API version: 1.38
Go version: go1.10.4
Git commit: e68fc7a
Built: Fri Oct 19 19:43:14 2018
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: 18.06.1-ce
API version: 1.38 (minimum version 1.12)
Go version: go1.10.4
Git commit: e68fc7a
Built: Thu Sep 27 02:39:50 2018
OS/Arch: linux/amd64
Experimental: false
root@chaource:~#
アプリのビルド
git clone
してmvn package
するだけなので省略…と言いたいところだけど、接続先のMySQLサーバがlocalhost
ではなくなるので、そこだけ確認・修正する。
git clone
VMのTomcatで動かしていたバージョンはv1.0.0
のタグをつけてるのでそれをclone
する
root@chaource:~/src# git clone https://github.com/zaki-lknr/javaee-memoapp2.git -b v1.0.0
Cloning into 'javaee-memoapp2'...
remote: Enumerating objects: 384, done.
remote: Counting objects: 100% (384/384), done.
remote: Compressing objects: 100% (158/158), done.
remote: Total 384 (delta 144), reused 355 (delta 115), pack-reused 0
Receiving objects: 100% (384/384), 39.46 KiB | 2.08 MiB/s, done.
Resolving deltas: 100% (144/144), done.
Note: checking out '3656f7114c526027c96c0a585b6a5152ce43947c'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
root@chaource:~/src#
接続先MySQLの設定
root@chaource:~/src# cd javaee-memoapp2/
root@chaource:~/src/javaee-memoapp2# ls
LICENSE.txt pom.xml README.md src
root@chaource:~/src/javaee-memoapp2# vi src/main/webapp/META-INF/context.xml
変更点はこんな感じ。
root@chaource:~/src/javaee-memoapp2# git diff
diff --git a/src/main/webapp/META-INF/context.xml b/src/main/webapp/META-INF/context.xml
index 2a0018b..7da0d93 100644
--- a/src/main/webapp/META-INF/context.xml
+++ b/src/main/webapp/META-INF/context.xml
@@ -31,6 +31,6 @@
username="memoapp"
password="memoapp"
driverClassName="com.mysql.jdbc.Driver"
- url="jdbc:mysql://localhost:3306/memoapp_db" />
+ url="jdbc:mysql://memoapp-db:3306/memoapp_db" />
</Context>
memoapp-db
というホストへDB接続する設定にしているけど、これはこの名前でDBのコンテナを起動し、この名前でAPのコンテナから名前解決するよう構築する予定。
ビルド
これはVM上でビルドと一緒。
Mavenがインストールされてなければaptで入れる。
root@chaource:~/src/javaee-memoapp2#
root@chaource:~/src/javaee-memoapp2#
root@chaource:~/src/javaee-memoapp2# mvn package
:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building memoapp2 Maven Webapp 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
:
:
[INFO] Packaging webapp
[INFO] Assembling webapp [memoapp2] in [/root/src/javaee-memoapp2/target/memoapp2]
[INFO] Processing war project
[INFO] Copying webapp resources [/root/src/javaee-memoapp2/src/main/webapp]
[INFO] Webapp assembled in [65 msecs]
[INFO] Building war: /root/src/javaee-memoapp2/target/memoapp2.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:00 min
[INFO] Finished at: 2019-01-27T08:26:21+09:00
[INFO] Final Memory: 19M/46M
[INFO] ------------------------------------------------------------------------
root@chaource:~/src/javaee-memoapp2# ls target/
classes maven-archiver memoapp2
generated-sources maven-status memoapp2.war
root@chaource:~/src/javaee-memoapp2#
ビルドされたwarファイル
root@chaource:~/src/javaee-memoapp2# ll target/memoapp2.war
-rw-r--r-- 1 root root 3905453 Feb 4 21:43 target/memoapp2.war
Dockerネットワークの作成
以前はDockerでのコンテナ間通信は--link
オプションを使用することでコンテナ名で名前解決したり通信したりできたが、現在このオプションは非推奨(廃止予定)となっている。
現在どうするかというと、「Dockerネットワーク」を一つ作り、相互に通信が必要なコンテナをそのネットワークに所属するように設定してあげれば、そのDockerネットワーク内でコンテナ間通信ができるようになる。
(これはさくらインターネットさんの入門記事見るのが早いです笑)
root@chaource:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
3a1b834bcf14 bridge bridge local
312a61b7e4d9 host host local
031ce5d26836 none null local
root@chaource:~#
root@chaource:~# docker network create memoapp-network
308817de4a7fd68fdf811af09ac00eceb20a20ac7b522d1b89bc16db8130d288
root@chaource:~#
root@chaource:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
3a1b834bcf14 bridge bridge local
312a61b7e4d9 host host local
308817de4a7f memoapp-network bridge local
031ce5d26836 none null local
memoapp-network
が作成されました
MySQLのデプロイ
DockerHubにMySQLのOfficialイメージが公開されていて、これは現在8.0が最新になっている
が、今まで5.7を使ってきたので、一応5.7でやってみましょう。
起動パラメタはDockerHubを見れば載っている。
ただ、コンテナオーケストレーションだとなかった--character-set-server=utf8
という神対応のオプションががが。
それから、コンテナ間通信用に作成したネットワークの指定も忘れずに。
root@chaource:~/src/javaee-memoapp2# docker run --network memoapp-network --name memoapp-db -e MYSQL_DATABASE=memoapp_db -e MYSQL_USER=memoapp -e MYSQL_PASSWORD=memoapp -d mysql:5.7 --character-set-server=utf8
Unable to find image 'mysql:5.7' locally
5.7: Pulling from library/mysql
5e6ec7f28fb7: Pull complete
4140e62498e1: Pull complete
e7bc612618a0: Pull complete
1af808cf1124: Pull complete
ff72a74ebb66: Pull complete
3a28cb03e3dc: Pull complete
2b52dda3bd7d: Pull complete
dd1e5bc08c44: Pull complete
2cbf322d346d: Pull complete
7193a395fe03: Pull complete
d177f9940737: Pull complete
Digest: sha256:1590f2540fd87e39605686873fb10206da4cbd7e83df2bc4110abe9fb740699e
Status: Downloaded newer image for mysql:5.7
36717545d79a19ede42b9f088c6f2420c863aab6ac448cb11b7f2fe3f1c32398
root@chaource:~/src/javaee-memoapp2#
root@chaource:~/src/javaee-memoapp2# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@chaource:~/src/javaee-memoapp2# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
151d1c502fc3 mysql:5.7 "docker-entrypoint.s…" 4 seconds ago Exited (1) 3 seconds ago memoapp-db
あれ?
エラーで止まってる。
ログを見てみる。
root@chaource:~/src/javaee-memoapp2# docker logs memoapp-db
error: database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
root@chaource:~/src/javaee-memoapp2#
rootパスワードをなんかセットしないとダメらしい。
お試し動作なのでMYSQL_RANDOM_ROOT_PASSWORD
でランダム設定にしてみる。
root@chaource:~/src/javaee-memoapp2# docker rm memoapp-db
memoapp-db
root@chaource:~/src/javaee-memoapp2# docker run --network memoapp-network --name memoapp-db -e MYSQL_DATABASE=memoapp_db -e MYSQL_USER=memoapp -e MYSQL_PASSWORD=memoapp -e MYSQL_RANDOM_ROOT_PASSWORD=yes -d mysql:5.7 --character-set-server=utf8
root@chaource:~/src/javaee-memoapp2# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2b7c5b914055 mysql:5.7 "docker-entrypoint.s…" 2 seconds ago Up 2 seconds 3306/tcp, 33060/tcp memoapp-db
うごいた。
ちなみにエンコード設定は…
root@chaource:~/src/javaee-memoapp2# docker exec -it memoapp-db bash
root@2b7c5b914055:/# mysql -u memoapp -p -D memoapp_db
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.25 MySQL Community Server (GPL)
Copyright (c) 2000, 2019, 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> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
mysql>
おぉ、utf8になってる。Dockerすばらしい。
ちなみに、パラメタの指定順序が適当すぎたりすると動かなかったりする。
root@chaource:~# docker run --network memoapp-network --name memoapp-db -d mysql:5.7 -e MYSQL_DATABASE=memoapp_db -e MYSQL_USER=memoapp -e MYSQL_PASSWORD=memoapp -e MYSQL_RANDOM_ROOT_PASSWORD=yes --character-set-server=utf8
07425255c74377d2cec7b30ec1d16d58b39acf791605bdf6cfa779defd8de47f
root@chaource:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@chaource:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07425255c743 mysql:5.7 "docker-entrypoint.s…" 13 seconds ago Exited (1) 12 seconds ago memoapp-db
root@chaource:~# docker logs memoapp-db
ERROR: mysqld failed while attempting to check config
command was: "mysqld -e MYSQL_DATABASE=memoapp_db -e MYSQL_USER=memoapp -e MYSQL_PASSWORD=memoapp -e MYSQL_RANDOM_ROOT_PASSWORD=yes --character-set-server=utf8 --verbose --help"
2019-02-04T22:19:33.614318Z 0 [ERROR] mysqld: unknown option '-e'
2019-02-04T22:19:33.619595Z 0 [ERROR] Aborting
root@chaource:~#
基本的に以下の順序でオプションを並べておけばOK
- コマンド名(
docker
) - Dockerのサブコマンド(
run
とかexec
とか) - Docker(のサブコマンド)に対するオプション(
-d
とか--name
とか-e
とか) - 起動するイメージ:タグ名(
mysql:5.7
) - 起動するコンテナ(今回はMySQL)に対する引数(
--character-set-server=utf8
とか)- 引数が有効かどうかは、コンテナの定義次第
Tomcat/webappのデプロイ
TomcatもOfficialイメージが公開されているので、これを使いましょう。
パターンA: 手動でwar配置
コンテナの構造がわからないときはまずここから。
(といってもDockerHubのDescriptionとDockerfile見ればわかるんだけど)
基本的に効率的に安全な Dockerfile を作るには - Qiitaの要領で作業すればいい感じにできます。
まずはわかりやすさ重視で1ステップずつやります。
Tomcatコンテナのpullと起動とポートフォワード設定
まずはDockerHubのレジストリからTomcatのイメージを取得。
ただしこの手順は省略可能(未取得の状態でrun
すると、勝手にpull
してくれる)
root@chaource:~# docker pull tomcat:8.5
8.5: Pulling from library/tomcat
ab1fc7e4bf91: Pull complete
35fba333ff52: Pull complete
f0cb1fa13079: Pull complete
3d79c18d1bc0: Pull complete
ff1d0ae4641b: Pull complete
8883e662573f: Pull complete
adab760d76bd: Pull complete
86323b680e93: Pull complete
14a2c1cdce1c: Pull complete
ee59bf8c5470: Pull complete
067f988306af: Pull complete
Digest: sha256:296b26baeee450a9814b2733e9d085f3d26af1c48e5fdc2000496ff7e12bc897
Status: Downloaded newer image for tomcat:8.5
root@chaource:~#
そして実行
root@chaource:~/src/javaee-memoapp2# docker run --network memoapp-network -p 18080:8080 -d tomcat:8.5
d9e3953b0b7e38a0c3d1b4868b26654291045cae968c306f2e23dba4b36ebd2f
root@chaource:~/src/javaee-memoapp2# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9e3953b0b7e tomcat:8.5 "catalina.sh run" 11 seconds ago Up 10 seconds 0.0.0.0:18080->8080/tcp zealous_banach
起動時に、MySQLのデプロイでは指定してなかった-p 18080:8080
を指定している。
これは「ホストOSへの18080/TCPアクセスをコンテナの8080/TCPへbindする」というオプション。
これを指定することで、(図のWindowsのように)Tomcatコンテナへ直接アクセスできなくてもホストOS(図のUbuntu 18.04)の18080/TCPへアクセスすれば、Tomcat(の8080ポート)へアクセスできるようになる。
コンテナと直接アクセスできる場合(図のUbuntu 18.04からのブラウザアクセス)であれば、このオプションは必要ない。
その場合は、実行しているコンテナのIPアドレスを確認し、そのIPアドレスの8080ポートにアクセスすればよい。
コンテナのIPアドレスの確認方法はdocker inspect
でIPAddress
の行を探す。
(docker exec
でシェルログインし、ip a
とか実行してももちろんOK)
root@chaource:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee586da83b13 mysql:5.7 "docker-entrypoint.s…" 36 hours ago Up 36 hours 3306/tcp, 33060/tcp docker_memoapp-db_1
4d114d7a8376 memoapp:latest "catalina.sh run" 36 hours ago Up 36 hours 0.0.0.0:18082->8080/tcp docker_memoapp_1
root@chaource:~# docker inspect 4d11 | grep -i ipaddress
"SecondaryIPAddresses": null,
"IPAddress": "",
"IPAddress": "172.23.0.2",
root@chaource:~#
この出力であれば、http://172.23.0.2:8080/ にアクセスすれば良い。
コンテナにシェルログインする
コンテナの指定は、docker ps
で表示されるCONTAINER ID
かNAMES
を指定する。
コンテナID(ハッシュ値)は実は全桁入力せずに先頭3-4桁で特定できるなら一部の入力でも動く。
root@chaource:~/src/javaee-memoapp2# docker exec -it d9e bash
root@d9e3953b0b7e:/usr/local/tomcat#
内部の状態
root@a15a72232cfe:/usr/local/tomcat# env | sort
CATALINA_HOME=/usr/local/tomcat
GPG_KEYS=05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
HOME=/root
HOSTNAME=d9e3953b0b7e
JAVA_DEBIAN_VERSION=8u181-b13-2~deb9u1
JAVA_HOME=/docker-java-home/jre
JAVA_VERSION=8u181
LANG=C.UTF-8
LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-lib
OPENSSL_VERSION=1.1.0j-1~deb9u1
PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/usr/local/tomcat
SHLVL=1
TERM=xterm
TOMCAT_ASC_URLS=https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz.asc https://www-us.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz.asc https://www.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz.asc https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz.asc
TOMCAT_MAJOR=8
TOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-lib
TOMCAT_SHA512=be6d6df8b49a760b2e181d4a45d8e6dc7bba5ef2ec6a000f8562cf5f34db5b7fac300cba65bca782bfd25a9f9d8d4a48625f1ad046115c1d6629ea5f210a2718
TOMCAT_TGZ_URLS=https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz https://www-us.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz https://www.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz
TOMCAT_VERSION=8.5.37
_=/usr/bin/env
root@d9e3953b0b7e:/usr/local/tomcat#
Tomcatにwarファイルをデプロイするうえでチェックするのは、環境変数CATALINA_HOME
root@d9e3953b0b7e:/usr/local/tomcat# echo $CATALINA_HOME/
/usr/local/tomcat/
root@d9e3953b0b7e:/usr/local/tomcat# ls $CATALINA_HOME/webapps/
ROOT docs examples host-manager manager
このパス($CATALINA_HOME/webapps/
)にアプリケーションのwarを置けばOK (これはコンテナ云々じゃなくてTomcatの話)
ちなみに、肝心のコンテナ間通信については
root@d9e3953b0b7e:/usr/local/tomcat# ping -c 4 memoapp-db
PING memoapp-db (172.18.0.2) 56(84) bytes of data.
64 bytes from memoapp-db.memoapp-network (172.18.0.2): icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from memoapp-db.memoapp-network (172.18.0.2): icmp_seq=2 ttl=64 time=0.077 ms
64 bytes from memoapp-db.memoapp-network (172.18.0.2): icmp_seq=3 ttl=64 time=0.102 ms
64 bytes from memoapp-db.memoapp-network (172.18.0.2): icmp_seq=4 ttl=64 time=0.369 ms
--- memoapp-db ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3061ms
rtt min/avg/max/mdev = 0.043/0.147/0.369/0.130 ms
root@d9e3953b0b7e:/usr/local/tomcat#
名前解決もできてるし疎通も確認できる。
(本当はDB接続できているかはmysql
コマンドとかないと厳しけど、Tomcatコンテナからは無理なので省略)
ホストOSからコンテナへファイルをコピーする
このファイル
root@chaource:~/src/javaee-memoapp2# ls target/memoapp2.war
target/memoapp2.war
を
root@chaource:~/src/javaee-memoapp2# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9e3953b0b7e tomcat:8.5 "catalina.sh run" About a minute ago Up About a minute 0.0.0.0:18080->8080/tcp zealous_banach
このコンテナにコピーする。
ホストOSからコンテナへファイル転送するにはdocker cp
で。
root@chaource:~/src/javaee-memoapp2# docker cp target/memoapp2.war d9e3953b0b7e:/usr/local/tomcat/webapps/
root@chaource:~/src/javaee-memoapp2#
これでwarファイルの転送ができ、アプリケーションのデプロイが完了
root@d9e3953b0b7e:/usr/local/tomcat# ls -l $CATALINA_HOME/webapps/
total 3840
drwxr-xr-x 3 root root 4096 Jan 23 07:56 ROOT
drwxr-xr-x 14 root root 4096 Jan 23 07:56 docs
drwxr-xr-x 6 root root 4096 Jan 23 07:56 examples
drwxr-xr-x 5 root root 4096 Jan 23 07:56 host-manager
drwxr-xr-x 5 root root 4096 Jan 23 07:56 manager
drwxr-x--- 4 root root 4096 Feb 4 23:21 memoapp2
-rw-r--r-- 1 root root 3905453 Feb 4 12:43 memoapp2.war
root@d9e3953b0b7e:/usr/local/tomcat#
Tomcatのログ
root@chaource:~/src/javaee-memoapp2# docker logs d9e
:
:
04-Feb-2019 23:21:56.508 INFO [localhost-startStop-2] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/memoapp2.war]
04-Feb-2019 23:21:57.746 INFO [localhost-startStop-2] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
04-Feb-2019 23:21:57.804 INFO [localhost-startStop-2] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/memoapp2.war] has finished in [1,295] ms
さすが--character-set-server=utf8
の威力!
コンテナの環境変数は使えないのか…な?
root@chaource:~/src/javaee-memoapp2# docker cp target/memoapp2.war d9e3953b0b7e:'$CATALINA_HOME/webapps/'
no such directory
パターンB: war組み込みのカスタムイメージ作成
ここまでだと、実行環境をVMからDockerに置き換えただけで、手順的にもapt
やyum
のインストール・systemctl
でのサービス起動/停止操作が、docker pull
やdocker run
に変わったのと、さほど違いがない。
そこで『「Tomcatコンテナを起動して手動でwarをデプロイ」したあとの状態のイメージ』を作成して、いつでもアプリケーションの初期状態をrun
できるようにする。
これを作ることで再作成(再起動ではない)が容易になったり、アプリケーションをほかの環境へ配布したりすることができる。
Dockerfileの作成
カスタムイメージを作るにはDockerfile
を作り、docker build
する。
今回はOfficialのTomcatイメージにアプリケーションwarをcopyするだけのカスタムイメージを作る。
といってもこれだけ
FROM tomcat:8.5
COPY memoapp2.war /usr/local/tomcat/webapps/
FROM
がベースイメージの指定で、(デフォルト設定ではDockerHubのレジストリが指定されているので)Tomcatのイメージ名とタグ名を指定する。
COPY
でイメージに入れ込むファイルをコピーする。
同様のコマンドにADD
があり、こちらは単純なファイルコピーだけでなく、web上のファイルを指定してイメージに組み込むこともできる。
本来はこれ以外にもCMD
やENTRYPOINT
でコンテナ起動後に実行するコマンドを指定したり、アプリケーションが使用するポート番号指定のEXPOSE
などあるが、この辺りはベースイメージ(今回FROM
で指定したtomcat:8.5
)のものが継承されるため、指定していない。
(※ 素のdebianやcentosをベースに必要なパッケージをapt
やyum
でRUN
コマンドでインストールして、、、みたいに作る場合は、実行するコマンドの指定をする)
- Dockerfile リファレンス — Docker-docs-ja 17.06.Beta ドキュメント
- Dockerfile のベストプラクティス — Docker-docs-ja 1.9.0b ドキュメント
イメージのビルド
root@chaource:~/docker# docker build -t memoapp2 .
Sending build context to Docker daemon 3.908MB
Step 1/2 : FROM tomcat:8.5
---> 7ee26c09afb3
Step 2/2 : COPY memoapp2.war /usr/local/tomcat/webapps/
---> 598d605d24ce
Successfully built 598d605d24ce
Successfully tagged memoapp2:latest
root@chaource:~/docker#
warを入れるだけだと秒で完了する。
できたイメージがこちら。(タグ名を指定しなかったのでlatest
になっている)
root@chaource:~/docker# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
memoapp2 latest 598d605d24ce 10 seconds ago 466MB
カスタムイメージからコンテナ起動
カスタムイメージはあくまでコンテナの中身のカスタムを行っているので、コンテナの起動/実行に関するオプション(ネットワークの指定など)は指定が必要。
素のTomcatコンテナの起動に18080
ポートを使っているので、今度は18081
で起動
root@chaource:~/docker# docker run --network memoapp-network -p 18081:8080 -d memoapp2
4255587eb565b20e040c50ea3516900a5bb96d99b23cc8549868d7e9d0c76c99
root@chaource:~/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4255587eb565 memoapp2 "catalina.sh run" 4 seconds ago Up 3 seconds 0.0.0.0:18081->8080/tcp reverent_mahavira
アクセス先DBが同じなので、先に起動して実行したアプリケーションで登録したデータが見えている。
追加もOK
Docker Compose
ここまでで「DBコンテナ」「APサーバコンテナ」の二つを連携させたが、大きなシステムほど構成要素が増え、また依存関係(APの前にDBが起動してないといけない、とか)もでてくる。
これを手動で管理するのは大変だし、シェルスクリプト作ってでできなくもないけど、Docker ComposeというYAMLファイルで構成を定義して起動や停止などを管理できる機能があるので、それについて。
インストール
Docker本体に入ってないのでインストールする。
Ubuntuだとapt
で入る
root@chaource:~# apt install docker-compose
root@chaource:~# docker-compose version
docker-compose version 1.17.1, build unknown
docker-py version: 2.5.1
CPython version: 2.7.15rc1
OpenSSL version: OpenSSL 1.1.0g 2 Nov 2017
APとDBのコンテナをデプロイするYAMLファイル
書式はだいたいここ
すでにdocker run
で起動確認できているmysql:5.7
と作成済みカスタムイメージmemoapp2:latest
に対して、次のようにdocker-compose.yml
ファイルを作成する
version: '3'
services:
memoapp:
image: memoapp2:latest
ports:
- 18082:8080
memoapp-db:
image: mysql:5.7
environment:
- MYSQL_DATABASE=memoapp_db
- MYSQL_USER=memoapp
- MYSQL_PASSWORD=memoapp
- MYSQL_RANDOM_ROOT_PASSWORD=yes
command: mysqld --character-set-server=utf8
実行
root@chaource:~/docker# docker-compose up -d
Creating network "docker_default" with the default driver
Creating docker_memoapp-db_1 ...
Creating docker_memoapp_1 ...
Creating docker_memoapp-db_1
Creating docker_memoapp-db_1 ... done
root@chaource:~/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2c8be6cb4308 memoapp2:latest "catalina.sh run" 24 seconds ago Up 23 seconds 0.0.0.0:18082->8080/tcp docker_memoapp_1
5e18c0aca11d mysql:5.7 "docker-entrypoint.s…" 24 seconds ago Up 22 seconds 3306/tcp, 33060/tcp docker_memoapp-db_1
root@chaource:~/docker# docker exec -it docker_memoapp_1 bash
root@2c8be6cb4308:/usr/local/tomcat# ping memoapp-db
PING memoapp-db (172.20.0.3) 56(84) bytes of data.
64 bytes from docker_memoapp-db_1.docker_default (172.20.0.3): icmp_seq=1 ttl=64 time=0.181 ms
64 bytes from docker_memoapp-db_1.docker_default (172.20.0.3): icmp_seq=2 ttl=64 time=0.087 ms
64 bytes from docker_memoapp-db_1.docker_default (172.20.0.3): icmp_seq=3 ttl=64 time=0.080 ms
64 bytes from docker_memoapp-db_1.docker_default (172.20.0.3): icmp_seq=4 ttl=64 time=0.091 ms
^C
--- memoapp-db ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3052ms
rtt min/avg/max/mdev = 0.080/0.109/0.181/0.043 ms
root@2c8be6cb4308:/usr/local/tomcat# exit
root@chaource:~/docker#
docker-compose.ymlでは明示的に記述しなかったが、何も書かなかったらdocker_default
というネットワークが作成され、そのネットワーク上でコンテナ間通信ができるようになる。
停止(破棄)するには
root@chaource:~/docker# docker-compose down
Stopping docker_memoapp_1 ... done
Stopping docker_memoapp-db_1 ... done
Removing docker_memoapp_1 ... done
Removing docker_memoapp-db_1 ... done
Removing network docker_default
root@chaource:~/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@chaource:~/docker#
綺麗になりました。
APイメージのビルドも含めてYAMLで定義
前段では作成済みカスタムイメージができている状態で、それをデプロイするだけの定義だったが、カスタムビルドをビルドする処理も含めてDocker Composeで定義することもできる。
ディレクトリ構成
イメージのビルドに関連するファイルのディレクトリ構成はこの通り
.
├── docker
│ ├── docker-compose.yml
│ └── Dockerfile
└── target
└── memoapp2.war
Dockerfileの仕様で、COPY
はカレントディレクトリ以下のファイルしか扱えない。
そのため、dockerディレクトリから../target/memoapp2.war
というパスのCOPYはできない。
じゃあどうするかというと、docker-compose.yml
の定義で、「どのディレクトリを基準とするか」を定義するcontext
という設定項目があるので、これを..
つまりdocker
やtarget
ディレクトリのあるディレクトリが基準となるよう設定する。
そしてdockerfile
のDockerfileのある場所の指定で、docker/Dockerfile
と指定する。
Dockerfileの中のwarファイルのCOPY
処理は、基準がtarget
の上位ディレクトリなので、target/memoapp2.war
をCOPY
できるようになる。
(うまく説明できない)
docker-compose.yml
ビルドを定義するにはbuild
で定義を記述する。
version: '3'
services:
memoapp:
build:
context: ..
dockerfile: docker/Dockerfile
image: memoapp:latest
ports:
- 18082:8080
memoapp-db:
image: mysql:5.7
environment:
- MYSQL_DATABASE=memoapp_db
- MYSQL_USER=memoapp
- MYSQL_PASSWORD=memoapp
- MYSQL_RANDOM_ROOT_PASSWORD=yes
command: mysqld --character-set-server=utf8
Dockerfile
FROM tomcat:8.5
COPY target/memoapp2.war /usr/local/tomcat/webapps/
ビルドとデプロイ
root@chaource:~/src/javaee-memoapp2/docker# docker-compose up -d
Creating network "docker_default" with the default driver
Building memoapp
Step 1/2 : FROM tomcat:8.5
---> 7ee26c09afb3
Step 2/2 : COPY target/memoapp2.war /usr/local/tomcat/webapps/
---> 2cd39d9db4c2
Successfully built 2cd39d9db4c2
Successfully tagged memoapp:latest
WARNING: Image for service memoapp was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating docker_memoapp_1 ...
Creating docker_memoapp-db_1 ...
Creating docker_memoapp_1
Creating docker_memoapp_1 ... done
root@chaource:~/src/javaee-memoapp2/docker#
root@chaource:~/src/javaee-memoapp2/docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee586da83b13 mysql:5.7 "docker-entrypoint.s…" 17 seconds ago Up 15 seconds 3306/tcp, 33060/tcp docker_memoapp-db_1
4d114d7a8376 memoapp:latest "catalina.sh run" 17 seconds ago Up 15 seconds 0.0.0.0:18082->8080/tcp docker_memoapp_1
(画面は同じなのでもう省略するね。。)