この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
そろそろコンテナやってみる
社内ではDockerを使った開発やインフラ構築が盛んですが、私はあまり触っていなかったので、今回公式チュートリアルを使って体験してみようと思います。
Dockerってなんですか?という方は、是非過去の記事をご覧になってください。
Docker Toolbox
まずはセットアップということですが、Docker Toolboxというバイナリが用意されています。これをダウンロードしてインストールすれば直ぐに使えます。
私がインストールしたのは、バージョン1.11.1でした。
コンソールインタフェースとグラフィカルインタフェースが用意されています。
Docker Quickstart Terminal
クイックスタート用のアイコンをクリックすれば準備は整います。
bash --login '/Applications/Docker/Docker Quickstart Terminal.app/Contents/Resources/Scripts/start.sh'
Macintosh-2:~ satoshi$ bash --login '/Applications/Docker/Docker Quickstart Terminal.app/Contents/Resources/Scripts/start.sh'
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
docker is configured to use the default machine with IP 192.168.99.100
For help getting started, check out the docs at https://docs.docker.com
試しにDockerと入力するとオプションが出てきます
$ docker
Usage: docker [OPTIONS] COMMAND [arg...]
docker [ --help | -v | --version ]
A self-sufficient runtime for containers.
Options:
--config=~/.docker Location of client config files
-D, --debug Enable debug mode
-H, --host=[] Daemon socket(s) to connect to
-h, --help Print usage
-l, --log-level=info Set the logging level
--tls Use TLS; implied by --tlsverify
--tlscacert=~/.docker/machine/machines/default/ca.pem Trust certs signed only by this CA
--tlscert=~/.docker/machine/machines/default/cert.pem Path to TLS certificate file
--tlskey=~/.docker/machine/machines/default/key.pem Path to TLS key file
--tlsverify=true Use TLS and verify the remote
-v, --version Print version information and quit
Commands:
attach Attach to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on a container or image
kill Kill a running container
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
network Manage Docker networks
pause Pause all processes within a container
port List port mappings or a specific mapping for the CONTAINER
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart a container
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop a running container
tag Tag an image into a repository
top Display the running processes of a container
unpause Unpause all processes within a container
update Update configuration of one or more containers
version Show the Docker version information
volume Manage Docker volumes
wait Block until a container stops, then print its exit code
Run 'docker COMMAND --help' for more information on a command.
公式チュートリアル動画を見る
さて、Dockerの起動確認までできましたので、公式チュートリアル動画を見始めましょう。以下のサイトから確認することができます。
Tutorials - Docker Fundamentals
さて、ここからかなり端折った説明で進めていきたいと思います。
Imageレイヤー
Dockerは、カーネルの上に多階層のImageレイヤーがあり、一番下にベースとなるImageがあります。これは概ね、DebianとかUbuntuなどのOSに相当する部分です。そして、この上に、ミドルウェアの層が重なります。たとえば、emacsやApacheなどです。それぞれのレイヤーは、下位のレイヤーを参照しています。下位のレイヤーは読み取り専用です。また、最上位のレイヤーは、書き込みできるようになっていて、下位のレイヤーに機能を付け足して独自のImageになりえます。この書き込む操作がCommitです。
Commitをする際のコマンドは、以下のようになっています。
$ docker commit [options] [containar ID] [repository:tag]
例)
$ docker commit 1234567890 satoshi7/myapp:1.0
OSを起動してみる
試しにUtuntuを起動してみます。
$ docker run -it ubuntu:14.04 bash
root@09d4d84350d2:/#
あっさり起動しましたw。試しにcurlコマンドを打ってみます。しかし、そんなコマンドは無いと言われます。DockerのImageは最小構成のミドルウェアしか入っていません。必要なものを自分で追加する必要があります。
root@09d4d84350d2:/# curl 127.0.0.1
bash: curl: command not found
ミドルウェアを追加して新たなImageとする
curlコマンドを追加インストールして、新たなレイヤーとしてImageをコミットしたいと思います。
root@09d4d84350d2:/# apt-get install -y curl
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package curl
エラーになりました。これは、apt-getのパッケージ取得を全くおこなっていないためです。updateコマンドを実行して必要なパッケージを取り込んでからインストールします。ちゃんと動きましたね。
root@09d4d84350d2:/# apt-get -qq update
root@09d4d84350d2:/# apt-get install -y curl
....
root@09d4d84350d2:/# curl 127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused
無事に新しいミドルウェアが入りましたのでコミットしたいと思います。psコマンドで利用しているコンテナのIDが出てきます。
root@09d4d84350d2:/# exit
exit
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09d4d84350d2 ubuntu:14.04 "bash" 10 minutes ago Exited (0) 36 seconds ago determined_snyder
先ほどセットアップしたImageのコンテナIDを指定してコミットして新しいImageを作成します。
$ docker commit 09d4d84350d2 satoshi7/curl:1.0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
satoshi7/curl 1.0 951c6ef7cae3 32 seconds ago 221.1 MB
Imageを指定して起動
新しいImageができましたので、このIDを指定して起動してみましょう。起動直後からcurlを使えるはずです。
$ docker run -it satoshi7/curl:1.0 bash
root@d8980b8a2220:/# curl 127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused
Dockerfileとは
Dockerの起動方法やコミットの方法が分かりました。次にDockerfileというものをご紹介します。これは、Dockerイメージ作成時のコンフィグファイルです。継続的インテグレーションや開発プロセスの役に立つはずです。
FROMでベースImageを指定します。RUNで自動実行するスクリプトを指定します。
このスクリプトは、Buildコマンドを実行時にパスを指定します。これでログインすることなく、新しいImagew作成できますね。
実際にやってみましょう。
$ mkdir DockerTest
$ cd DockerTest/
$ vi Dockerfile
FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
作成したDockerfileを指定してBuildしてみます。
$ docker build -t satoshi7/testimage:1.0 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:14.04
---> 8fa7f61732d6
Step 2 : RUN apt-get update
---> Running in 65c379dfb7e9
......
Successfully built b7726e1f74a0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
satoshi7/testimage 1.0 b7726e1f74a0 2 minutes ago 264.3 MB
ちなみに、RUNコマンドは、複数行ではなく、1行にまとめて書くことで多段階にImageを作成することなく1回で作成できるので処理が早くなります。
コマンド実行
Dockerfile内でCMDキーワードを使うことでdocker runした際に、任意のコマンドを実行できます。
Dockerfileに書いてみましょう
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y curl vim
CMD ping 127.0.0.1 -c 30
そしてbuildを実行します。
$ docker build -t satoshi7/testimage:1.1 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:14.04
---> 8fa7f61732d6
Step 2 : RUN apt-get update && apt-get install -y curl vim
---> Using cache
---> f4e8c45becff
Step 3 : CMD ping 127.0.0.1 -c 30
---> Using cache
---> 3548ff10a927
Successfully built 3548ff10a927
ちなみに、Dockerfileの記述で過去に同じ指示をしている場合、Imageがキャッシュ化されていますので、Buildは高速に終わります。
docker runでコマンドが実行されるか確認してみましょう。
$ docker run -t satoshi7/testimage:1.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.036 ms
もし、起動時に他のコマンドを実行させたければ、引数の最後に指定することもできます。
$ docker run -t satoshi7/testimage:1.1 echo "hello world"
hello world
エントリーポイントの指定
Dockerを起動時にあらかじめ指定したコマンドを実行したいことがあります。この場合は、エントリーポイントを用います。以下の様にDockerfileを書きます。実行時には引数を指定することができます。
$ vi Dockerfile
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y curl vim
ENTRYPOINT ["ping"]
$ docker build -t satoshi7/testimage:1.2 .
$ docker run -t satoshi7/testimage:1.2 127.0.0.1 -c 5
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.100 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.041 ms
コンテナの開始と停止
現在起動中のコンテナ一覧を表示したり、開始や停止を行うことができます。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0605016b02e9 satoshi7/testimage:1.2 "ping 127.0.0.1 -c 5" 4 minutes ago Exited (0) 4 minutes ago high_almeida
c5d63603a451 ef3af9c54122 "/bin/sh -c ping 127." 4 minutes ago Exited (2) 4 minutes ago small_cori
$ docker stop 0605016b02e9
0605016b02e9
$ docker start 0605016b02e9
0605016b02e9
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0605016b02e9 satoshi7/testimage:1.2 "ping 127.0.0.1 -c 5" 6 minutes ago Up 2 seconds high_almeida
c5d63603a451 ef3af9c54122 "/bin/sh -c ping 127." 6 minutes ago Exited (2) 6 minutes ago small_cori
ターミナルアクセス
ターミナルとは、コンテナのメインプロセスです。ターミナルにアクセスする方法としてEXECコマンドがあります。試しにTomcatを起動したコンテナにアクセスしてみます。
$ docker run -d tomcat:7
98779177af02013830c3b6e3a1266d07da80bb953910e66fcafa5d297a0e1f1d
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
98779177af02 tomcat:7 "catalina.sh run" 15 seconds ago Up 14 seconds 8080/tcp admiring_leakey
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
98779177af02 tomcat:7 "catalina.sh run" 5 minutes ago Up 5 minutes 8080/tcp admiring_leakey
$ docker exec -it 98779177af02 bash
root@98779177af02:/usr/local/tomcat# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 1 16:39 ? 00:00:04 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/loggin
root 44 0 0 16:45 ? 00:00:00 bash
root 48 44 0 16:45 ? 00:00:00 ps -ef
root@98779177af02:/usr/local/tomcat# exit
exit
$
コンテナの削除
rmコマンドで削除できます。
$ docker rm 98779177af02
Error response from daemon: You cannot remove a running container 98779177af02013830c3b6e3a1266d07da80bb953910e66fcafa5d297a0e1f1d. Stop the container before attempting removal or use -f
$ docker rm -f 98779177af02
98779177af02
または
$ docker stop 98779177af02
$ docker rm 98779177af02
イメージの削除
イメージを削除するときは、rmiコマンドを用います。コンテナが起動中の場合には削除できませんので、停止して削除してから実行しましょう。
$ docker rmi ef3af9c54122
Error response from daemon: conflict: unable to delete ef3af9c54122 (must be forced) - image is being used by stopped container 1215cab46320
$ docker rmi 0c19b849e34f
Untagged: satoshi7/testimage:1.2
Deleted: sha256:0c19b849e34f7711501cfacd34dd63dcb523cb78ffb4068da1ba61dc92ebfd18
Docker Hubレポジトリ
ローカルで作成したイメージをみんなで共有することができます。Docker Hubのアカウントを作成済みであれば、アップロード可能です。pushコマンドを用います。
ボリューム
ボリュームは、コンテナのライフサイクルとは独立した、永続データを保管するディレクトリーです。コンテナ間で共有することが可能です。ボリュームの設定は、Dockerfile内で指定することも可能です。コンテナが削除されると永続化されます。
実際に、コンテナのライフサイクルと独立しているか確認してみましょう。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 8fa7f61732d6 5 days ago 188 MB
$ docker run -d -P -v /www/website1 nginx:1.7
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4d93a2b27199 nginx:1.7 "nginx -g 'daemon off" 51 seconds ago Up 51 seconds 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp elated_brattain
ボリュームを指定したコンテナの起動を確認したらターミナルに入ります。次に、作成したボリューム内にテキストファイルを作成します。
$ docker exec -it 4d93a2b27199 bash
root@4d93a2b27199:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var www
root@4d93a2b27199:/# cd www/website1/
root@4d93a2b27199:/www/website1# echo "hello" >> test
root@4d93a2b27199:/www/website1# cat test
hello
root@4d93a2b27199:/www/website1# exit
exit
コンテナから抜けて、停止をし、イメージを作成します。
$ docker stop 4d93a2b27199
4d93a2b27199
$ docker commit 4d93a2b27199 satoshi7/myimage:1.0
sha256:433097fcc4551e745669d4c51adcea3d4f1de90f4bcb7387d8922112b9135dcb
作成したイメージからコンテナを起動します。この際に、ボリュームの指定はしていません。
$ docker run -it satoshi7/myimage:1.0 bash
root@5a6c2cd607b0:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var www
root@5a6c2cd607b0:/# cd www/website1/
root@5a6c2cd607b0:/www/website1# ls
root@5a6c2cd607b0:/www/website1#
ボリュームを指定しなかったので、先ほど作成したテキストファイルは見当たりませんでした。
ポートのマッピング
コンテナ内で起動しているプログラムのポートを割り当てることができます。nginx80から8080に割り当ててみます。
$ docker run -d -p 8080:80 nginx
b579e0249c538c5a619cebe522917a7b67dfec88ef2caa145ba73e5a11edf811
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b579e0249c53 nginx "nginx -g 'daemon off" 15 seconds ago Up 15 seconds 443/tcp, 0.0.0.0:8080->80/tcp gloomy_engelbart
$ curl http://192.168.99.100:8080/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
.....
ちなみに、-Pオプションをつけると自動的にポートを割り当てます。また、Dockerfile内でEXPOSEを指定してポート番号を指定することもできます。指定されたポートは、コンテナ外に知らせることができます。コンテナ間通信で活用されたりします。
コンテナ間のリンク
コンテナはリンクすることで相互に通信を行うことができます。リンクを設定する際には、ソースのコンテナから起動する必要があります。
$ docker run -d --name dbms postgres
$ docker run -it --name website --link dbms:db ubuntu:14.04 bash
root@0d79e00e45ca:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 db 46140c452eba dbms
172.17.0.3 0d79e00e45ca
root@0d79e00e45ca:/# exit
exit
データベースのIPアドレスがHostsファイルに登録されていることを確認できました。
まとめ
Docker公式サイトのチュートリアル通りにコマンドを実行するだけで、簡単にDockerの使い方を把握することができました。Dockerという言葉だけ知っているレベルから、使ったことあるレベルまで到達することができました。さて、次のステップでは、具体的にどのようにDockerを使いこなすことで、継続的なインテグレーションなどインフラやミドルウェアの構築やメンテナンスに役立つのでしょうか。今は未だ正直まだフワっとしています。AnsibleとかCloudFormationとかとの使い分けやポジションなどもモヤモヤしています。ということで、ゴールデン・ウィーク明けに社内で議論を深めたいと思います。