Azure Container Serviceを使う（１） 基本のデプロイ編

最近話を聞くことが多い Microsoft Azure ですが、その中で個人的に気になるサービスが、 Azure Container Service です。

昨今のコンテナ技術の盛り上がりや、枕詞になりつつある Micro Services から、コンテナの管理に割く労力が多くなっていくでしょう。ただ、 SaasなどのManaged Service に慣れた身からすると、コンテナ管理のためのインフラ管理とか、中々やってられません。

Azure Container Service（以下ACS）は、 Azure 上でコンテナベースのサービスを動かすに足る機能を提供してくれるのか？といったところを、何個かの記事で検証していきます。

今回は以下のような内容でやっていきます。

- ACSってどんなもの
- 構築してみる
- 実際にコンテナを稼働させてみる

コンテナを動かすのは、今回はローカルから手動で行います。理由は後ほど・・・。

今回利用するリポジトリは以下です。

https://github.com/derui/acs-sample

また、Azureにちょっとでも触ったことがある、もしくは知っているレベルの知識を前提とします。

## Azure Container Serviceとは ##
では早速・・・といく前に、 ACSとはなんなのか、を改めて見てみましょう。

ACSの説明として、Azure ポータル上では以下のように書かれています。

> Azure Container Service (ACS) provides a way to simplify the creation, configuration, and management of a cluster of virtual machines that are preconfigured to run containerized applications. Using an optimized configuration of popular open-source scheduling and orchestration tools, ACS enables you to use your existing skills or draw upon a large and growing body of community expertise to deploy and manage container-based applications on Microsoft Azure.

コンテナ化されたアプリケーションを実行出来るようにした、Virtual Machineのクラスタを

- 作成して
- 設定を施して
- クラスタを管理する

ための方法・・・と書かれているように、 **ACSは Managed Service ではありません** 。実際に構築してみるとわかりますが、ACSは Auto ScalingやVirtualMachineなど、各種リソースをまとめて作成する（VirtualMachine などの設定も行う）、という、サービスというか **テンプレートです** （作成するときにテンプレートって書いてある）。

