APIゲートウェイKongを試す
はじめに
最近触れた技術としてKongと呼ばれるNginxベースのAPIゲートウェイがあります。個人的に興味が湧いたので調べてまとめようと思います。以下のようなことをまとめたいなと思います。
- Kongの概要
- 基本的な機能の使い方(インストールはDocker前提)
- ServiceとRouteの登録
Kongとは
公式の「Kong APIとは」のページに以下のようなことが書かれていました。
Kong は、API ゲートウェイです。つまり、クライアントと API ベースのアプリケーションをつなぐミドルウェアの一種です。 Kong を使うことにより、API の機能を一貫して簡単に拡張できます。Kong で導入できる主な機能には、 認証、セキュリティ、トラフィック制御、 サーバーレス、 アナリティクス & モニタリング、リクエスト/レスポンス変換、および ログなどが挙げられます。
複数のAPIに共通の処理を入れたい場合、APIゲートウェイと呼ばれるようなプロキシを通し、共通処理やルーティングを行なうことで、APIの管理や実行を容易にすることが可能になります。
ざっと全体を読む限り、Kongはクラウドでの利用を意識しているようで、公式サイトでクラウドネイティブという言葉を多くみることができました。
導入してみる
Kongのインストール
Kongのインストールに関して、Kong Inc によりいくつかの方法が用意されています。
今回はDockerでの利用をしてみたいと思います。 KongのDocker Hubは以下のところになります。
docker-composeのテンプレートも用意されておりますが、今回は純粋にDockerのみでのインストールを使いたいと思います。
また、ここで、Kongのバージョンは現在(2020年4月2日時点)でのDocker Hubでのlatest
タグがつけられているイメージで利用可能な2.0.2
を用います。
Kong実行の際にデータベースを利用する or しないの選択を行なう必要があります。
もし、DBを利用しない、DBレスモードで動かす場合は以下のようなことに注意しておく必要があります。
- Kongのノード間における中央調整ポイントがない
- Kongを複数ノードで実行している場合に、それぞれのKongのインスタンスがノード内で完全に独立します。設定の共有などは行われませせん。
- 読み取り専用のAdminAPI
- DBレスモードでは、宣言的な設定ファイルでのみの設定が有効になっており、AdminAPIが読み取り専用になっています。更新APIを叩こうとすると
Method Not Allowed 405
が返って来ます。
- DBレスモードでは、宣言的な設定ファイルでのみの設定が有効になっており、AdminAPIが読み取り専用になっています。更新APIを叩こうとすると
今回は、DBレスモードで特に問題がなさそうなのでそちらを利用したいと思います。
それでは、KongのDocker Installationを参考にインストールしていきます。
Docker networkを作成する
以下のコマンドで、Docker networkを作成します。
$ docker network create kong-net
一旦、公式に従っていますが、kong-net
の部分は適当な値を当てておくことが可能なようです。
また、このDocker networkの設定自体はDBレスモードで必ず必要と言うわけでは無いですが、レイトリミットプラグインを導入したい場合などに必要になるので、実行しておくのが良いと書かれていました。
また、今回は後ほど必要となるので作成しておきます。
Docker Volumeの作成
以下のコマンドでDocker Volumeの作成を行います。
$ docker volume create kong-vol $ docker volume inspect kong-vol [ { "CreatedAt": "2020-04-02T13:47:01+09:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/kong-vol/_data", "Name": "kong-vol", "Options": {}, "Scope": "local" } ]
マウントポイントが/var/lib/docker/volumes/kong-vol/_data
となっているのがわかります。
次のステップで、書かれますが、実際にKongの設定を書く際は上記のディレクトリにkong.yml
を作成し、書いていくことになります。
KongのDBレスモードを起動する。
起動時には以下のコマンドを利用しmKongのDBレスモードで起動します。
が、今の状態で起動しようとするとKongのkong.ymlが無いことで怒られて起動に失敗するのでまずはkong.yml
をホストPCの/var/lib/docker/volumes/kong-vol/_data
に作成します。
_format_version: "1.1" services: - name: my-service url: https://example.com plugins: - name: key-auth routes: - name: my-route paths: - / consumers: - username: my-user keyauth_credentials: - key: my-key
設定の詳細に関しては後ほどまとめますので、ここでは深く考えずに一旦以上の設定を記述します。
それでは、設定ファイルの準備をできたところで、Kongの起動コマンドを少し見てみようと思います。
$ docker run -d --name kong \ --network=kong-net \ -v "kong-vol:/usr/local/kong/declarative" \ -e "KONG_DATABASE=off" \ -e "KONG_DECLARATIVE_CONFIG=/usr/local/kong/declarative/kong.yml" \ -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, 0.0.0.0:8444 ssl" \ -p 8000:8000 \ -p 8443:8443 \ -p 127.0.0.1:8001:8001 \ -p 127.0.0.1:8444:8444 \ kong:latest
色々書かれていますが、環境変数として設定されているKONG_DATABASE=off
、KONG_DECLARATIVE_CONFIG
、KONG_ADMIN_LISTEN
の3つの部分に注目します。
まず、KONG_DATABASE=off
では、DBモードをoff
にしており、この設定を入れることによって、KongがDBレスモードで起動します。
KONG_DECLARATIVE_CONFIG
のところではKongの設定ファイルであるkong.yml
を配置するディレクトリに指定しています。また、-v "kong-vol:/usr/local/kong/declarative"
で先程作成したkong-vol
を/usr/local/kong/declarative
に当てているため、ホストの/var/lib/docker/volumes/kong-vol/_data
に配置したkong.yml
がkongのコンテナ内でKongの設定として読み込まれるようになっています。
KONG_ADMIN_LISTEN
では、AdminAPIのエンドポイントのバインディング設定を書いてます。
ここで、設定したエンドポイントをポートフォワードでコンテナ外に公開しているようです。
https用に0.0.0.0:8444 ssl
も設定していますが、今回は基本的に8001
のポートにバインディングされたものを使いたいと思います。
上記のDockerコマンドでKongを起動してみましょう。 起動ができたら以下のcurlを叩くと、kong.ymlのService entityを得ることができます。
$ curl -i http://localhost:8001/services HTTP/1.1 200 OK Date: Fri, 03 Apr 2020 02:48:01 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Access-Control-Allow-Origin: * Server: kong/2.0.2 Content-Length: 316 X-Kong-Admin-Latency: 128 {"next":null,"data":[{"host":"example.com","created_at":1585882034,"connect_timeout":60000,"id":"0855b320-0dd2-547d-891d-601e9b38647f","protocol":"https","name":"my-service","read_timeout":60000,"port":443,"path":null,"updated_at":1585882034,"client_certificate":null,"tags":null,"write_timeout":60000,"retries":5}]}
kong.confで設定していたサービスが取得でき、無事、Kongが立ち上がってそうですね。
ServiceとRouteの設定をしてみる
Kongが起動できたところで、実際にその設定を書いて行きたいと思います。
Kongでは以下の2つの設定方法が用意されています。
- AdminAPI
- The Declarative Configuration
AdminAPIを通しての設定はCRUDのWebAPIがKongに用意されており、そのAPIを通して、設定を行なうことが可能です。
AdminAPIに対して、The Declarative Configurationの方はKongの宣言的な設定ファイルをを記述し、Kong側からその設定ファイルを読み込ませる機能です。今までにkong.yml
を用意しましたが、これがその設定ファイルに当たります。
DBレスモードではAdminAPIはリードオンリーになっているため、The Declarative Configurationの方を使うことになります。また、Infrastructure as Codeの観点からも設定をファイルで保存しておくことは良いプラクティスであると思われます。
よって、この記事では基本的にはThe Declarative Configuration
の機能の方を利用していこうと思います。
The Declarative Configurationについて
The Declarative ConfigurationはKognのバージョン1.1から追加されています。
この機能を利用することに寄って、
先程、インストールの際に一旦追加しておいたkong.yml
を見てます。
_format_version: "1.1" services: - name: my-service url: https://example.com plugins: - name: key-auth routes: - name: my-route paths: - / consumers: - username: my-user keyauth_credentials: - key: my-key
まず、一行目に記述されている_format_version: "1.1"
では、APIのバーションを指定しています。
kong.ymlの設定ではこの部分のみが必須項目で後のトップレベルの項目は書かなくても起動できたっぽいです。
次にトップレベルで設定されているservices
とconsumers
ですが、これらはKongのentityとなります。
kong.confではentityとその設定を宣言的に記述することができます。
Kongのentityには主に以下のようなものがあります。
- Service Object
- Consumer Object
- サービスの利用者(ユーザ等)を指します。
- Route Object
- クライアントのリクエストにマッチするルールを定義し、それらのルールをサービスに紐付けることで、ルーティングの設定を行なうことができます。
- Plugin Object
ちなみに公式ではObjectという呼び方を指定していたりentityという呼び方をしていたりしますが、違いがあるのかはよくわかっていないです(この辺知っている方がいたら教えてほしいです...)。
ここまでまとめたところで、もう一度記述しているkong.ymlを見てみます。
まずは、Serviceの方から
services: - name: my-service url: https://example.com plugins: - name: key-auth routes: - name: my-route paths: - /
このサービスでは、/
のアクセスに対してhttps://example.com
へのリクエストを流すサービスを定義しています。また、Pluginとしてkey-auth
というのを使っているようです(今回は、このプラグインに関しては深く触れません。というか、調べてみたけどまだ良くわかなかったので、今回のゴールはここを深く触れなくても達成できると思ったので、一旦スルーします)
次に、consumerです
consumers: - username: my-user keyauth_credentials: - key: my-key
ここでは新たにmy-user
というユーザを追加しています。Consumerを定義することによりサービス利用者等を定義することができ、タグをつけフィルタリングをかけたりすることができます。
具体的に利用イメーシがついてないのが正直なところですが、一旦深堀はここまでにしておきます。
ルーティング先を用意する。
それではルーティングの設定を書いていきますが、その前にKongがルーティングするサーバを2つほど用意しておきます。
用意するサーバはNginxでさくっと立ち上げておこうと思います。
サーバ1
$ docker run -d --name kong-nginx \ --network kong-net \ -p 127.0.0.1:8111:80 \ nginx:1.12 $ docker exec -it kong-nginx bash root@<コンテナID>: echo "Hello, kong." > /usr/share/nginx/html/index.html $ curl -i localhost:8111 HTTP/1.1 200 OK Server: nginx/1.12.2 Date: Sat, 04 Apr 2020 16:57:59 GMT Content-Type: text/html Content-Length: 15 Last-Modified: Sat, 04 Apr 2020 16:57:54 GMT Connection: keep-alive ETag: "5e88bc92-f" Accept-Ranges: bytes Hello, kong.
それぞれのNginxのサーバはHello, kong
を返すようにしておきます。
また、KongのコンテナからNginxのコンテナへの通信を行えるようにネットワークにkong-net
を指定しておきましょう。
Kongの設定を記述する
先ほどを立てたNginxのサーバに対して、サービスとルートを登録してみようと思います。
まずはkong.ymlに先程作成したサービスを追加します。
_format_version: "1.1" services: - name: my-service url: https://example.com plugins: - name: key-auth routes: - name: my-route paths: - / # ServiceとRouteの設定を追記する。 - name: kong-service url: http://172.18.0.3 routes: - name: kong-route paths: - /kong consumers: - username: my-user keyauth_credentials: - key: my-key
/kong
でkong-nginx
につながるような設定を記述しました。また、ServiceオブジェクトのURLのホストはそれぞれのコンテナのIPを入れました。
設定、記述後にコンテナを再起動します。
それではKongのそれぞれのパスにアクセスして結果を見てみたいと思います。 Kongはデフォルトでは、8000番ポートのトラフィックを上流サービスにプロキシします。
$ curl localhost:8000/kong Hello, kong.
Kongを通して、それぞれのNginxへアクセスできているみたいですね。
感想
まだ、わからないことが多くてところどころごまかしながらやりましたが、Kongの概要把握と動かしてみることはできたので一旦OKとしようと思います。
プラグインを自作することもできるみたいなので、また別の機会に試してみたいとおもいます。