Dockerを使ってみた　⑴とりあえずDocker for Macを動かしてみる（とコマンド備忘録）

#Dockerとは？
ハードウェア全体を仮想化する従来のサービスと異なり、あるアプリケーションやサービス単位で仮想化を行う。例えばVisual MachineやVMWareなどはPC全部を仮想化するが（ハイパーパイザー型というらしい）、Dockerは例えばあるRailsのアプリケーションであったり、PostgresqlなどのDBであったりといった個々のサービスごとでの仮想化が可能。（こちらはコンテナ型と言います）。
詳しくは[Docker入門](http://docker.yuichi.com/about/docker/index.html)

##どうして便利？

アプリ開発者にとっては、

- 開発環境を簡単に用意できる。例えば[DockerをインストールするだけでRails開発環境をサクッと作れたり](http://post.simplie.jp/posts/114)とか。
- 開発環境の共通化が簡単。例えば複数人で開発するとき、ある人が最新のRuby2.4.0を使って途中まで開発したものを、私がRuby2.3.0を使って一緒に開発しようとするとエラーが大量に出てしまったり。Dockerは開発環境ごとパッケージ化することで、こういった複数人での間や開発/本番での開発環境を揃えることが簡単になる。[開発環境で使うDocker入門](http://dev.classmethod.jp/tool/docker/develop-with-docker/)

他にもインフラ開発者にとってはコンピューターリソースのオーバーヘッドが少ないとかインフラ構成管理のテキスト化とかの利点などもある（らしい）。[こんな記事](http://www.atmarkit.co.jp/ait/articles/1405/16/news032.html)がDockerが何をもたらすかを丁寧に説明してくれてます。

##DockerイメージとDockerコンテナ

Dockerの「コンテナ型」仮想環境を言うのは、Dockerがソフトウェア（上で言うrailsアプリケーションなど）を動かすとき、「Dockerコンテナ」という箱として動かすため。そしてこの「コンテナ」はDockerイメージと呼ばれるファイルから作られます。Dockerイメージが設計図で、それを元に必要なものを集めて建設作業を進めるとDockerコンテナができる、とイメージすればいいかもしれません。

つまりDockerイメージさえ持って来ればDocker上でソフトウェアを動かすことができ、また開発が終わってこのコンテナがもう必要なくなれば、コンテナ、イメージともに簡単には廃棄ができます。

##とりあえずチュートリアル
MacならばDocker For Macが昨年リリースされ、これを使うと結構すぐDockerを使い始められます。
~~私は最初に読んだドキュメントがDocker-Machineを使ってたので、今週から使い始めたのに今日まで毎回virtulbox立ち上げてましたが~~
[公式](https://docs.docker.com/docker-for-mac/)にチュートリアルはあるのですが、正式な日本語版はないらしい…？のでDockerに関する公式文書の日本語化プロジェクトがあったりする。
大まかな流れとしては、
(1)Docker for Macを公式サイトからインストールする。[ここから](https://docs.docker.com/docker-for-mac/install/)
インストールしてクジラアイコンのDockerアプリを起動するとこんな感じでツールバーにもアイコンが出現します。
![image](https://qiita-image-store.s3.amazonaws.com/0/147809/55c9bc4b-050c-f9f1-4473-3fcf2997043d.png)

(2)ターミナルで
`$ docker -v`と入力してバージョンが確認できればもうインストールは出来ています。ちなみにさっき出てきたDockerイメージは`$ docker images`というコマンドで一覧で見られるのですが、インストール直後は何も入っていません。

(3)今度は`$ docker run hello-world`とターミナルで打つと、以下のような長い文章が。
~~一瞬、あエラーかなとか思いますが、~~ちゃんと読むと「インストール成功してるよ！」って言っています。

```
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
78445dd45222: Pull complete
Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
Status: Downloaded newer image for hello-world:latest

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.
 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.

```
今回のコマンドでDockerが行ったのは、

1. Dockerデーモン（サーバー）にDocker Client（つまりこのコマンドを叩いたこのコンピュータ）がアクセス。
2. hello-worldというDockerイメージからコンテナを作成しようとしたけどローカルにそんなファイルはなかった。
3. だからDockerデーモンがDocker-hubからhello-worldというDockerImageをpullしてきた。
(githubのDocker版のようなもの。Docker上で動かすことのできるたくさんのdockerイメージが集まっており、RubyやJavaなどが公式に提供しているimageも。)
4. Docker Imageからコンテナを作り、実際にプロジェクトを実行した。

ちなみにここで
`$docker images`と入力すると、さっきとは異なりDockerイメージが増えていることがわかります。

```
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              14.04               b969ab9f929b        3 weeks ago         188 MB
hello-world         latest              48b5124b2768        4 weeks ago         1.84 kB
```

##Dockerで良く使うコマンドまとめ

以下は完全に備忘録。

- Dockerイメージの作成
`$ docker build -t [Dockerイメージの名前] .`
（Dockerイメージを作成するためにはDockerfileを先に作る必要があります）

- イメージからコンテナを作る
`$ docker create [イメージの名前]`

- コンテナの起動
`$ docker run [OPTIONS] [イメージの名前] [COMMAND] [ARG...]`

- 起動中のコンテナ一覧を見る
`$ docker ps`

- 起動していないものも含め、コンテナ一覧を見る
`$ docker ps -a`

- コンテナを消去する。
`$ docker rm [コンテナID]`

- コンテナを起動する
`$ docker start [コンテナID]`

- コンテナを停止する
`$ docker stop [コンテナID]`


- Composeファイルを使ってDockerイメージをbuildする
`$ docker-compose build`

- Composeファイルを使ってDockerコンテナを起動する
`$ docker-compose run`

- 上二つを同時に行う
`$docker-compose run --build`

- 起動中のコンテナを停止する
`$ docker-compose stop`
(これを忘れてserver is runningを見る経験、誰でも一回はするはず…)

- コンテナの中にはいる
`$ docker exec -it [コンテナID] bash`
(例えば動いているコンテナの中で`rake db:migrate`してみたりもできます)


##補足

### runコマンドのオプション
公式ドキュメントは[こちら](https://docs.docker.com/engine/reference/commandline/run/)。
 - イメージからコンテナを起動する
`$ docker run -i -t -d IMAGE /bin/bash`
 - ホスト側の8080ポートの通信をコンテナ側80ポートに渡して動かす
 `$docker run -i -t -p 8080:80 IMAGE /bin/bash`
とかはよく使います。

###docker-compose.ymlを使う
ただ実際の開発を進めたりするときにオプションでどんどん渡したり、環境変数をたくさん打ち込むのは面倒。docker-compose.ymlというファイルを作成して、上のdocker-compose向けのコマンドを使うとdocker-compose upという非常に短いコマンドでコンテナの起動ができて便利。
docker-compose.ymlに書く内容としては、ポート番や実行コマンド、またpostgresqlなどのDBを利用する時はそのイメージを読み込み、webのlinksで接続などを行っています。

```
db:
  image: postgres
  expose:
    - "5432"
web:
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  ports:
    - "3000:3000"
  links:
    - db
```

また開発環境、本番環境、テスト環境など設定したい時はweb以下にenvironmentの設定を追加する。
（デフォルトだとproductionになる？）

```
 environment:
      RAILS_ENV: development
```


### Dockerfileをちゃんと書くのはちょっと大変。あと毎回buildはしない

詳細は[Dockerfileのベストプラクティス](http://docs.docker.jp/engine/articles/dockerfile_best-practice.html)。

`RUN apt-get update && apt-get install -y \`でg++、などbundle installで必要なパッケージを入れ忘れると後でこける。ちなみにこう言ったbundle installで必要だけど実際に動かす時には使わない、みたいなパッケージは`apt-get remove -y`で消してしまうのがベター。

ちなみに私は毎回docker-buildして（待つ...）=>(よっしゃ行った！！！)=>（後ろの方でこける）=>ハ━━ヾ(#｀･Д･´)ﾉ━━ァ??!を繰り返していたんですが、[runをしてコンテナ内で作業](http://qiita.com/pottava/items/452bf80e334bc1fee69a)すればよかったらしい。

### .envファイルを読み込む時の注意

```docker-compose.ynl
 env_file:
   - .env
```
と記述すると、railsでの.envファイルのように環境変数をまとめて読み込める。ただし、
`AWS_ACCESS_KEY_ID=HOGE`という感じに変数名とバリューの間にスペースを入れず、　またバリューをシングルクオートで囲ったりしない（VAR=VAL）とうまく読みこまれない。
つまりrailsの環境変数のように`AWS_ACCESS_KEY_ID="HOGE"`とするとちゃんと環境変数が読み込まれない（と思う）。もともと普通に開発していたrailsのアプリで.envを読み込んでいて、かつ後からDockerfile、docker-compose.yamlを作成して最初に作成した.envをそのまま使う時は注意(これに一時間とかした顔)。

###必要なくなったコンテナ、イメージデータボリュームはきちんと削除する
意外と忘れがちなのですが、もう開発を行って必要なくなったコンテナ等は定期的に整理しましょう。上記のコマンドで一つ一つrmしていってもいいのですが、めんどくさいので`$ docker system prune`などで一気に削除したり、起動していないコンテナやコンテナに紐付いていないデータボリューを一気に整理することもできます。~~ちなみに私はこれをちゃんとやっていなかったので知らない間に15GBを占領されていました。~~

[Docker for Macを使っていたら50GB位ディスク容量を圧迫していたのでいろんなものを削除する](http://qiita.com/shinespark/items/526b70b5f0b1ac643ba0)