Azure Container Serviceを使う（２） 自動化してみる編

1回目はこちらです。

[Azure Container Serviceを使う（１） 基本のデプロイ編](http://qiita.com/derui@github/items/64cc13016c002db69308)

前回は、Azure Container Service（以下ACS）を利用してみました。しかし、利用していく過程で問題となりそうな事柄が見つかった、というところでお開きとなりました。
今回は、前回の課題を、出来るだけ Azure のサービスを利用して解決していってみたいと思います。

## 課題のおさらい ##
前回、最後に出てきた課題としては、以下のようなものでした。

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

継続的デリバリ（CI）などで、Dockerコンテナを自動的に置き換えていく、といった場合、どうしても自動化が必要になります。しかし、このSSHトンネルのために利用する秘密鍵というのは、ACS を作成したユーザーが自分で管理しなければなりません。

この点が一番のネックとなります。なので、これをどのようにして解消していくか、を検討していきます。

## どういう形にしたいか ##
まずは、今回は一体どういう形にしたいのか、を考えてみたいと思います。

* 秘密鍵はAzure上に置きたい
* サードパーティから秘密鍵を取り出したい
 * 本当は秘密鍵を展開したくはないですが、止むを得ないというか。。。
* CUIベースで動かしたい
 * 自動化という面だとこれはやりたい

ひとまずは、コンテナのビルドとアップロードまでをかんがえると、このくらいできれば大丈夫でしょう。
では、それぞれ実現方法を見ていってみます。

## 秘密鍵を管理したい ##

秘密鍵をAzure上に置いて管理する、ということを考えると、次のような手段が考えられるんじゃないかと思います。

* Storageに秘密鍵を置いて、CUIから取得
* Key Vaultに秘密鍵を入れて、CUIから取得

秘密にしておかなければならないものを入れる場合、Key Vaultで展開しないと見ることが出来ない、かつKey Vault自体、実行するユーザーを指定して許可することが出来るので、キーがあればアクセスできてしまうStorageと比較すると、余計なキーやらの管理が不要というところもポイントかと思います。

まだプレビュー段階ではありますが、今回はKey Vaultを利用していきます。

### Key Vaultとは ###

さて、突然出てきた [Azure Key Vault](https://azure.microsoft.com/ja-jp/services/key-vault/) について、すごく簡単に紹介します。

Azure Key Vaultとは、すごい簡単に言うと、Azure しか知らない秘密鍵を使って、秘密にしたい情報を作ったり管理したりできるサービスです。知っている人であれば、 AWS の [Key Management Service](https://aws.amazon.com/jp/kms/) と同じようなイメージでいいんでないかと思います。

Key Vaultに、自分が管理している鍵を入れて、暗号化などに利用するってことも出来ますが、今回は **秘密鍵を保管したい** ということなので、暗号化のために使うんじゃなく、あくまで保管するために使います。

## CUIベースで動かしたい ##

AzureにアクセスするためのCUIは、 [こちらのように](https://azure.microsoft.com/ja-jp/documentation/articles/xplat-cli-install/) Nodeベースのものか、もしくはPowerShellベースのものが提供されています。今回は、Node.js版を利用するということで先に進めます。

上のページでは、 ``azure login`` を行い、ブラウザで認証コードを入れるように書いてある箇所があります。自動化や、CIサービスを利用したりする場合、毎回こんなことをやってられませんので、もうちょっとなんとかならないかを探ってみます。

``azure login`` コマンドのヘルプを見てみます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/12490/01fa01a4-0d29-c119-cdec-c9478712c016.png)

すると、ユーザー名とパスワード、またはService Principalというもので、特定のアプリケーションとしてログインすることが出来ます。アカウントを利用するよりは、特定のサービス用の認証情報を利用するほうが、より実際的だと思いますので、今回はこれで行ってみます

## 実際にDockerイメージのビルドを自動化してみる ##
それでは、簡単な方針が決まったところで、実際に Docker イメージの作成と、作成したイメージを ACS 上に上げる、というところまでやっていきたいと思います。

### Service Principalを用意する ###
[公式ドキュメント](https://azure.microsoft.com/ja-jp/documentation/articles/resource-group-authenticate-service-principal-cli/) にしっかりした手順が載ってるので、これに沿って行きましょう。

以下、手順だけ追っていきます。

```
# 色々実行するためにログイン
azure login
# Service Principalを作成する
azure ad sp create -n sample --home-page http://dummy --identifier-uris http://dummy -p {password}
# roleを割り当てる（この設定だと、全てのリソースに対する閲覧権限らしい）
azure role assignment create --objectId {object id} -o Reader -c /subscriptions/{subscriptionId}/
# tenant id が必要なので取得する
azure account show --json | jq ".[0].tenantId"
# Service Principalでログインする
azure login -u http://dummy --service-principal -p {password} --tenant {tenant-id}
```

``azure ad sp`` で指定するパスワード自体は何でも良さそうです。また、URL/URIについても、仕様にさえ準じていれば、存在するかどうかは特にチェックされません。

今回はRoleとして、読み取りとはいえかなり強い権限を渡しているので、実際にはちゃんと権限を必要最小限に絞る必要があるかと思います。

### Key Vaultに証明書を入れる ###

今回の肝となる部分です。Key Vaultでは、シークレットとして、任意の文字列を暗号化して入れることができます。以下のコマンドは、とりあえず ``azure login`` としてログインしておくことをオススメします。

```
# 最初の一回だけでOK
azure provider register Microsoft.KeyVault
# vault-nameはユニークじゃないとダメっぽいので要注意。
azure keyvault create --vault-name 'SecretKey' --resource-group 'acs' --location 'japaneast'
# secretとして、秘密鍵の内容を設定
azure keyvault secret set --vault-name 'SecretKey' --secret-name 'ACSSecret' --value <ACSで使った秘密鍵のテキスト>
```

secretとして秘密鍵を設定する時は、忘れずにbase64 でエンコーディングしてあげる必要があります。

ちゃんと入ったかどうかは、以下で確認できます。

```
azure keyvault secret show --vault-name 'SecretKey' --secret-name 'ACSSecret' --json | jq -r ".value" | base64 -d > tmp.secret
diff tmp.secret <ACSで使った秘密鍵>
```

差分が無ければOKです、が、このままだと Service Principal 側で利用権限がないので、取得時にエラーになります。CLIでやってもいいんですが、これはポータルからでも設定が分かりやすかったので、ポータルからやってしまいましょう。

> 全てのリソースからKey Vaultを検索→選択

![2.png](https://qiita-image-store.s3.amazonaws.com/0/12490/7d777e3d-2754-17cc-e98b-1ae7530ba85a.png)

> アクセスポリシー→新規追加→プリンシパルの選択（sp createで作ったもの）

![3.png](https://qiita-image-store.s3.amazonaws.com/0/12490/8c92486a-ce9d-d2dc-bccb-4240522edb72.png)

あとは、 **シークレット アクセス許可** で、読み込み権限を設定すれば、 Service Principal からアクセスすることが出来ます。

### CIに組み込むためのスクリプトを作る ###

ここまでと、前回やったことをまとめて、スクリプトを組みます。まずは今回やった、秘密鍵を Azure から取得してくるためのスクリプトです。

```bash
#!/usr/bin/env bash
SEC=/home/azure-acs-private

azure login -u 'http://dummy' --service-principal -p "$ACS_SP_PASSWORD" --tenant 'c60ec04f-5190-4d2b-8e42-f7b49dd83080'
azure keyvault secret show --vault-name 'AcsSecretKey' --secret-name 'ACSSecret' --json | jq -r ".value" | base64 -d > $SEC

chmod 0600 $SEC
```

実際には、これを docker run から、以下のようにして動かします。

```
sudo docker run --rm -v .:/home microsoft/azure-cli sh <script>
```

ここまで来たら、後はCIに組み込むだけです。実際にやってみたものは、 [こちら](https://github.com/derui/acs-sample) から見ることが出来ます。

リポジトリでは、CircleCIを利用していますが、Jenkinsなりを利用しても、肝になる部分さえなんとかなってれば出来ると思います。

## まとめ ##
前回、今回とで、ACSを利用する上で注意する点や、自動化する際に留意すべき点について、実際に試してみた結果をまとめてみました。

AWS の ECSや、 GCP の GKE に比べて情報が少ないというか、中身が Docker Swarm/DC/OS がそのままだった、というのが、情報が出てこない一つの要因なんじゃないかと思いますが。。。

私も今回やってみるまで、 Azure Resource Manager が一体どれくらい使えるようになってるのか、よく知りませんでしたが、今回やってみた感じでは、結構いけるようになってる、と思います。
当然、当初からAPIがあることが前提で、CLIを提供していたAWSやGCPにはまだまだ及びませんが、すごい勢いで開発が進んでいるようですし、どんどんサポートも広がっていくんじゃないでしょうか。

現状、 Azure 縛りで **コンテナを利用したいなー** 、となった場合、ファーストチョイスは ACS になると思いますので、少しでも参考になればと。
他にACSに対するノウハウがあれば、ぜひQiitaなりブログで共有していきましょう。