Docker入門【ドットインストール】

せっかくならよく耳にする**Docker**を利用して仮想環境を構築しようと思い、例によってドットインストール様の動画を見ながら勉強、および構築を行いました。
<a href="http://dotinstall.com/lessons/basic_docker" target="_blank">Docker入門</a>
# #01 Dockerとは何か？
* **軽量な仮想化環境**
* **Build once, run anywhere**

環境を簡単に集約できることはもちろんのこと、その環境を他の開発者がすぐに利用できる、という点も利点として挙げられる。
> Dockerは、アプリケーションとOSをパッケージし、イメージ化する機能だけでなく、コンテナの機能に加えて、APIの提供やインターネットを通じて世界中の開発者の成果物を入手したり、逆に成果物をアップロードしたりすることで、成果物を効率よく管理、利活用する仕組みや、それらの一連の作業を自動化する機構などが備わっています。クラウド基盤ソフトウェアに比べ、導入のハードルも比較的低く、これらの魅力的な機能を簡単に試すことができるため、多くの開発者やIT部門の管理者での利用が急激に広まっています。
> <a href="https://thinkit.co.jp/story/2015/08/05/6284" target="_blank">巷で話題のDockerとは？ - Think IT</a>

<a href="https://www.docker.com/" target="_blank">Docker公式サイト</a>
（頻繁に仕様が変わるため、困ったら見ると良い）
# #02 Ubuntuを用意しよう
今回のレッスンでは、Vagrantにて**Ubuntu**を立ち上げる。
CentOSがVagrantではよく利用されているが、DockerはUbuntuにて開発されているため、今回はUbuntuを利用する。
<a href="http://maplesystems.co.jp/blog/programming/6478.html" target="_blank">サーバの土台となる！Linuxの各ディストリビューションの特徴まとめ</a>

1.<a href="http://www.vagrantbox.es/" target="_blank">Vagrantbox.es</a>より、**Ubuntu 14.04**のURLをコピー。
（https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box）

2.仮想環境を構築するディレクトリまで入り、インストールする

```sh
$ vagrant box add trusty64 https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
```

3.インストールが完了したら、Vagrantfileを作成する

```sh
# Docker用のディレクトリを作成する
$ mkdir Docker
$ cd Docker/
# Vagrantfileを作成
$ vagrant init trusty64
```

4.Vagrantfile内のipアドレスを変更する

```diff:Vagrantfile
- # config.vm.network "private_network", ip: "192.168.33.10"
+ config.vm.network "private_network", ip: "192.168.55.44"
```

5.Vagrantを立ち上げる

```sh
$ vagrant up
```

6.VagrantにSSH接続する

```sh
$ vagrant ssh
```

このような表示になっていれば、成功。

```sh
vagrant@vagrant-ubuntu-trusty-64:~$
```

# #03 Dockerをインストールしよう
このあたりは動画と私の端末で若干異なったため、勉強も兼ねて取り組む。
## インストール情報
Docker公式サイト https://docs.docker.com/
⇒ DOCS（右上）
⇒ Docker Engine（サイドバー）
⇒ Install
⇒ On Linux distributions
⇒ Installation on Ubuntu

対象の中に、今回インストールした`Ubuntu Trusty 14.04`を発見。
## 前提条件
カーネルが3.10より古いと動かないようなので、OSを確認。

```sh
# OSのリリースを表示
$ uname -r
# 3.13.0-85-generic
```

## システムをアップグレードする

```sh
$ sudo apt-get update
```

