概要
Dockerの使い方を学習したまとめ記事です。内容は以下の4つのパートに分けています。
- その1: 基本的なコマンドの使い方
- その2: Dockerfileからイメージをビルド
- その3: 複数コンテナの連携
- その4: docker-composeの使い方
環境
- Windows 10 Professional
- PowerShell 5.1
- Docker for Windows Community Edition Version 17.06.2-ce-win27
参考
- [Get started with Docker for Windows] (https://docs.docker.com/docker-for-windows/)
- [開発環境をDockerに乗せる方法とメリットを3ステップで学ぶチュートリアル] (https://qiita.com/KeitaMoromizato/items/ae1a57fc62b41b942d71)
- [[Docker] 初心者が知っておくと便利かもしれない15の知識] (https://qiita.com/enta0701/items/b872eef6d910908c0e6c)
インストール
ダウンロードページよりWindows版のインストーラーをダウンロードして実行します。特に選択する項目はなくすぐに終了しました。インストール終了画面のメッセージ(Close and log out)にしたがってインストール終了後に一度ログインしなおします。
インストール終了
Welcome画面
再ログイン後にWelcome画面が立ち上がります。
インストール後の設定
リソースの割り当て
タスクトレイにあるDockerアイコンを右クリックしコンテキストメニューから"Settings..."を選択します。
左ペインのAdvancedを選択しDockerで使用できるリソースを割り当てます。
共有ドライブの設定
Shared Drivesからコンテナから利用できるドライブを設定します。今のところ(2017/10)ディレクトリ単位での設定はできないようです。ApplyボタンをクリックするとWindowsアカウントのパスワードを求められますので入力して設定が完了します。
バージョンの確認
この記事ではdockerコマンドの実行にPowerShellを使用しています。PowerShellの起動はWin + Rで「ファイル名を指定して実行」の欄に"powershell"と入力します。
PowerShellのバージョンの確認
PS> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.15063.608
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.15063.608
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
dockerのバージョン確認
PS> docker version
Client:
Version: 17.06.2-ce
API version: 1.30
Go version: go1.8.3
Git commit: cec0b72
Built: Tue Sep 5 19:57:19 2017
OS/Arch: windows/amd64
Server:
Version: 17.06.2-ce
API version: 1.30 (minimum version 1.12)
Go version: go1.8.3
Git commit: cec0b72
Built: Tue Sep 5 19:59:19 2017
OS/Arch: linux/amd64
Experimental: true
docker-composeのバージョン確認
PS> docker-compose version
docker-compose version 1.14.0, build c7bdf9e3
docker-py version: 2.3.0
CPython version: 2.7.13
OpenSSL version: OpenSSL 1.0.2j 26 Sep 2016
docker-machineのバージョン確認
- この記事では使用しません。
PS> docker-machine version
docker-machine.exe version 0.12.2, build 9371605
その1: 基本的なコマンドの使い方
[ubuntu] (https://hub.docker.com/_/ubuntu/)のイメージを使って基本的なdockerコマンドの使い方を確認します。
イメージのダウンロード (pull)
名前:タグで指定するイメージをレジストリからダウンロードします。
PS> docker pull ubuntu:17.10
イメージを一覧表示 (images)
PS> docker images
イメージIDだけ表示 (images -q)
PS> docker images -q
コンテナの実行 (run)
名前:タグで指定するイメージから新しいコンテナ作成して実行します。コンテナに名前を付けたい場合はオプションに--name
で指定します。
PS> docker run --name my-ubuntu -it ubuntu:17.10 bash
実行後にコンテナを削除したい場合はオプションに--rm
を指定します。
PS> docker run --rm -it ubuntu:17.10 bash
実行中のコンテナを一覧表示 (ps)
PS> docker ps
すべてのコンテナを一覧表示 (ps -a)
PS> docker ps -a
コンテナIDだけ表示 (ps -q)
PS> docker ps -q
実行中のコンテナを停止 (stop)
停止するコンテナのIDまたはコンテナ名を指定します。この例ではコンテナ名(my-ubuntu)を指定しています。
PS> docker stop my-ubuntu
停止中のコンテナを起動 (start)
停止中のコンテナをコンテナのIDまたはコンテナ名を指定して再起動します。この例ではコンテナ名(my-ubuntu)を指定しています。
PS> docker start my-ubuntu
実行中のコンテナで指定するコマンドを実行 (exec)
この例では実行中のコンテナでbash
を実行します。
PS> docker exec -it my-ubuntu bash
この例ではapt-get update
でパッケージを更新します。
PS> docker exec my-ubuntu apt-get update
コンテナの削除 (rm)
コンテナを削除するにはコンテナIDまたはコンテナ名を指定します。この例ではコンテナIDを指定しています。
PS> docker ps -a -q
d035184f4ba2
PS> docker rm d035184f4ba2
イメージの削除 (rmi)
イメージを削除するにはイメージIDまたは名前:タグを指定します。この例ではイメージIDを指定しています。
PS> docker images -q
2e8302ea9a68
PS> docker rmi 2e8302ea9a68
Dockerfileやdocker-compose.ymlでビルドを行っているとREPOSITORY:TAGが<none>:<none>
というイメージが出来ていることがあります。
このイメージを一覧表示するには以下のコマンドを実行します。
PS> docker images --filter "dangling=true"
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> c09af2b1125c 17 hours ago 197MB
<none> <none> 45f8e04c9735 17 hours ago 420MB
一括削除するにはオプション-q
を付けてイメージIDだけを出力するようにします。
PS> docker rmi $(docker images -q --filter "dangling=true")
停止中のコンテナをすべて削除 (container prune)
PS> docker container prune -f
他にPowerShellの式展開「$(式)
」を使う方法があります。
PS> docker rm $(docker ps -a -q)
その2: Dockerfileからビルドする
Dockerfileからカスタマイズしたイメージを作成します。
Dockerfileの作成
適当なディレクトリに作成し、そこに下記の内容のDockerfileを作成します。
FROM ubuntu:16.04
ENV LANG ja_JP.utf8
ENV TZ Asia/Tokyo
RUN apt-get update \
&& apt-get install -y vim locales tzdata \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8 \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& dpkg-reconfigure --frontend noninteractive tzdata
CMD ["/bin/bash"]
- もともとUbuntu 17.10で確認していたのですがタイムゾーンの設定がうまく出来なかったので16.04に下げました。
イメージのビルド (build)
オプション-t, --tag
でイメージにユーザー名/名前:タグを指定できます。
PS> docker build -t rubytomato/ubuntu:0.0.1 .
任意のファイル名のDockerfileを使いたい場合はオプション-f
で指定します。
PS> docker build -f Dockerfile-test -t rubytomato/ubuntu:0.0.1 .
ビルドしたイメージの確認
PS> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rubytomato/ubuntu 0.0.1 7f75f1fbe69a About a minute ago 194MB
コンテナの実行
この例ではオプション-d
を指定してコンテナをデタッチしています。
PS> docker run --name my-ubuntu -it -d rubytomato/ubuntu:0.0.1
デタッチしたコンテナにはattachコマンドでアタッチすることができます。
PS> docker attach my-ubuntu
アタッチすればコンテナ内で任意の操作を行うことができます。
バージョンの確認
# cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.3 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.3 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
localeの確認
# locale
LANG=ja_JP.utf8
LANGUAGE=
LC_CTYPE="ja_JP.utf8"
LC_NUMERIC="ja_JP.utf8"
LC_TIME="ja_JP.utf8"
LC_COLLATE="ja_JP.utf8"
LC_MONETARY="ja_JP.utf8"
LC_MESSAGES="ja_JP.utf8"
LC_PAPER="ja_JP.utf8"
LC_NAME="ja_JP.utf8"
LC_ADDRESS="ja_JP.utf8"
LC_TELEPHONE="ja_JP.utf8"
LC_MEASUREMENT="ja_JP.utf8"
LC_IDENTIFICATION="ja_JP.utf8"
LC_ALL=
timezoneの確認
# date
2017年 10月 3日 火曜日 19:21:09 JST
イメージをDocker Hubへプッシュする
先にDocker Hubでリポジトリを作成しておきます。
リポジトリ名を入力します。今回はubuntuをカスタマイズしたイメージなので"ubuntu"としました。
リポジトリが出来たので次に作成したイメージをプッシュします。
プッシュするためにログインします。
PS> docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: rubytomato
Password: **********
Login Succeeded
イメージをプッシュします。
PS> docker push rubytomato/ubuntu:0.0.1
The push refers to a repository [docker.io/rubytomato/ubuntu]
//...省略
プッシュに成功したら、Docker HubのDashboardページで確認します。
Docker Hubにプッシュしておけば、あとは他のイメージと同様にダウンロードすることができます。
PS> docker pull rubytomato/ubuntu:0.0.1
その3: 複数のコンテナを連携させる
dockerコマンドを使って複数のコンテナから成るアプリケーションの実行環境を構築します。
動作検証用のアプリケーションはSpring Bootで開発したRest APIアプリケーションです。
コンテナ名 | イメージ:タグ | ポート |
---|---|---|
mysql-server | mysql:5.7.19 | 3306 |
app-server | openjdk:8u131-jdk-alpine | 9000 |
nginx-server | nginx:1.13.5-alpine | 80:80 |
ネットワークの作成
これから作成する各コンテナが接続するネットワークを作成します。
PS> docker network create --driver bridge my-network
ネットワークの一覧
NAMEがbride,host,noneはデフォルトで作成されているネットワークです。
PS> docker network ls
NETWORK ID NAME DRIVER SCOPE
37b1a0338435 bridge bridge local
077244cb331b host host local
ec11b19b4f20 my-network bridge local
4b6c82e8b7a5 none null local
ネットワークの状態
作成した直後のネットワークの状態を確認します。まだこのネットワークに接続しているコンテナは無いのでContainersは空になっています。
PS> docker network inspect my-network
[
{
"Name": "my-network",
"Id": "ec11b19b4f20b50851d829cfb8ae2d734e08c8b823d45b074a2c28575de46e8f",
"Created": "2017-10-03T22:43:37.5049737Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
ネットワークの削除
PS> docker network rm my-network
DBコンテナの作成
イメージのダウンロード
officialの[mysql-server] (https://hub.docker.com/r/mysql/mysql-server/)で公開されているイメージを利用します。
PS> docker pull mysql:5.7.19
コンテナの実行
データを永続化したいのでオプション-v
でデータディレクトリを共有します。
この例ではD:/dev/docker-volume/mysql-5.7.19/data
とコンテナ上の/var/lib/mysql
をマップしています。
ちなみにPowerShellで改行するにはバッククォート(`)を使用します。
PS> docker run --name mysql-server `
-v D:/dev/docker-volume/mysql-5.7.19/data:/var/lib/mysql `
-e MYSQL_ROOT_PASSWORD=password `
-e TZ=Asia/Tokyo `
--network my-network `
-d `
mysql:5.7.19 --character-set-server=utf8 --collation-server=utf8_general_ci --explicit-defaults-for-timestamp=1 --default-time-zone='+9:00'
ログの確認
データディレクトリを共有すると(環境にもよると思いますが)初回のMySQLの起動に時間が掛かります。これは物理的なデータファイルの作成に時間がかかっているためのようですが、psコマンドでコンテナのステータスを確認すると起動しているように見えます。
PS> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9dc09ba82ff8 mysql:5.7.19 "docker-entrypoint..." 9 seconds ago Up 8 seconds 3306/tcp mysql-server
しかし実際には、起動中なためMySQL Clientなどで接続しようとすると失敗します。このため実際に起動完了しているかどうかはログを確認します。
PS> docker logs --follow --tail 20 mysql-server
このような感じのログが出力されていればMySQL Serverの起動が完了していると思います。
//...省略
[Note] mysqld: ready for connections.
Version: '5.7.19' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
[Note] Executing 'SELECT * FROM INFORMATION_SCHEMA.TABLES;' to get a list of tables using the deprecated partition engine. You may use the startup option '--disable-partition-engine-check' to skip this check.
[Note] Beginning of list of non-natively partitioned tables
[Note] End of list of non-natively partitioned tables
MySQL Clientから接続
別のコンテナを立ち上げてそこから実行するMySQL Clientで接続します
PS> docker run `
--network my-network `
-it `
--rm `
mysql:5.7.19 sh -c 'exec mysql -h mysql-server -P 3306 -uroot -p'
オプションが反映されていることを確認します。
mysql> show variables like '%character%';
+--------------------------+----------------------------+
| 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.01 sec)
mysql> show variables like '%zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | JST |
| time_zone | +09:00 |
+------------------+--------+
2 rows in set (0.00 sec)
動作検証用アプリケーションで使用するDBの作成
補足の動作検証用アプリケーションで使用するDBの内容で、データベース、ユーザー、テーブルを作成します。
コンテナの停止、起動
コンテナを停止するにはstopコマンドを使用します。
PS> docker stop mysql-server
コンテナが作成できていれば以降はstartコマンドで起動することができます。
PS> docker start mysql-server
APPコンテナの準備
Javaアプリケーションを実行するためのコンテナです。また、コンテナ実行時にJavaアプリケーションを実行するのではなく、コンテナとは別のタイミングで実行するようにします。
イメージのダウンロード
officialの[openjdk] (https://hub.docker.com/_/openjdk/)で公開されているイメージを利用します。
PS> docker pull openjdk:8u131-jdk-alpine
バージョンの確認
PS> docker run --rm openjdk:8u131-jdk-alpine java -version
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (IcedTea 3.4.0) (Alpine 8.131.11-r2)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
コンテナの実行
アプリケーションのプロジェクトディレクトリを共有しコンテナ内からアプリケーションのビルドおよび起動・停止が行えるようにします。
この例ではD:/dev/IdeaProjects/demo
にあるプロジェクトディレクトリをコンテナ上の/app
にマップしています。
PS> docker run `
--name app-server `
-v D:/dev/IdeaProjects/demo:/app:rw `
--network my-network `
-it `
-d `
openjdk:8u131-jdk-alpine sh
アプリケーションの起動
Windows環境側で実行可能なjarをビルドしておけば、下記のコマンドでアプリケーションを起動できます。
PS> docker exec -it app-server java -jar '-Dspring.profiles.active=docker' /app/target/demo.jar
コンテナ内でビルド、起動・停止を行う
コンテナにアクセスします。
PS> docker exec -it app-server sh
mavenプラグインを使ってアプリケーションを起動する方法
# cd /app
# ./mvnw spring-boot:run -Drun.profiles=docker
ビルドしたjarを使ってアプリケーションを起動する方法
# cd /app
# ./mvnw clean package -Dmaven.test.skip=true
# java -jar -Dspring.profiles.active=docker target/demo.jar
WEBコンテナの準備
イメージのダウンロード
officialの[nginx] (https://hub.docker.com/_/nginx/)で公開されているイメージを利用します。
PS> docker pull nginx:1.13.5-alpine
動作確認のため、コンテナを実行してブラウザでページにアクセスしてみます。
PS> docker run --name my-nginx --rm -d -p 80:80 nginx:1.13.5-alpine nginx-debug -g 'daemon off;'
ブラウザからlocalhostにアクセスして下図のページが表示されることを確認します。
確認出来たらコンテナを停止させます。
PS> docker stop my-nginx
コンテナの実行
クライアントからのアクセスをAPPサーバーへプロキシするのでjava-appコンテナと連携します。
この例ではAPPサーバーへプロキシさせるconfファイルをD:/dev/docker-volume/nginx-1.13.5/conf.d
に配置し、このディレクトリとコンテナ上の/etc/nginx/conf.d
とマップさせています。
PS> docker run `
--name nginx-server `
-v D:/dev/docker-volume/nginx-1.13.5/conf.d:/etc/nginx/conf.d:ro `
--network my-network `
-p 80:80 `
-d `
nginx:1.13.5-alpine
設定ファイル
アプリケーションサーバーへのプロキシ設定を下記内容のdefault.confファイルに記述しました。
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
location /app/ {
proxy_pass http://app-server:9000/app/;
proxy_redirect off;
proxy_cookie_path /app /;
}
}
3つのコンテナが立ち上がった状態
上記の内容で実行したコンテナが立ち上がっている状態です。
PS> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b98e5fce9bb4 nginx:1.13.5-alpine "nginx -g 'daemon ..." 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp nginx-server
c0bfc8bef336 openjdk:8u131-jdk-alpine "sh" 4 minutes ago Up 4 minutes app-server
2c2eb4d0e040 mysql:5.7.19 "docker-entrypoint..." 6 minutes ago Up 6 minutes 3306/tcp mysql-server
作成したネットワークに上記3つのコンテナが接続されていることが確認できます。
PS> docker network inspect my-network
[
{
"Name": "my-network",
"Id": "ec11b19b4f20b50851d829cfb8ae2d734e08c8b823d45b074a2c28575de46e8f",
"Created": "2017-10-03T22:43:37.5049737Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"2c2eb4d0e040d523a911b7f875b6a77799cc38d2b502533c6fc999d2dd828b4e": {
"Name": "mysql-server",
"EndpointID": "54bcfb53d937fbc2d56f533335cb7239327c2dbe62cbf7428c8aaef3be40bac7",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"b98e5fce9bb4ac0ef13b6d899bc69b2bcd0ec7a93f601568b2e6b4c52916a75a": {
"Name": "nginx-server",
"EndpointID": "7fb9c4b8448fab4a28c8d13fe91db75553d734999305b78f9c9e06389ecc32d6",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": ""
},
"c0bfc8bef3361a4cc92c8b6271986b78d12e31f32e08356c01cf5d0d30370743": {
"Name": "app-server",
"EndpointID": "471ee5e713b606a0c3d487acd2d27406ba7bd13a9c34efa53e1220ae60e0a594",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
アプリケーションの動作確認
ブラウザから下記のアドレスにアクセスしてjsonのレスポンスが返ってくることを確認します。
localhost/app/memo/list
localhost/app/memo/id/1
動作確認できたらコンテナ停止、削除します。
PS> docker stop nginx-server app-server mysql-server
PS> docker rm nginx-server app-server mysql-server
その4: docker-composeの使い方
その3で構築した環境をdocker-composeを使って構築してみます。
(これまでに作成したネットワーク、イメージ、コンテナはすべて削除して行いました。)
プロジェクトの構造
docker-compose.ymlの他、各コンテナのイメージをビルドするためのDockerfileやコンテナにコピーするファイルを管理するプロジェクトです。
複数メンバーで開発環境を共有する場合、このプロジェクトをVCSで管理するという想定です。各自でdockerをインストールし、このプロジェクトをチェックアウトしdocker-composeで環境を構築します。
/root
|
+--- docker-compose.yml
|
+--- /mysql
| |
| +--- Dockerfile
| |
| +--- /conf
| | |
| | +--- mysqld.cnf
| |
| +--- /sql
| |
| +--- 1_schema.sql
| +--- 2_init_memo_data.sql
|
+--- /app
| |
| +--- Dockerfile
|
+--- /nginx
|
+--- Dockerfile
|
+--- /conf
| |
| +--- default.conf
|
+--- /repo
|
+--- nginx.repo
docker-compose.yml
version: "3"
services:
db:
container_name: mysql-server
build:
context: ./mysql
volumes:
- dbdata:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=password
networks:
- my-network
restart: always
app:
container_name: app-server
build:
context: ./app
volumes:
- ${PROJECT_HOME}:/app
environment:
- SPRING_PROFILES_ACTIVE=docker
depends_on:
- db
networks:
- my-network
restart: always
tty: true
web:
container_name: nginx-server
build:
context: ./nginx
depends_on:
- app
ports:
- 80:80
networks:
- my-network
restart: always
networks:
my-network:
driver: bridge
volumes:
dbdata:
driver: local
app-serverコンテナが参照するローカルのプロジェクトディレクトリを${PROJECT_HOME}
という変数で定義しています。
この変数の値は環境変数で設定します。
PowerShellで環境変数を定義するにはset-itemを使用します。
(この方法だとPowerShellを立ち上げるたびに定義しないといけないので、PCのシステムプロパティに登録するか$PROFILEに記述した方が便利です。)
PS> set-item env:PROJECT_HOME -value D:\dev\IdeaProjects\demo
DBコンテナ
Dockerfile
コンテナ上の/etc/mysql/mysql.conf.d
へカスタマイズした設定ファイルを配置するとその内容が反映されます。
また、コンテナ上の/docker-entrypoint-initdb.d
にshまたはsqlファイルを配置するとそのファイルが実行されます。この例ではデータベース、ユーザー、テーブルの作成および初期データの投入を行っています。
FROM mysql:5.7.19
COPY ./conf/mysqld.cnf /etc/mysql/mysql.conf.d
COPY ./sql/1_schema.sql /docker-entrypoint-initdb.d
COPY ./sql/2_init_memo_data.sql /docker-entrypoint-initdb.d
RUN chmod 644 /etc/mysql/mysql.conf.d/mysqld.cnf
ENV TZ=Asia/Tokyo
conf
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
max_connections = 30
explicit_defaults_for_timestamp = 1
character_set_server = utf8
collation_server = utf8_general_ci
log_output = FILE
general_log = 1
log_queries_not_using_indexes = 1
log_slow_admin_statements = 1
log_syslog = 0
log_timestamps = SYSTEM
long_query_time = 3
slow_query_log = 1
general_log_file = /var/log/mysql/general_query_all.log
log-error = /var/log/mysql/error.log
slow_query_log_file = /var/log/mysql/slow_query.log
sql
補足の動作検証用アプリケーションで使用するDBに記載しています。
- 1_schema.sql
- 2_init_memo_data.sql
APPコンテナ
Dockerfile
FROM centos:7
RUN yum update -y && yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel && yum reinstall -y glibc-common && yum -y clean all
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
RUN unlink /etc/localtime
RUN ln -s /usr/share/zoneinfo/Japan /etc/localtime
EXPOSE 9000
WEBコンテナ
Dockerfile
FROM centos:7
COPY ./repo/nginx.repo /etc/yum.repos.d
RUN yum update -y && yum install -y --enablerepo=nginx nginx && yum reinstall -y glibc-common && yum -y clean all
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
RUN unlink /etc/localtime
RUN ln -s /usr/share/zoneinfo/Japan /etc/localtime
COPY ./conf/default.conf /etc/nginx/conf.d
RUN chmod 664 /etc/nginx/conf.d/default.conf
RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]
conf
APPサーバーへプロキスする設定を記述したconfファイルです。
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
location /app/ {
proxy_pass http://app-server:9000/app/;
proxy_redirect off;
proxy_cookie_path /app /;
}
}
repo
yumでnginxをインストールするのに必要なrepositoryの設定ファイルです。いまのところ(2017/10)この設定がないとyumでインストールできませんでした。
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
docker-composeコマンド
ビルド (build)
docker-compose.ymlのあるディレクトリで下記コマンドを実行してイメージをビルドします。
PS> docker-compose build
キャッシュを使わずにビルドする場合はオプション--no-cache
を指定します。
PS> docker-compose build --no-cache
起動 (up)
PS> docker-compose up -d
Creating volume "dockerdev_dbdata" with local driver
Creating network "dockerdev_my-network" with driver "bridge"
Creating mysql-server ...
Creating mysql-server ... done
Creating app-server ...
Creating app-server ... done
Creating nginx-server ...
Creating nginx-server ... done
イメージのビルドと起動を同時に行うこともできます。ビルドは変更のあるイメージに対してのみ行われます。
PS> docker-compose up --build -d
サービス名を指定して個別に起動する場合、他のサービスと依存関係があれば自動的にそれらのサービスも起動してくれます。
PS> docker-compose up -d app
Creating mysql-server ...
Creating mysql-server ... done
Creating app-server ...
Creating app-server ... done
一覧 (ps)
PS> docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
app-server /bin/bash Up 9000/tcp
mysql-server docker-entrypoint.sh mysqld Up 3306/tcp
nginx-server nginx -g daemon off; Up 0.0.0.0:80->80/tcp
任意のコマンドを実行 (exec)
各コンテナは起動していますがapp-serverではまだSpring Bootのアプリケーションは起動していません。
下記のexecコマンドでコンテナに接続してアプリケーションを起動します。なお、ここで指定しているappはコンテナ名ではなくサービス名です。
PS> docker-compose exec app bash
mavenプラグインでアプリケーションのビルドと実行を行います。その3ではプロファイルを指定していましたが、その4では環境変数(SPRING_PROFILES_ACTIVE)に定義しているため省略可能です。
# cd /app
# ./mvnw spring-boot:run
// ... 省略
INFO 151 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 9000 (http)
INFO 151 --- [ restartedMain] com.example.demo.DemoApplication : Started DemoApplication in 6.065 seconds (JVM running for 6.562)
アプリケーションの動作確認
各コンテナが連携していれば正常なレスポンスが返ってきます。
http://localhost/app/memo/list
http://localhost/app/memo/id/1
実行中のプロセスの確認 (top)
topコマンドで各サービスのプロセスを確認できます。
PS> docker-compose top
app-server
PID USER TIME COMMAND
-------------------------------
12625 root 0:00 /bin/bash
mysql-server
PID USER TIME COMMAND
-----------------------------
11915 999 0:00 mysqld
nginx-server
PID USER TIME COMMAND
----------------------------------------------------------------
12773 root 0:00 nginx: master process nginx -g daemon off;
12828 999 0:00 nginx: worker process
停止 (down)
PS> docker-compose down
Stopping nginx-server ... done
Stopping app-server ... done
Stopping mysql-server ... done
Removing nginx-server ... done
Removing app-server ... done
Removing mysql-server ... done
Removing network dockerdev_my-network
ログ (logs)
サービスが起動しないなどの原因を調べたい場合はlogsコマンドでログを確認します。
PS> docker-compose logs db
補足
[posh-docker] (https://github.com/samneirinck/posh-docker)のインストール
PowerShellでdockerコマンドのタブ補完を行ってくれる拡張機能です。Docker for Windowsを使う上で必須ではありませんが便利なのでインストールしています。
Powershell tab completion for Docker
NuGetが必要です。まだインストールされていない場合は、管理者権限でPowerShellを起動し下記コマンドを実行してインストールします。
PS> Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Name Version Source Summary
---- ------- ------ -------
nuget 2.8.5.208 https://onege... NuGet provider for the OneGet meta-package manager
続いて、下記コマンドでposh-dockerのインストールを行います。こちらは管理者権限でなくても大丈夫です。
PS> Install-Module -Scope CurrentUser posh-docker
信頼されていないリポジトリ
信頼されていないリポジトリからモジュールをインストールしようとしています。このリポジトリを信頼する場合は、Set-PSReposit
ory コマンドレットを実行して、リポジトリの InstallationPolicy の値を変更してください。'PSGallery'
からモジュールをインストールしますか?
[Y] はい(Y) [A] すべて続行(A) [N] いいえ(N) [L] すべて無視(L) [S] 中断(S) [?] ヘルプ (既定値は "N"): A
インストールできたら最後に下記コマンドを実行します。これでコマンドのタブ補完が有効になります。
この設定を永続化するためにこのコマンドを$PROFILEに書き込む必要があります。
PS> Import-Module posh-docker
$PROFILEに書き込むには下記の内容をPowerShellのコマンドプロンプトから実行します。
if (-Not (Test-Path $PROFILE)) {
New-Item $PROFILE –Type File –Force
}
Add-Content $PROFILE "`nImport-Module posh-docker"
$PROFILEがすでに存在する場合は、テキストエディタで直接編集することも可能です。プロンプトに$PROFLIE
と入力して実行するとファイルの存在場所がフルパスが表示されます。
PS> $PROFILE
実行ポリシーを変更する
スクリプトの実行ポリシーを変更しないと$PROFILEに加えた設定が実行されない場合があります。その場合は管理者権限で起動したPowerShellから下記のコマンドを実行して実行ポリシーを変更します。
PS> Set-ExecutionPolicy RemoteSigned
現在の実行ポリシーを確認する
PS> Get-ExecutionPolicy
インストールされているモジュールを確認
PS> Get-Module –ListAvailable
アンインストール
PS> Uninstall-Module posh-docker
$PROFILEに追加した行を削除
PS> notepad $PROFILE
動作検証用アプリケーションで使用するDB
アプリケーションサーバーで実行するSpring Bootアプリケーションが使用するデータベースおよびテーブルの情報です。
1_schema.sql
CREATE DATABASE sample_db DEFAULT CHARACTER SET = utf8mb4;
CREATE USER 'test_user'@'%' IDENTIFIED BY 'test_user' PASSWORD EXPIRE NEVER;
GRANT ALL ON sample_db.* TO 'test_user'@'%';
USE sample_db;
CREATE TABLE IF NOT EXISTS memo (
id BIGINT AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
done BOOLEAN DEFAULT FALSE NOT NULL,
updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) CHARACTER SET = utf8mb4, COLLATE utf8mb4_general_ci;
2_init_memo_data.sql
USE sample_db;
START TRANSACTION;
INSERT INTO memo (title, description, done, updated) VALUES ('Memo A', 'aISms0a02jsy47xk4kao28FlqUqnwl', false, '2017-10-01');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo B', 'i5hxoG8rm29quqububMr9gu1OQia75', false, '2017-10-02');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo C', '5L18coGlrHao3yz9xur8c9vpDhfu6o', true, '2017-10-02');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo D', 'Mw8Xu1itnr8fkdn4lbpWJfpe91mg71', false, '2017-10-03');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo E', 'Xl6ngkzic8w05orn6hc7b82hthXJrK', true, '2017-10-03');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo F', '5kspemtnWUQ94lemehf0f0aM482iqo', false, '2017-10-03');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo G', 'lB82Lq8riepbo395UejquBnbu40syd', false, '2017-10-04');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo H', 'ptye0qPrig7tyZh59Sut74Lqnwk4j3', true, '2017-10-05');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo I', '9d7sien1mgyxu37gI6nqHfhFmx95iV', true, '2017-10-06');
INSERT INTO memo (title, description, done, updated) VALUES ('Memo J', 'zPwyxLEp50am18quX0d7bnajeo1k2j', true, '2017-10-06');
COMMIT;
動作検証用アプリケーション
コンテナの動作検証用にRest APIアプリケーションをSpring Bootで開発しました。
以下にコントローラーのソースコードとpom.xml、application.ymlの内容を記載します。
アプリケーションはmemoテーブルのデータをjsonフォーマットでレスポンスする単純なRest APIです。
エンドポイントは下記の2つだけです。
localhost:9000/app/memo/list
localhost:9000/app/memo/id/{id}
コントローラー
@RestController
@RequestMapping(path = "memo", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Slf4j
public class MemoController {
private MemoService service;
@Autowired
public MemoController(MemoService service) {
this.service = service;
}
@GetMapping(path = "id/{id}")
public ResponseEntity<Memo> id(@PathVariable(value = "id") Long id) {
Memo memo = service.findById(id);
return new ResponseEntity<>(memo, HttpStatus.OK);
}
@GetMapping(path = "list")
public ResponseEntity<List<Memo>> title(Pageable page) {
Page<Memo> memos = service.findAll(page);
return new ResponseEntity<>(memos.getContent(), HttpStatus.OK);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>true</excludeDevtools>
<executable>true</executable>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<compilerVersion>1.8</compilerVersion>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-Xlint:all,-options,-path</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
# SPRING CORE
spring:
application:
name: demo
beaninfo:
ignore: true
# OUTPUT
output:
ansi:
enabled: detect
# PROFILES
profiles:
active: dev
# DATASOURCE
datasource:
url: jdbc:mysql://localhost:3306/sample_db?useSSL=false
username: test_user
password: test_user
driverClassName: com.mysql.jdbc.Driver
# JPA
jpa:
properties:
hibernate:
show_sql: true
format_sql: true
use_sql_comments: true
jackson:
serialization:
write-dates-as-timestamps: false
# EMBEDDED SERVER CONFIGURATION
server:
port: 9000
context-path: /app
logging:
level:
root: INFO
org.springframework: INFO
com.example: DEBUG
---
spring:
profiles: docker
datasource:
url: jdbc:mysql://mysql-server:3306/sample_db?useSSL=false
username: test_user
password: test_user
driverClassName: com.mysql.jdbc.Driver
Dockerfileの備忘
CMD、RUNの記述形式にはshell形式とexec形式の2通りあります。
CMD
shell形式
CMD command param1 param2
exec形式
CMD ["executable","param1","param2"]
RUN
shell形式
RUN <command>
exec形式
RUN ["executable", "param1", "param2"]