Othlo Tech ハンズオン手順
1. ハンズオンの目的と方針
Docker プラットフォームの基本動作を、手を動かしながら学びます。はじめに、鯨が喋るプログラムを例に、Docker コンテナの実行と、イメージ構築を行えるようにます。それから、サンプルのウェブアプリケーション、Nginx、WordPress(PHP+MySQL)を例にしてコンテナのネットワークとボリュームについて学びます。
2. 事前準備
今回のハンズオン作業は、さくらのクラウド上のサーバで作業を行います。
- さくらのクラウドのコントロールパネルにログインし、仮想サーバの作成
- 仮想サーバへ SSH でログイン
- Docker Hub アカウントの登録と確認
※ 今回の手順は VirtualBox など、皆さんの PC 上で行っても構いませんが、サポートの関係上、今回はクラウド上の仮想サーバを使います。
2.1 仮想サーバの作成
2.1.1 さくらのクラウドの、コントロールパネルにログイン
ウェブ・ブラウザを起動し、コントロールパネルの URL を開きます。今回のハンズオン用の認証情報を、画面の右側に入力し、ログインできるかどうかを確認します。認証情報の用紙が手元になければお知らせください。
2.1.2 仮想サーバの起動
ログイン状態のクラウドには、何も環境がありません。Docker (ドッカー)を使うための仮想サーバを準備します。
- 【 さくらのクラウド(IaaS)】をクリックします。
- メニュー【 サーバ 】から【 追加 】をクリックします。
- ディスクイメージは【 CentOS 7.4 64bit 】を使います。
- 「サーバプラン」と「ディスクプラン」を選択します(※今回は変更しません)。
- 【 管理ユーザのパスワード 】で root パスワードを設定します。8文字以上の「アルファベット」「数字」「記号」の組み合わせが必要です。
- ホスト名を【 docker 】、作成数【 1 】として【 作成 】ボタンをクリックします。
- 確認画面では【 作成 】をクリックします。
- サーバ追加作業が完了するまで待ちます。起動後は【 閉じる 】をクリックします。
- メニューの【 サーバ 】をクリックし、作成したサーバ「 docker 」を確認します。
2.2 仮想サーバへ SSH でログイン
仮想サーバに接続する IP アドレスを確認の後、SSH (Simple Secure Shell)でログインします。
- IP アドレスを確認します。インターフェースを右クリックし【 IP アドレスをコピー 】します。
- Tera Term (テラ・ターム; Windowsの設定手順は、こちらをご覧ください) やターミナルなどを開き、対象サーバに SSH でログインします。
- ログイン時のIDは「root」、パスワードは作成時に入力したものを指定します
- ターミナルでは「ssh -l root 」か「ssh root@」を実行します
$ ssh -l root <IPアドレス>
The authenticity of host '59.106.xxx.xxx (59.106.xxx.xxx)' can't be established.
ECDSA key fingerprint is SHA256:8kqxjRIPV/0S8g5BlKhICZgCo3eJS9jI7shtFoJzxL2.
Are you sure you want to continue connecting (yes/no)? yes ←【yes】と入力し、接続継続を許可
Warning: Permanently added '59.106.xxx.xxx' (ECDSA) to the list of known hosts.
root@59.106.xxx.xxx's password: ←ここでパスワードを入力
[root@docker ~]#
2.3 Docker Hub アカウントの登録と確認
※ 既に Docker Hub(ドッカー・ハブ)アカウントをお持ちの場合は不要です。
Dockerイメージを公開するために、 [Docker Hub] にアカウントを作成します。アカウントの作成・維持に費用はかかりません。
- Docker Hub のサイト https://hub.docker.com/ にアクセスします。
- ユーザ名、メールアドレス、パスワードを入力し、 Signup (サインアップ)を押します。
- 暫くすると、登録したメールアドレス宛に確認用のメールが届きます。届いたら、メール本文にある確認用のリンクをクリックします。
- Docker Hub にログインできているのを確認します。
※ ここで作成するユーザ名は、あとから変更できません。
3 ハンズオン
以降は、実際にサーバ上で Docker の環境構築と作業を進めます。
A:【Docker 初歩編】セットアップと、初めてのコンテナ実行
ゴール:Docker コンテナを動かす環境を理解します。
A-1 Docker Engine のセットアップ
1. curl(カールまたはシーユーアールエル、サーバから様々なプロトコルを通してデータを転送するツール)を使い、自動的に Docker Engine パッケージをセットアップします。
# curl -fsSL get.docker.com -o get-docker.sh
# sh ./get-docker.sh
このコマンドを実行すると、サーバ上では次の処理を自動的に行います。
- Docker が提供する Docker CE (ココミュニティ・エディション)のリポジトリを利用可能に設定
-
docker-ce
パッケージをセットアップ(Docker Engine とdocker
クライアントを利用可能にします)
( # コマンド
の箇所は、 root 権限でのコマンド実行を意味します。一方 $ コマンド
の場合は
2. Docker Engine を systemctl start docker
で起動し、 systemctl status docker
で起動状態を確認します。
# systemctl start docker
# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since 金 2017-10-27 11:54:13 JST; 6s ago
Docs: https://docs.docker.com
Main PID: 1343 (dockerd)
Memory: 17.1M
CGroup: /system.slice/docker.service
tq1343 /usr/bin/dockerd
mq1346 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.soc..
3. docker version
コマンドを実行し、 docker
クライアントが Docker Engine サーバ側( dockerd
)に接続できるかどうか確認します。次のように Server:
のバージョンが表示されれば正常です。
# docker version
Client:
Version: 17.10.0-ce
API version: 1.33
Go version: go1.8.3
Git commit: f4ffd25
Built: Tue Oct 17 19:04:05 2017
OS/Arch: linux/amd64
Server:
Version: 17.10.0-ce
API version: 1.33 (minimum version 1.12)
Go version: go1.8.3
Git commit: f4ffd25
Built: Tue Oct 17 19:05:38 2017
OS/Arch: linux/amd64
Experimental: false
もしも次のようなエラーが出てしまう場合は、 Docker を起動しているかどうか確認します。
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
4. サーバ再起動後も、自動的に Docker を起動するように設定します。
# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
A-2 はじめてのコンテナ実行
hello-world
コンテナを実行しながら、基本的な挙動を見ていきましょう。
1. コンテナを動かす前に、 docker image ls
コマンドを実行し、サーバのローカル環境上に Docker イメージがないことを確認します。
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
このように、インストール直後は Docker イメージが1つもありません。
2. docker container run
コマンドを使い、 hello-world
イメージを実行します。
# docker container run hello-world
3. この時、どのような処理を行ったのか確認します。
コマンドを実行すると、Docker が内部でどのような処理を行っているか、画面上に結果を表示します。
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
5b0f327be733: Pull complete
Digest: sha256:07d5f7800dfe37b8c2196c7b1c524c33808ce2e0f74e7aa00e603295ca9a0972
Status: Downloaded newer image for hello-world:latest
それぞれ上から、次の意味があります。
- イメージ
hello-world:latest
(リポジトリ名hello-world
の、latest
タグを持つもの)がローカルに無い - リポジトリ
library/hello-world
から、latest
(最新)のタグを持つイメージを取得(pull
) - イメージ・レイヤ
5b0f327be733
のダウンロード完了 - ダウンロードしたイメージのハッシュ値は
07d5f7800dfe37b8c2196c7b1c524c33808ce2e0f74e7aa00e603295ca9a0972
- 状態(
Status
)はhello-world:latest
の最新イメージをダウンロード完了
そして、以降のメッセージは hello-world
イメージ(中に含まれているバイナリ・プログラム)の実行結果が、そのまま標準出力されたものです。
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
つまり、 docker container run
を実行すると、 hello-world
イメージ使ったコンテナを実行し、イメージ内に含まれるコマンドを実行の後、コンテナは終了しました。
4. コンテナの状態を docker container ls
/ docker ps
コマンドで確認します。
# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
通常は「実行中」のコンテナしか表示しません。
5. 終了したコンテナを含む、全てのコンテナ情報を docker container ls -a
で表示します。
# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d98925cc5735 hello-world "/hello" 11 minutes ago Exited (0) 11 minutes ago jovial_easley
- コンテナにはコンテナ ID が割り当てられます。この例では
d98925cc5735
に該当します。 - イメージ
hello-world
を使っています - コマンド
/hello
を実行しています - 正常に終了
Exited (0)
しています - コンテナ名は
jovial_easley
です
このようにして、コンテナの状態を確認できます。
なお、コンテナ名は実行時に --name
オプションで指定できますが、コンテナの名前を重複して起動できません。また、コンテナ名の指定がなければ、「形容詞」+「著名な科学者かハッカーの名前」で自動的に割り振られます(詳細:名前生成のソースコード)
6. 再び docker container run hello-world
を実行します。
# docker container run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
(省略)
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
何度実行しても、すぐに起動できます。なぜだか分かりますか? 今回は既に hello-world
イメージをローカルにダウンロード済みのため、ダウンロード(pull)の処理は行われず、すぐにコンテナを実行できました。
7. docker ps -a
で2つめ以降のコンテナが実行されたのを確認します。
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d442c8a19807 hello-world "/hello" About a minute ago Exited (0) About a minute ago laughing_curie
d98925cc5735 hello-world "/hello" 21 minutes ago Exited (0) 2 minutes ago jovial_easley
8. コンテナ(用のイメージ・レイヤ)を docker container rm
で削除します。
停止中のコンテナは削除用コマンドで削除できます(実行中のコンテナは -f
オプションを付けて、強制削除できます)。削除後は復旧できません。
# docker container rm [コンテナID]
あるいは docker container prune
コマンドを実行すると、停止中のコンテナを全て削除します。
# docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
d442c8a198076a2f4d2c648e1241bb73a5ef88b01702664423335ee7b6e9414d
d98925cc5735fc974b80d6ece4c6620b98d023f0b0ef49e792f7b210f7601b1d
Total reclaimed space: 0B
9. コンテナが何も残っていないのを確認します。
# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
B:docker/whale を使ったDocker コンテナ実行と Docker イメージ構築
ゴール:Docker の基本コマンドとイメージの構築をはじめ、Docker Hub をつかった一通りのライフサイクルを学びます。
B-1 docker/whalesay イメージのダウンロードとコンテナ実行
1. docker/whalesay
という鯨に何かを喋らせるプログラムが入ったイメージをダウンロードします。イメージをダウンロードするコマンドは docker image pull
です。
# docker image pull docker/whalesay
Using default tag: latest
latest: Pulling from docker/whalesay
e190868d63f8: Extracting 51.81MB/65.77MB
909cd34c6fd7: Download complete
0b9bfabab7c1: Download complete
a3ed95caeb02: Download complete
00bf65475aba: Download complete
c57b6bcc83e3: Download complete
8978f6879e2f: Download complete
8eed3712d2cf: Download complete
Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b
Status: Downloaded newer image for docker/whalesay:latest
先ほどの hello-world
イメージと同様、ローカルになかったためリモート(Docker Hub)からイメージをダウンロードしました。
2. イメージがダウンロードされているのを docker image ls
コマンドで確認します。
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 05a3bd381fc2 6 weeks ago 1.84kB
docker/whalesay latest 6b362a9f73eb 2 years ago 247MB
3. イメージ docker/whalesay
を使い、コンテナとして実行します。 docker container run
コマンドを実行します。
# docker run docker/whalesay
実行しても何も表示しません。このイメージを実行しても、 /bin/sh
を実行して終了する挙動の設定だからです( docker image inspect docker/whalesay
の Cmd
を参照 )。
4. このイメージにある cowsay
プログラムを実行します。
# docker run docker/whalesay cowsay
_
< >
-
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
5. cowsay
に引数を追加し、何か鯨に喋らせます。
# docker run docker/whalesay cowsay "hello my world"
________________
< hello my world >
----------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
B-2 もっと賢そうな鯨のイメージを構築
docker/whalesay
イメージをもとに、カスタマイズした新しい Docker イメージを作ります。今回は入力したテキストではなく fortune
という名前のプログラム(名言や格言のようなメッセージを表示します)を実行します。
Docker イメージを作る(buildする)には、 2つの方法があります。
-
docker container commit
コマンドで、コンテナ用のイメージ・レイヤをイメージ化する方法 -
docker image build
コマンドで、Dockerfile
の命令に従い、docker container commit
を自動実行してイメージ化する方法
ここでは後者の Dockerfile
でイメージを構築する方法を進めます。
1. 作業用ディレクトリを作成し、移動します。
# mkdir mywhale && cd mywhale
2. Dockerfile を作成します。
# cat << 'EOF' > Dockerfile
FROM docker/whalesay:latest
RUN apt-get -y update && apt-get install -y fortunes
CMD /usr/games/fortune -a | cowsay
EOF
ファイル Dockerfile
の内容を確認します。
# cat Dockerfile
FROM docker/whalesay:latest
RUN apt-get -y update && apt-get install -y fortunes
CMD /usr/games/fortune -a | cowsay
上から1行ずつ Docker は読み込み、イメージを自動構築します。
-
FROM
で元にするイメージ名を指定します(ベース・イメージと呼びます)。ローカルにイメージがなければ、ダウンロードします。 -
RUN
は、コンテナを実行し、その中で実行するコマンドです。終了後、コンテナ用のイメージ・レイヤをイメージ・レイヤとしてコミットします。- ここでは
apt-get -y update
を実行し、その結果が正常であればapt-get install -y fortune
を実行します。
- ここでは
-
CMD
は、そのイメージを使ったコンテナが、デフォルトで何のコマンドを実行するかの指定です。- ここでは
fortune
プログラムを実行した標準出力を、cowsay
プログラムにパイプします。
- ここでは
3. docker image build -t mywhale .
コマンドでイメージを自動構築します。
オプションで -t イメージ名
と、末尾に .
(どこに Dockerfile や Docker イメージに格納するかを示すファイルのパス)を指定します。
# docker image build -t mywhale .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM docker/whalesay:latest
---> 6b362a9f73eb
Step 2/3 : RUN apt-get -y update && apt-get install -y fortunes
---> Running in 32219a5feef0
Ign http://archive.ubuntu.com trusty InRelease
Get:1 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB]
Get:2 http://archive.ubuntu.com trusty-security InRelease [65.9 kB]
(省略)
Step 3/3 : CMD /usr/games/fortune -a | cowsay
---> Running in 84a8a20038c5
---> f70198e1d8e0
Removing intermediate container 32219a5feef0
Removing intermediate container 84a8a20038c5
Successfully built f70198e1d8e0
Successfully tagged mywhale:latest
4. docker image ls
コマンドで mywhale
イメージが作成されているのを確認します。
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mywhale latest f70198e1d8e0 54 seconds ago 257MB
5. docker image history mywhale
を実行し、イメージ・レイヤの情報を確認します。
# docker image history mywhale
IMAGE CREATED CREATED BY SIZE COMMENT
f70198e1d8e0 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/u... 0B
d8f783332f70 3 minutes ago /bin/sh -c apt-get -y update && apt-get in... 9.83MB
6b362a9f73eb 2 years ago /bin/sh -c #(nop) ENV PATH=/usr/local/bin:... 0B
<missing> 2 years ago /bin/sh -c sh install.sh 30.4kB
<missing> 2 years ago /bin/sh -c git reset --hard origin/master 43.3kB
<missing> 2 years ago /bin/sh -c #(nop) WORKDIR /cowsay 0B
<missing> 2 years ago /bin/sh -c git clone https://github.com/mo... 89.9kB
<missing> 2 years ago /bin/sh -c apt-get -y update && apt-get in... 58.6MB
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\... 1.9kB
<missing> 2 years ago /bin/sh -c echo '#!/bin/sh' > /usr/sbin/po... 195kB
<missing> 2 years ago /bin/sh -c #(nop) ADD file:f4d7b4b3402b5c5... 188MB
6. 新しく作成したイメージで、コンテナを実行します。
# docker container run mywhale
_________________________________________
/ "In the event of a percieved failing of \
| the project leadership #debian is |
| empowered to take drastic and descisive |
| action to correct the failing, |
| including by not limited to expelling |
| officials, apointing new officials and |
| generally abusing power" |
| |
| -- proposed amendment to Debian |
\ Constitution /
-----------------------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
実行するたびに表示するメッセージ内容は変わります。
B-3 Docker Hub に送信
作成した Docker イメージを公開イメージ・レジストリ Docker Hub に公開します。
1. docker login
で Docker Hub と通信し、認証トークンを取得します。
# 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: ← ここで Docker Hub のユーザ名
Password: ←パスワードを入力
Login Succeeded
Login Succeeded
(ログイン成功)が表示されなければ、ユーザ名とパスワードが正しいかどうか確認します。
2. 認証情報のファイルを確認します。
# cat ~/.docker/config.json
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "**************"
}
},
"HttpHeaders": {
"User-Agent": "Docker-Client/17.10.0-ce (linux)"
}
}
このファイルがあれば、Docker Hub への送信(push)が可能になります。
3. イメージを送信する前に、イメージにタグを付けます。
$ docker image tag mywhale:latest <DockerHubユーザ名>/mywhale:latest
これは、イメージ送信用のコマンド docker image push
を実行する前に、送信対象のイメージにユーザ名(の名前空間)付きのイメージを準備しておく必要があるためです。
また、1つのイメージに対して複数のタグをつけることができます。そのため、0からイメージを構築する必要はなく、いまあるイメージに対して別のタグを重複して付与しました。
4. イメージ一覧 docker image ls
で、同じイメージ ID に対して、複数のタグが付与されているのを確認します。
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mywhale latest f70198e1d8e0 15 minutes ago 257MB
zembutsu/mywhale latest f70198e1d8e0 15 minutes ago 257MB
IMAGE ID
の ID が同じイメージは、実体としては同じ1つのイメージです。
5. イメージを docker image push <ユーザ名>/mywhale
でイメージを Docker Hub に送信(push)します。
# docker image push zembutsu/mywhale
The push refers to a repository [docker.io/zembutsu/mywhale]
d6e92dbe255a: Pushed
5f70bf18a086: Layer already exists
d061ee1340ec: Layer already exists
d511ed9e12e1: Layer already exists
091abc5148e4: Layer already exists
b26122d57afa: Layer already exists
37ee47034d9b: Layer already exists
528c8710fd95: Layer already exists
1154ba695078: Layer already exists
latest: digest: sha256:82bcd174553c98e2e7c626ffc23cfec4884192d354874bdbc9c5627f2294b360 size: 2613
この時、この例では Docker Hub に送信したのは新しいイメージ・レイヤ d6e92dbe255a
にあたる部分だけです。その他のレイヤは既に Docker Hub 上に存在しているため、重複しての送信は行われていません。
6. ローカルのイメージを削除します。
イメージを削除する前に、ローカルのコンテナを削除します(利用中のコンテナがあると、削除時に警告が出るためです)。
# docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y ←「yを入力」
それから docker image rm mywhale
( docker rmi mywhale) でイメージを消します。
# docker image rm mywhale
Untagged: mywhale:latest
# docker image rm zembutsu/mywhale
Untagged: zembutsu/mywhale:latest
Untagged: zembutsu/mywhale@sha256:82bcd174553c98e2e7c626ffc23cfec4884192d354874bdbc9c5627f2294b360
Deleted: sha256:f70198e1d8e0977780a2ec81293dac31c919757096d51f161d1784bbaf2871c7
Deleted: sha256:d8f783332f70b5878ad9e9d97a8d063551ccff39f3a2ca8884d9e26379469965
Deleted: sha256:7bd915d5a3ae086cd75920ed1bddcadbb440ecd3e94653c212e032badfcf4e2a
1回目のイメージ削除では「Untagged」とあり、イメージの実体はそのままで、タグだけが削除されています。2回目のイメージ削除では、タグの削除だけでなく、イメージ・レイヤも不要となったため同時に削除されています。
あとは、 docker image ls
でイメージが存在していないのを確認します。
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 05a3bd381fc2 6 weeks ago 1.84kB
docker/whalesay latest 6b362a9f73eb 2 years ago 247MB
7. アップロードしたイメージを docker container run <ユーザ名>/mywhale
で実行します。
# docker container run zembutsu/mywhale
Unable to find image 'zembutsu/mywhale:latest' locally
latest: Pulling from zembutsu/mywhale
e190868d63f8: Already exists
909cd34c6fd7: Already exists
0b9bfabab7c1: Already exists
a3ed95caeb02: Already exists
00bf65475aba: Already exists
c57b6bcc83e3: Already exists
8978f6879e2f: Already exists
8eed3712d2cf: Already exists
396d4892383e: Pull complete
Digest: sha256:82bcd174553c98e2e7c626ffc23cfec4884192d354874bdbc9c5627f2294b360
Status: Downloaded newer image for zembutsu/mywhale:latest
_________________________________
/ Patageometry, n.: \
| |
| The study of those mathematical |
| properties that are invariant |
| |
\ under brain transplants. /
---------------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
8. docker logout
でログアウトします。
# docker logout
Removing login credentials for https://index.docker.io/v1/
C:Nginxコンテナとネットワーク・ボリュームの理解
C-1 Alpine Linux 対応イメージのダウンロード
ゴール:コンテナのポートをホスト側に公開(EXPOSE)する方法、コンテナとホスト間でデータをやりとりする方法を学びます。
1. docker image pull nginx:alpine
を実行し、Nginx ウェブ・サーバ用の Docker イメージをダウンロードします。
# docker image pull nginx:alpine
alpine: Pulling from library/nginx
b1f00a6a160c: Pull complete
b5441325f46d: Pull complete
049763556f13: Pull complete
555a8317e22d: Pull complete
Digest: sha256:4a97b863a4386ba588cd4f264582d1f306bc9da46fe3e02540bd171709ce09d7
Status: Downloaded newer image for nginx:alpine
2. docker image ls
で、イメージを確認します。
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine ea7bef82810a 29 hours ago 15.5MB
ここでは nginx
イメージに alpine
タグを指定して取得しました。タグは通常、何も指定しなければ latest
となります。 alpine
は Alpine Linux という最小で 4MB 程度の Linux ディストリビューションです。容量がとても小さいながらパッケージ管理ツール(apk)が導入されており、セキュリティも考慮されていることから、コンテナ用の OS として注目を集めています。
C-2 コンテナとホスト側との通信
1. Nginx コンテナを docker container run -d nginx:alpine
で実行します。
# docker container run -d nginx:alpine
4c977341985555599c98085defe9548fbc1e3abbeb1ba87c4c65db81334d32ba
新しいオプション -d
はデタッチド(detach)・モードといい、バックグランドでコンテナ(のプロセス)を実行し、コンテナ ID を 画面に表示します。 docker container ls
を実行すると、起動中だと分かります。
# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c9773419855 nginx:alpine "nginx -g 'daemon ..." 2 minutes ago Up 2 minutes 80/tcp peaceful_raman
しかし、このままでは Nginx のサイトをウェブ・ブラウザでは確認できません。確認できるようにするには、 -P
オプションまたは -p
オプションで、コンテナとホスト側のポートを割り当て(マッピング)する必要があります。
2. ホスト側の空きポートを自動的に使ってコンテナを起動するには -P
オプションをつけ、 docker container run -d -P nginx:alpine
を実行します。
# docker container run -d -P nginx:alpine
de88fc4ba6860b8161a62d8938fb1eedc335b02df247bba763367fa3f8bf886e
3. docker container ls
コマンドで何番のポートを使っているか調べます。
# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
de88fc4ba686 nginx:alpine "nginx -g 'daemon ..." 59 seconds ago Up 58 seconds 0.0.0.0:32768->80/tcp modest_jackson
この例では 「PORTS」列に 0.0.0.0:32768->80/tcp
とあり、 0.0.0.0
(ホスト側)のポート 32768
が、コンテナ内のポート 80
に tcp
で接続しているのが分かります。
ブラウザから http://<IPアドレス>:32768/
を入力すると、Nginx コンテナの応答状況を確認できます。
4. 何度か docker container run -d -P nginx:alpine
コマンドを実行し、複数の Nginx 環境が起動しているのを確認できます。
5. ホスト側のポート 8080 をコンテナ内の 80 に割り当てるには -p
オプションを使い、 -p 8080:80
のように指定します。
# docker container run -d -p 8080:80 nginx:alpine
2c89576e996254da4d48c7d5b428da93b2e6fd6e2995363a86c604502c51b509
ブラウザから http://IPアドレス:8080
にアクセスすると、Nginx の画面を確認できます。
なお、ホスト側では同じポートを重複して起動できません。起動を試みても次のようにエラーとなります。
# docker container run -d -p 8080:80 nginx:alpine
7643383ba268beeb1c7a80b24dc4c6ac6d0b2bb22856bce0fe2d81bbb5e3e218
docker: Error response from daemon: driver failed programming external connectivity on endpoint quizzical_pike (4b68fe9d1b741ac711190e89d1bffa181e0abdc95de7d34966556ba467db90c7): Bind for 0.0.0.0:8080 failed: port is already allocated.
既に割り当てられているコンテナを停止後は、再び割り当て可能です。
6. docker network ls
でネットワーク情報を確認します。
# docker network ls
NETWORK ID NAME DRIVER SCOPE
401ef0b7bf29 bridge bridge local
924cd8e9ded7 host host local
5be81d2d1321 none null local
7. docker network inspect bridge | less
を実行し、ネットワークの詳細設定を確認できます。
表示された内容から、IP アドレス( IPv4Address
の項目 )を記録しておきます。例: 172.17.0.2
8. ホスト側から ping
コマンドを実行し、疎通しているのを確認します。
# ping -c 5 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.088 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.102 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.096 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.077 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.074 ms
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4000ms
rtt min/avg/max/mdev = 0.074/0.087/0.102/0.013 ms
9. 新しいブリッジ・ネットワーク mynet
を作成します。
# docker network create --driver bridge \
--subnet 192.168.10.0/24 \
--gateway 192.168.10.1 \
mynet
10. docker network ls
で、新しいネットワークが追加されているのを確認します。
# docker network ls
NETWORK ID NAME DRIVER SCOPE
401ef0b7bf29 bridge bridge local
924cd8e9ded7 host host local
aba8e4b4f857 mynet bridge local
5be81d2d1321 none null local
11. alpine
イメージを使い、新しく作成した mynet
に接続するコンテナを作成します。
# docker run -it alpine /bin/sh
/ #
-
-it
は-i
と-t
オプションを同時に指定しています。 -
-i
は標準入力を受け付けます -
-t
は疑似ターミナル(Pseudo-tty)を有効にします
12. コンテナ内で ping <先ほどのNginxのIPアドレス>
を実行します。
/ # ping -c 5 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.171 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.196 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.171 ms
64 bytes from 172.17.0.2: seq=3 ttl=64 time=0.172 ms
64 bytes from 172.17.0.2: seq=4 ttl=64 time=0.202 ms
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.171/0.182/0.202 ms
ここで疎通しているのは、 bridge
という名前の、始めからあるブリッジ・ネットワークに接続してコンテナが起動しているからです。
13. exit
で終了します。
# exit
14. mynet
ネットワークを指定してコンテナを起動します。
# docker run -it --net mynet alpine /bin/sh
/ #
15. 再び ping
コマンドで疎通を確認します。
# ping -c 5 192.17.0.2
PING 192.17.0.2 (192.17.0.2): 56 data bytes
^C
--- 192.17.0.2 ping statistics ---
5 packets transmitted, 0 packets received, 100% packet loss
応答がなくなるので Ctrl+C
で処理を中断します。これは、このコンテナが先ほどの bridge
ネットワークとは違う mynet
ネットワークに接続しているからです。
/ # ip route
default via 192.168.10.1 dev eth0
192.168.10.0/24 dev eth0 src 192.168.10.2
16. exit
でコンテナを終了します。
# exit
このように、コンテナ起動時にネットワークを指定すると、コンテナ間でお互いに接続できない環境を作ることもできます。
C-3 コンテナとボリューム
コンテナとコンテナな間はディレクトリが独立(isolate)しているため、お互いのデータを参照できません。参照するためにはボリューム(volume)と呼ぶ特別なディレクトリを使う必要があります。
1. ボリューム myvolume
を docker volume create myvolume
で作成します。
# docker volume create myvolume
myvolume
2. ボリューム一覧を docker volume ls
で確認します。
# docker volume ls
DRIVER VOLUME NAME
local myvolume
3. alpine コンテナ実行時に、 -v
オプションを付け、 myvolume
ボリュームをコンテナ内の /data
に割り当てます。
# docker run -it -v myvolume:/data alpine /bin/sh
/ #
4. コンテナ内で df
コマンドを実行します。
/ # df
Filesystem 1K-blocks Used Available Use% Mounted on
overlay 16446312 2753152 12838036 18% /
tmpfs 65536 0 65536 0% /dev
tmpfs 508136 0 508136 0% /sys/fs/cgroup
/dev/vda3 16446312 2753152 12838036 18% /data
(省略)
5. /data
ディレクトリに移動し、ファイルを作成します。
/ # cd /data/
/data # echo 'hello my world' > hello.txt
/data # cat hello.txt
hello my world
6. exit
でコンテナを終了します。
/ # exit
7. 手順 3 ~6 を繰り返し、別の Alpine コンテナを実行しても、ディレクトリ内容のデータが保持されているのを確認します。
C-4 ボリュームを指定した Nginx コンテナ・PHP コンテナの起動
デフォルトの Nginx コンテナは、ドキュメント・ルートが /usr/share/nginx/html/
ですが、ここにコンテンツをコピーする必要があります。ここでは、ボリュームのマウント機能を使い、 Nginx のドキュメントルートを指定します。
1. Nginx コンテナに myvolume
ボリュームをマウントして起動します。
# docker container run -d -v myvolume:/usr/share/nginx/html -p 8081:80 nginx:alpine
2. ブラウザからポート 8081
を開きます。 http://<IPアドレス>:8081/hello.txt
を開き、先ほど作成した hello.txt
の内容が見えるかどうか確認します。
3. 次は、ホスト側のディレクトリをボリュームとしてマウントする方法を試します。作業用ディレクトリを作成します。また、何らかのファイルを作成します。
$ cd
$ mkdir mydocroot && cd mydocroot
$ echo 'hello' > onhost.txt
4. -v ホスト側ディレクトリ:コンテナ側ディレクトリ
のオプションを使い、 nginx コンテナを起動します。
# docker container run -d -v `pwd`:/usr/share/nginx/html -p 8082:80 nginx:alpine
5. ディレクトリ内のファイルを編集し、反映されるかどうかを確認します。
6. 次は PHP のウェブサーバを動かします。
# docker run -d -v `pwd`:/var/www/html -p 8083:80 php:7.0-apache
7. ブラウザから http://<ip>:8083/onhost.txt
を表示します。
- PHP のファイルを実行します。
サーバ上で info.php
ファイルを作成します。
# echo '<?php phpinfo(); ?>' > info.php
ブラウザから見えるかどうかを確認します。
このように、ボリュームを使えば、コンテナ間のデータ共有や、ホスト上のディレクトリをコンテナ内からも参照できます。
D:WordPress を動かす複数のコンテナを swarm mode で動かす
ゴール:実際のサービスを動かす例として、swarm モード上で、サービスとして WordPress および MySQL を簡単に動かす方法を学びます。
D-1 swarm モードの初期化
1. docker swarm init
コマンドを実行します。
# docker swarm init
Swarm initialized: current node (3eszf2xqjh5qlmdlxjv3ew8r8) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4bmfzudkx6y0btzyrcrp55wk167b1fj2zfxb9xxxkz3l0mmz8x-126epkruq47ug5tnc2ighkc4f 59.106.***.****:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
画面に出てくるコマンドは、複数の Docker Engine を1つのクラスタ(swarm)として扱うため、クラスタにワーカーとして追加するためのコマンドです(今回は使いません)。
2. クラスタ状態の確認のため docker node ls
を実行します。
# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
3eszf2xqjh5qlmdlxjv3ew8r8 * docker Ready Active Leader
D-2 swarm mode で WordPress を実行
WordPress を swarm モードで動かします。この基本動作を覚えることで、みなさんの PC 上で作った環境も、インターネット側の環境に、そのままデプロイ可能となります。
1. 作業用ディレクトリを作成し、移動します。
$ cd
$ mkdir wordpress && cd wordpress
2. 以下のコマンドを実行し、 `docker-compose.yml' ファイルを作ります。
# cat << 'EOF' > docker-compose.yml
version: '3'
services:
wordpress:
image: wordpress
depends_on:
- mysql
ports:
- 80:80
volumes:
- ./data/var/www/html:/var/www/html
environment:
WORDPRESS_DB_PASSWORD: example
mysql:
image: mysql:5.7
volumes:
- ./data/var/lib/mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: example
EOF
3. データ保存用ディレクトリを作成します。
# mkdir -p ./data/var/www/html
# mkdir -p ./data/var/lib/mysql
4. docker stack deploy
コマンドで、WordPress を起動します。
# docker stack deploy -c ./docker-compose.yml wordpress
Creating service wordpress_wordpress
Creating service wordpress_mysql
5. watch
コマンドでサービスの状態を確認します。
# watch -n 1 'docker stack ps wordpress'
毎秒情報が表示されます。 DESIRED STATE
(望ましい状態)が Running
になるまで待ちます。
ID NAME IMAGE NODE DESIRED STATE
CURRENT STATE ERROR PORTS
2k2uz809j7fy wordpress_wordpress.1 wordpress:latest docker Running
Running 14 seconds ago
g9sw449yug8t wordpress_mysql.1 mysql:5.7 docker Running
Running 17 seconds ago
ブラウザから http://<ipアドレス>/
にアクセスし、WordPress の設定画面が開かれるのを確認します。
6. 停止・終了は次のコマンドを実行します。
# docker stack rm wordpress
Removing service wordpress_mysql
Removing service wordpress_wordpress
Removing network wordpress_default
なお、データは ./data
以下に残っていますので、再び docker stack deploy
コマンドを実行すると、 WordPress の環境を再開できます。