Docker の新機能 Desktop to Cloud + α

Docker ID で swarm クラスタへサービスをデプロイできるというもの。

そもそも評価環境や本番環境へは、ビルドはもちろんテストグリーンが保証された
CI/CD 環境などからデプロイされるべきだろうし、開発中にローカルでない環境で
ちょっと確認してみたいというレベルなら docker-machine でもいいだろうし
何がいいものかいまいちわからなかったのでさわってみました。

# まとめ

## Desktop to Cloud

- Docker for Mac などで行われる認証を利用して
    - ユーザごとに利用可能な swarm クラスタの一覧表示
    - （関連付いた組織にもすぐスイッチできる）
    - （管理下にある Docker イメージの一覧も並ぶ）
- あとはクラスタを選択するだけで
    - クラウド上の swarm クラスタに繋がったターミナルが起動
    - Docker Cloud が使うプロキシ型ではなく個別 TCP ソケット接続

## Docker Cloud

- Docker for AWS / Azure が Docker Cloud に統合されていた
- dockercloud/client で認証すると
    - dockercloud/client-proxy がローカルに起動して
    - export DOCKER_HOST=tcp://127.0.0.1:32768 などで
    - クラウド上の swarm と直接やりとりできるようになってた
- 少なくともここまでの範囲は無料でできる


# Docker Cloud から swarm クラスタ作成

既存の swarm クラスタを持ち込まず、
Docker Cloud から作る手順を確認してみる。

## 1. Docker Cloud へのログイン

Docker ID でログインできます。

https://cloud.docker.com/

もしログイン後の画面が下図のように Swarm Mode でなかったなら

<img width="366" alt="ログイン" src="https://qiita-image-store.s3.amazonaws.com/0/66457/e7082197-8ac1-a715-9523-ab99474fb3d9.png">

クリックして以下の画面に切り替えてください。

<img width="387" alt="Swarm モードへ" src="https://qiita-image-store.s3.amazonaws.com/0/66457/fb251b7f-c175-687a-8e90-08e6e0cb3ca6.png">

## 2. swarm クラスタの作成

