本稿では、Cloud Endpointsとは何か、どんな場合に活用できるのか、それを使うとどんなメリットがあるのかについて解説します。また実際のソースコードを使って認証機能を持ったAPIを構築する例をご紹介します。本稿を読むことで、Cloud Endpointsを使ったAPI構築から活用までの流れを把握することができます。
本稿ではOpenAPIを使用したCloud Endpointsについての記事です。Cloud EndpointsはgRPCや AppEngine/Java, Pythonにも対応していますが、本稿ではそれらについては言及しません。予めご承知おき下さい。
目次
Cloud Endpointsとは
Cloud EndpointsはGoogle Cloud Platform(GCP)のサービスの1つで、API管理のための機能を提供します。Cloud Endpointsの主な機能は3つです。
- 認証(APIキー、JWT)
- モニタリング(メトリクス分析、ロギング)
- 共有APIドキュメント
APIのリクエストやレスポンスの仕様(ルール)を定義し、それをデプロイすることでその仕様を実際のAPIに適用することができます。リクエストがAPIバックエンドに届く前にCloud Endpointsがルールを元にリクエストをチェックし、リクエストを通すかどうかを判断します。
Cloud Endpointsは複数のコンポーネントの集まりとして構成されています。例えば、APIルールをデプロイ・管理するツールやサービス、リクエストを監視するリバースプロキシです。これらを操作することによってAPIに上記の3つの機能を付加することができます。
Cloud Endpointsのユースケース
APIを外部に公開する
APIを外部に公開する場合、認証機能をAPIに付与することで、APIにアクセスするユーザーを識別することができ、悪意のあるユーザーからのリクエストを遮断できます。認証方法はAPIキーかOAuth2のどちらか、もしくは両方を選択することができます。
マイクロサービスを使ったアプリケーションを構築する
マイクロサービスを構築する際、それぞれのマイクロサービスにサービスアカウントキーを持たせることでマイクロサービスとAPI間の通信に認証機能を付加することができます。そうすることでAPIを利用するマイクロサービスを限定することができ、セキュリティが向上します。
Cloud Endpointsを使うメリット
APIのドキュメント化が簡単
Cloud EndpointsはOpenAPI仕様に対応しています。OpenAPIはコードベースのAPI定義フォーマットです。コードベースなのでGitで管理することが可能です。またOpenAPIではAPI定義ファイルからドキュメントを自動生成することができますので、別途APIドキュメントを作る手間が省けます。
APIの管理・デプロイが簡単
APIルールは1つの定義ファイルの中で管理されているので、それを編集することによりAPIの追加や削除は簡単に行えます。またAPIキーやOAuthなどのセキュリティルールの定義を一度行えば、ルールを全APIに適用したり、一部のAPIのみに適用するといった設定も簡単に行えます。作成したAPIルールはコマンド一回でデプロイすることができます。
APIの利用状況の分析ができる
Cloud EndpointsにはAPIモニタリング用の画面が用意されており、そこで個々のAPIの利用状況をモニタリングしたり、ログを見ることができます。これを活用することで、デバッグやAPI開発のヒントを得ることができます。
Cloud Endpointsを試してみる
Cloud Endpointsの仕組みについてはこちらが詳しいです。なので本稿では仕組みについては詳しく触れません。その代わり、GKEを使用したEndpointsの使用例を紹介することでCloud Endpointsの全体像を掴んでもらいたいと思います。
構築の手順は以下の通りです。
- APIバックエンドのコンテナイメージを作成し、Google Container Registryにアップロードする
- 作成したコンテナイメージを元にGKEでバックエンドAPIのクラスタを構築する
- OpenAPIフォーマットのAPI定義ファイルをCloud SDKでデプロイする
上記の手順を行うと以下のようなアーキテクチャが構築できます。クライアントはプロジェクトに割り当てられたAPIキーをあらかじめ持っておき、それをAPIのリクエストに含めることでAPIへのアクセスが可能となります。逆に、APIキーをリクエストに含めない場合はエラーになります。
コンテナイメージを作成し、Google Container Registryにアップロードする
デフォルトのプロジェクトを設定します。[PROJECT_ID]はご自身のプロジェクトIDに置き換えてください。
$ gcloud config set project [PROJECT_ID]
以下のファイルを作り同じディレクトリに配置します。今回作るAPIはリクエストに対し「Hello, World」とプレーンテキストを返すだけの単純なものです。
package main
import (
"fmt"
"net/http"
)
type String string
func (s String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, s)
}
func main() {
http.Handle("/hello", String("Hello, World"))
http.ListenAndServe("0.0.0.0:8080", nil)
}
FROM golang:1.11.2-alpine3.8
WORKDIR /go
ADD app.go .
RUN ["go", "build", "app.go"]
ENTRYPOINT ["./app"]
コンテナイメージをビルドします。
$ docker build -t gcr.io/[PROJECT_ID]/backend-go .
コンテナイメージをContainer Registryにプッシュします。
$ docker push gcr.io/[PROJECT_ID]/backend-go
Google Kubernetes EngineでバックエンドAPIのクラスタを構築する
Kubernetesの構成ファイルを用意します。今回は以下の構成ファイルを使います。
kind: Service
apiVersion: v1
metadata:
name: endpoints-service
spec:
selector:
app: myendpoints-app
ports:
- protocol: TCP
port: 80
targetPort: 8081
type: LoadBalancer
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: endpoints-deployment
labels:
app: myendpoints-app
spec:
replicas: 1
selector:
matchLabels:
app: myendpoints-app
template:
metadata:
labels:
app: myendpoints-app
spec:
containers:
- name: esp
image: gcr.io/endpoints-release/endpoints-runtime:1
args: [
"-p", "8081",
"-a", "0.0.0.0:8080",
"-s", "sample-api.endpoints.[PROJECT_ID].cloud.goog",
"-R", "managed"
]
ports:
- containerPort: 8081
- name: backend-go
image: gcr.io/[PROJECT_ID]/backend-go
ports:
- containerPort: 8080
GKEクラスタを作成します。
$ gcloud container clusters create endpoints-cluster --zone asia-east1-b --preemptible
構成ファイルをクラスタにデプロイします。
$ kubectl apply -f backend.yaml
EPサービスをデプロイする
OpenAPI定義ファイルを用意します。今回は以下の定義ファイルを使います。
swagger: "2.0"
info:
description: "A simple Google Cloud Endpoints API example."
title: "Endpoints Example"
version: "1.0.0"
host: "sample-api.endpoints.[PROJECT_ID].cloud.goog"
x-google-endpoints:
- name: "sample-api.endpoints.[PROJECT_ID].cloud.goog"
target: "[BACKEND_IP]"
paths:
/hello:
get:
operationId: helloWorld
description: Returns greeting message.
produces:
- text/plain
responses:
'200':
description: returns hello world.
schema:
type: string
security:
- api_key: []
securityDefinitions:
api_key:
type: apiKey
name: key
in: query
hostはEndpointsにデプロイされるEPサービスの一意な名前です。
host: "sample-api.endpoints.[PROJECT_ID].cloud.goog"
x-google-endpointsは任意のドメインを使用してAPIにアクセスしたい場合に記述します。nameは所有しているドメイン(.endpoints.[PROJECT_ID].cloud.googドメインは自由に使うことができます)、targetはバックエンドのIPアドレスを記載します。今回はGKEにデプロイしたk8sサービスの外部IPアドレスを使用します。
x-google-endpoints:
- name: "sample-api.endpoints.[PROJECT_ID].cloud.goog"
target: "[BACKEND_IP]"
K8sサービスの外部IPアドレスを確認します。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
endpoints-service LoadBalancer 10.31.248.72 [BACKEND_IP] 80:30738/TCP 17h
kubernetes ClusterIP 10.31.240.1 443/TCP 1d
k8sサービスのEXTERNAL-IPの値をコピーし、openapi.yamlのファイルの[BACKEND_IP]の値と置き換えます。
securityDefinitionsにはAPIのセキュリティルールを記載します。例えば以下の場合、APIキーをクエリ文字列のkeyの値にセットしてリクエストを送信しなければならないというルールを定義しています。
securityDefinitions:
api_key:
type: apiKey
name: key
in: query
このルールをAPIに適用するには、APIのメソッド直下にsecurityプロパティを追加し、定義した認証ルールの名前を記載します。(リストは空で構いません)
paths:
/hello:
get:
// 中略
security:
- api_key: []
OpenAPI定義ファイルをデプロイします。
$ gcloud endpoints services deploy openapi.yaml
これで手順は全て完了です。試しに構築したAPIを使って、APIキーを使った場合と使わなかった場合の動作比較をしてみたいと思います。
構築したAPIを試してみる
APIキーを取得する
Cloud Consoleにアクセスし、サービスメニューから「APIとサービス」→「認証情報」のページへ移動します。
認証情報のページに移動したら、「認証情報を作成」→「APIキー」の順にクリックし、生成されたAPIキーをクリップボードにコピーします。
リクエストを投げる
APIキーがある場合
$ curl sample-api.endpoints.[PROJECT_ID].cloud.goog/hello?key=[API_KEY]
Hello, World
APIキーが無い場合
$ curl sample-api.endpoints.[PROJECT_ID].cloud.goog/hello
{
"code": 16,
"message": "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",
"details": [
{
"@type": "type.googleapis.com/google.rpc.DebugInfo",
"stackEntries": [],
"detail": "service_control"
}
]
}
APIキーをクエリに含めなかった場合、APIの呼び出しに失敗しました。
APIのドキュメントを見る
デプロイしたAPI定義ファイルからドキュメントを自動生成してプロジェクトで共有することができます。これを見るには、Cloud Consoleから「エンドポイント」→「デベロッパーポータル」にアクセスし、サービスリストからEPサービスを選択します。
「Try this API」でAPIを試しに実行することもできます。
APIをモニタリングする
APIのリクエスト数やレイテンシなどのメトリクスをモニタリングするには、Cloud Consoleから「エンドポイント」→「サービス」へアクセスします。
またAPIリストの各行にある「ログを表示」ボタンをクリックすると、各APIのログを見ることができます。
まとめ
いかがでしたでしょうか。 Cloud Endpointsを使うとAPIの管理が簡単にできることがお分かりいただけたと思います。 個人的には、APIのドキュメントを自動で作成してくれるデベロッパーポータルが特に魅力的でした。これを使えば、APIのドキュメントを別途Gitなどで管理する必要が無くなり、属人化が発生しにくくなります。使いこなすには少し知識が必要ですが、一度使いこなすととても便利なツールです。 皆さんもぜひこの機会にCloud Endpointsを試してみてはいかがでしょうか。