### APTとは
> APTとは、Linuxでソフトウェアの導入や管理、削除に用いられるパッケージ管理システムの一つ。Debian Projectによって開発されたもので、Debian系ディストリビューションでよく使われている。
> APTは関連する様々な作業をまとめて自動的に実行してくれるため、利用者が明示的に個々のステップを指示する必要がない。例えば、あるパッケージを導入するには「apt-get install パッケージ名」というコマンドを入力するだけで、インターネットからのファイルのダウンロードやソースコードのコンパイル、実行可能ファイルの作成・配置などをすべて行なってくれる。その際、そのパッケージが依存している別のパッケージがある場合には、これも自動的に探してきてインストールしてくれる。パッケージの更新や削除に関しても同様である。ディストリビューションを丸ごとアップグレードする機能もある。
> <a href="http://e-words.jp/w/APT-1.html" target="_blank">APT 【 Advanced Packaging Tool 】 - e-Words</a>

同じ略称で、<a href="http://e-words.jp/w/APT-2.html" target="_blank">Advanced Persistent Threats（持続的標的型攻撃）</a>もあるようだ。

## Dockerのインストール
このあたりからこちらのサイトを参考にして実施した。
<a href="http://docs.docker.jp/index.html" target="_blank">Docker ドキュメント日本語化プロジェクト</a>

```sh
$ curl -fsSL https://get.docker.com/ | sh
```

curlコマンドは以下を参照。
<a href="https://hydrocul.github.io/wiki/commands/curl.html" target="_blank">https://hydrocul.github.io/wiki/commands/curl.html</a>

## GPGキーを加える

> 「GnuPG」（GNU Privacy Guard）という暗号化ソフトで生成される公開鍵です。Linuxの場合，apt-getコマンドやyumコマンドを使ってインターネットから入手できるパッケージが正しい配布先のものかどうかのチェックなどに利用しています。
> <a href="http://itpro.nikkeibp.co.jp/article/Keyword/20091204/341579/?rt=nocnt" target="_blank">GPGキーとは - 日経コンピュータ</a>

```sh
$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
```

## Dockerのバージョンを確認

```sh
$ docker --version
# Docker version 1.11.0, build 4dc5990
```

今回インストールしたDockerは**1.11.0**のようです。
# #04 作業の流れと用語を理解しよう
このレッスンでは、表題の内容の解説でしたが、自分なりにDockerの特徴も踏まえて調べてみました。
参考にしたサイトはこちら⇒<a href="http://docker.yuichi.com/index.html" target="_blank">Docker 入門</a>
## Dockerの特徴
<img src="http://docker.yuichi.com/resources/ppt/about_vm.png" width=300px>
画像元：<a href="http://docker.yuichi.com/about/docker/index.html" target="_blank">Dockerの特徴 - Docker 入門</a>

上図は仮想化方式の仕組み。
Hyper Visor（左）はOSそのものが仮想化のために設計されているため、オーバーヘッド（処理や負荷）が少なくなる。
それに対して、MacやWindowsなどのOS上で動くものは、ユーザーが操作しやすい反面、オーバーヘッドが大きくなる。

<img src="http://docker.yuichi.com/resources/ppt/about_docker.png" width=300px>
画像元：<a href="http://docker.yuichi.com/about/docker/index.html" target="_blank">Dockerの特徴 - Docker 入門</a>

Dockerはどうなのか？
上図にHyper VisorとDockerの比較図を載せるが、私がざっくり覚えた感じは…
従来の方法・・・OSに全部乗っかっている。
Docker・・・コンテナごとに独立したプロセスとして管理できる。
（いやいや全然分かってないよ、という方ご指摘お願いします。）
もっと詳細に解説しているサイトは⇒<a href="http://www.atmarkit.co.jp/ait/articles/1407/14/news122.html" target="_blank">Docker - @IT</a>

そしてこのコンテナを別の開発者の方に利用してもらうこともできる。
（この辺りはGitと同じようなイメージ？）
# #05 Imageを操作してみよう
DockerではOSやアプリケーションのことを**Image**という。
Docker Indexで索引が可能だが、<a href="https://hub.docker.com/" target="_blank">Docker Hub</a>に登録しないといけないようなので、ユーザー登録をする。
（Githubと似たような感じ）
## Imageの検索
右上の検索ボタンで可能。
例えば、`centos`とやると下図のようになる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/118817/2ce80a72-c295-47de-f24a-3df1966cc496.png" width=400px>
## Imageをpullする
Docker Hubからもできるようだが、コマンドラインでImageをプルする。

