Docker 事始め

docker初心者なので、環境構築、超簡単なContainerの起動、Dockerfileとdocker xxのコマンドライン辺りをチラシの裏しておきます。


Dockerfileは人様の完成品を元にカスタマイズするとハマる事なく捗ります。

* [他人のDockerfileを再利用して楽をする](http://qiita.com/iwag@github/items/a2218de56913f5c0c1c2)
* [GithubのDockerfiles](https://github.com/dockerfile)
* [Dockerhubに登録されたDockerfile](https://registry.hub.docker.com/search?q=dockerfile&searchfield)

## Docker環境をEC2にsetupする
まずEC2を建ててDockerを動かして見ましょう。EC2はt2-microで十分です。
`apt-get install docker.io`でinstallされますがv1.0系が入ってしまいます。fig等を使いたい場合には、v1.3以上が必要なので、docker.ioから直接持ってくるべし。

```
#curl -sSL https://get.docker.io/ubuntu/ | sudo sh
#apt-get update
#apt-get -y install sysv-rc-conf
#sysv-rc-conf docker on
```

`#docker version` でdocker clientのverを確認

```
# docker version
Client version: 1.4.1
Client API version: 1.16
 ...
```

## 初めてのDocker
初めての方は、まずは簡単なnginxなどのContainerを作ってみて、色々dockerコマンドを触ってみると良いです。慣れてきたら[Dockerfileのベストプラクティス](http://postd.cc/building-good-docker-images/)で最適化して下さい。

以下をDockerfileという名前で保存します。Ubuntu14.04ベースにcurlとnginxが入ったContainerを作る設定。

```
FROM ubuntu:14.04
RUN apt-get update && apt-get -y install nginx curl
RUN echo "daemon off;" >> /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx"]
```

そうしたら、作ったDockerfileのdirectoryから、何も考えずに、以下のコマンドを流してみる。

```
#docker build -t test1/test:1.0 ./
#docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
test1/test          1.0                 55469de80222        57 seconds ago      250.3 MB
ubuntu              14.04               5ba9dab47459        12 days ago         192.7 MB

#docker run -p 25525:80 -d test1/test:1.0
#docker ps
CONTAINER ID  IMAGE          COMMAND       CREATED         STATUS         PORTS                   
b54eb8dd4253  test1/test:1.0 "/bin/sh"     8 seconds ago   Up 8 seconds   0.0.0.0:25525->80/tcp           

#curl localhost:25525
```
curlに対して、Welcome to nginxのhtmlが表示されたら、containerのnginxが反応してくれているので成功です！

## Dockerハマりポイント
以下、Docker初心者として踏んだ地雷、ハマりポイントを列挙しておきます。

### ProcessがForegroundで動いていないとContainerは終了する
これ超重要！

Docker Containerでnginxとかmongoとかelasticsearchを動かしたい場合には、Dockerfileに`RUN service nginx start`とかじゃダメなんです！Background実行だけじゃダメ絶対！

ちなみに、上のDockerfileにある`echo "daemon off;" >> /etc/nginx/nginx.conf`という謎のオマジナイは、nginxをdaemon化(background実行)する事を防ぐ為の物です。『Docker』『フォアグラウンド』とかでググると、この問題に対するBest practiceが見つかります。

自分が見つけた範囲では、以下の様な解決のApproachがありました。流行はSupervisorなんですかね。
 * [Supervisorを使う](http://qiita.com/kaishuu0123/items/eaa22b4230753355f7af)
 * [無限Loopのshell scriptを作って、DockerfileのCMDで呼び出す](http://www.hilotech.jp/blog/it/153)
 * [docker runでcontainer起動時に、serviceも起動する](http://blog.cloudpack.jp/2014/08/21/docker-run-apache-on-foreground/)

`docker run xxx`して、`docker ps`しても、起動中のContainerが見つからない場合には、これが原因の可能性があります。
`docker ps -a`でContainerが終了しているか確認してください。


### docker containerのshellを操作したい

Containerを動かしたは良いが、しばらくしてどうも調子が良くないので、中に入ってshell操作して動作状況を確認したい、と言うケースは多々あると思います。そんなときは、`docker exec` を使ってください。docker v1.3からサポートされた便利ツールで、`#docker exec –it <containerID> bash`でOKです。

ちなみに、v1.3以前は以下の様な方法がとられていましたが、v1.3以降はdocker execで捗る様になります。

* `docker logs <containerID>`でstdoutのlogを眺める
* containerのlogを/var/logなどに吐き出す様にしておき、/var/logを `docker run -v`でhost側からもアクセス出来るようにする
* containerにsshdを仕込んでおき、sshでcontainerにlogin/shell操作する
* nsenterというtoolをcontainerに仕込んでおき、 containerのprocessに入りshell操作する


### docker containerのresource消費量を知りたい

docker v1.5から、`docker stats <containerID>`でCPU, Memory, network trafficの量を吐き出してくれるようになりました。
`docker stats <containerID1> <containerID2> <containerID3>`とcontainer IDを続けて列挙すると、それら全てを纏めて吐き出してくれます。`docker stats $(docker ps -q)`とすると、動作中のcontainerの全てのresource消費量を吐き出してくれます。


## Dockerコマンド

### docker build
Dockerfileから、docker imageを作成。以下の場合、./dokcertest以下の`Dockerfile`を見に行く

```
#docker build -t test1/test:1.0 ./dockertest
```

`#docker images`で作成したimageができているか確認

```
#docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZ
test1/test          1.0                 407b5768bc5f        5 hours ago         467.5 MB
ubuntu              14.04               5ba9dab47459        10 days ago         192.7 MB
```

`#docker build --no-cache -t test1/test:1.0 ./dockertest`と`--no-cache`を付けると、強制的に再度docker imageを作成。



### docker run (一番ベタな方法)
docker imageからContainerを起動 (`#docker images`で表示されたImiage IDか、Build時に`-t`で指定したrepository/tagを指定する)。`-d`でbackground実行です。

```
#docker run -d 407b5768bc5f
#docker run -d test1/test:1.0
```

`docker images -q | head -1` が一番新しいimage IDをくれるので、一番直近に作ったimageを起動する場合は以下でもOK

```
#docker run -d $(docker images -q | head -1)
```


### docker run (Port指定)
Containerのport80を、hostの25525にmapして起動。

```
#docker run -p 25525:80 -d 407b5768bc5f
#docker run -p 25525:80 -d test1/test:1.0
```

host上で、`curl localhost:25525`すると、Container上のport80に渡され、Container側のhttp serverの応答を受け取れます。(Container側で、http serverが起動する設定になっていれば)

### docker run (Containerのshellに遷移)
`-it` を付けると、Container起動後、Containerのshellに遷移してします。Dockerfileの`CMD`や`ENDPOINT`でforeground実行されるAppがある場合は、そのlogが表示されます。foreground実行されるAppが無い場合は、Container側のShell操作が可能です。`ctl+p → ctl+q`でHost側のshell操作に戻って来れます。

```
#docker run -it 407b5768bc5f
#docker run -it test1/test:1.0
```

注意点
* `-it`する時は、`-d` を付けないでください(でないとBackground起動されちゃいます)。


### docker run (HostのdirectoryをContainerからもアクセスできるようにする)
-v オプションで、(host側の絶対path):(Container側の絶対path)と表記します。要絶対パス

```
#docker run -v /home/ubuntu:/root/test -d 407b5768bc5f
#docker run -v /home/ubuntu:/root/test -d test1/test:1.0
```


### docker run (Containerを強制的にshell状態で起動)

```
#docker run -it 407b5768bc5f /bin/sh
#docker run -it test1/test:1.0 /bin/sh
```

`docker run xxx /bin/sh`とかすると、Containerの起動時に(Dockerfileの`CMD`の内容を上書きして) Dockerfileの`CMD`の内容は行われずにContainerのshell状態になります。Containerが期待通りの動作をしない様な場合に、上記の様に`docker run -it xxx /bin/sh`でCMDの内容の実行を抑止しつつContainerのshellに入り、そこでCMDの内容をdebug logを沢山吐く設定で動かして見る、などで使います。

ちなみにDocker始めたたての頃、人様のDocker コマンドの記事を見ていて、docker runする時は、`docker run -d 407b5768bc5f /bin/sh`の様に、最後に/bin/shのoptionが常時必要だと思っていました(恥ずかし)。 

### docker link
他のcontainerと連携させる場合に使います。長くなるので、興味のある人は[こちらの記事](http://qiita.com/taka4sato/items/b1bf33941a1ec8b69fd2)を参照下さい。


### docker ps
dockerの起動状態を確認。`docker stop`等で、Containerを止めたいときにContainer IDを確認するのによく使います。

```
#docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS
NAMES
6707e5555b5a        test1/test:1.0      "/bin/sh"           3 seconds ago       Up 2 seconds        24224/tcp, 80/tcp
romantic_blackwell
```

`docker ps -a`すると、過去のContainerも含めたstatusが見れるので、containerが勝手に死んでいるなどの疑いがあるときにはこれで確認。

### docker stop
docker containerの停止(`#docker ps`で表示されたContainer IDを指定する)  

```
#docker stop 6707e5555b5a
```

全ての動作中containerの停止

```
#docker stop $(docker ps -q)
```



### docker logs
docker containerのstdoutのlogを表示します。Containerの調子が悪いときにstdoutのlogを見るのに使います。
docker containerの中に入って、debug等の目的でshell commandを色々実行したい場合には、docker execを使って下さい。

```
#docker logs 6707e5555b5a
```

### docker exec
docker containerに入って、containerの動作状況やlogの確認をしたい場合に使います。
docker v1.3からサポートされました(超便利!) 。
それまでは、containerにsshdを仕込んで居たり、nsenterってtoolを使ったりしてましたが、docker tool側がサポートしてくれました

```
#docker exec –it 6707e5555b5a bash
```
### docker rmi
docker imageの削除

```
#docker rmi 407b5768bc5f

REPOSITORY が <none> になっているものを強制削除する場合
#docker rmi -f $(docker images | awk '/^<none>/ { print $3 }')

全てのDocker imageを強制削除
#docker rmi -f $(docker images -q)
```

### docker rm
docker containerの削除

```
#docker rm `docker ps -a -q`
```



## 参考になった記事
 * [dockerコマンド, DockerfileのOptionなど](http://krrrr.hatenablog.com/entry/2014/12/17/092649)