すでにある swarm クラスタを持ち込むこともできますが、ここはあえて少し面倒な
Docker Cloud へ AssumeRole で安全に AWS の操作権限を渡し、Docker Cloud の
コンソールから swarm クラスタを生成する手順にしてみます。
（原文の手順は [こちら](https://docs.docker.com/docker-cloud/cloud-swarm/link-aws-swarm/) です）

### 2.1 AWS で IAM ロールを発行する

https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/roles

IAM コンソールにログインし、新しいロールを作ります。

<img width="495" alt="ロールの作成" src="https://qiita-image-store.s3.amazonaws.com/0/66457/971978ef-b25b-dcf5-81b2-0ed8d972dc32.png">

クロスアカウントアクセスのためのロールを選び、

<img width="500" alt="クロスアカウントアクセス" src="https://qiita-image-store.s3.amazonaws.com/0/66457/f5212cd9-a9eb-95f8-20ff-6fe699d73f7c.png">

[手順](https://docs.docker.com/docker-cloud/cloud-swarm/link-aws-swarm/)に沿って、DockerCloud の AWS Account ID と、自分の Docker ID をそれぞれ入力します。

<img width="500" alt="ID の指定" src="https://qiita-image-store.s3.amazonaws.com/0/66457/ff70b0de-684a-4016-b30c-6d20f4aeb6cf.png">

名前を決めたら、右下のボタンからロールを生成しましょう。

<img width="500" alt="ロール作成" src="https://qiita-image-store.s3.amazonaws.com/0/66457/d71de068-5266-00e2-390c-36dd32fc3e40.png">

### 2.2 Docker Cloud に渡す権限を設定する

今作った IAM ロールに、適切なポリシーを設定します。
ロールの詳細画面の `Permission タブ` の中の下方、
`Inline Policies` をクリックして `click here` を押します。

<img width="500" alt="インラインポリシー" src="https://qiita-image-store.s3.amazonaws.com/0/66457/7e6db696-df94-2625-8853-5e38928be07d.png">

カスタムポリシーを選択し

<img width="500" alt="権限の設定" src="https://qiita-image-store.s3.amazonaws.com/0/66457/a2543dae-1644-1ce9-8734-92baba289e97.png">

ポリシー名を適宜入力した上で、
Docker Cloud の要求する [この権限](https://docs.docker.com/docker-for-aws/iam-permissions/)[^1] を貼り付け、保存してください。
[^1]: Resource が * だったり、少々過大な権限になってますね・・

<img width="500" alt="ポリシーの編集" src="https://qiita-image-store.s3.amazonaws.com/0/66457/f45b220b-1c8b-ec59-4698-2984e1bbed60.png">

### 2.3 ロールの ARN をコピーする

ロールの詳細画面の一番上に表示されるこれですね。
arn:aws:iam::.. の部分を `Ctrl + C` しましょう。

<img width="500" alt="ARN の取得" src="https://qiita-image-store.s3.amazonaws.com/0/66457/3e2c7a13-1883-2725-da16-55d38723f2ef.png">

### 2.4 Docker Cloud で swarm クラスタ作成

画面上部から、Swarm の新規作成を選びます。

<img width="500" alt="Swarm クラスタ新規作成" src="https://qiita-image-store.s3.amazonaws.com/0/66457/ae58d365-3e2f-59f4-e2f1-50cfd94a779a.png">

クラスタ名を入れつつ、サービスプロバイダに AWS を選択。
先ほどコピーした値を保存すると `connected` になります。

<img width="500" alt="接続確認" src="https://qiita-image-store.s3.amazonaws.com/0/66457/84a746d9-cea1-6bcf-74d4-88110c256d30.png">

どんなクラスタにするかを決めます。
t2.micro の manager 1 台だけのクラスタにしてみます。

<img width="500" alt="クラスタ定義" src="https://qiita-image-store.s3.amazonaws.com/0/66457/f8cf7d01-7ac2-2deb-fd65-ccb7c3606cb6.png">

Create しましょう。

## 3. swarm クラスタの確認

AWS 側では、Docker for AWS が起動します。

### 3.1 システム構成の確認

内部的には CloudFormation が使われるので、
[コンソール](https://ap-northeast-1.console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks) からはテンプレートなども簡単に確認できます。

試しにデザイナで開いてみたら、最新ってこんななのですね・・

<img width="500" alt="CFn 定義" src="https://qiita-image-store.s3.amazonaws.com/0/66457/4f99791c-eeb8-8165-cacf-b5086d6add0f.png">

### 3.2 接続テスト

Docker Cloud の該当クラスタを選択すると、
そこへ接続するためのコマンドが表示されます。

  <img width="500" alt="接続情報" src="https://qiita-image-store.s3.amazonaws.com/0/66457/6ca2f8f5-126d-49fb-5ac2-f2256b8565ac.png">

ターミナルで実行すると、Docker ID での認証を求められ、
成功すると

```
=> You can now start using the swarm pottava/swarm by executing:
	export DOCKER_HOST=tcp://127.0.0.1:32768
```

といったメッセージが表示され、
実際ローカルにはクラスタへのプロキシが起動しています。

```sh:local
$ docker container list
CONTAINER ID        IMAGE                      COMMAND             CREATED             STATUS              PORTS                       NAMES
2719c26c64bc        dockercloud/client-proxy   "/client-proxy"     27 seconds ago      Up 26 seconds       127.0.0.1:32768->2375/tcp   client_proxy_pottava_swarm
```

言われた通りに DOCKER_HOST をプロキシに向けてみると・・

```sh:swarm
$ export DOCKER_HOST=tcp://127.0.0.1:32768
$ docker container list
CONTAINER ID        IMAGE                                            COMMAND                  CREATED             STATUS              PORTS                          NAMES
996127204e3b        dockercloud/server-proxy                         "/server-proxy"          24 minutes ago      Up 24 minutes       2376/tcp                       dockercloud-server-proxy.xgglvp1y2ys4sa5bphjzuxjwt.t1bdegqxaq16cxujw0ssaendn
d0b6073c4490        docker4x/l4controller-aws:aws-v17.03.1-ce-aws1   "loadbalancer run ..."   24 minutes ago      Up 24 minutes                                      l4controller-aws
ce985fdca15a        docker4x/meta-aws:aws-v17.03.1-ce-aws1           "metaserver -iaas_..."   24 minutes ago      Up 24 minutes       172.31.13.108:9024->8080/tcp   meta-aws
b5ad87ccaca8        docker4x/shell-aws:aws-v17.03.1-ce-aws1          "/entry.sh /usr/sb..."   24 minutes ago      Up 24 minutes       0.0.0.0:22->22/tcp             shell-aws
5cee36ea2eab        docker4x/guide-aws:aws-v17.03.1-ce-aws1          "/entry.sh"              24 minutes ago      Up 24 minutes                                      guide-aws
```

なるほどいい感じですね。
ノードも指定通りに立ち上がっていることがわかります。

```sh:nodes
$ docker node list
ID                            HOSTNAME                                           STATUS              AVAILABILITY        MANAGER STATUS
xgglvp1y2ys4sa5bphjzuxjwt *   ip-172-31-13-108.ap-northeast-1.compute.internal   Ready               Active              Leader
```

### 3.3 ハローワールド

Web サービスを 2 つ作ってみます。

```sh:web-services
$ docker service create --name hello -p 80:80 --detach=true dockercloud/hello-world
$ docker service create --name nginx -p 8080:80 nginx:1.11-alpine
```

Redis も立ててみます。

```sh:redis
$ docker service create --name redis -p 6379:6379 --detach=true redis:3.0-alpine
```

Docker for AWS はサービスの生成に合わせ
ELB のリスナを自動設定してくれるわけわけですが
それを確認してみましょう。

起動した ELB の接続先は AWS-CLI などで見つかります。

```sh:elb-dns-name
$ cluster_name=<Swarm クラスタ名>
$ dns_name=$(aws elb describe-load-balancers --query "LoadBalancerDescriptions[?LoadBalancerName==\`${cluster_name}-ELB\`].DNSName" --output text)
```

または、Docker Cloud の該当クラスタから情報が取得できます。

<img width="500" alt="接続先ホスト名" src="https://qiita-image-store.s3.amazonaws.com/0/66457/fd3cef67-3bde-fb28-3ffb-81b5fca3d15d.png">

接続してみましょう。

```sh:health-check
$ curl -i $dns_name
$ curl -i $dns_name:8080
$ redis-cli -h $dns_name
```

うまく動いていることが確認できたのでサービスを停止します。

```sh:stop-services
$ docker service rm hello nginx redis
```


## 4. Desktop to Cloud でデプロイ

Docker for Mac の機能を使って Swarm クラスタに接続します。

今回のように Docker for AWS な環境だとあまり恩恵も感じませんが
持ち込みの Swarm クラスタだと少しうれしいかもしれません。
かもしれません。

### 4.1 ログイン

Mac 右上のメニューバーから Docker ID でログイン

<img width="464" alt="ログイン" src="https://qiita-image-store.s3.amazonaws.com/0/66457/d7bc3277-c5d9-66af-9e22-abdf0a96c222.png">

### 4.2 クラスタの選択

認証されると、そのユーザに紐づく swarm クラスタや
管理下にある Docker イメージが一覧として表示されます。

そこから接続したいクラスタを選びます。

<img width="422" alt="Screen Shot 2017-04-19 at 13.41.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/66457/e330fe2e-bb1c-3ae8-4abc-ae2561552605.png">

### 4.3 接続確認

起動したターミナルは DOCKER_HOST がクラウド側の
swarm をみているので、すぐクラスタに接続できます。

```sh:nodes
[swarm] ~ $ docker node list
ID                            HOSTNAME                                           STATUS              AVAILABILITY        MANAGER STATUS
xgglvp1y2ys4sa5bphjzuxjwt *   ip-172-31-13-108.ap-northeast-1.compute.internal   Ready               Active              Leader
```

プロキシも立たないまま、3.2 と同じ状況になりましたね！

### 4.4 デプロイ

デモでやっていたように、スタックでデプロイしてみましょう。
Docker 社がよく使う投票アプリのスタック定義を取得して

```sh:stack
[swarm] ~ $ curl -O https://raw.githubusercontent.com/docker/example-voting-app/master/docker-stack.yml
```

デプローイ。

```sh:deploy
[swarm] ~ $ docker stack deploy --compose-file docker-stack.yml voting
Creating network voting_default
Creating network voting_frontend
Creating network voting_backend
Creating service voting_visualizer
Creating service voting_redis
Creating service voting_db
Creating service voting_vote
Creating service voting_result
Creating service voting_worker
```

t2.micro のリソース的になかなかシビアな感じはありつつも
サービスがこんな感じで REPLICA 数揃うまで待ちます。

```sh:list-services
[swarm] ~ $ docker service list
ID                  NAME                       MODE                REPLICAS            IMAGE                                          PORTS
anka9rf9o3ea        voting_redis               replicated          2/2                 redis:alpine                                   *:0->6379/tcp
ibqx2lcvxr45        voting_db                  replicated          1/1                 postgres:9.4                                   
ie62ji0m4pys        voting_result              replicated          1/1                 dockersamples/examplevotingapp_result:before   *:5001->80/tcp
n0atzubw917t        voting_visualizer          replicated          1/1                 dockersamples/visualizer:stable                *:8080->8080/tcp
p6clvuqr507g        dockercloud-server-proxy   global              1/1                 dockercloud/server-proxy:latest                *:2376->2376/tcp
rpkhch1gk8er        voting_worker              replicated          1/1                 dockersamples/examplevotingapp_worker:latest   
xc3lkdefp2n4        voting_vote                replicated          2/2                 dockersamples/examplevotingapp_vote:before     *:5000->80/tcp
```

この状態で ELB のリスナーを確認すると

<img width="500" alt="ELB リスナー" src="https://qiita-image-store.s3.amazonaws.com/0/66457/d2f820b1-f63c-6549-ba5f-e066c2927ca2.png">

増えてます。
接続してみましょう！

`http://${dns_name}:5001/` で投票結果を起動しつつ
`http://${dns_name}:5000/` で投票すると、結果が変わりますね。
複数ブラウザで UserAgent を変えれば票も増えます。

これが

<img width="500" alt="投票結果" src="https://qiita-image-store.s3.amazonaws.com/0/66457/968f6c0c-9cb8-8f66-0f44-6cd4f25a3e4a.png">

こっちでクリックすると

<img width="500" alt="投票" src="https://qiita-image-store.s3.amazonaws.com/0/66457/4604bef6-e0d2-bdcf-8ddf-058a9c4fed2f.png">

こうなる

<img width="500" alt="結果が変わる" src="https://qiita-image-store.s3.amazonaws.com/0/66457/eb1d49c5-2064-a5a0-2420-844ef3d323c2.png">

### 4.5 後片付け

DockerCon のデモではサービスのアップデートをしていましたが
まあできるでしょうということで、あとは片付けます。

```sh:deploy
[swarm] ~ $ docker stack rm voting
Removing service voting_redis
Removing service voting_db
Removing service voting_result
Removing service voting_visualizer
Removing service voting_worker
Removing service voting_vote
Removing network voting_default
Removing network voting_backend
Removing network voting_frontend
```

Docker Cloud から Swarm クラスタを破棄します。

<img width="500" alt="クラスタの破棄" src="https://qiita-image-store.s3.amazonaws.com/0/66457/d9866acb-b66d-b730-8d70-5ddeaf1b9293.png">

おわり

### ではありません！！！！

おい、**Docker for AWS で生成したリソースが消えてないぞ。**

あれですかね、持ち込みの Swarm クラスタと勘違いしてるのかな？
Docker Cloud 上のマスタだけ決して満足してしまったのかw

ということで CloudFormation コンソールに赴いて
手動でしっかり消しましょう・・・

<img width="487" alt="スタックの削除" src="https://qiita-image-store.s3.amazonaws.com/0/66457/77cdf048-e6bd-7b0a-235e-0e89548570ee.png">



## 所感

冒頭の疑問はあまり解消されませんでした・・