Docker Machine 入門(AWSの場合)

# 背景
過去に大好評だったDocker入門の内容を2016年版にupdateした再入門投稿3本が終わったので、
まだ紹介していない機能を投稿していきます。

- [Docker 再入門3 2016](http://qiita.com/ohhara_shiojiri/items/cabc644f8a4d1aaf2e36)
- [Docker 再入門2 2016](http://qiita.com/ohhara_shiojiri/items/31a76913cbfdd9d2fe13)
- [Docker 再入門1 2016](http://qiita.com/ohhara_shiojiri/items/98573b074185381d46c8)
- [Docker 入門](http://www.slideshare.net/ShinichiroOhhara/docker-39456836) (SlideShare)

# 動作環境
- ThinkPad X200s OS:Linux MINT 18

個人的に開発環境のOSはLinuxなので、MacOSやWindowsについては優先度が低いのでご了承ください。

# Docker Machine
Docker Engineが動作するにはLinuxカーネルが必要ですが、ホストOSがLinuxの場合はともかく、WindowsやMacOSの場合はVMなどで用意する必要があります。
また、ローカルの開発環境だけでなく本番環境のクラウド側にも必要になります。
このDocker Engineが動作する環境を構築するツールがDocker Machineです。
Docker環境の自動構築ツール、いわゆるオーケストレーションツールがこのDocker Machineです。
2015年8月にDocker Toolboxが登場して大きく状況が変わり、WindowsやMacOSではBoot2Dockerに代わりDocker Machineが推奨されています。
ローカルのVirtualboxだけではなく対応するドライバによって複数の異なる環境下でDockerが構築出来ます。

## インストール
Docker Machineのインストール方法については、[Docker 再入門1 2016](http://qiita.com/ohhara_shiojiri/items/98573b074185381d46c8)にて紹介済みですので、参照して見てください。
Docker for windows の場合にはDocker Engineと共に一緒にインストールされています。

## AWSでDockerを使う
みんな大好きIaaSクラウド最大手のAWS(Amazon Web Service)でDockerを使ってみます。
普通に考えたらEC2でLinuxインスタンスを起動してSSHログインしてDocker Engineをインストールする訳ですが、Docker Machineを使うと簡単に構築が出来ます。

### AWSで事前に準備すること
AWSの詳しい使い方はここでは紹介しませんが、探すと他にも沢山出てきますので割愛します。
事前に準備することは以下の通りです。

- IAM(Identity and Access Management)設定を済ませてユーザーアカウントを用意する。
- アカウント作成時のCSVファイル(credentials.csv)でAccess Key IdとSecret Access Keyを取得する。
- EC2のVPC番号を確認しておく。

### docker-machie create
では早速、AWSにDocker Engineが動作するインスタンスを作成してみましょう。
以下のオプション指定が必要になります。

- --driver amazonec2 ：AWSのEC2用ドライバー指定
- --amazonec2-access-key :自分のAccess Key Idを指定
- --amazonec2-secret-key :自分のSecret Access Keyを指定
- --amazonec2-vpc-id　：自分のVPC番号を指定
- --amazonec2-region　：EC2のリージョンを指定
- --amazonec2-ami　：EC2インスタンスのソースイメージAMI番号を指定


EC2のリージョンコードについては次のページに掲載されています。
- [Regions and Availability Zones](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-regions-availability-zones)(AWS)

以下のコマンド例ではus-west-2(米国西部オレゴン)のEC2を選択しています。
AMIは「Ubuntu Server 16.04 LTS (HVM), SSD Volume Type - ami-746aba14」を指定しました。
EC2インスタンス名にaws-sandboxとしています。

```
$ docker-machine create --driver amazonec2 --amazonec2-access-key AKI0123456789 --amazonec2-secret-key abcdefghijklnmopqrstuvwxyz --amazonec2-vpc-id vpc-12345678 --amazonec2-region us-west-2 --amazonec2-ami ami-746aba14 aws-sandbox
Running pre-create checks...
Creating machine...
(aws-sandbox) Launching instance...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with ubuntu(systemd)...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env aws-sandbox
```

この例では、AWSのEC2オレゴンにUbuntu 16.04LTSのインスタンスをSSH公開鍵のキーペアと共に作成して、Docker Engineのインストールまで自動的に実行します。作成状態はAWSのEC2のWeb画面でも確認が出来ます。
ただ、毎回長いオプションを指定する事は面倒ですし重要なキー情報をコマンドラインに入力するのも避けたいので、以下の設定ファイル(.aws/credentials)に記述して省略させましょう。

``` /home/user/.aws/credentials
[default]
aws_access_key_id = AKI0123456789
aws_secret_access_key = abcdefghijklnmopqrstuvwxyz
aws_vpc_id = vpc-12345678
```

それぞれの項目は自分のキー情報を指定します。
省略したコマンド実行例は以下の通りです。

```
$ docker-machine create --driver amazonec2 --amazonec2-region us-west-2 --amazonec2-ami ami-746aba14 aws-sandbox2
```

### docker-machine ls
作成したDocker Machineの状態を一覧表示します。

```
$ docker-machine ls
NAME           ACTIVE   DRIVER      STATE     URL                        SWARM   DOCKER    ERRORS
aws-sandbox    -        amazonec2   Running   tcp://123.456.789.01:2376           v1.12.3   
aws-sandbox2   -        amazonec2   Running   tcp://123.456.789.02:2376           v1.12.3   
```

### docker-machine ssh EC2インスタンス名
作成したDocker MachieのインスタンスにSSHログインが簡単に出来ます。

```
$ docker-machine ssh aws-sandbox
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-36-generic x86_64)
```

AMIを指定しない場合デフォルトではUbuntu 15.10のAMIでインスタンスが作成されていました。
そのままDocker Engineが動作するか確認してみます。

```
ubuntu@aws-sandbox:~$ docker version
Client:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 21:53:11 2016
 OS/Arch:      linux/amd64
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
```

ここで最後にエラー行が表示されて正常に動作しません。
ソケットファイルは一般ユーザーに書き換え権限がないため、sudoコマンドでroot権限に昇格しないと、単にdockerコマンドを実行するとエラーが表示されます。ユーザーアカウントubuntuをdockerグループに追加することで、sudoコマンドを不要に出来ます。

```
$ sudo gpasswd -a ubuntu docker
```

ここでは、-aオプションでユーザー名(ubuntu)を指定してます。
グループ追加が有効になる為には一旦アカウントからログアウトして、再ログインします。

Ubuntuのパッケージを最新にアップグレードしてEC2インスタンスを再起動します。

```
ubuntu@aws-sandbox:~$ sudo apt-get -y update && sudo apt-get -y upgrade
・・・中略・・・
ubuntu@aws-sandbox:~$ sudo reboot
```

再度、SSHにてログインして動作確認してみましょう。

```
$ docker-machine ssh aws-sandbox
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-45-generic x86_64)
```

```
ubuntu@aws-sandbox:~$ docker version
Client:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 22:01:48 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 22:01:48 2016
 OS/Arch:      linux/amd64
```

今度はエラー表示されませんでした。正常に動作している様子です。
では一度、ローカルにexitで戻りましょう。

```
ubuntu@aws-sandbox:~$ exit
logout
```

### docker-machine scp EC2インスタンス名
SSHログインが出来るわけですから、当然SCPによるファイルコピーも出来ます。
適当なテキストファイルを作成して実行した例が以下です。

```
$ echo "Docker TEST is AWS" > aws-test.txt
$ cat aws-test.txt
$ docker-machine scp -r aws-test.txt aws-sandbox:~
$ docker-machine ssh aws-sandbox
$ cat aws-test.txt
```

コマンドでは-rオプションでディレクトリを指定すればリモートへファイルコピーされます。
当然、パーミッション制限がありますので、ここではユーザーホームディレクトリを指定しました。
IPアドレスやアカウント名を意識することなく安全にSCPが簡単に実行出来ました。

### docker-machine ip EC2インスタンス名
作成したEC2インスタンスのIPアドレスを表示します。

```
$ docker-machine ip aws-sandbox
123.456.789.01
```

### docker-machine inspect EC2インスタンス名
詳しい内容を表示します。

```
$ docker-machine inspect aws-sandbox
{
    "ConfigVersion": 3,
    "Driver": {
        "IPAddress": "123.456.789.01",
        "MachineName": "aws-sandbox",
        "SSHUser": "ubuntu",
        "SSHPort": 22,

・・・中略・・・

        }
    },
    "Name": "aws-sandbox"
}
```

### docker-machine env EC2インスタンス名
dockerコマンドの環境変数を特定のDocker Machineに変更します。
コマンドを実行すると環境変数が表示されるので、最終行の指示にあるようにevalコマンドでシェル環境を特定のDocker Machineへ変更させます。
元に戻す場合は、-uのオプションを使用します。

```
$ docker-machine env -u
```

以下の例では、ローカルのdocker環境からEC2インスタンスのaws-sandboxに変更しています。

```
$ docker-machine env aws-sandbox
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://123.456.789.01:2376"
export DOCKER_CERT_PATH="/home/user/.docker/machine/machines/aws-sandbox"
export DOCKER_MACHINE_NAME="aws-sandbox"
# Run this command to configure your shell: 
# eval $(docker-machine env aws-sandbox)
```

```
$ eval $(docker-machine env aws-sandbox)
```

一見ローカルシェル環境のままですが、Dockerの対象はAWS側のDocker Machine(aws-sandbox)を操作します。
このまま直接、dockerコマンドでnginxをTCP 8000番で実行してみましょう。

```
$ docker run -d -p 8000:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
43c265008fae: Pull complete 
e4c030a565b1: Pull complete 
685b7631c1ce: Pull complete 
Digest: sha256:
Status: Downloaded newer image for nginx:latest
```

自動的に、Docker Hubからnginxのイメージがダウンロードされてnginxサービスが実行されます。
しかしこれはローカル環境ではなく、AWS上のaws-sandboxインスタンスで実行しています。
では、動作確認の為にcurlコマンドやwebブラウザで該当IPアドレスを表示させてみますが、その前にAWSのセキュリティグループを設定してTCP 8000番を開放しておきましょう。
標準のDockerセキュリティグループ(docker-machine)は、ssh(22/tcp)とdocker(2376/tcp)だけ設定されています。

```
$ curl $(docker-machine ip aws-sandbox):8000
```

webブラウザでも8000番ポート指定でnginx標準ページが表示されるはずです。
では、SSHでaws-sandboxへログインして中身の動作確認をしてみましょう。

```
$ docker-machie ssh aws-sandbox

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                           NAMES
abc123456789        nginx               "nginx -g 'daemon off"   7 seconds ago       Up 7 seconds        443/tcp, 0.0.0.0:8000->80/tcp   stoic_ritchie

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              e43d811ce2f4        10 days ago         181.5 MB
```

ちゃんとDocker Hubからイメージがダウンロードされて実行されているのが確認できました。
では一度、ローカルにexitで戻りましょう。
また、ローカル環境に戻しておきます。

```
ubuntu@aws-sandbox:~$ exit
logout

$ docker-machine env -u
unset DOCKER_TLS_VERIFY
unset DOCKER_HOST
unset DOCKER_CERT_PATH
unset DOCKER_MACHINE_NAME
# Run this command to configure your shell: 
# eval $(docker-machine env -u)

$ eval $(docker-machine env -u)
```

### docker-machine stop EC2インスタンス名
AWSのインスタンスを停止します。

```
$ docker-machine stop aws-sandbox
Stopping "aws-sandbox"...
Machine "aws-sandbox" was stopped.

$ docker-machine ls
NAME          ACTIVE   DRIVER      STATE     URL   SWARM   DOCKER    ERRORS
aws-sandbox   -        amazonec2   Stopped                 Unknown   
```

### docker-machine restart EC2インスタンス名
停止したAWSのインスタンスを再起動します。

```
$ docker-machine restart aws-sandbox
Restarting "aws-sandbox"...
Starting "aws-sandbox"...
Machine "aws-sandbox" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Waiting for SSH to be available...
Detecting the provisioner...
Restarted machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
```

最終行のメッセージは、再起動時にAWSインスタンスのIPアドレスが変更した事を知らせています。

### docker-machine rm EC2インスタンス名
AWSのインスタンスを削除します。

```
$ docker-machine rm aws-sandbox
About to remove aws-sandbox
Are you sure? (y/n): y
Successfully removed aws-sandbox

$ docker-machine ls
NAME   ACTIVE   DRIVER   STATE   URL   SWARM   DOCKER   ERRORS
```

本当に削除するか問い合わせて来ますので、Yと答えると削除実行されます。