Google Kubernetes Engine で Kotlin アプリを動かす
投稿者:國藤 篤規

こんにちは。
今回は 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)点もメリットといえます。