概要
この手順は 2019 年 6 月 22 日(土)開催の OthloEvent #48 における、開発環境構築や Docker、Docker Hub、Git、GitLabを利用するハンズオン向けです。サンプルのウェブアプリケーション、Nginx、WordPress(PHP+MySQL)を例にして Docker コンテナのネットワークとボリュームについて学びます。ハンズオンを通し、一般的な開発に必要なスキルの習得を目指します。
1. さくらのクラウド仮想マシン環境構築
目的
- 開発環境の土台となる Linux の仮想マシンをクラウド上に作成、起動し、ログインできるように準備します。
- Docker イメージ保管用の Docker Hub にアカウントを作成します。
概要
- クラウド・コンピューティング(Cloud Computing)とは、「共用計算資源(コンピューティング・リソース)の集まり、たとえば、ネットワーク、サーバ、ストレージ、アプリケーション、サービスに対して、どこからでも簡単に、必要に応じて、インターネットのようなネットワーク経由で接続可能にするモデル」(NISTによる定義, IPA訳のNIST定義 を参考)です。
- VPS(Virtual Private Server)、すなわち仮想マシン(サーバ)とは、ハードウェアを仮想化する技術を用います。1つの(物理的な)マシン上に複数の仮想マシン環境を作ることができます。
- クラウド上の仮想マシンとVPSとの違いは、利用目的や期間です。VPSであれば、物理サーバのように長期的に安定して実行し続けます。一方のクラウド上の仮想マシン(VM)の場合は、VPSのように使うこともできますし、必要に応じて短時間で使い捨て型としての利用も可能であり、短期間でのスケールアップ・ダウンも可能です。
手順
※補足:今回は「さくらのクラウド」の仮想マシンを使いますが、]VirtualBox](https://www.virtualbox.org/) や Vagrant でローカル PC 上でも仮想マシンを作成、実行することもできます。
1.1. さくらのクラウドのコントロールパネルにログイン
さくらのクラウド・コントロールパネル: https://secure.sakura.ad.jp/cloud/
まず、PC 上のウェブ・ブラウザを起動し、コントロールパネルの URL を開きます。今回のハンズオン用の認証情報を、画面の右側に入力し、ログインできるかどうかを確認します。認証情報の用紙が手元になければお知らせください。
1.2. 仮想サーバ(マシン)作成と起動
ログイン直後のクラウド環境上には、サーバも含めた一切の計算資源はありません。今回、開発環境向けとして、Docker (ドッカー)を使うための仮想サーバを準備します。
- 【 さくらのクラウド(IaaS)】をクリックします。
- メニュー【 サーバ 】から【 追加 】をクリックします。
- ディスクイメージは【 CentOS 7.4 64bit 】を使います。
- 「サーバプラン」と「ディスクプラン」を 【 4 仮想コア / 4 GB 】 に選択します。
- 【 管理ユーザのパスワード 】で root パスワードを設定します。8文字以上の「アルファベット」「数字」「記号」の組み合わせが必要です。
- ホスト名を【 docker 】、作成数【 1 】として【 作成 】ボタンをクリックします。
- 確認画面では【 作成 】をクリックします。
- サーバ追加作業が完了するまで待ちます。起動後は【 閉じる 】をクリックします。
- メニューの【 サーバ 】をクリックし、作成したサーバ「 docker 」を確認します。
1.3. 仮想サーバに 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 ~]#
1.4. Docker Hub アカウントの作成
※ 既に Docker Hub(ドッカー・ハブ)アカウントをお持ちの場合は不要です。
Dockerイメージを公開するために、 [Docker Hub] にアカウントを作成します。アカウントの作成・維持に費用はかかりません。
- Docker Hub のサイト https://hub.docker.com/ にアクセスします。
- ユーザ名、メールアドレス、パスワードを入力し、 Signup (サインアップ)を押します。
- 暫くすると、登録したメールアドレス宛に確認用のメールが届きます。届いたら、メール本文にある確認用のリンクをクリックします。
- Docker Hub にログインできているのを確認します。
※ ここで作成するユーザ名は、あとから変更できません。
2. 【Docker入門】Docker セットアップと、初めての Docker コンテナ実行
目的
- Docker の動作環境を Linux 上に構築する手順を理解し、
docker
コマンドでの操作に慣れていきます。
手順
2.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(dockerデーモン)を起動します。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 金 2019-06-21 14:14:42 JST; 3s ago
Docs: https://docs.docker.com
Main PID: 19613 (dockerd)
Tasks: 12
Memory: 31.7M
CGroup: /system.slice/docker.service
mq19613 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
(省略)
3. docker version
コマンドを実行し、 docker
クライアントが Docker Engine サーバ側( dockerd
)に接続できるかどうか確認します。次のように Server:
のバージョンが表示されていれば、正常です。
# docker version
Client:
Version: 18.09.6
API version: 1.39
Go version: go1.10.8
Git commit: 481bc77156
Built: Sat May 4 02:34:58 2019
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.6
API version: 1.39 (minimum version 1.12)
Go version: go1.10.8
Git commit: 481bc77
Built: Sat May 4 02:02:43 2019
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.
2.2. Hello World
コンテナの実行
hello-world
コンテナを実行しながら、基本的な挙動を見ていきましょう。hello-world コンテナは画面上に「Hello World」を表示するだけの、アセンブリ言語で書かれたプログラムが入っています。
1. コンテナを動かす前に、 docker images
(docker images ls)コマンドを実行し、サーバのローカル環境上に Docker イメージがないことを確認します。
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
このように、「REPOSITORY」などの行しか表示されず、インストール直後は Docker イメージが1つもありません。
2. docker run
(docker container run) コマンドを使い、 hello-world
イメージを使う Docker コンテナを実行します。
# docker run hello-world
3. この時、画面上で Docker がどのような処理を行ったのか確認します。
# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:41a65640635299bab090f783209c1e3a3f11934cf7756b09cb2f1e02147c6ed8
Status: Downloaded newer image for hello-world:latest
それぞれ上から、次の意味があります。
- イメージ
hello-world:latest
(リポジトリ名hello-world
の、latest
タグを持つもの)がローカルに無い - リポジトリ
library/hello-world
から、latest
(最新)のタグを持つイメージを取得(pull
) - イメージ・レイヤ
5b0f327be733
のダウンロード完了 - ダウンロードしたイメージのハッシュ値は
41a65640635299bab090f783209c1e3a3f11934cf7756b09cb2f1e02147c6ed8
- 状態(
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.
(amd64)
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://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
つまり、 docker container run
を実行すると、 hello-world
イメージ使ったコンテナを実行し、イメージ内に含まれるコマンドを実行の後、コンテナは終了しました。
4. コンテナの状態をdocker ps -a
コマンドで確認します。
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8e90d1973f23 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago amazing_gates
ここでは、コンテナ ID 8e90d1973f23
で、イメージに hello-world
を使ったものが、2分前に作成され、ステータス(状態)が Exited
になっているのがわかります。
- コンテナにはコンテナ ID が割り当てられます。この例では
8e90d1973f23
に該当します。 - イメージ
hello-world
を使っています - コマンド
/hello
を実行しています - 正常に終了
Exited (0)
しています - コンテナ名は
amazing_gates
です
なお、コンテナ名は実行時に --name
オプションで指定できますが、コンテナの名前を重複して起動できません。また、コンテナ名の指定がなければ、「形容詞」+「著名な科学者かハッカーの名前」で自動的に割り振られます(詳細:名前生成のソースコード)
5. 今度は docker ps
コマンドを実行します。
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
このように、docker ps
は「実行中」のコンテナしか表示しません。docker ps -a
は -a
オプション (all) があるので、停止中のコンテナを含めたすべてを表示します。
6. 再び docker run hello-world
を実行します。
# docker 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
399573d69055 hello-world "/hello" 3 seconds ago Exited (0) 2 seconds ago gallant_sutherland
8e90d1973f23 hello-world "/hello" 10 minutes ago Exited (0) 10 minutes ago amazing_gates
8. コンテナ(用のイメージ・レイヤ)を docker rm
で削除します。
停止中のコンテナは削除用コマンドで削除できます(実行中のコンテナは -f
オプションを付けて、強制削除できます)。削除後は復旧できません。
# docker 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:
399573d690559d2b81e7d255618df88403004a21062b9c59ef27ccf46c54e490
8e90d1973f23850279dfa1098ff9a36c149cd98ace77dabcdf9dfb4570caf628
Total reclaimed space: 0B
9. コンテナが何も残っていないのを確認します。
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2.3. 様々な Linux ディストリビューションのコンテナを実行
1. CentOS のコンテナを起動します。
# docker run -it centos:7 /bin/bash
Unable to find image 'centos:7' locally
7: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:7
[root@2f3c37eb6e00 /]#
2. ps ax
や pwd
や ls -al /
などのコマンドを実行します。何か気付きましたか?
3. exit
を入力してコンテナを終了します。
同様の手順で、他の Linux コンテナを起動します。
ubuntu:18.04
debian:9
alpine:latest
3. docker/whale を使ったDocker コンテナ実行と Docker イメージ構築
目的
- Docker の基本コマンド、イメージの構築をはじめ、Docker Hub をつかった一通りのライフサイクルを学びます。
手順
3.1. docker/whalesay イメージのダウンロードとコンテナ実行
1. docker/whalesay
という鯨に何かを喋らせるプログラムが入ったイメージをダウンロードします。イメージをダウンロードするコマンドは docker pull
(docker image pull) です。
# docker pull docker/whalesay
Using default tag: latest
latest: Pulling from docker/whalesay
e190868d63f8: Pull complete
909cd34c6fd7: Pull complete
0b9bfabab7c1: Pull complete
a3ed95caeb02: Pull complete
00bf65475aba: Pull complete
c57b6bcc83e3: Pull complete
8978f6879e2f: Pull complete
8eed3712d2cf: Pull complete
Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b
Status: Downloaded newer image for docker/whalesay:latest
2. イメージがダウンロードされているのを docker images
(docker image ls) コマンドで確認します。
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker/whalesay latest 6b362a9f73eb 4 years ago 247MB
3. イメージ docker/whalesay
を使い、コンテナとして実行します。 docker 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 __/
\ \ __/
\____\______/
3.2. Dockerfile の利用~もっと賢そうな鯨のイメージを構築
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 build -t mywhale .
コマンドでイメージを自動構築します。
オプションで -t イメージ名
と、末尾に .
(どこに Dockerfile や Docker イメージに格納するかを示すファイルのパス)を指定します。
# docker 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 images
コマンドで mywhale
イメージが作成されているのを確認します。
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mywhale latest f70198e1d8e0 54 seconds ago 257MB
5. docker history mywhale
を実行し、イメージ・レイヤの情報を確認します。
# docker 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 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 __/
\ \ __/
\____\______/
実行するたびに表示するメッセージ内容は変わります。
3.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 images
で、同じイメージ ID に対して、複数のタグが付与されているのを確認します。
# docker images
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 rmi mywhale
( docker image rm mywhale) でイメージを消します。
# docker rmi 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 run <ユーザ名>/mywhale
で実行します。
# docker 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/
4. Nginxコンテナとネットワーク・ボリュームの理解
4.1. Alpine Linux 対応 Nginx イメージのダウンロード
ゴール:コンテナのポートをホスト側に公開(EXPOSE)する方法、コンテナとホスト間でデータをやりとりする方法を学びます。
1. docker pull nginx:alpine
を実行し、Nginx ウェブ・サーバ用の Docker イメージをダウンロードします。
# docker 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 images
で、イメージを確認します。
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine ea7bef82810a 29 hours ago 15.5MB
ここでは nginx
イメージに alpine
タグを指定して取得しました。タグは通常、何も指定しなければ latest
となります。 alpine
は Alpine Linux という最小で 4MB 程度の Linux ディストリビューションです。容量がとても小さいながらパッケージ管理ツール(apk)が導入されており、セキュリティも考慮されていることから、コンテナ用の OS として注目を集めています。
4.2. コンテナとホスト側との通信
1. Nginx コンテナを docker run -d nginx:alpine
で実行します。
# docker run -d nginx:alpine
4c977341985555599c98085defe9548fbc1e3abbeb1ba87c4c65db81334d32ba
新しいオプション -d
はデタッチド(detach)・モードといい、バックグランドでコンテナ(のプロセス)を実行し、コンテナ ID を 画面に表示します。 docker ps
を実行すると、起動中だと分かります。
# docker ps
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 run -d -P nginx:alpine
を実行します。
# docker run -d -P nginx:alpine
de88fc4ba6860b8161a62d8938fb1eedc335b02df247bba763367fa3f8bf886e
3. docker ps
コマンドで何番のポートを使っているか調べます。
# docker ps
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 run -d -P nginx:alpine
コマンドを実行し、複数の Nginx 環境が起動しているのを確認できます。
5. ホスト側のポート 8080 をコンテナ内の 80 に割り当てるには -p
オプションを使い、 -p 8080:80
のように指定します。
# docker run -d -p 8080:80 nginx:alpine
2c89576e996254da4d48c7d5b428da93b2e6fd6e2995363a86c604502c51b509
ブラウザから http://IPアドレス:8080
にアクセスすると、Nginx の画面を確認できます。
なお、ホスト側では同じポートを重複して起動できません。起動を試みても次のようにエラーとなります。
# docker 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
このように、コンテナ起動時にネットワークを指定すると、コンテナ間でお互いに接続できない環境を作ることもできます。
4.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 コンテナを実行しても、ディレクトリ内容のデータが保持されているのを確認します。
4.4. ボリュームを指定した Nginx コンテナ・PHP コンテナの起動
デフォルトの Nginx コンテナは、ドキュメント・ルートが /usr/share/nginx/html/
ですが、ここにコンテンツをコピーする必要があります。ここでは、ボリュームのマウント機能を使い、 Nginx のドキュメントルートを指定します。
1. Nginx コンテナに myvolume
ボリュームをマウントして起動します。
# docker 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 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
ブラウザから見えるかどうかを確認します。
このように、ボリュームを使えば、コンテナ間のデータ共有や、ホスト上のディレクトリをコンテナ内からも参照できます。
5. Docker Compose
5.1. Docker compose のセットアップ
# yum install docker-compose
5.2. WordPress
# mkdir mywp
# cd mywp
# vi docker-compose.yml
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
# docker-compose up -d