LoginSignup
70
110

More than 5 years have passed since last update.

Docker for WindowsでDockerを学ぶ (バージョンCE 17.06.2)

Last updated at Posted at 2017-10-05

概要

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

参考

インストール

ダウンロードページよりWindows版のインストーラーをダウンロードして実行します。特に選択する項目はなくすぐに終了しました。インストール終了画面のメッセージ(Close and log out)にしたがってインストール終了後に一度ログインしなおします。

インストール終了

d1.png

Welcome画面

再ログイン後にWelcome画面が立ち上がります。

d2.png

インストール後の設定

リソースの割り当て

タスクトレイにあるDockerアイコンを右クリックしコンテキストメニューから"Settings..."を選択します。
左ペインのAdvancedを選択しDockerで使用できるリソースを割り当てます。

d3.png

共有ドライブの設定

Shared Drivesからコンテナから利用できるドライブを設定します。今のところ(2017/10)ディレクトリ単位での設定はできないようです。ApplyボタンをクリックするとWindowsアカウントのパスワードを求められますので入力して設定が完了します。

d4.png

バージョンの確認

この記事では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のイメージを使って基本的な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を作成します。

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
2017103日 火曜日 19:21:09 JST

イメージをDocker Hubへプッシュする

先にDocker Hubでリポジトリを作成しておきます。

h1.png

リポジトリ名を入力します。今回はubuntuをカスタマイズしたイメージなので"ubuntu"としました。

h2.png

リポジトリが出来たので次に作成したイメージをプッシュします。

h3.png

プッシュするためにログインします。

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ページで確認します。

h4.png

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で公開されているイメージを利用します。

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で公開されているイメージを利用します。

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で公開されているイメージを利用します。

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にアクセスして下図のページが表示されることを確認します。

n1.png

確認出来たらコンテナを停止させます。

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ファイルに記述しました。

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.cnf
[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ファイルです。

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 /;
    }
}
repo

yumでnginxをインストールするのに必要なrepositoryの設定ファイルです。いまのところ(2017/10)この設定がないとyumでインストールできませんでした。

nginx.repo
[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のインストール

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

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

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

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"]
70
110
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
70
110