現場データサイエンティスト奮闘記

とある企業で働くデータサイエンティストの日々のアウトプット

Cloud Endpoints + GKEで構築したAPIをマネージド証明書を用いてhttps通信に対応させる

概要

APIを作成する際に、GCPのサービスであるCloud Endpointsを使うとAPIのドキュメント管理や認証機能を簡単に実装できるなどいろいろと便利です。アプリケーションの部分はGKEで作ってそれらを連携させていたりします。

それらの詳しい方法は以下のリンクでチュートリアルを実際にやっていただくのがわかりやすいです。
Kubernetes での Endpoints のスタートガイド  |  OpenAPI を使用した Cloud Endpoints  |  Google Cloud

ですが、このチュートリアルではhttpでの通信を行うところまでしかできません。この記事では、マネージド証明書を用いてCloud Endpointsにて作成したAPIhttps通信に対応させる方法を記載します。

手順

GKEクラスタの作成

ここは普通にクラスタを作ります。 kubectl を使えるようにするために認証情報も取得しておきます。

gcloud container clusters create sample-cluster
gcloud container clusters get-credentials sample-cluster

静的IPの取得

Endpointsで使う静的IPアドレスを事前に用意しておきます。2行目のコマンドで作成されたIPアドレスを確認できます。

gcloud compute addresses create smaple-api-ip --global
gcloud compute addresses list

Endpoints DNSでAレコードの作成

Cloud Endpointsにデプロイする openapi.yaml ファイルを編集します。該当する箇所だけ抜粋すると以下のようになります。

swagger: "2.0"
host: "[API_NAME].endpoints.[PROJECT_ID].cloud.goog"
x-google-endpoints:
- name: "[API_NAME].endpoints.[PROJECT_ID].cloud.goog"
   target: "xx.xxx.xx.xx" #ここに先程の静的IPアドレスを記入
schemes:
- "https"

これを gcloud endpoints services deploy openapi.yaml コマンドでデプロイします。このyamlファイルをデプロイすると自動的にDNS Aレコードが作成されます。

ドメインIPアドレスが紐付いているかは dig [API_NAME].endpoints.[PROJECT_ID].cloud.goog のようにして確認することができます。

マネージド証明書の発行

以下のコマンドで証明書を発行します。

gcloud compute ssl-certificates create sample-api-cert \
  --domains [API_NAME].endpoints.[PROJECT_ID].cloud.goog

発行された証明書は gcloud compute ssl-certificates list で確認できます。

GKEのDeploymentの作成

Deploymentもチュートリアル通りに作ります。

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: sample-api
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: sample-api
    spec:
      containers:
      - name: sample-api
        image: gcr.io/[YOUR_PROJECT]/[YOUR_APP]:[TAG] 
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
      - name: esp
        image: gcr.io/endpoints-release/endpoints-runtime:1
        imagePullPolicy: IfNotPresent
        args: [
          "--http_port=8081",
          "--backend=127.0.0.1:8080",
          "--service=[API_NAME].endpoints.[PROJECT_ID].cloud.goog",
          "--rollout_strategy=managed",
          "-z", "healthz"
        ]
        ports:
        - containerPort: 8081
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8081

1点注意しなくてはいけないことがあります。後にIngressを作成するのですが、GCEのHTTP(S) Load Balancingのヘルスチェックを受ける対象が esp コンテナになっており、チュートリアルの実装のままだとヘルスチェックに引っかかってエラーになります。これを避けるために readinessProbeesp コンテナの部分に追記します。

GKEのServiceの作成

Serviceもほぼチュートリアル通りですが、1点変更点があります。 type: LoadBalancertype: NodePort に変えておいてください。インターネットへの公開はIngressを用います。

apiVersion: v1
kind: Service
metadata:
  name: sample-api
spec:
  ports:
  - port: 80
    targetPort: 8081
    protocol: TCP
    name: http
  selector:
    app: sample-api
  type: NodePort

GKEのIngressの作成

ServiceではなくIngressロードバランサーを作成します。 annotaions で先程作成した静的IPアドレス名、証明書名を記述します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-api-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: smaple-api-ip
    ingress.gcp.kubernetes.io/pre-shared-cert: sample-api-cert
spec:
  rules:
  - host: [API_NAME].endpoints.[PROJECT_ID].cloud.goog
    http:
      paths:
      - path: /*
        backend:
          serviceName: sample-api
          servicePort: 80

Ingressの設定をGKEクラスタに反映させると証明書のステータスがACTIVEになるまで数分かかります。 kubectl apply -fで更新しても反映されないことがあるので、そのときは一旦削除して作り直してください。

問題なく証明書がACTIVEになればHTTPSで通信ができるようになっているはずです。

参考文献