まずはImageを検索する（今回はCentOS）。

```sh
$ sudo docker search centos | more
```

そうすると、CentOSのImage一覧が取得できる（公式や個人が作ったものと様々）。
この中からお目当てのImageをプルする。
今回は公式の`centos`をプル。

```sh
$ sudo docker pull centos
```
## コンテナのImage一覧を見る
プルできたら、Imageを確認する。

```sh
$ sudo docker images
```

これで、現在取得しているImageを見ることができる。
Imageは下表のような形ででてくる。

| REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
|:------------:|:------------:|:------------:|:------------:|:------------:|

また、詳細な内容を確認したければ、`inspect`を使用する。

```sh
$ sudo docker inspect centos:latest
```

このとき、`inspect`の引数には対象が一意に特定できるようにしたいため、**リポジトリ名:タグ名**もしくは**Image IDの最初の3〜4桁**を指定してあげる。
## Imageの削除

```sh
$ sudo docker rmi centos:latest
# rmi: remove image
```
# #06 Containerを操作してみよう
## Containerを作成する
```sh
$ sudo docker run centos echo "hello world"
```

これは`CentOS`ImageでContainerを作成して、`echo "hello world"`というコマンドを実行する。
## Containerの一覧を見る
```sh
# 実行中のContainer一覧
$ sudo docker ps

# 全てのContainer一覧
$ sudo docker ps -a

# 最新の5つを取得
$ sudo docker ps -a -n=5
```

また、この一覧のときに`CONTAINER ID`を取得できるので、`IMAGE ID`と同様に利用する。
## Containerの削除
```sh
# d9eはCONTAINER IDの頭3桁
$ sudo docker rm d9e
```

#07 実行中のContainerを操作しよう
今度は、バックグラウンドで動くコンテナを作成する。
`run -d`は、Dockerをデタッチモード（バックグラウンド）で起動する。
`free`はLinuxコマンド（<a href="http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230780/" target="_blank">【 free 】 メモリーの使用状況を表示する</a>）。

```sh
$ sudo docker run -d centos free -s 3
```

これは常に動いているため、`ps`で見ることができる。
また、Dockerのログを見るためには、`logs`を利用する。

```sh
# 158はCONTAINER IDの頭3桁
$ sudo docker logs 158
```
バックグラウンドで動いているコンテナをフォアグラウンドに持ってくることもできる。
`attach`は実行中のコンテナに接続する。
`--sig-proxy=false`オプションにて、`Ctrl+C`で抜けてもコンテナは実行を続ける。
（`true`にするとその逆。）

```sh
$ sudo docker attach --sig-proxy=false 158
```
## Containerの停止、終了
強制終了は`kill`。

```sh
$ sudo docker kill 158
```

停止は`stop`。

```sh
$ sudo docker stop 158
```

開始は`start`。

```sh
$ sudo docker start 158
```
こちらの方の記事が非常に参考になりました↓
<a href="http://qiita.com/kooohei/items/0e788a2ce8c30f9dba53" target="_blank">Dockerコンテナの作成、起動〜停止まで</a>
# #08 ContainerからImageを作ってみよう
Containerの中でImageを作成したり、変更したりする。
1.Containerにインタラクティブモードで入る（`run -i`）
2.ターミナルを立ち上げる（オプション`-t`）
3.引数で与えられた`/bin/bash`でシェルを指定

```sh
$ sudo docker run -i -t centos /bin/bash
```

これで、Containerの中に入れるため、試しに`ls`で構成を見てみる。
ここに新しく`hello.txt`ファイルを作成する。
（`touch`コマンドを利用しました。 ⇒ <a href="http://www.linux-beginner.com/linux_kihon30.html" target="_blank">空のファイルを作成しよう！！</a>）

