boot2dockerを利用してDocker上のnginxにアクセスしてみる


Dockerを使い始めてみたので、覚え書き的に書いていきます。
おかしいところなどあればご指摘下さいm(_ _)m
##今回のゴール
・Dockerの基本機能の把握＋理解
・ローカル環境でnginxが動作するDockerコンテナを構築する。

##Dockerとは
[Docker](https://www.docker.com/)はImmutable Infrastructureという概念を採用しており、どの環境にデプロイしても冪等性を担保したインフラを実現する技術である。
つまり、
・デプロイしたら動かなかった
・デプロイ先によってバージョンが異なる
といった問題が生じない

Dockerはコンテナと呼ばれるアプリケーションのパッケージを作成することでき、Dockerfileに設定を記述することで独自のコンテナを作成することができる。
もちろん予め用意されたイメージを利用することも可能で、[dockerhub](https://hub.docker.com/)というサイト上に存在するイメージをpullしてきて利用ができる。
Dockerfile内に利用したいイメージを記述することで既存のイメージに設定の追加した独自のイメージを作成することも可能。


DockerはLinuxでしか利用できないためMacで利用するにはboot2docker経由でDockerを利用する必要がある。
http://boot2docker.io/

##Virtualboxのインストール
boot2dockerはvirtualbox上で走るcoreosの仮想マシンなのでまずはVirtualboxをインストールする
https://www.virtualbox.org/wiki/Downloads


##Dockerのインストール


brewでDocker/boot2dockerをインストール

```zsh
brew install docker boot2docker
```
インストールされたことを確認

```zsh
boot2docker version
docker -v
```
まずはdockerを動かすための仮想マシンであるboot2dockerを初期化→起動

```zsh
boot2docker init
boot2docker up
```
upした時点でDOCKER_HOSTという環境変数を設定するように出力されるので、それに従って~/.zshrcや~/.bash_profileなどに適宜設定する。

##CentOSイメージを取得
DockerHub上には多数の公式イメージも存在している
https://registry.hub.docker.com/

今回はそこからCentOSの公式イメージをインストールする。

```zsh
docker pull centos
```
docker pullはイメージを取得してくるコマンド

```zsh
docker images
```
docker imagesでcentosが表示され、pullされていることを確認する

##早速動かしてみる
早速インストールしてきたイメージを動かしてみる。
↓のサンプルはcentosイメージに"hello docker"を出力させる例

```zsh
docker run centos echo "hello docker"
```

また、以下のように標準入力を開く事も可能である

```zsh
% docker run -i -t centos /bin/bash
bash-4.2# echo "hello docker"
hello docker
bash-4.2# exit
exit
```

##イメージを保存する
さらに、イメージに対して変更を加えた場合（例えば、標準入力内でyum installなどを行った際など）、その変更適用済みのイメージを他の部分でも使いたい場面などがある。
Dockerにはcommitという変更を適用した状態をセーブする機能が存在し、commitすればその後、そのコミットした状態からイメージを操作することができる。
↓の例では``` echo "hello world"```を実行し、```docker ps -a```で実行済みのプロセスも含め表示させている。

```zsh
% docker run centos echo "hello world"
hello world
Reo-no-MacBook-Pro% docker ps -a
CONTAINER ID        IMAGE              COMMAND                CREATED            STATUS                    PORTS                NAMES
43fa67c118f5        centos:centos7      echo 'hello world'    24 hours ago        Exited (0) 3 seconds ago                        mad_lumiere
```
するとそれぞれにCONTAINER_IDというユニークなIDが発行されるので、そのIDをcommitしていく

```zsh
% docker commit 43fa67c118f5 centos:helloworld
de44ab74e61aa20156013946717c3f13937802b63e88378d5c8cac4b55ea9ae6
```
↑の例では43fa67c118f5というcontainer_idに対してcentos:helloworldというイメージを作成している
イメージの名前は「:」で区切られているが、手前がイメージ名、後ろがタグとなっている。
実際にイメージが作成出来ているかを確認するために、イメージの一覧を出力する```docker images```を実行する

```zsh
% docker images
REPOSITORY          TAG                IMAGE ID            CREATED            VIRTUAL SIZE
centos              helloworld          de44ab74e61a        24 hours ago        236.4 MB
```
実際にtagがhelloworldとなっているdockerイメージが生成されているのを確認できた。
##Dockerイメージを作成する
###Dockerfileを作成
これまでは既存のdockerイメージを利用していたが、実際に自分でイメージをビルドして使ってみる。
Dockerのイメージをビルドする際はDockerfileというファイルを作成し、その中に環境を記述してあげれば、思い通りのイメージを作成できる。
以下の例ではnginxをインストールし、実行する命令を記述している。

```Dockerfile
FROM centos

MAINTAINER reoy

RUN yum update -y

ADD nginx.repo /etc/yum.repos.d/
RUN yum install -y nginx

EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]

```
Dockerfileの説明としては
```FROM```は作成するイメージのもととなるイメージ。ここではcentosの環境を利用したいのでFROMにcentosを指定している。
```MAINTAINER```は作成者
```RUN```はビルド時に実行される命令を設定することができるコマンド
```ADD```はファイルをローカルからイメージの中にコピーするコマンド
```EXPOSE```はイメージがコンテナとして実行された際に開放するポートを指定するコマンド
```ENTRYPOINT```は```CMD```というコマンドと似ているが両方共にビルド時ではなくdocker runのタイミングで実行されるコマンド。それぞれの違いは主にシェルを通してコマンドを実行しているかどうかである。
また、上記の例のnginx.repoは
http://wiki.nginx.org/Install
↑のサイトを参考に作成している
###ビルドしてみる
ここまでで作成したDockerfileを基に実際にビルドしてみる

```zsh
docker build -t centos/nginx:test .
```
↑ではビルドを実行しており、-tオプションをつけることでタグをつけている。つまり例ではcentos/nginxという名前のイメージを作成し、そのイメージにtestというタグをつけている。
末尾の「.」はカレントディレクトリを指しており、絶対パスでDockerfileのあるディレクトリを指定する事も可能。
```docker images```を実行して、先ほど作成したイメージが作成されていることを確認

```
% docker images
centos/nginx        test                775fd7e82bf1        37 hours ago        321.8 MB
```
###RUNしてみる
それでは先ほど作成したイメージを実行してみる

```zsh
% docker run -d -p 80:80 centos/nginx:test
6a9d9f667462d7d216f76f2a41753c0362221c4f85dc47e2f99b304bbc93e519
% docker ps
CONTAINER ID        IMAGE              COMMAND                CREATED            STATUS              PORTS                NAMES
6a9d9f667462        centos/nginx:test  /usr/sbin/nginx -g '  38 hours ago        Up 13 hours        0.0.0.0:80->80/tcp  lonely_ritchie
```
```docker run```コマンドに```-p```オプションを付けることでホストOSとdockerコンテナのポートを紐付ける事が可能となる。この場合はホストの80番ポートとコンテナ内の80番ポートの紐付けを行っている。
```docker ps```で実際にnginxが実行されてことを確認できた。
それでは```curl```をローカルホストに投げてみる

```zsh
curl http://localhost:80
curl: (7) Failed connect to localhost:80; Connection refused
```
refuseされたがこれは当然の事である。
先ほど```-p```オプションをつけてポートを80番に設定しているがそれは「仮想マシン(boot2docker)の80番ポートとdockerの80番ポート」を紐付けたに過ぎないため、OSX上のポートとは紐付いていない。
そこでVirtualboxのポートフォワーディング機能（GUI）を利用してOSXの8080番ポートと仮想マシンの80番ポートを紐付ける必要がある。
もちろん以下のVBoxManageコマンドを利用すればコマンドラインからVirtualBoxの仮想マシンのポートフォワーディングを実行できる。

```zsh
VBoxManage controlvm "boot2docker-vm" natpf1 "nginx,tcp,127.0.0.1,8080,,80"
```
ポートフォワーディングを実行したうえでもう一度curlを実行し、値が返ってくることを確認

```zsh
% curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```
もちろんブラウザからもlocalhost:8080にアクセスで確認可能

##次回予告
AWS Elastic Beanstalkを使って実際にrailsアプリをデプロイするところまでやってみようと思いますー。