投稿者:國藤 篤規(エヌアイシーソフト)

こんにちは。
今回は GCP の Managed Kubernetes サービスである、Google Kubernetes Engine でアプリを動かしてみます。デプロイするアプリは引き続き、こちらの Kotlin アプリです。画像に変化がなくすみません・・・

今回はいくつかのコンポーネントが登場するので、概要図を作成しました。図と対応させながら読んでいただくとわかりやすいと思います。

概要図

Dockerイメージの作成


Kubernetes は Dockerイメージを動かす環境なので、まずは Dockerfileを作成します。図はCloud Buildの部分が対応します。
Dockerfile はイチから書いてもいいのですが、gcloud コマンドで Dockerfile を生成することもできます。 アプリケーションのjarファイルを置いたディレクトリで以下を実行します。

gcloud beta app gen-config --custom

以下の Dockerfile が生成されました。

Dockerfile

FROM gcr.io/google_appengine/openjdk
ADD KotlinGAE-1.0-SNAPSHOT-all.jar /app/
CMD ["java", "-jar", "/app/KotlinGAE-1.0-SNAPSHOT-all.jar"]

GCP Console のプロジェクト->APIとサービスから、Cloud Build API を有効にしておきます。 以下のコマンドで、コンテナイメージを作成します。

gcloud builds submit --tag gcr.io/gke-kotlin/kotlin-app .

Kubernetes へのデプロイ

GCP Console のプロジェクト->APIとサービスから、Kubernetes Engine API を有効にしておきます。 まず、クラスタを作成します。

gcloud container clusters create kotlin-cluster

アプリケーションの外部からのアクセスポイントである、Service を作成します。

kotlin-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: kotlin-service
spec:
  type: LoadBalancer
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    run: kotlin-app

type を LoadBalancer とすると、外部IPが割り当てられます。また、selector はのちに出てくる pod の label と対応します。 cloud shell から以下を実行して反映します。

gcloud container clusters get-credentials kotlin-cluster
kubectl create -f kotlin-service.yaml

次に DB(Firestore) への接続です。Kubernetes では、外部のリソースへの接続情報を管理するために、Secret という仕組みを用意していますので、これを使います。

Firestore のインスタンスのあるプロジェクトを GCP Console で開き、IAMと管理->サービスアカウントを選択します。サービスアカウントの作成をクリックし、アカウント名を入力します。STEP.2 で、Firestore へのアクセスに必要な権限を付与します。STEP.3 でキーの作成をすると、以下のようなキーファイルがダウンロードされます。

サービスアカウントの作成

{
  "type": "service_account",
  "project_id": "alert-tiger-999999",
  "private_key_id": "????????????",
  "private_key": "-----BEGIN PRIVATE KEY-----\n????????=\n-----END PRIVATE KEY-----\n",
  "client_email": "firestore@alert-tiger-999999.iam.gserviceaccount.com",
  "client_id": "999999999",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firestore%40alert-tiger-999999.iam.gserviceaccount.com"
}

firestore へアクセスするための秘密鍵が含まれています。このファイル全体を base64 コマンドなどでbase64して、Secret の定義に埋め込みます。

kotlin-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: kotlin-secret
type: Opaque
data:
  sa_json: |
    ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYWxlcnQtdGln
    ... 中略 ...
    MGFsZXJ0LXRpZ2VyLTIyNDUwOS5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIKfQo=
kubectl create -f kotlin-secret.yaml

最後に、Pod の定義と、Secret の組み込みを行います。

kotlin-app.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: kotlin-app
spec:
  replicas: 2
  template:
    metadata:
      labels:
        run: kotlin-app
    spec:
      containers:
      - name: kotlin-app
        image: gcr.io/gke-kotlin/kotlin-app
        ports:
        - containerPort: 8080
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /etc/gcp/service_account.json
        volumeMounts:
        - mountPath: /etc/gcp
          readOnly: true
          name: kotlin-secret-volume
      volumes:
      - name: kotlin-secret-volume
        secret:
          secretName: kotlin-secret
          items:
          - key: sa_json
            path: service_account.json

いくつかポイントがあります。

まず replicas で 2を指定することで、LoadBalancer の後ろに 2つのインスタンスを持つ構成にすることができます。LoadBalancer との紐付けのために、labels は service の selector と一致させておきます。
image で、Cloud Build で作成したイメージのID を指定します。

それ以降は、サービスアカウントのための設定です。volumes で、Secret を指定します。volumeMounts で、定義したvolumeを mountPath にアタッチします。ここまでの時点で、コンテナの内部からは、/etc/gcp/service_account.json にサービスアカウントファイルが存在しているように見えます。

env で定義した環境変数を使って、アプリケーションへファイルパスを渡します。

FirestoreOptions.getDefaultInstance().service

アプリケーションからの接続方法に変更はありません。クライアントライブラリが GOOGLE_APPLICATION_CREDENTIALS をチェックし、サービスアカウントのキーファイルに従って firestore へ接続してくれます。

最後に、作成したYAMLを反映します。

kubectl create -f kotlin-app.yaml

これで無事、動作させることが出来ました。

まとめ


GAE と比べると、手順、作成するYAMLファイルも多くなってしまいますが、高いカスタマイズ性が手に入ります。また、従来はコマンドなどで設定を行っていた部分がYAMLファイルになる(Infrastructure As Code)点もメリットといえます。