> 補足：テンプレートとは？
> Azureでは、 [Azure Resource Managerテンプレート](https://azure.microsoft.com/ja-jp/documentation/articles/resource-group-authoring-templates/)という仕組みが存在します。
> 物凄い荒い解説だと、 *Azure版のAWS CloudFormation* です。
> [AWS CloudFormation](https://aws.amazon.com/jp/cloudformation/)は、AWS内の各種リソース構成を、テンプレートとしてJSON/YAML形式で記述し、実際にリソースの生成などについてはAWS側に任せることで、Infrastracture as Sourceを実現するサービスです。
> テンプレートには、外部から指定できるパラメータを含めることが出来、これによってテンプレートを再利用することができます。

> Azureの次世代リソース管理の仕組みである Azure Resource Manager では、同様の仕組みでリソース構成を管理することができ、ACSを立ち上げたときに色々なリソースが作成されるのは、ACSが提供しているテンプレートに、仮想マシンの設定やDNSの設定が含まれているためです。

他にも同じようなサービスを提供している、 Amazon Web Services（AWS）と Google Cloud Platform（GCP）におけるコンテナサービスと比較してみましょう。

| サービス名 | Elastic Container Service | Google Container Engine | Azure Container Service  |
|:---:|:---:|:----:|:----:|
| Managed Serviceか？| Yes | Yes | No |
| Open Sourceを利用しているか | 不明 | Kubernetes | Docker Swarm または DC/OS |
| API | あり（独自） | あり（独自） | Docker Swarm / DC/OS自体のAPI |

すごいザックリした比較ですが、これを見ても、 ACS はテンプレートである、ということが何となくつかめると思います。

## ACS を使ってリソースを作る ##
それでは、まずは実際に ACS を使って、自分用のクラスタを立ててみます。と言っても簡単です。

Azure のポータルで **＋新規** をクリックして

![1.png](https://qiita-image-store.s3.amazonaws.com/0/12490/70e2709e-6bd0-6e1d-c1f6-218f60d9dc18.png)

検索欄に **Azure Container Service** と入れて検索。するとこんな感じになります。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/12490/5aa11555-d1a6-f386-451b-8378a124902c.png)

一番上の **Azure Container Service** を選択すると、初期設定画面が出てきます。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/12490/19932f2f-1bd5-be45-0e1c-12698960d3ea.png)

この設定の中で最も重要なのが、SSH Public Keyです。ここでは、専用のキーペアを作成して入れます。

![4.png](https://qiita-image-store.s3.amazonaws.com/0/12490/893b744e-ecbc-15c5-623c-8417564505d5.png)

利用するフレームワークを選択します。 **DC/OS** と **Swarm** のいずれかを選びます。今回はSwarmです。

![5.png](https://qiita-image-store.s3.amazonaws.com/0/12490/9167e109-e410-7532-59fd-d496b0f85adf.png)

生成するエージェントやDNSプレフィックスを設定します。ハテナマークにマウスを合わせると説明が出てくるので、読んどきましょう。

設定項目はこれだけです。大体10分くらいで生成できます。生成すると、設定で指定した名前のリソースグループに、色々とリソースが入ってるのがわかります。

![6.png](https://qiita-image-store.s3.amazonaws.com/0/12490/208f37ca-b114-8c56-94d3-4303a4c33cb9.png)

## ACS に接続してみる ##
早速作ったリソースにアクセスしてみます・・・と行きたいところですが、ブラウザで直接アクセスしたり、 Curl でアクセスしたりしても、残念ながらSwarmにアクセスできません。

じゃあどうするのかというと、ここで、作成前の設定で入力したSSH Keyを使います。

```
ssh -L PORT:localhost:PORT -f -N [USERNAME]@[DNSPREFIX]mgmt.[REGION].cloudapp.azure.com -p 2200 -i <設定したPublicKeyに対応するPrivateKey>
```

ACS で生成される仮想マシンでは、80/8080/443ポートにはDNS経由でアクセスできますが、その他のポートに関しては、SSHトンネルを経由しないとアクセスできないようになっています。上記のコマンドを実行したあと、試しに以下のコマンドを実行してみます。

```
$ curl http://localhost:2375/images/json
[]
```

ちゃんと繋がったようです。SSHトンネルを通さずに直接アクセスしてもタイムアウトしてしまいます。

## ACS でのコンテナイメージ管理戦略 ##
ACS 上の Swarm でコンテナイメージを利用するとき、いくつか方法があるかと思います。

* Docker Hubに置く
* AWS の Elastic Container Registry に置く
* Docker Registryを使って BLOB に置く

Azureの話をしていてAWSを利用するというのも何か違う気がしますし(IAMの管理が煩雑になるのもマイナスです）、Public な Docker Hub に置いてしまうと、それは実際の利用を想定したときにあり得ない選択肢になってしまうので、今回はBLOBに置いてみます。

Docker Registry で Azure を利用するため、専用のストレージアカウントを作成します。

![7.png](https://qiita-image-store.s3.amazonaws.com/0/12490/1f4a32bb-06d9-d3dc-d8a8-ea97e6a2787e.png)

暗号化とかは簡単のため無視しときます。作成したら、

* ストレージアカウントの名前
* ストレージアカウントのアクセスキー（どれか一つ）

をメモっておきます。

今回、Docker RegistryのAzure Storage Driverを利用するので、Docker Registry の storage 部分はこのようになります。

```yaml
storage:
  azure:
    accountname: <ストレージアカウントの名前>
    accountkey: <ストレージアカウントのアクセスキー>
    container: images
```

ただ、accountkey はそのままコミットとかすると笑えないので、実際には環境変数から受け渡すようにするのがベターでしょう。

今回は、ローカルに上げた仮想マシンでDockerを動かして、そこから ACS でコンテナを走らせてみます。まずはDocker Registryを動かしますが、結構設定とか環境変数の設定とかが面倒なので、 docker-compose を利用します。

```
$ sudo su
# curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# exit
$ sudo docker-compose up -d registry
```

実際の設定ファイルはリポジトリの docker-compose.yml を参照してください。

イメージのビルドまでは、以下の順でコマンドを実行してやるとできます。

```
$ sudo docker build -t "localhost:5000/flask" .
$ sudo docker push "localhost:5000/flask"
```

### ACS 上で Private Registry から取得する ###
後は ACS の Master に向けて `docker run` すれば〜・・・と行きたい所ですが、

* Swarm がホストの時は、ローカルのRegistryが使えない（当たり前）
* Swarm がホストで `localhost:5000` にアクセスすると、 **マスタ側で Registry が動いていないとエラーになる**

という制約があります。そのため、設定ファイルとかを volume で指定していた場合は、 Swarm のマスタ上にファイルを置くか、image 自体にファイルを含めておく必要があります。

今回は、リポジトリ上の `Dockerfire.registry` という Dockerfile で、設定ファイルだけ上書きした Registry の image を用意しておくことにします。

さて、後はACS上で動かす、というだけなんですが、前述の通り、 ACS は SSH トンネリングが必須であるため、仮想マシン側に ACS を構築したときの鍵をコピーしておく必要があります。

後、docker-compose 経由で環境変数を受け渡す必要がありますが、普通に sudo 付きでやる場合、そのままやると受け渡せません。 docker コマンドを実行する権限があれば別ですが、大抵は無いと思います。いくつか方法はあるかと思いますが、今回は簡単のため、 `sudo su` で root になって行います。

```
$ sudo su
$ ssh -L 2375:localhost:2375 -f -N [USERNAME]@[DNSPREFIX]mgmt.[REGION].cloudapp.azure.com -p 2200 -i <設定したPublicKeyに対応するPrivateKey>
$ export DOCKER_HOST=":2375"
# 事前に swarm-registry という名前でビルドしておく。このときは、ローカルにしかないイメージでも使える。
$ docker-compose up -d swarm-registry
$ docker run -d -p 80:80 "localhost:5000/flask"
```

最後の `docker run` では、 Swarm 内に起動した Registry から ダウンロードするため、ローカルに image が存在していない状態でも起動できます。

ここまでできたら、 ACS のリソースグループから、エージェント側のDNSを探して開けば、ちゃんとデプロイされたの確認できると思います。

## コンテナ作成を自動化したい
さて、とりあえずはローカルからACS上のコンテナへのデプロイ、については出来ました。

ただ、実際チームでやったり、検証環境や本番環境へデプロイして・・・などといったことを考えると、手動でこれらを継続して行うのは、かなりの危険をはらむことだと思います。

実際には、テストやコンテナの生成とかをCI（Jenkinsなりサービスなり）で行って、自動的にACS上にデプロイして・・・など考えたくなりますが、ACS を利用してこれらを行うためには、いくつか解決しないとならない課題があります。

* ACS 上の Swarm マスタに接続するためには、秘密鍵が必要
* SSHトンネルを構成しないとならない

特に、秘密鍵の管理が問題です。当然ながら、コミットに含んではならない類のものですし、外で共有するにも、出来るだけ安全に行いたいものです。

というわけで、次回はそのへんをなんとかしつつ、CI環境上から、ACSへのデプロイまでをできるようにしてみたいと思います。