Kong & Konga を Docker で動かして API を追加してみる

Kong とは、 オープンソースのマイクロサービスAPIゲートウェイプラットフォームです。

Dockerで起動させることができます。

[Kong/docker-kong](https://github.com/Kong/docker-kong/tree/master/compose)


以下のような docker-compose.yml を用意します。

```yaml:docker-compose.yml
version: '3.7'

volumes:
  kong_data: {}

networks:
  kong-net:
    external: false

services:
  kong-migrations:
    image: "${KONG_DOCKER_TAG:-kong:latest}"
    command: kong migrations bootstrap
    depends_on:
      - db
    environment:
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
      KONG_PG_HOST: db
      KONG_PG_USER: ${KONG_PG_USER:-kong}
      KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    networks:
      - kong-net
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure

  kong-migrations-up:
    image: "${KONG_DOCKER_TAG:-kong:latest}"
    command: kong migrations up && kong migrations finish
    depends_on:
      - db
    environment:
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
      KONG_PG_HOST: db
      KONG_PG_USER: ${KONG_PG_USER:-kong}
      KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    networks:
      - kong-net
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure

  kong:
    image: "${KONG_DOCKER_TAG:-kong:latest}"
    user: "${KONG_USER:-kong}"
    depends_on:
      - db
    environment:
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ERROR_LOG: /dev/stderr
      KONG_PROXY_LISTEN: "${KONG_PROXY_LISTEN:-0.0.0.0:8000}"
      KONG_ADMIN_LISTEN: "${KONG_ADMIN_LISTEN:-0.0.0.0:8001}"
      KONG_CASSANDRA_CONTACT_POINTS: db
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
      KONG_PG_HOST: db
      KONG_PG_USER: ${KONG_PG_USER:-kong}
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
      KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    networks:
      - kong-net
    ports:
      - "8000:8000/tcp"
      - "127.0.0.1:8001:8001/tcp"
      - "8443:8443/tcp"
      - "127.0.0.1:8444:8444/tcp"
    healthcheck:
      test: ["CMD", "kong", "health"]
      interval: 10s
      timeout: 10s
      retries: 10
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
    
  db:
    image: postgres:9.5
    environment:
      POSTGRES_DB: ${KONG_PG_DATABASE:-kong}
      POSTGRES_USER: ${KONG_PG_USER:-kong}
      POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "${KONG_PG_USER:-kong}"]
      interval: 30s
      timeout: 30s
      retries: 3
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
    stdin_open: true
    tty: true
    networks:
      - kong-net
    volumes:
      - kong_data:/var/lib/postgresql/data

secrets:
  kong_postgres_password:
    file: ./POSTGRES_PASSWORD
```

同じディレクトリに`POSTGRES_PASSWORD`を用意して、PostgresSQLのパスワード kong と書いておきます（[][GitHub のリポジトリ](https://github.com/Kong/docker-kong/blob/master/compose/POSTGRES_PASSWORD)通りです）


docker-compose を起動すると、 Kong が立ち上がります。

```console
$ docker-compose up
```

次にチュートリアルに従って Kong を使ってみます。

[Kong Gateway (OSS)  Getting started](https://docs.konghq.com/gateway-oss/2.4.x/getting-started/configuring-a-service/)

### サービスの設定

Kong に最初の Service を追加します。

[service-object](https://docs.konghq.com/gateway-oss/2.4.x/admin-api/#service-object)

```
$ curl -i -X POST \
  --url http://localhost:8001/services/ \
  --data 'name=example-service' \
  --data 'url=http://mockbin.org'

## 以下、レスポンスです

HTTP/1.1 201 Created
Date: Mon, 24 May 2021 14:33:14 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Content-Length: 361
X-Kong-Admin-Latency: 19
Server: kong/2.4.1

{"updated_at":1621866794,"read_timeout":60000,"ca_certificates":null,"write_timeout":60000,"host":"mockbin.org","protocol":"http","tls_verify":null,"retries":5,"tls_verify_depth":null,"path":null,"client_certificate":null,"port":80,"name":"example-service","tags":null,"connect_timeout":60000,"id":"9ff4a83a-54b4-43cf-a9d6-d2439a40fd13","created_at":1621866794}%
```

追加された Service は `http://localhost:8001/services` で確認できます。

![スクリーンショット 2021-05-24 23.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888099/ab715788-91b3-6b89-4ea4-31b58cbb41df.png)


### Routes を追加する

上で作った Service に Route と呼ばれるルーティング設定を追加します。
1つのサービスには多くの Route が関連付けられます。

Route エンティティにはクライアントのリクエストにマッチするルールを定義します。

[route-object](https://docs.konghq.com/gateway-oss/2.4.x/admin-api/#route-object)

```console
$ curl -i -X POST \
  --url http://localhost:8001/services/example-service/routes \
  --data 'hosts[]=example.com'

## 以下、レスポンス

HTTP/1.1 201 Created
Date: Mon, 24 May 2021 14:35:08 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Content-Length: 480
X-Kong-Admin-Latency: 12
Server: kong/2.4.1

{"updated_at":1621866908,"service":{"id":"9ff4a83a-54b4-43cf-a9d6-d2439a40fd13"},"tags":null,"request_buffering":true,"response_buffering":true,"https_redirect_status_code":426,"preserve_host":false,"paths":null,"methods":null,"sources":null,"destinations":null,"protocols":["http","https"],"hosts":["example.com"],"strip_path":true,"path_handling":"v0","created_at":1621866908,"regex_priority":0,"headers":null,"name":null,"id":"4b29c91b-bd88-42f5-bc5e-9a69c6d4f18a","snis":null}
fj@fjshnoMacBook-Pro: ~
```

最後に、Kong を通してリクエストを転送してみます。

```console
$ curl -i -X GET \
  --url http://localhost:8000/ \
  --header 'Host: example.com'
```

上のようなリクエストを投げると、最初の Service の `--data 'url=http://mockbin.org'` で設定した`http://mockbin.org`にリクエストがフォワードされます。
 

### `/apis/`への POST リクエストで "Not found" が返ってくる場合

```console
$ curl -i -X POST \
> --url http://localhost:8001/apis/ \
> --data 'name=mockbin' \
> --data 'upstream_url=http://mockbin.com/' \
> --data 'request_host=mockbin.com'
HTTP/1.1 404 Not Found
Date: Mon, 24 May 2021 14:21:19 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Content-Length: 23
X-Kong-Admin-Latency: 0
Server: kong/2.4.1

{"message":"Not found"}%
```

`/apis/` で 404 が返ってくるのはKong のバージョンが新しくなって、`/apis`のエンドポイントが廃止されたためです。

[Not found: /apis](https://discuss.konghq.com/t/not-found-apis/2979)


## Konga を使って Kong Admin API をもっと楽に操作する

[GitHub - Konga](https://github.com/pantsel/konga)
[dockerhub - Konga](https://hub.docker.com/r/pantsel/konga/)

`docker-compose.yml` に Konga の設定を追加します。

network を kong と同じにしないと、あとで Connection を作成するところでエラーが出ます。

```yaml:docker-compose.yml
  konga:
    image: pantsel/konga
    ports:
      - "1337:1337"
    environment:
      - "DB_ADAPTER=postgres"
      - "DB_HOST=konga-db"
      - "DB_USER=konga"
      - "DB_PASSWORD=konga"
    restart: "on-failure:3"
    networks:
      - kong-net
    depends_on:
      - konga-db

  konga-db:
    image: "postgres:9.6"
    environment:
      POSTGRES_USER: "konga"
      POSTGRES_PASSWORD: "konga"
      POSTGRES_DB: "konga"
    networks:
      - kong-net
    volumes:
      - ./konga_data:/var/lib/postgresql/data
```

Docker を立ち上げます。

```
$ docker-compose up
```

`http://localhost:1337/`で Konga の登録画面が開きます。

![スクリーンショット 2021-05-25 0.29.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888099/9422866b-7049-2d20-ff97-8da60cec2fbd.png)

適当に Admin ユーザーを登録すると、 Konga のWelcome 画面にログインできます。

![スクリーンショット 2021-05-25 0.29.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888099/390e81a5-dd65-9f7f-4b33-3623bfc82035.png)

Kong Admin URL には`http://kong:8001`と入力します。
![スクリーンショット 2021-05-25 0.43.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888099/fa29855f-2d11-5a40-f6e3-44a733928cfd.png)



試しに`http://localhost:8000/mock`へのリクエストを `https://www.yahoo.co.jp` にフォワードしてみます。

ダッシュボードの左ペインの SERVICES を開き、「ADD NEW SERVICE」ボタンを押して新たにサービスを作ります。

Name: forward-service
Protocol: https
Host: www.yahoo.co.jp
Port: 443

![スクリーンショット 2021-05-25 1.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888099/75bb8e26-c6f3-07f6-eef7-ebf7cc53ca2f.png)


サービスの下に Routes を作ります。
（ Routes は　Service を作らないと作れません）

Name: mock
Hosts: localhost
Paths: /mock
Methods: GET

![スクリーンショット 2021-05-25 1.14.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888099/25988404-fdb9-82f6-755e-9a7f150ee681.png)


「SUBMIT CHANGES」ボタンを押して、 Routes を作成します。

すると、ブラウザから `http://localhost:8000/mock` を叩いたときに Yahoo の画面が表示されます。

このように Kong はリクエストをバックエンドのサーバにフォワードすることができます。