公式チュートリアルで始めるDocker
そろそろコンテナやってみる
社内では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とかとの使い分けやポジションなどもモヤモヤしています。ということで、ゴールデン・ウィーク明けに社内で議論を深めたいと思います。