Dockerを体験してみるハンズオン Part1


前回はdockerを使う動機ということを書いたのですが今回は実際に動かしてみるハンズオン的なものです。

ここで使用しているソースコードはこちらに格納してあります。
https://github.com/NewGyu/docker-demo
readme.mdにもある程度のことを書いてあるので参考にしてください。

前提

解説すること

  • dockerコマンドの簡単な説明
  • およびその概念

解説しないこと

用意するもの

  • AWSのt2.microインスタンスを起動できるAWSアカウントと少々のお金
  • EC2インスタンスにssh接続できるスキル
  • 少々のLinuxコマンドの知識

※Vagrantなどで自分のローカルにLinuxサーバーを立てても構いません

まずは動かしてみよう

1. dockerが動くEC2インスタンスをつくる

  • ECS-Optimized Amazon Linux AMIからt2.microにEC2インスタンスを作成(リッチな人はもっと良いインスタンスでも構いません)
  • セキュリティグループでは80番ポートを開けておいてください

2. デモアプリのコンテナを動かす

$ docker run -it -p 80:80 newgyu/docker-sample:1.0.0

Unable to find image 'newgyu/docker-sample:1.0.0' locally
1.0.0: Pulling from newgyu/docker-sample
e2a4fb18da48: Pulling fs layer 
58016a5acc80: Pulling fs layer 
3f8d2e13b904: Pulling fs layer 
f82bfe122da5: Pulling fs layer 
0ae98a5db0c5: Pulling fs layer 
2b61a94751a3: Pull complete 
:

Digest: sha256:3137e6df67b07bd3f19ec08bdec7c9049a50a07900a45d1f2febfe9b256822a3
Status: Downloaded newer image for newgyu/docker-sample:1.0.0
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.111. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.111. Set the 'ServerName' directive globally to suppress this message
[Sun Oct 25 14:54:49.402642 2015] [mpm_event:notice] [pid 9:tid 140328118753152] AH00489: Apache/2.4.17 (Unix) configured -- resuming normal operations
[Sun Oct 25 14:54:49.412396 2015] [core:notice] [pid 9:tid 140328118753152] AH00094: Command line: 'httpd -D FOREGROUND'

さて、これで、

の2つが確認できると思います。(Tomcatの起動に10秒くらいかかるので せっかちにアクセスするとService Unavailableがでるかもしれません)

コンソールの方を見てみると、

111.238.90.15 - - [25/Oct/2015:15:28:35 +0000] "GET /index.jsp HTTP/1.1" 200 125
111.238.90.15 - - [25/Oct/2015:15:28:40 +0000] "GET /hello HTTP/1.1" 200 103

こんな感じのアクセスログが出ているかと思います。

終了は普通のフォアグラウンドで動いているプロセスを止めるのと同じで、Ctrl+Cです。

これでdockerのコンテナを動かすことが出来ました。パチパチ。

さて、解説

アプリケーションの構成

もう一度動かして確認

今度はバックグラウンドで動かす

$ docker run -d -p 80:80 newgyu/docker-sample:1.0.0

先ほど-itだったところを-dに変えて実行します。
docker runのオプションの意味はこんな感じです。

オプション 意味
i ターミナルからコマンドの入力ができます
t 標準出力に実行したコマンドの結果が出力されます。普通は-itとセットで使います。
d バックグラウンドでデーモンの用に動きます

See: https://docs.docker.com/reference/commandline/run/

さて、今度は先ほどのようなtomcatとapacheの起動ログは出ずにすぐに制御が返ってきましたね。

プロセスを確認する

$ ps -ef | grep -E "(httpd|tomcat)"
root     14352  2235  0 15:56 ?        00:00:00 /bin/sh -c /usr/local/bin/httpd-foreground
root     14367 14352  0 15:56 ?        00:00:00 httpd -DFOREGROUND
root     14396 14352 17 15:56 ?        00:00:37 /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
bin      14405 14367  0 15:56 ?        00:00:00 httpd -DFOREGROUND
bin      14406 14367  0 15:56 ?        00:00:00 httpd -DFOREGROUND
bin      14407 14367  0 15:56 ?        00:00:00 httpd -DFOREGROUND
ec2-user 19434 13661  0 15:59 pts/0    00:00:00 grep --color=auto -E (httpd|tomcat)

ホストマシンにはインストールした覚えのないhttpdやjavaのプロセスが動いていますね。
このようにdocker runで動かしたコンテナは普通のプロセスとして動作します。

今度はdocker psというコマンドを使ってみましょう。

]$ docker ps
CONTAINER ID        IMAGE                        COMMAND                CREATED             STATUS              PORTS                          NAMES
84eb0313086b        newgyu/docker-sample:1.0.0   "/bin/sh -c /usr/loc   5 minutes ago       Up 5 minutes        0.0.0.0:80->80/tcp, 8080/tcp   stupefied_goodall   

CONTAINER ID=84eb0313086bこれが先ほどdocker runで起動したコンテナのIDです。このIDはdockerの世界におけるプロセス番号みたいなものでコンテナを起動するたびに変わるものです。

このようにしてdockerのコンテナの動作状況を確認することが出来ます。

ポートを確認する

$ netstat -tan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State      
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      
tcp        0      0 :::80                       :::*                        LISTEN      
tcp        0      0 :::22                       :::*                        LISTEN      

80番ポートが開いていますね。dockerは仮想マシンのようなものでホストのポートを勝手に開けたりしないのですがなぜでしょう?
ヒントは先ほどdocker psした時のPORTS=0.0.0.0:80->80/tcp, 8080/tcpというところにあります。そしてdocker runした時の-p 80:80です。

オプション 意味
p ホストのポートとコンテナのポートをマッピングします。 -p ホストのポート:コンテナのポート

このようにホストのポートからコンテナのポートにフォワードすることが出来ます。iptablesみたいですね。

$ sudo iptables -L -4
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain DOCKER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             ip-172-17-8-239.ap-northeast-1.compute.internal  tcp dpt:http

dockerが裏でiptablesにルールを追加しているのです。

See: https://docs.docker.com/userguide/dockerlinks/#connect-using-network-port-mapping

コンテナのIPアドレス

コンテナには仮想マシンのNATモードの様にIPアドレスがふられます。
docker inspectで確認できます。

$ docker inspect -f "{{.NetworkSettings.IPAddress}}" 84eb031
172.17.8.239

※84eb031はコンテナIDです。フル桁指定しなくても一意になるところまで省略可能です。

このIPはdockerホスト内だけで有効なIPなので外部から直接コンテナにアクセスすることは出来ません。そのため、上記のような-pでポートのマッピングを行います。
また、コンテナを起動するたびにdockerが自動で割り振りをします。

docker inspect

単に次のようにしてみましょう。

$ docker inspect コンテナId

長いJSONが出ましたね。 -fで指定しているのはjqコマンドの評価式と同じようなものです。
正しくはGo言語のテンプレート式のようです。 ごめんなさいこのへんはあまり詳しくないんでこちらを参考にしてください。

See: https://docs.docker.com/reference/commandline/inspect/


もっと色々書こうと思っていたのですが、疲れたのでまた今度続きを書きたいと思います。
寝ます。

Part2はコチラ