- Google Cloudに関する記事
AutopilotでもCloud Endpointsがしたい
GCPでREST APIを提供するなら、Cloud Endpointsを使わない選択肢はほとんどあり得ません、かどうかは知りませんが、筆者は利用しなかったことがありません。
Cloud EndpointsはそのバックエンドとしてAppEngine, Kubernetes Engine, Cloud Runといったサービスが利用できますが、先日リリースされたGKE Autopilotでの利用を想定して素振りをするのがこの記事の目的です。
今ここまで読んでパッとやり方のイメージができない人, Workload Identityという言葉を理解していない人, Cloud Endpointsを使ったことがない人の役に立つかもしれません。
ポイントは、AutopilotでCloud Endpointsを利用するにはWorkload Identityを設定することが必須となる、ということだけです。
準備
Autopilotクラスタを作成する
サービスアカウントを1つ作成して役割を付与する
esp-v2
という名前でGCPのサービスアカウントを作成します。
付与する役割は、Cloud Trace Agent
とService Controller
です。
サンプルコードのダウンロード
今回はGCPが提供してくれているサンプルコードの一部を改変して利用します。
openapi.yamlの書き換え
ダウンロードしたopenapi.yamlの中のYOUR_PROJECT_ID
の部分を任意のIDに変更してください。
https://github.com/GoogleCloudPlatform/golang-samples/blob/d06287ee79c9082cb0b4e55b4aa685bf67926059/endpoints/getting-started/openapi.yaml#L21
kubernetesのマニフェストファイルを用意する
サンプルコードのマニフェストファイルは記述が古かったので、大部分を書き直しました。
YOUR_PROJECT_ID
の部分を読み替えて参考にしてください。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: esp-echo
spec:
backend:
serviceName: esp-echo
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: esp-echo
annotations:
cloud.google.com/neg: '{"ingress": true}'
cloud.google.com/backend-config: '{"default": "esp-echo"}'
spec:
ports:
- port: 80
targetPort: 8081
protocol: TCP
name: http
selector:
app: esp-echo
type: ClusterIP
---
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: esp-echo
spec:
healthCheck:
type: HTTP
requestPath: /healthz
port: 8081
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: esp-echo
spec:
replicas: 1
selector:
matchLabels:
app: esp-echo
template:
metadata:
labels:
app: esp-echo
spec:
serviceAccountName: esp-v2 # ここがあとで重要
containers:
# [START esp]
- name: esp
image: gcr.io/endpoints-release/endpoints-runtime:2
args: [
"--listener_port", "8081",
"--backend", "127.0.0.1:8080",
"--service", "echo-api.endpoints.YOUR_PROJECT_ID.cloud.goog",
"--rollout_strategy", "managed",
"--healthz=/healthz",
]
readinessProbe:
httpGet:
path: /healthz
port: 8081
# [END esp]
ports:
- containerPort: 8081
- name: echo
image: gcr.io/google-samples/echo-go:1.0
ports:
- containerPort: 8080
デプロイ
Cloud Endpoints Service
修正したopenapi.yamlを利用して次のようにします。
$ gcloud endpoints services deploy openapi.yaml
Waiting for async operation...
確認
$ gcloud endpoints services list
NAME TITLE
echo-api.endpoints.YOUR_PROJECT_ID.cloud.goog
Workload Identity
Workload Identityとは、KubernetesのService Account(KSA)とGCPのService Account(GSA)を結びつけ、Kubernetesクラスタ内で実行されるPodにGSAの役割を付与するものです。
Autopilotクラスタでは、デフォルトでWorkload Identityが有効化されています。
Cloud Endpointsでは、Extensive Service Proxy(ESP)と呼ばれるものが自分たちのコンテナの前段にProxyとして配置され、リクエストカウント, エラー率, レイテンシ, 認可などの処理を行ってくれます。
Extensive Service Proxyがあるから、Cloud Endpointsが下画像のように各指標をダッシュボードで表示できるのです。
この指標を計測するために、準備で作成したサービスアカウントに必要な役割を付与しました。
つまり、任意のKSAがGSA esp-v2
として振る舞えるようにします。
Workload Identityを利用するには大きく3つのステップが必要です
– KSAの作成
– GSAにKSAのバインディング
– KSAにアノテーションを追加
これらを実行していきます。
今回はKSAもesp-v2
という名前でdefault
namespaceに作成することにします。
$ kubectl create serviceaccount --namespace default esp-v2
更に、KSAがGSAの権限を利用できるようにバインディングをします。
$ gcloud iam service-accounts add-iam-policy-binding \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:YOUR_PROJECT_ID.svc.id.goog[default/esp-v2]" \
esp-v2@YOUR_PROJECT_ID.iam.gserviceaccount.com
[default/esp-v2]
を一般化すると [namespace/KSA]
です。
今回はdefault
namespaceの esp-v2
というKSAなので上記のようになります。
最後にKSAにアノテーションを追加します。
$ kubectl annotate serviceaccount \
--namespace default esp-v2 \
iam.gke.io/gcp-service-account=esp-v2@YOUR_PROJECT_ID.iam.gserviceaccount.com
ここで、kubernetesのマニフェストファイルに1度戻りましょう。Deployment中の次の行を探してください
serviceAccountName: esp-v2
これは、このDeploymentで起動するPodにKSAesp-v2
が割り当てられることを意味しています。
つまり、これらのPodはGSAesp-v2
の権限を持つことになるわけです。
Autopilotでは、NodeのService Accountが利用できないため、必ずこのようにWorkload Identityを利用する必要があります。
アプリケーション
あとはKubernetesのマニフェストファイルをデプロイすれば、リクエストがESPを通してアプリケーションコンテナに到達できます。
$ kubectl apply -f k8s/esp_echo_http.yaml
IngressのExternal IPを確認したら、次のようにリクエストを送ってみましょう。
$ kubectl get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
esp-echo <none> * 35.201.76.254 80 129m
$ curl --request POST \
--header "content-type:application/json" \
--data '{"message":"hello world"}' \
"http://35.201.76.254:80/echo"
{"message":"UNAUTHENTICATED: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.","code":401}
するとこのように401エラーが返ってくるはずです。
これは、サンプルのopenapi.yaml
が、APIキーをパラメータとして要求するためです。
上記はESPが不適切なリクエストに対して返しているレスポンスです。
GCPのCredentialsのページでAPIキーを発行して次のように付与すると、正常なレスポンスが得られます。
$ curl --request POST \
--header "content-type:application/json" \
--data '{"message":"hello world"}' \
"http://35.201.76.254:80/echo?key=YOUR_API_KEY"
{"message":"hello world"}
このように、Workload Identityさえ使えば今までのGKEでやっていたことと同じようにCloud Endpointsを利用することができました。めでたしめでたし。
3大クラウド最新比較資料はこちらから
GCP・AWS・Azure 3大クラウドサービス比較表では各社クラウドのあらゆるサービスや料金等の比較を網羅的に行なっております。よりクラウドサービスを体型的にご理解いただける内容となっておりますのでこちらもぜひお読みください。
この記事を共有する