新しくファイルの作成が確認できたら、`exit`でインタラクティブモードから抜ける。

そして、Imageを作成する。
（このあたりはGitに似ているかも。）

```sh
# CONTAINER IDの取得
$ sudo docker ps -a

# commitでImageを作成
$ sudo docker commit 0f2 naoki85/hello

# Imageを確認
$ sudo docker images
```

これで作成したContainerがImageとして保存された。
# #09 Dockerfileを使ってみよう
1.Imageを取得して、2.Containerを作成して、3.再びImageにする。
この作業を一連の流れとしてビルドすることができる。
その際には、`Dockerfile`を利用する。

カレントディレクトリに`Dockerfile`を作成し、以下のように記述する。
（今回は`echo`するだけ。）

```sh
# 元にするImageを書く
FROM centos
# 誰が書いたか記述
MAINTAINER naoki85 <naoki85@gmail.com>
# RUN: buildするときに実行される
RUN echo "now building..."
# CMD: runするときに実行される
CMD ["echo","now running..."] # CMD echo "now running..."
```

これを以下のコマンドでビルドする。
詳しくは下記のリファレンスに記載されているが、`build -t`でImageにタグ付けして構築している。
<a href="http://docs.docker.jp/engine/reference/commandline/build.html?highlight=build#t" target="_blank">build - コマンドライン・リファレンス</a>

```sh
$ sudo docker build -t naoki85/echo .
# 以下、処理中の表示
Sending build context to Docker daemon 15.36 kB
Step 1 : FROM centos
 ---> 778a53015523
Step 2 : MAINTAINER naoki85 <naoki85@gmail.com>
 ---> Running in 235bbf9e23b6
 ---> 368aad18e229
Removing intermediate container 235bbf9e23b6
Step 3 : RUN echo "now building..."
 ---> Running in ac042091f261
now building...
 ---> 0cee1630782e
Removing intermediate container ac042091f261
Step 4 : CMD echo now running...
 ---> Running in a5c7a1380e79
 ---> 682ab136f943
Removing intermediate container a5c7a1380e79
Successfully built 682ab136f943
```

これで、Imageが作成された。
試しに`run`をしてみると、`CMD`で記述したコマンドが実行される。

```sh
sudo docker run naoki85/echo
# now running...
```

# #10 Webサーバーを立ち上げてみよう
**httpdがインストールされないため、ここは注意が必要。**
（バグ？他の方の記事にもあったよう⇒<a href="http://qiita.com/kaakaa_hoe/items/602f0cef1fa50ebdcbfc" target="_blank">Ubuntu上のdocker build で error</a>）
また、ちょっと古い仕様だから、という指摘も受けた。
こちらについては調査する。

ビルドの際にWebサーバーをインストールし、`run`で確認する。

```sh
FROM centos
MAINTAINER naoki85 <naoki85@gmail.com>
RUN yum install -y httpd
# index.htmlをコピー
ADD ./index.html /var/www/html/
# 80番ポートをあける
EXPOSE 80
CMD ["usr/sbin/httpd","-D","FOREGROUND"]
```

適当な`index.html`を作成してビルドする。

```sh
$ sudo docker build -t naoki85/httpd .
```

ビルドが成功したら、`run`。

```sh
$ sudo docker run -p 8080:80 -d naoki85/httpd
```

成功していれば、Webページが表示されている。
# #11 Imageをpushしてみよう
Imageをプッシュするためには、Docker Hubにログインしなければならない。

```sh
$ sudo docker login
# ユーザーネームとパスワードが聞かれる
# ログアウトはsudo docker logout
```

その後、Imageをプッシュする

```sh
$ sudo docker push naoki85/httpd
```

すると、Docker Hubの方に登録されている。
## 終わりに
httpdのインストールのところは現在の仕様だとうまくいかないようなので、解決法を探す。