概要
この記事は以前に投稿した「[Docker for WindowsでDockerを学ぶ (バージョンCE 17.06.2)] (https://qiita.com/rubytomato@github/items/eec2118e89ee9bd8d17a)」を、2018年7月時点で最新のDocker for Windows Community Edition Version 18.03.1で改定した記事です。
環境
- Windows 10 Professional
- PowerShell 5.1
- Docker Community Edition 18.03.1-ce-win65
- API Version 1.37
参考
- [Get started with Docker for Windows] (https://docs.docker.com/docker-for-windows/)
- [Docker for Windows Stable Release notes] (https://docs.docker.com/docker-for-windows/release-notes/)
- [Docker run reference] (https://docs.docker.com/engine/reference/run/)
インストール
ダウンロードページよりWindows版のインストーラーをダウンロードして実行します。インストールが終了するとデスクトップにDockerアイコンが作成されますが、ここで一旦PCを再起動します。
インストール終了
Welcome
再起動すると自動的にDockerが開始されWelcome画面が立ち上がります。
Hyper-V
Hyper-Vマネージャで仮想マシン(MobyLinuxVM)が作成されていることを確認します。
(Hyper-Vマネージャはスタートメニューの"Windows 管理ツール" → "Hyper-Vマネージャ"でアクセスできます。またはスタートメニューから直接"Hyper-V"と入力して検索)
バージョンの確認
dockerのバージョン確認
PS> docker version
Client:
Version: 18.03.1-ce
API version: 1.37
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:12:48 2018
OS/Arch: windows/amd64
Experimental: false
Orchestrator: swarm
Server:
Engine:
Version: 18.03.1-ce
API version: 1.37 (minimum version 1.12)
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:22:38 2018
OS/Arch: linux/amd64
Experimental: false
docker-composeのバージョン確認
PS> docker-compose version
docker-compose version 1.21.1, build 7641a569
docker-py version: 3.2.1
CPython version: 3.6.4
OpenSSL version: OpenSSL 1.0.2k 26 Jan 2017
docker-machineのバージョン確認
- この記事では使用しません。
PS> docker-machine version
docker-machine.exe version 0.14.0, build 89b8332
インストール後の設定
タスクトレイにあるDockerアイコンを右クリックしコンテキストメニューから"Settings..."を選択します。
General
PC起動時にDockerが立ち上がらないように"Start Docker when you log in"のチェックを外しました。
リソースの割り当て
この記事では下図のようにリソースを割り当てました。ApplyボタンをクリックするとDockerが再起動します。
共有ドライブの設定
コンテナから利用できるドライブを設定します。今のところ(2018/07)ディレクトリ単位での設定はできないようです。ApplyボタンをクリックするとWindowsアカウントのパスワードを求められますので入力して設定が完了します。
ネットワーク
イメージのダウンロードができない場合などは、DNS Serverを8.8.8.8
に固定すると改善する場合があります。
基本的なdockerコマンドの使い方
docker 1.13よりコマンドのグループ化が行われ、以下の管理コマンド(Manage Command)へ再編成されています。(従来の(~1.12)コマンドも有効です。)
ただしdocker build
とdocker run
は再編後もtop level commandとして残っています。
またdocker network
やdocker volume
など1.13以前の段階でコマンドの体系がグループ化されていたものがあります。
参考
- Restructure CLI commands by adding docker image and docker container commands for more consistency [#26025] (https://github.com/moby/moby/pull/26025)
DOCKER_HIDE_LEGACY_COMMANDS
DOCKER_HIDE_LEGACY_COMMANDS
環境変数に1をセットすると、docker --helpの出力からレガシーコマンドを隠します。
PS> $env:DOCKER_HIDE_LEGACY_COMMANDS = 1
PS> docker --help
[docker image] (https://docs.docker.com/engine/reference/commandline/image/)
イメージのダウンロード (pull)
PS> docker image pull ubuntu:18.10
18.10: Pulling from library/ubuntu
//...省略...
Status: Downloaded newer image for ubuntu:18.10
イメージの一覧表示 (ls)
PS> docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.10 64a6a5be4188 3 days ago 70.1MB
イメージIDだけ表示 (ls -q)
PS> docker image ls -q
64a6a5be4188
イメージの削除 (rm)
イメージIDは半角スペースで区切って複数指定できます。
PS> docker image rm 64a6a5be4188
未使用イメージの削除 (prune)
PS> docker image prune
WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
イメージのビルド (build)
Dockerfileのあるディレクトリで下記のbuildコマンドを実行します。
PS> docker image build -t rubytomato/ubuntu:0.0.1 .
Sending build context to Docker daemon 2.048kB
Step 1/5 : FROM ubuntu:18.10
---> 64a6a5be4188
//...省略...
Successfully built 205ed036002c
Successfully tagged rubytomato/ubuntu:0.0.1
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permission
s. It is recommended to double check and reset permissions for sensitive files and directories.
Dockerfile
使用するDockerfile
FROM ubuntu:18.10
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"]
PS> docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
rubytomato/ubuntu 0.0.1 205ed036002c 3 minutes ago 146MB
ubuntu 18.10 64a6a5be4188 3 days ago 70.1MB
[docker container] (https://docs.docker.com/engine/reference/commandline/container/)
コンテナの実行 (run)
PS> docker run --name my-ubuntu -it ubuntu:18.10 bash
root@71e3519cab5c:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.10 (Cosmic Cuttlefish)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu Cosmic Cuttlefish (development branch)"
VERSION_ID="18.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=cosmic
UBUNTU_CODENAME=cosmic
root@71e3519cab5c:/# exit
exit
PS>
exitまたはCtrl + Dを押すとコンテナから抜け、コンテナは停止します。
コンテナを停止せずにコンテナから抜ける(デタッチ)にはCtrl + P + Qを押します。コンソールに"read escape sequence"と表示されコンテナから抜けることができます。
root@71e3519cab5c:/# read escape sequence
PS>
実行中コンテナの一覧表示 (ls)
PS> docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
94ad277059c4 ubuntu:18.10 "bash" 34 seconds ago Up 32 seconds my-ubuntu
すべてのコンテナの一覧表示 (ls -a)
PS> docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
94ad277059c4 ubuntu:18.10 "bash" 5 minutes ago Exited (0) 14 seconds ago my-ubuntu
コンテナIDだけ表示 (ls -q)
PS> docker container ls -q
94ad277059c4
実行中のコンテナを停止 (stop)
コンテナID又はコンテナ名は半角スペースで区切って複数指定できます。
PS> docker container stop my-ubuntu
my-ubuntu
停止中のコンテナを起動 (start)
コンテナID又はコンテナ名は半角スペースで区切って複数指定できます。
PS> docker container start my-ubuntu
my-ubuntu
コンテナの実行時にデタッチする (run -d)
-dオプションを付けてコンテナを実行するとデタッチします。デタッチするとコンテナはバックグラウンドで実行され制御がプロンプトに戻ります。
PS> docker run --name my-ubuntu -it -d ubuntu:18.10 bash
1777798c58e9cee397a1f623a60a5beba63b16f950a9e92c30ee1aad4adadc4c
PS>
コンテナにアタッチする (attach)
デタッチしたコンテナにアタッチします。
exitまたはCtrl + Dで抜けるとコンテナも停止します。
PS> docker container attach my-ubuntu
root@1777798c58e9:/#
実行中のコンテナで指定するコマンドを実行 (exec)
PS> docker container exec -it my-ubuntu bash
root@1777798c58e9:/#
コンテナの削除 (rm)
コンテナID又はコンテナ名は半角スペースで区切って複数指定できます。
PS> docker container rm my-ubuntu
my-ubuntu
停止中のコンテナをすべて削除 (prune)
PS> docker container prune -f
Deleted Containers:
71e3519cab5c87ed029e32b3096d864da059cd6dc018f485701b6f2f4f17ba83
Total reclaimed space: 25B
[docker volume] (https://docs.docker.com/engine/reference/commandline/volume/)
Child command | Notes |
---|---|
docker volume create | API 1.21+ |
docker volume inspect | API 1.21+ |
docker volume ls | API 1.21+ |
docker volume prune | API 1.25+ |
docker volume rm | API 1.21+ |
Docker volumeを作成 (create)
Docker volumeを作成します。
PS> docker volume create share_data
share_data
作成したvolumeをコンテナへマウントします。
PS> docker run --name c1 -it -d -v share_data:/share_data busybox sh
^^^^^^^^^^ ^^^^^^^^^^^
| |
| +--- コンテナのマウントポイント
+-------------- Docker volumeの名前
volumeは複数のコンテナで共有することができます。
PS> docker run --name c2 -it -d -v share_data:/share_data busybox sh
c1コンテナのマウントポイント(/share_data)でtest.txtというファイルを作成し、
PS> docker container exec -it c1 sh
/ # cd /share_data
/share_data # echo 'test from c1' > test.txt
c2コンテナのマウントポイント(/share_data)にtest.txtファイルが存在することを確認します。
PS> docker container exec -it c2 sh
/ # cd /share_data
/share_data # cat test.txt
test from c1
Docker volumeの一覧表示 (ls)
Docker volumeを一覧表示します。
PS> docker volume ls
DRIVER VOLUME NAME
local share_data
Docker volumeの詳細確認 (inspect)
PS> docker volume inspect share_data
[
{
"CreatedAt": "2018-07-20T22:31:58Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/share_data/_data",
"Name": "share_data",
"Options": {},
"Scope": "local"
}
]
Docker VolumeはDocker Host(Windows 10のHyper-Vを利用した環境ではMobyLinuxVMという仮想マシン)内に作成されます。上記のinspectの結果のMountpointはDocker Hostのディレクトリになります。
以下の方法でDocker Hostにアクセスして、Docker Volumeが存在するか確認してみます。
PS> docker run --net=host --ipc=host --uts=host --pid=host -it --security-opt=seccomp=unconfined --privileged --rm -v /:/host alpine /bin/sh
/ # chroot /host
/ # cd /var/lib/docker/volumes/share_data/_data
/var/lib/docker/volumes/share_data/_data # cat test.txt
test from c1
参考
- [How can I SSH into the Beta’s MobyLinuxVM] (https://forums.docker.com/t/how-can-i-ssh-into-the-betas-mobylinuxvm/10991)
Docker volumeの削除 (rm)
PS> docker volume rm share_data
share_data
コンテナにマウントしているvolumeは削除できません。
[docker network] (https://docs.docker.com/engine/reference/commandline/network/)
Child command | Notes |
---|---|
docker network connect | |
docker network create | |
docker network disconnect | |
docker network inspect | |
docker network ls | |
docker network prune | API 1.25+ |
docker network rm |
Docker networkの作成 (create)
PS> docker network create my-network
920d8c6fa442cc01c6ebf5e7a25be02ad636e9b44efa2014ab7279a3c720d4d0
コンテナの実行時に作成したnetworkへ参加させます。
PS> docker run --name c1 -it -d --network my-network busybox sh
PS> docker run --name c2 -it -d --network my-network busybox sh
この2つのコンテナは同一のセグメントに属しているのでpingで疎通確認ができます。
PS> docker exec -it c1 sh
/ # ping c2
PING c2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.134 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.133 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.114 ms
64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.115 ms
64 bytes from 172.18.0.3: seq=4 ttl=64 time=0.115 ms
^C
--- c2 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.114/0.122/0.134 ms
Docker networkの一覧表示 (ls)
bridge,host,noneはデフォルトで作成されているnetworkです。
PS> docker network ls
NETWORK ID NAME DRIVER SCOPE
05832b6662f4 bridge bridge local
deb5dd87efce host host local
920d8c6fa442 my-network bridge local
0b4c7027e5ec none null local
Docker networkの詳細表示 (inspect)
下記はmy-networkにc1、c2の2つのコンテナを参加させた状態でinspectした結果です。
結果の"Containers"にネットワークに参加しているコンテナが確認できます。
PS> docker network inspect my-network
[
{
"Name": "my-network",
"Id": "920d8c6fa442cc01c6ebf5e7a25be02ad636e9b44efa2014ab7279a3c720d4d0",
"Created": "2018-07-22T14:54:21.4393187Z",
"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": {
"0e2b1cb2190b04c6ae2e6ba178a01d1db6e8cd91364f8275722fd725d85606b0": {
"Name": "c2",
"EndpointID": "af87cd616d873959b58f5ffe44f2374eb508f9836f3cbd30c55f27a9bb643eb7",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"eb822a594258bd9c9b44b9aa3cb436d67ce995c09f881fa36c7341ccaa9ac6e1": {
"Name": "c1",
"EndpointID": "1a80a179fb27644d66fdf344dc16369d076c700783618ceae54e43144ce0718b",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
Docker networkへ接続 (connect)
networkに参加していないコンテナをnetworkへ接続させます。
PS> docker network connect my-network c1
Docker networkから切断 (disconnect)
networkに参加しているコンテナを切断します。
PS> docker network disconnect my-network c1
Docker networkの削除 (rm)
PS> docker network rm my-network
my-network
[docker system] (https://docs.docker.com/engine/reference/commandline/system/)
child command | Legacy command | Notes |
---|---|---|
docker system df | API 1.25+ | |
docker system events | [docker events] (https://docs.docker.com/engine/reference/commandline/events/) | |
docker system info | [docker info] (https://docs.docker.com/engine/reference/commandline/info/) | |
docker system prune | API 1.25+ |
ディスク使用量の確認 (df)
Dockerのディスク使用量を確認します。
PS> docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 8 2 1.475GB 1.029GB (69%)
Containers 3 2 171B 136B (79%)
Local Volumes 1 0 13B 13B (100%)
Build Cache 0B 0B
-vオプションを指定するとさらに詳細な内容が確認できます。
PS> docker system df -v
イベントの監視 (events)
特定のdockerコマンドで発生するイベントをリアルタイムに監視します。
最初にeventsコマンドを実行してイベント監視状態に入ります。
PS> docker system events
別のターミナルからdockerコマンドを実行すると、
PS> docker run --name c1 -it busybox sh
/ #
eventsコマンドを実行したターミナルにそのコマンドのイベントがリアルタイムに出力されます。
下記の結果は、上記のdocker run
コマンドのイベントです。
PS> docker system events
2018-07-23T00:32:35.501520700+09:00 container create 3be9867cb27d7070e75257998194ed4ebc3aad421e08a90559127cabf88a6e26 (i
mage=busybox, name=c1)
2018-07-23T00:32:35.504967300+09:00 container attach 3be9867cb27d7070e75257998194ed4ebc3aad421e08a90559127cabf88a6e26 (i
mage=busybox, name=c1)
2018-07-23T00:32:35.556587300+09:00 network connect 05832b6662f4186620418696aa5dccd311bc9bdec0b736c606d450039f058d41 (co
ntainer=3be9867cb27d7070e75257998194ed4ebc3aad421e08a90559127cabf88a6e26, name=bridge, type=bridge)
2018-07-23T00:32:35.987835600+09:00 container start 3be9867cb27d7070e75257998194ed4ebc3aad421e08a90559127cabf88a6e26 (im
age=busybox, name=c1)
2018-07-23T00:32:35.992184000+09:00 container resize 3be9867cb27d7070e75257998194ed4ebc3aad421e08a90559127cabf88a6e26 (h
eight=50, image=busybox, name=c1, width=207)
システム情報の確認 (info)
Dockerのシステム情報を確認します。
PS> docker system info
-fオプションで出力フォーマットを指定することができます。
下記はjsonで出力する例です。
PS> docker system info -f '{{json .}}'
その他のコマンド
管理コマンドに編成されていないtop level commandです。
[login] (https://docs.docker.com/engine/reference/commandline/login/)
Docker registryにログインします。
PS> docker login -u <username>
Password: *********
Login Succeeded
ログインするとDocker registryにローカルのイメージをpushすることができるようになります。
(pushするには先にDocker Hubでリポジトリを作成しておく必要があります。)
PS> docker push rubytomato/ubuntu:0.0.1
The push refers to repository [docker.io/rubytomato/ubuntu]
673dabc4635f: Pushed
2869bec4b1a5: Mounted from library/ubuntu
4a11639c84e2: Mounted from library/ubuntu
d6d789572265: Mounted from library/ubuntu
5eee0d150402: Mounted from library/ubuntu
0.0.1: digest: sha256:bb2f883ea6e512e21b95af8cc3f2bb399114fc88272ab2de19720ac7afa61fd0 size: 1362
[logout] (https://docs.docker.com/engine/reference/commandline/logout/)
Docker registryからログアウトします。
PS> docker logout
[search] (https://docs.docker.com/engine/reference/commandline/search/)
Docker Hubから条件を満たすイメージを検索します。
PS> docker search --filter is-official=true mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 6575 [OK]
mariadb MariaDB is a community-developed fork of MyS… 2080 [OK]
percona Percona Server is a fork of the MySQL relati… 350 [OK]
[version] (https://docs.docker.com/engine/reference/commandline/version/)
Dockerのバージョン情報を出力します。
PS> docker version
Client:
Version: 18.03.1-ce
API version: 1.37
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:12:48 2018
OS/Arch: windows/amd64
Experimental: false
Orchestrator: swarm
Server:
Engine:
Version: 18.03.1-ce
API version: 1.37 (minimum version 1.12)
Go version: go1.9.5
Git commit: 9ee9f40
Built: Thu Apr 26 07:22:38 2018
OS/Arch: linux/amd64
Experimental: false
複数のコンテナを連携させる
dockerコマンドを使って複数のコンテナで構成するJavaアプリケーションの実行環境を構築します。
コンテナ名 | 利用するイメージ:タグ | ポート |
---|---|---|
db-server | mysql:8.0.11 | 3306 |
app-server | openjdk:8u171-jdk-alpine3.8 | 9000 |
http-server | nginx:1.15.1-alpine | 80:80 |
networkの作成
これから作成する各コンテナが接続するnetworkを作成します。
PS> docker network create --driver bridge my-network
networkの一覧
PS> docker network ls
NETWORK ID NAME DRIVER SCOPE
3b7067f92b97 bridge bridge local
deb5dd87efce host host local
e0b994908c8c my-network bridge local
0b4c7027e5ec none null local
networkの状態
PS> docker network inspect my-network
[
{
"Name": "my-network",
"Id": "e0b994908c8c12f91a47a9cd7793994458e32313efff75eb7229560eb0467a64",
"Created": "2018-07-20T21:23:37.0589799Z",
"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": {}
}
]
volumeの作成
DBのデータを永続化するためのvolumeを作成します。
PS> docker volume create db_data
volumeの一覧
PS> docker volume ls
DRIVER VOLUME NAME
local db_data
DBサーバー用のコンテナを作成
MySQL Serverを実行するコンテナを作成します。データは永続化できるようにDocker volumeをマウントします。
イメージのダウンロード
officialの[mysql-server] (https://hub.docker.com/r/mysql/mysql-server/)で公開されているイメージを利用します。
PS> docker image pull mysql:8.0.11
8.0.11: Pulling from library/mysql
// ...省略...
Status: Downloaded newer image for mysql:8.0.11
コンテナの実行
PS> docker run --name db-server `
-v db_data:/var/lib/mysql `
-e MYSQL_ROOT_PASSWORD=password `
-e TZ=Asia/Tokyo `
--network my-network `
-d `
mysql:8.0.11 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --default-time-zone='+9:00'
DBサーバーが起動したかログで確認
container lsコマンドで確認するとDBサーバーが起動しているように見えますが、実際には起動中の場合があるのでログで確認します。
PS> docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb0f360d84fc mysql:8.0.11 "docker-entrypoint.s…" 27 seconds ago Up 25 seconds 3306/tcp db-server
container logsコマンドでログの出力を監視します。
下記のようなログ(ready for connections. ...)が出力されていればDBサーバーの起動は完了しています。
PS> docker container logs --follow --tail 20 db-server
//...省略...
2018-07-20T21:27:15.538249Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.11' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Serve
r - GPL.
コンテナのシェルにアクセス
コンテナのシェルにアクセスして、コンテナ内からDBサーバーにログインします。
PS> docker exec -it db-server bash
root@eb0f360d84fc:/# mysql -h localhost -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.11 MySQL Community Server - GPL
Copyright (c) 2000, 2018, 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>
mbind: Operation not permitted
ログにmbind: Operation not permitted
というメッセージが出力されることがあります。
[mysql 8.0.11 docker: mbind: Operation not permitted] (https://github.com/docker-library/mysql/issues/422)
動作検証用アプリケーションで使用するDBスキーマの作成
補足欄に記載しているSQLで、データベース、ユーザー、テーブルを作成します。
コンテナの停止、起動
container stopコマンドでコンテナを停止します。
PS> docker container stop db-server
container startコマンドでコンテナを起動します。
PS> docker container start db-server
APPサーバー用のコンテナを作成
Javaアプリケーションを実行するためのコンテナです。コンテナ実行時にJavaアプリケーションを実行するのではなく、任意のタイミングで実行するようにします。
イメージのダウンロード
officialの[openjdk] (https://hub.docker.com/_/openjdk/)で公開されているイメージを利用します。
PS> docker image pull openjdk:8u171-jdk-alpine3.8
8u171-jdk-alpine3.8: Pulling from library/openjdk
//...省略...
Status: Downloaded newer image for openjdk:8u171-jdk-alpine3.8
Javaのバージョン確認
PS> docker run --rm openjdk:8u171-jdk-alpine3.8 java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (IcedTea 3.8.0) (Alpine 8.171.11-r0)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)
実行するJavaアプリケーション
コンテナの連携を確認するために使用するJavaアプリケーションはSpring-Bootを利用したRest APIアプリケーションです。詳細は補足欄に記載しています。
コンテナの実行
ローカルPC上のアプリケーションのプロジェクトディレクトリをコンテナと共有し、コンテナ内からアプリケーションのビルドおよび起動・停止が行えるようにします。
この例ではD:/dev/IdeaProjects/demo
というプロジェクトディレクトリをコンテナの/app
にマウントしています。
PS> docker run `
--name app-server `
-v D:/dev/IdeaProjects/demo:/app:rw `
--network my-network `
-it `
-d `
openjdk:8u171-jdk-alpine3.8 sh
Javaアプリケーションの起動
ローカルPCで実行可能なjarをビルドしておけば、下記のコマンドでアプリケーションを起動できます。
PS> docker container exec -it app-server java -jar '-Dspring.profiles.active=docker' /app/target/demo.jar
コンテナ内でビルド、起動・停止を行う
コンテナにアクセスします。
PS> docker container exec -it app-server sh
spring-bootプラグインを使ってアプリケーションを起動する方法
/ # cd /app
/app # ./mvnw spring-boot:run -Drun.profiles=docker
ビルドしたjarを使ってアプリケーションを起動する方法
/ # cd /app
/app # ./mvnw clean package -Dmaven.test.skip=true
/app # java -jar -Dspring.profiles.active=docker target/demo.jar
HTTPサーバー用のコンテナを作成
イメージのダウンロード
officialの[nginx] (https://hub.docker.com/_/nginx/)で公開されているイメージを利用します。
PS> docker image pull nginx:1.15.1-alpine
1.15.1-alpine: Pulling from library/nginx
//...省略...
Status: Downloaded newer image for nginx:1.15.1-alpine
動作確認のため、コンテナを実行してブラウザでページにアクセスしてみます。
PS> docker run --name my-nginx --rm -d -p 80:80 nginx:1.15.1-alpine nginx-debug -g 'daemon off;'
ブラウザからlocalhostにアクセスして下図のページが表示されることを確認します。
確認出来たらコンテナを停止させます。
PS> docker stop my-nginx
コンテナの実行
この例ではAPPサーバーへプロキシさせる設定ファイルをD:/dev/docker-mount/nginx-1.15.1/conf.d
に配置し、このディレクトリをコンテナの/etc/nginx/conf.d
へマウントしています。
PS> docker run `
--name http-server `
-v D:/dev/docker-mount/nginx-1.15.1/conf.d:/etc/nginx/conf.d:ro `
--network my-network `
-p 80:80 `
-d `
nginx:1.15.1-alpine
設定ファイル
APPサーバーへのプロキシ設定は下記の通りです。
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 container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
94cbf2d12701 nginx:1.15.1-alpine "nginx -g 'daemon of…" 18 seconds ago Up 17 seconds 0.0.0.0:80->80/tcp http-server
3ec8d007bca0 openjdk:8u171-jdk-alpine3.8 "sh" 14 minutes ago Up 14 minutes app-server
055717c7f8a0 mysql:8.0.11 "docker-entrypoint.s…" 2 hours ago Up 2 hours 3306/tcp db-server
Javaアプリケーションの動作確認
ブラウザから下記のアドレスにアクセスしてjsonのレスポンスが返ってくることを確認します。
GET http://localhost/app/memo/1
GET http://localhost/app/memo/list
docker-composeで複数のコンテナを起動する
dockerコマンドで構築した上記の環境をdocker-composeで構築してみます。
これまでに作成したイメージ、コンテナ、network、volumeはすべて削除してから行いました。
プロジェクトの作成
docker-compose.yml、各コンテナのイメージをビルドするためのDockerfileやコンテナにコピーするファイルを管理するプロジェクトです。
複数メンバーで開発環境を共有する場合、このプロジェクトをVCSで管理するという想定です。各自でdockerをインストールし、このプロジェクトをチェックアウトしdocker-composeで環境を構築します。
/project-root
|
+--- docker-compose.yml
|
+--- .env
|
+--- /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
app-serverコンテナが参照するローカルのプロジェクトディレクトリを${PROJECT_HOME}という環境変数で定義しています。
この環境変数は後述する.envで設定します。
version: "3.6"
services:
db:
container_name: db-server
build:
context: ./mysql
volumes:
- db-data:/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
- m2-cache:/root/.m2
environment:
- SPRING_PROFILES_ACTIVE=docker
depends_on:
- db
networks:
- my-network
restart: always
tty: true
www:
container_name: http-server
build:
context: ./nginx
depends_on:
- app
ports:
- 80:80
networks:
- my-network
restart: always
networks:
my-network:
driver: bridge
volumes:
db-data:
driver: local
m2-cache:
driver: local
appサービスのttyをtrueにしているのは、コンテナにアクセスしてJavaアプリケーションを起動させる必要があるためです。
.env
.envファイルで定義した環境変数はdocker-compose.ymlやコンテナ内から参照できます。
PROJECT_HOME=D:\dev\IdeaProjects\demo
DBサーバー用コンテナ
Dockerfile
FROM mysql:8.0.11
COPY ./conf/mysqld.cnf /etc/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 664 /etc/mysql/conf.d/mysqld.cnf
ENV TZ=Asia/Tokyo
mysqld.conf
[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_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
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
HTTPサーバー用コンテナ
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;"]
default.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
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 /;
}
}
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 network "docker-java-develop_my-network" with driver "bridge"
Creating volume "docker-java-develop_db-data" with local driver
Creating db-server ... done
Creating app-server ... done
Creating http-server ... done
サービスのビルドと起動を同時に行うこともできます。ビルドは変更のあるサービスに対してのみ行われます。
PS> docker-compose up --build -d
コンテナの一覧表示 (ps)
PS> docker-compose ps
指定されたパスが見つかりません。
Name Command State Ports
----------------------------------------------------------------------
app-server /bin/bash Up 9000/tcp
db-server docker-entrypoint.sh mysqld Up 3306/tcp
http-server nginx -g daemon off; Up 0.0.0.0:80->80/tcp
任意のコマンドを実行 (exec)
コンテナは起動していますがapp-serverコンテナではまだSpring Bootのアプリケーションは起動していません。
下記のexecコマンドでapp-serverコンテナに接続してアプリケーションを起動します。なお、ここで指定しているappはコンテナ名ではなくサービス名です。
PS> docker-compose exec app bash
[root@36b2e310620f /]#
spring-bootプラグインでアプリケーションのビルドと実行を行います。プロファイルは環境変数(SPRING_PROFILES_ACTIVE)に定義しているため省略可能です。
初回は依存関係にあるライブラリのダウンロードが行われるため時間がかかりますが、ダウンロード先をDocker volumeにしているので2回目以降は時間はかからないと思います。
[root@36b2e310620f /]# cd /app
[root@36b2e310620f app]# ./mvnw spring-boot:run
Javaアプリケーションの動作確認
各コンテナが連携していればmemoテーブルのデータがjsonで返ってきます。
GET http://localhost/app/memo/1
GET http://localhost/app/memo/list
実行中のプロセスの確認 (top)
topコマンドで各サービスのプロセスを確認できます。
PS> docker-compose top
app-server
指定されたパスが見つかりません。
PID USER TIME COMMAND
-------------------------------
15312 root 0:00 /bin/bash
db-server
指定されたパスが見つかりません。
PID USER TIME COMMAND
-----------------------------
15125 999 0:00 mysqld
http-server
指定されたパスが見つかりません。
PID USER TIME COMMAND
----------------------------------------------------------------
15568 root 0:00 nginx: master process nginx -g daemon off;
15692 999 0:00 nginx: worker process
コンテナの停止 (down)
コンテナを停止します。
PS> docker-compose down
Stopping http-server ... done
Stopping app-server ... done
Stopping db-server ... done
Removing http-server ... done
Removing app-server ... done
Removing db-server ... done
Removing network docker-java-develop_my-network
コンテナのログを確認 (logs)
サービスが起動しないなどの原因を調べたい場合はlogsコマンドでコンテナのログを確認します。
PS> docker-compose logs
特定のコンテナに絞りたい場合はサービス名を指定します。
PS> docker-compose logs db
補足
動作検証用のDB、アカウントの作成
1_schema.sql
CREATE DATABASE IF NOT EXISTS sample_db
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci
;
CREATE USER IF NOT EXISTS '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(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
PRIMARY KEY (id)
) CHARACTER SET = utf8mb4, COLLATE utf8mb4_0900_ai_ci;
2_init_memo_data.sql
INSERT INTO memo (title, description, done) VALUES ('title 1', 'description 1', false);
INSERT INTO memo (title, description, done) VALUES ('title 2', 'description 2', false);
INSERT INTO memo (title, description, done) VALUES ('title 3', 'description 3', true);
INSERT INTO memo (title, description, done) VALUES ('title 4', 'description 4', false);
INSERT INTO memo (title, description, done) VALUES ('title 5', 'description 5', true);
INSERT INTO memo (title, description, done) VALUES ('title 6', 'description 6', false);
INSERT INTO memo (title, description, done) VALUES ('title 7', 'description 7', false);
INSERT INTO memo (title, description, done) VALUES ('title 8', 'description 8', true);
INSERT INTO memo (title, description, done) VALUES ('title 9', 'description 9', true);
INSERT INTO memo (title, description, done) VALUES ('title 10', 'description 10', true);
動作検証用のJavaアプリケーション
コンテナの動作検証用にRest APIアプリケーションをSpring Bootで開発しました。
以下にコントローラーのソースコードとpom.xml、application.ymlの内容を記載します。
アプリケーションはmemoテーブルのデータをjsonフォーマットでレスポンスする単純なRest APIです。
エンドポイントは下記の2つだけです。
GET localhost:9000/app/memo/list
GET localhost:9000/app/memo/{id}
コントローラー
@RestController
@RequestMapping(path = "memo", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class MemoController {
private MemoService service;
public MemoController(MemoService service) {
this.service = service;
}
@GetMapping(path = "{id}")
public ResponseEntity<Memo> memo(@PathVariable(value = "id") Long id) {
Memo memo = service.findById(id);
return new ResponseEntity<>(memo, HttpStatus.OK);
}
@GetMapping(path = "list")
public ResponseEntity<List<Memo>> list(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 application</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.14.RELEASE</version>
<relativePath/>
</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>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version><!--$NO-MVN-MAN-VER$-->
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</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-devtools</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>
<configuration>
<compilerArgs>
<arg>-Xlint:all,-options,-path</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
# SPRING CORE
spring:
application:
name: demo
# OUTPUT
output:
ansi:
enabled: detect
# PROFILES
profiles:
active: dev
# DATASOURCE
datasource:
url: jdbc:mysql://localhost:3306/sample_db?useSSL=false&allowPublicKeyRetrieval=true
username: test_user
password: test_user
driver-class-name: com.mysql.cj.jdbc.Driver
tomcat:
maxActive: 4
maxIdle: 4
minIdle: 0
initialSize: 4
# JPA
jpa:
open-in-view: true
properties:
hibernate:
show_sql: true
format_sql: true
use_sql_comments: true
jackson:
serialization:
indent_output: true
write-dates-as-timestamps: false
write-durations-as-timestamps: true
# 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://db-server:3306/sample_db?useSSL=false&allowPublicKeyRetrieval=true
username: test_user
password: test_user
driver-class-name: com.mysql.cj.jdbc.Driver