Azure Web App for Containers 上で kong (API gateway) を docker で動かす

# はじめに
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/84e3f337-8911-8af3-90d8-0c87b09f03de.png)

## この記事で説明する/しないこと
* [kong](https://getkong.org/) 自体の説明は割愛したい。API Gateway のソフトウェア。
  * Hosted なサービスである、Mashape というサービスが、 そのプラットフォームである Kong をオープンソース化した。
  * kong の代替は[このあたり](https://alternativeto.net/software/kong/)。 [Apigee](https://apigee.com/api-management/)、[Tyk](https://tyk.io/)、[KrakenD](http://www.krakend.io/) あたりとのこと。
* なぜ API Gateway か、についても割愛したい。すでに多くは [API Gateway Pattern](http://microservices.io/patterns/apigateway.html) などで言及されている。
* 大事：kong は client から接続用と admin から接続用で二つポートが必要なのだが、Azure Web App for Containers はポートを一つしか公開できない制約があるため、Web App をそれぞれようにデプロイする。以下のような具合。
  1. client 接続用 **kong**.azurewebsite.net -> 8000 port
  2. admin 接続用 **kong-admin**.azurewebsite.net -> 8001 port

## なぜ
* Web App for Containers 上に API Gateway を置くことで、API アプリケーションを複数または単体で公開するときに Gateway レイヤを設けることができる。
* Azure の App Service プランの性質上、**複数アプリケーションを一つのプラン内で作成できる**ので、（端的に言うと、価格は1インスタンス分で複数アプリケーション）トラフィックの成長に合わせて少ないうちは節約できる。
* なぜ kong を選んだか、についてはいくつか理由はあるが、ひとつ挙げると、**nginx 上に OpenResty で実装されていて、軽量そうなところが個人的に好みである**、という点。Gateway Layer に重厚なものは避けたい。
  * KrakenD というのは今回知ったが、もっとgolang 製でさらに軽量らしい。試してみたい。
* 必要なもの全て Cloud 上の PaaS 環境を使って構築したい。

## 環境
* Local: Windows 10, Docker for Windows, [Windows Subsystem on Linux Ubuntu](https://www.microsoft.com/ja-jp/store/p/ubuntu/9nblggh4msv6) 20170830.1 build of Ubuntu 16.04 LTS
* Local: Docker

```
$ docker version
Client:
 Version:       17.12.1-ce
 API version:   1.35
 Go version:    go1.9.4
 Git commit:    7390fc6
 Built: Tue Feb 27 22:17:40 2018
 OS/Arch:       linux/amd64

Server:
 Engine:
  Version:      17.12.0-ce
  API version:  1.35 (minimum version 1.12)
  Go version:   go1.9.2
  Git commit:   c97c6d6
  Built:        Wed Dec 27 20:12:29 2017
  OS/Arch:      linux/amd64
  Experimental: true
```

* [Kong Docker Image on DockerHub](https://hub.docker.com/_/kong/)
* Cloud: [Azure Web App for Containers](https://azure.microsoft.com/en-us/services/app-service/containers/)
* Cloud: [Azure Database for PostgreSQL](https://azure.microsoft.com/ja-jp/services/postgresql/)

# 手順
原則、Kong 公式の手順通りだが、デプロイ先を local docker コンテナではなく、Azure Web App for Containers と Azure Database for PostgreSQL としている。
https://getkong.org/install/docker/

## まずは、Local kong -> Azure PostgreSQL

### Azure Database for PostgreSQL
Azure PostgreSQL から作る。Azure ポータルからポチポチ作った。

次にローカル環境から接続するので、ここでメニュー「接続のセキュリティ」から「自分の IP を追加」しておく。

さらに、同じメニュー内で 「SSL 設定」の 「SSL 接続を強制する」を "無効" にしておく。
この設定は本来は非推奨。今回、最終的に接続は Azure 内（Web App -> PostgreSQL）に閉じるのでまだいいが。
TODO: ちゃんと SSL 接続する手順は後ほど追記したい。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/d17e38eb-a396-3961-670b-e0b96f76f24d.png)


接続の確認は楽をしたいので GUI で済ませたい。ローカルの docker コンテナに、 pgadmin4 を起動して確認した。
https://hub.docker.com/r/dpage/pgadmin4/
手順は、Docker Hub 上記ページに詳細はあるが、ざっくりと以下の具合。

```
docker pull dpage/pgadmin4
docker run -p 8080:80 \
  -e "PGADMIN_DEFAULT_EMAIL=container@pgadmin.org" \
  -e "PGADMIN_DEFAULT_PASSWORD=Conta1ner" \
  -d dpage/pgadmin4
```

Web UI http://localhost:8080 のログインはデフォルト以下で。
Default: container@pgadmin.org
Default: Conta1ner

### Azure 上 PostgreSQL に初期データを投入する
pgadmin4 上で `kong` という database を作成する。  

:exclamation: 注意：オリジナルの手順ではこのステップがない。PostgreSQL は docker コンテナ上で起動していて、`kong` Database は既に作成済みなため。

`kong migrations bootstrap` コマンドを実行する

```
$ docker run --rm \
    -e "KONG_DATABASE=postgres" \
    -e "KONG_PG_HOST=****.postgres.database.azure.com" \
    -e "KONG_PG_USER=****" \
    -e "KONG_PG_PASSWORD=****" \
    kong:latest kong migrations bootstrap --vv
```
**** 部分はそれぞれの環境に応じて置き換えて。--vv を付けると debug モードでやってくれる
上記の接続元 IP 設定や、SSL設定が漏れていると、ここで接続エラーになってしまうはず。


## local docker container 上に kong アプリケーションを起動する
docker run （**** 部分はそれぞれの環境に応じて置き換えて。）

```
docker run -d --name kong \
    -e "KONG_DATABASE=postgres" \
    -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
    -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
    -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
    -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
    -e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \
    -e "KONG_ADMIN_LISTEN_SSL=0.0.0.0:8444" \
    -e "KONG_PG_HOST=****.postgres.database.azure.com" \
    -e "KONG_PG_USER=****" \
    -e "KONG_PG_PASSWORD=****" \
    -p 8000:8000 \
    -p 8443:8443 \
    -p 8001:8001 \
    -p 8444:8444 \
    kong:latest
```

確認する。 8001 ポートは admin API のほう。

```
curl -i http://localhost:8001 
```

## Azure Web App に kong をデプロイする
さあ、これで最後。大事なことをもう一回。

> * 大事：kong は client から接続用と admin から接続用で二つポートが必要なのだが、Azure Web App for Containers はポートを一つしか公開できない制約があるため、Web App をそれぞれようにデプロイする。以下のような具合。
  1. client 接続用 **kong**.azurewebsite.net -> 8000 port
  2. admin 接続用 **kong-admin**.azurewebsite.net -> 8001 port

Web App for Containers は **二つ** 作成する。Azure Portal から Docker Hub の "kong:latest" イメージで作成する。

上記 docker run -e "HOGEHOGE=hogehoge" で指定した環境変数は、Azure Web App ではアプリケーション設定として設定する。
Azure Portal 上から設定も可能だが CLI が楽できる。
参考：[Azure CLI: az webapp config appsettings set](https://docs.microsoft.com/en-us/cli/azure/webapp/config/appsettings?view=azure-cli-latest#az_webapp_config_appsettings_set)

Kong の設定、 `/etc/kong/kong.conf` の内容は、実行環境の環境変数によって上書きすることができる。
> 参考：どんな設定ができるか。 Kong [Configuration Reference](https://getkong.org/docs/0.12.x/configuration/)
> Environment variables
> All environment variables prefixed with `KONG_`

### 1. Client 接続用
Web App が作成されたら、環境変数を設定する。
Web App の公開ポートは WEBSITES_PORT で設定可能。

```
export RG=****（作成したリソースグループ）****
export APPNAME=****（作成したApp名）****
az webapp config appsettings set -g $RG -n $APPNAME --settings \
  KONG_DATABASE=postgres \
  KONG_PROXY_ACCESS_LOG=/dev/stdout \
  KONG_ADMIN_ACCESS_LOG=/dev/stdout \
  KONG_PROXY_ERROR_LOG=/dev/stderr \
  KONG_ADMIN_ERROR_LOG=/dev/stderr \
  KONG_ADMIN_LISTEN=0.0.0.0:8001 \
  KONG_ADMIN_LISTEN_SSL=0.0.0.0:8444 \
  KONG_PG_HOST=****.postgres.database.azure.com \
  KONG_PG_USER=**** \
  KONG_PG_PASSWORD=**** \
  WEBSITES_PORT=8000
```

アクセスしてみる。URL はそれぞれの環境に応じて。ここでは hello-kong としている。ここでポートを 8000 と付ける必要はない。80 で公開されている。

```
curl -i https://hello-kong.azurewebsites.net
```

ちゃんど起動しているか、こんな CLI コマンドでログを tail できる。

```
az webapp log tail -g $RG -n $APPNAME 
```

以下のようなメッセージが表示されたらOK。hello-kong の部分は アプリケーション名がくる。

```
2018-03-16 HH:MM:SS.SSS INFO  - Container hello-kong_0 for site hello-kong initialized successfully.
```

### 2. Admin 接続用

```
export RG=****（作成したリソースグループ）****
export APPNAME=****（作成したApp名 admin 用）****
az webapp config appsettings set -g $RG -n $APPNAME --settings \
  KONG_DATABASE=postgres; \
  KONG_PROXY_ACCESS_LOG=/dev/stdout; \
  KONG_ADMIN_ACCESS_LOG=/dev/stdout; \
  KONG_PROXY_ERROR_LOG=/dev/stderr; \
  KONG_ADMIN_ERROR_LOG=/dev/stderr; \
  KONG_ADMIN_LISTEN=0.0.0.0:8001; \
  KONG_ADMIN_LISTEN_SSL=0.0.0.0:8444; \
  KONG_PG_HOST=****.postgres.database.azure.com; \
  KONG_PG_USER=****; \
  KONG_PG_PASSWORD=****; \
  WEBSITES_PORT=8001
```

アクセスしてみる。URL はそれぞれの環境に応じて。ここでは hello-kong-admin としている。ここでポートを 8001 と付ける必要はない。80 で公開されている。

```
curl -i https://hello-kong-admin.azurewebsites.net
```

ちゃんど起動しているか、こんな CLI コマンドでログを tail できる。

```
az webapp log tail -g $RG -n $APPNAME 
```

以下のようなメッセージが表示されたらOK。hello-kong の部分は アプリケーション名がくる。

```
2018-03-16 HH:MM:SS.SSS INFO  - Container hello-kong-admin_0 for site hello-kong-admin initialized successfully.
```

# 参考 URL
* [kong](https://getkong.org/) 
* [kong install](https://getkong.org/install/docker/)
* [Kong Docker Image on DockerHub](https://hub.docker.com/_/kong/)
* [Kong Configuration Reference](https://getkong.org/docs/0.12.x/configuration/)
* Cloud: [Azure Web App for Containers](https://azure.microsoft.com/en-us/services/app-service/containers/)
* Cloud: [Azure Database for PostgreSQL](https://azure.microsoft.com/ja-jp/services/postgresql/)
* [Things You Should Know: Web Apps and Linux](https://blogs.msdn.microsoft.com/waws/2017/09/08/things-you-should-know-web-apps-and-linux/)
  * [Azure Web Apps and Linux/Containers について知るべきこと - 日本語意訳](https://qiita.com/hoisjp/items/51ad840daeaa8c8ba0a9)

# やり残し
* 全体の構成図を追記する
* SSL 接続の手順を追記する