オープンソースのAPI Gateway「Kong」

 2015/10/14

全国100万人のモノリシック巨大アプリケーションに苦しむみなさんこんにちは。

世の中猫も杓子もマイクロサービスだ!!とかAPIだ!!とか言っていますが、実際にマイクロサービス環境にしようとすると、どのようにしてAPIのサービスを取りまとめるかが課題になります。

一般的には以下のようなやり方になります。

  • 複数のサービスに分散しているAPIを統合するゲートウェイを用意する
  • そのゲートウェイでは以下のようなことをおこなう
    • クライアントからのアクセスのシングルエンドポイントの役目を果たす
    • APIの実体へのルーティング
    • 認証
    • アクセス記録の収集
    • スロットリング(過度なアクセスの抑止)
    • 実体がダウンしている場合のデグレーション

このようなAPIゲートウェイの機能は既にAWSではAmazon API Gatewayとして提供されていますが、オープンソースでもいくつかのプロダクトがあります。今回はそのうち一番開発が活発そうな、Kongについて紹介しましょう。

Kongとは?

KongはオープンソースのAPI管理ツールです。2015/10/14時点の最新バージョンは0.5.1になります。GitHubのレポジトリは https://github.com/mashape/kongです。

主な特徴としては

  • NginxとCassandraを使って実装
  • APIの管理などの各種操作は全てREST APIを使っておこなう
  • プラグインによる機能拡張が可能
  • 動作環境を選ばずオンプレミスでもクラウドでも動作する

などがあげられます。

Kongのインストール

では早速試してみましょう。簡単に試せるようにDockerのイメージやAWS CloudFormationのテンプレートなども用意されていますが、Vagrant用のスクリプトも用意されているので今回はそちらを使います。

単純に以下のようにしてレポジトリをチェックアウトしてください。

git clone https://github.com/Mashape/kong-vagrant

それが終わったら、チェックアウト先のディレクトリに移動し、

vagrant up --provision

を実行してください。precise64のボックスを利用するので、もし未登録の場合はダウンロードがおこなわれるため少し時間がかかるかもしれません。 プロビジョニングが終わったら、vagrant sshで仮想マシンにログインし以下のようにしてサービスを起動します。

sudo kong start

初回の場合は、データベースのマイグレーションが行われます。以下のようなログが出れば正常です。

[INFO] Using configuration: /etc/kong/kong.yml
[INFO] Kong version.......0.5.1
       Proxy HTTP port....8000
       Proxy HTTPS port...8443
       Admin API port.....8001
       dnsmasq port.......8053
       Database...........cassandra keepalive=60000 timeout=1000 contact_points=localhost:9042 keyspace=kong
[INFO] Connecting to the database...
[INFO] Database not initialized. Running migrations...
[OK] core migrated up to: 2015-01-12-175310_skeleton
[OK] core migrated up to: 2015-01-12-175310_init_schema
[OK] jwt migrated up to: 2015-06-09-jwt-auth
[OK] acl migrated up to: 2015-08-25-841841_init_acl
[OK] oauth2 migrated up to: 2015-08-03-132400_init_oauth2
[OK] oauth2 migrated up to: 2015-08-24-215800_cascade_delete_index
[OK] key-auth migrated up to: 2015-07-31-172400_init_keyauth
[OK] hmac-auth migrated up to: 2015-09-16-132400_init_hmacauth
[OK] basic-auth migrated up to: 2015-08-03-132400_init_basicauth
[OK] rate-limiting migrated up to: 2015-08-03-132400_init_ratelimiting
[OK] response-ratelimiting migrated up to: 2015-08-21_init_response-rate-limiting
[INFO] Auto-generating the default SSL certificate and key...
[INFO] dnsmasq started (dnsmasq)
[WARN] ulimit is currently set to "1024". For better performance set it to at least "4096" using "ulimit -n"
[OK] Started

これで準備は完了です。Vagrantfileの中でローカル環境の8000番ポートと8001番ポートをポートフォワードしてVagrant側の環境にアクセスできるようになっています。

使い方

各種の設定は全てREST API経由で行ないます。

公開されているAPIの確認

現時点でどんなAPIが利用者に公開されているかは以下のようなリクエストを投げます。

curl -i -X GET --url http://localhost:8001/apis

この時点では何も公開されていないので、

{"data":[]}

という応答が返ります。

APIを追加する

では次に実際に利用者が使えるようにAPIを公開しましょう。

APIの追加の追加は以下のようなコマンドを実行します。

curl -i -X POST \
  --url http://localhost:8001/apis/ \
  -d 'name=slides' \
  -d 'upstream_url=http://slide.meguro.ryuzee.com/api/v1/slides' \
  -d 'request_host=slide.meguro.ryuzee.com' \
  -d 'request_path=/slides'
  • 最初の--urlは管理用のエンドポイントを指定します。
  • 次のnameパラメータはAPIを一意に識別する名前です。実際のリクエストURLとは関係ありません。
  • 次のupstream_urlがこのAPIの実体のアクセス先です。今回の例では、以前作っておいたスライド公開アプリのスライド一覧取得APIを指定してみました
  • 次のrequest_hostはリクエスト先のホスト名です
  • 最後のrequest_pathは、このAPIのゲートウェイでどんなパスでリクエストを受けるかを指定します。

