• Google Cloudに関する記事
8分で読める

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クラスタを作成する

https://cloud.google.com/kubernetes-engine/docs/how-to/creating-an-autopilot-cluster?hl=ja#create_an_autopilot_cluster

サービスアカウントを1つ作成して役割を付与する

esp-v2という名前でGCPのサービスアカウントを作成します。
付与する役割は、Cloud Trace AgentService 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大クラウドサービス比較表では各社クラウドのあらゆるサービスや料金等の比較を網羅的に行なっております。よりクラウドサービスを体型的にご理解いただける内容となっておりますのでこちらもぜひお読みください。

この記事を共有する

合わせて読みたい