Kongの設定ファイルを環境ごとに切り替える

## はじめに

OSSの[Kong](https://docs.konghq.com/gateway/latest/)は世界で最も人気のあるAPI Gatewayで、認証認可や流量制御などプラグインを有効化するだけで用意することができます。
プロキシ先のurlやパスなどの設定をDBに保管し、管理用APIやGUIで設定を行うことができますが、一方でyamlファイルで設定を宣言的に管理しDBレスの構成を取ることも可能です([ドキュメント](https://docs.konghq.com/gateway/latest/production/deployment-topologies/db-less-and-declarative-config/))。

DBレス構成で設定ファイルでの管理において、**環境ごとに設定値を変えたい場合、Kongには機能がないので工夫が必要になります。**

上記の対応を備忘録として記載します。  


## KongのDockerコンテナの起動

DBレスモードでkongのコンテナを起動します。
例として[httpbin](http://httpbin.org/)へのルーティング設定を記載し、`rate-limitng`のプラグインを有効化します。

```yaml:kong.yml
_format_version: "1.1"

services:
  - name: example_service
    url: http://httpbin.org/status/200
    routes:
      - name: example_route
        paths:
          - /example
    plugins:
      - name: rate-limiting
        config:
          second: 5
          hour: 10000
          policy: local
```

Dockerfileでkong.ymlをコピーし、`KONG_DECLARATIVE_CONFIG`にファイルパスを指定します。

```Dockerfile:Dockerfile
FROM kong:3.0.0-alpine
USER root

COPY kong.yml /kong/declarative/kong.yaml

ENV KONG_DATABASE off
ENV KONG_DECLARATIVE_CONFIG=/kong/declarative/kong.yaml
ENV KONG_PROXY_ACCESS_LOG /dev/stdout
ENV KONG_ADMIN_ACCESS_LOG /dev/stdout
ENV KONG_PROXY_ERROR_LOG /dev/stderr
ENV KONG_ADMIN_ERROR_LOG /dev/stderr

USER kong
```

docker-compose.ymlを作成し、コンテナを起動します。

```yaml:docker-compose.yml
version: "3.9"
services:
  kong:
    build: .
    container_name: dbless_kong
    restart: always
    ports:
      - 8000:8000
```

起動後にcurlでHTTP STATUS 200で返ってくることを確認します。また`RateLimit-Limit`は指定通り5になっていることを確認します。

```shell
docker-compose up -d --build
curl -i localhost:8000/example

> HTTP/1.1 200 OK
> Content-Type: text/html; charset=utf-8
> RateLimit-Limit: 5
> X-RateLimit-Remaining-Second: 4
> X-RateLimit-Limit-Second: 5
> X-RateLimit-Remaining-Hour: 9999
> X-RateLimit-Limit-Hour: 10000
> RateLimit-Remaining: 4
> RateLimit-Reset: 1
...
> Via: kong/3.0.0
```

## envsubstコマンドで環境ごとに設定切替

`envsubst`という軽量なテンプレートエンジンを使うことで、kong.ymlに環境変数を埋め込むことができます

まず、`envsubst`が含まれる`gettext`をイメージにインストールします。
また、テンプレートとしてイメージにコピーし、埋め込み後のファイルのために空のkong.ymlを生成しておきます。

```Dockerfile:Dockerfile
FROM kong:3.0.0-alpine
USER root

RUN apk add gettext #追加
COPY kong.yml /kong/template/kong.yml.template #変更
RUN mkdir -p /kong/declarative && touch /kong/declarative/kong.yml #追加
...
```

次にkong.ymlの表記を変更する。`${環境変数名}`とすることでenvsubstで埋め込むことができます。ここでは例としてrate-limitingの秒間リクエスト数を切り替えることとします。

```yaml:kong.yml
_format_version: "1.1"

services:
    ...
    plugins:
      - name: rate-limiting
        config:
          second: ${RATE_LIMIT_PER_SECOND}
          hour: 10000
          policy: local
```

最後にdocker-compose.ymlで環境変数の定義と、コンテナ起動時に埋め込むコマンドを追加します

```yaml:docker-compose.yml
version: "3.9"
services:
  kong:
    build: .
    container_name: dbless_kong
    environment:
      - RATE_LIMIT_PER_SECOND=5
    command: >
      /bin/bash -c "
      envsubst < /kong/template/kong.yml.template > /kong/declarative/kong.yml &&
      kong start"
    restart: always
    ports:
      - 8000:8000
```

この状態で起動し、/exampleにcurlしてみます。

```shell
docker-compose up -d --build
curl -i localhost:8000/example

> HTTP/1.1 200 OK
> Content-Type: text/html; charset=utf-8
> RateLimit-Limit: 5
> X-RateLimit-Remaining-Second: 4
> X-RateLimit-Limit-Second: 5
> X-RateLimit-Remaining-Hour: 9999
> X-RateLimit-Limit-Hour: 10000
> RateLimit-Remaining: 4
> RateLimit-Reset: 1
...
> Via: kong/3.0.0
```

問題なく`RateLimit-Limit`は指定通り5になっています。
kong.ymlを確認してみます。

```shell
docker exec -it dbless_kong /bin/bash
cat /kong/declarative/kong.yml

> _format_version: "1.1"

> services:
>  - name: example_service
>    url: http://httpbin.org/status/200
>    routes:
>      - name: example_route
>        paths:
>          - /example
>    plugins:
>      - name: rate-limiting
>        config:
>          second: 5
>          hour: 10000
>          policy: local
```

`RATE_LIMIT_PER_SECOND`に値が埋め込まれています。
このようにして、環境変数を埋め込むことができるので、環境ごとに環境変数を定義することで設定を切り替えることができます。