つまりこの例では、http://localhost:8000/slidesにアクセスすると、実際はupstream_urlで設定したAPIをコールします。実際に以下のようにAPIにアクセスしてみると、jsonが返ってくるのがわかります。

curl -i -X GET \
  --url http://localhost:8000/slides

APIを削除する

APIを削除する場合も管理用のエンドポイントにリクエストを投げればOKです。 末尾の箇所にAPIを作成するときにnameで指定した値を利用します。

curl -i -X DELETE --url http://localhost:8001/apis/削除したいAPI名

APIの利用時に認証を必須にする

利用者がAPIを呼び出す際に誰が呼び出しているかを識別したいケースは多々あるはずです。その場合もKongのプラグイン機構を使うことで簡単に対応できます。 たとえばKey認証を行う場合は、まずKongの設定を変更します。

/etc/kong/kong.ymlに以下を追加して再起動します(先ほど作成したVagrant環境では既に有効になっています)

plugins_available:
  - key-auth

次に認証を有効化します。認証をするかどうかはAPI単位で決めることができます。 たとえば先ほどの/slidesのAPIに認証を設定する場合は、

curl -i -X POST \
  --url http://localhost:8001/apis/slides/plugins/ \
  --data 'name=key-auth'

とします。この時点でもう一度APIにアクセスしてみると認証情報がないのでエラーになるはずです。

{"message":"No API Key found in headers, body or querystring"}

認証情報を作成する

認証情報を作成するには、まずユーザーを作成した上で、そのユーザー用のKeyを発行します。

認証用のユーザーを追加するには、以下のようにします。ここではryuzeeというユーザーを追加しています。

curl -i -X POST \
  --url http://localhost:8001/consumers/ \
  --data "username=ryuzee"

以下のような結果が返ってきます。

{"username":"ryuzee","created_at":1444714266000,"id":"addc1363-fbb4-441b-c4ef-20410692d9d8"}

この時点では認証用のキーは存在していないので、以下のようにしてキーを発行します。--urlの箇所でconsumersのあとにユーザー名を指定し、--dataの箇所でkey=キーの値という形で設定します。

curl -i -X POST \
  --url http://localhost:8001/consumers/ryuzee/key-auth/ \
  --data 'key=sushikuitai12345'

実行すると以下のような形で帰ってきて、キーの発行が完了しました。

{"created_at":1444714396000,"consumer_id":"addc1363-fbb4-441b-c4ef-20410692d9d8","key":"sushikuitai12345","id":"117beaab-b2ac-4380-c312-d7b0cf07da23"}

なお、当然のことながら実際のサービスで利用する場合は、別の画面でユーザー用のキーを発行するような仕掛けを作る必要があります。その中でKongの認証用ユーザーとキーの発行APIを呼び出すということになります。

これで以下のようにすればアクセスできます。

curl -i -X GET \
  --url http://localhost:8000/slides \
  --header "apikey: sushikuitai12345"

もしくは以下のようにクエリストリングで設定してもOKです。

curl -i -X GET \
  --url http://localhost:8000/slides?apikey=sushikuitai12345

APIへのリクエスト数を制限する(スロットリング)

大量のAPIリクエストは時としてサービスの問題発生につながります。 そういった事態を避けるために、1ユーザーからの秒あたり・分あたり・時間あたりのAPIリクエスト数を制限するのはベストプラクティスの1つです。

これもプラグインの機能で実現できます

/etc/kong/kong.ymlに以下の設定を行って再起動してください。

plugins_available:
  - ratelimiting

実際のスロットリングの設定は以下のようにします。この例では、slidesという名前のAPIにおいて秒間5件、一時間あたり10000件のリクエスト数までに制限しています。

curl -X POST http://localhost:8001/apis/slides/plugins \
    --data "name=rate-limiting" \
    --data "config.second=5" \
    --data "config.hour=10000"

これで試しに大量リクエストを投げると、閾値を超えたものは以下のような応答を返します。

HTTP/1.1 429
Date: Tue, 13 Oct 2015 06:07:37 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-RateLimit-Limit-hour: 10000
X-RateLimit-Remaining-hour: 9995
X-RateLimit-Limit-second: 5
X-RateLimit-Remaining-second: 0
Server: kong/0.5.0

{"message":"API rate limit exceeded"}

なお、APIのスロットリングを解除する場合は、最初にAPIの内部IDを取得してそれを引数にして削除します。

curl -i -X DELETE http://localhost:8001/apis/slides/plugins/814b46d2-84a3-4034-c075-60f9e2916314

まとめ

ここまで紹介したのはごく一部の機能ですが、プラグインを使うことで、アクセスコントロールを詳細におこなったり、アクセス元IPアドレスを制限したり、ログを他のサーバに飛ばしたりといったことも可能です。

このツール自体がAPIで出来ているので、監視システムなどと組み合わせて公開用のAPIの設定を自動で変更して固定の応答を返したりといったこともできます。

 2015/10/14

サイト内検索


著作

寄稿

Latest post: