Edited at

Google Cloud Functions(Python)からGoogle Kubernetes Engine(GKE)のジョブを登録する


概要

Google Kubernetes Engine(GKE)でバッチジョブを実行することができるのですが、Cloud Functionsからジョブ実行できたらCloud Storageなどのイベントをトリガーにできて捗るなぁと思いついて実際に可能か試してみました。

GKEのジョブ実行については下記を参照ください。

GKEを使ったバッチジョブ実行

http://otiai10.hatenablog.com/entry/2017/12/19/162430


前提

下記記事の環境を流用しています。

実際に環境構築する際は、合わせてご参考ください。

Google Kubernetes EngineでUnity ML-Agentsを動かしてみる(V0.5.0対応)

https://qiita.com/kai_kou/items/3a4d860f8353ff1b3110


  • ローカルにDockerがインストール済み

  • ローカルにgcloudkubectl がインストール済み

  • GKEでクラスタ作成済み

  • ジョブ実行するDockerイメージがGoogle Container RegistryにPUSH済み


Cloud Functions関数の実装

Cloud Functionsにデプロイするファイルを用意します。

kubernetesのジョブ登録をPythonから行うのに、公式のClient Libraryを利用しました。

kubernetes-client/python

https://github.com/kubernetes-client/python

kubernetesのClient Libraryが利用できるようにします。


requirements.txt

kubernetes


GKEへジョブ登録するのに必要な情報をYamlファイルとして用意します。

内容は先の記事のものを流用しています。


job.yaml

apiVersion: batch/v1

kind: Job
metadata:
name: GKEクラスタのpod名(任意)
spec:
template:
spec:
containers:
- name: unity-ml-agents-on-gke
image: gcr.io/[GCPのプロジェクトID]/unity_ml_agents_on_gke:latest
command: ["mlagents-learn", "trainer_config.yaml", "--env", "3DBall", "--train"]
restartPolicy: OnFailure

GKEのクラスタへアクセスできるようにconfigファイルを用意します。

> gcloud container clusters get-credentials [GKEのクラスタ名]

上記コマンドで、クラスタへの接続情報が~/.kube/config ファイルに保存されます。

このファイルをCloud Functionsにデプロイする際に含めるようにします。

ローカル環境でジョブ登録などのコマンドを実行していると、ファイルにaccess-tokenexpiry が含まれている可能性があります。

Cloud Functionsで実行する場合、GKEへアクセスするのに必要なaccess-token はCloud Functionsのデフォルトのサービス アカウントを参照してくれるので、自前でサービスアカウントを作成する必要はありませんでした。

configファイルにもaccess-tokenexpiry は不要となるので、行ごと削除して問題ありません。

サーバー間での本番環境アプリケーションの認証の設定

https://cloud.google.com/docs/authentication/production#auth-cloud-implicit-python

configファイルにはクラスタのIPアドレスなどが含まれるため、実運用の際にはCloud KMSなどを利用してファイルを暗号化しておきましょう。

https://cloud.google.com/kms/

> cp ~/.kube/config .

Cloud Functionsで実行するソースコードです。


main.py

import os

from kubernetes import client, config
import subprocess
import yaml

def create_gke_job(request):

subprocess.check_output(['cp', './config', '/tmp/config'])
config.load_kube_config('/tmp/config')

with open(os.path.join(os.path.dirname(__file__), "./job.yaml")) as f:
dep = yaml.load(f)

k8s = client.BatchV1Api()
resp = k8s.create_namespaced_job(body=dep, namespace="default")
print("Deployment created. status='%s'" % str(resp.status))


ポイントとしては、kubernetesのconfigファイルをload_kube_config メソッドで呼び出すと、ファイルの読み込みだけでなくaccess-token などの追記がされるので、/tmp ファルダにコピーして書き込み可能にする必要がありました。

job.yamlに定義している、metadata.name がpodの名称となり一意である必要があるため、今回の実装だと、関数を複数回実行すると、pod名の重複エラーとなるため、yaml.load 後に、書き換えが必要となります。

kubernetesのClient Libraryについては、APIが多くて、どのAPIを利用すればよいのか(非常に)わかりにくいですが、ドキュメントがしっかり用意されているので、探せば大抵のことはわかるっぽいです(未確認)

python/kubernetes/README.md

https://github.com/kubernetes-client/python/blob/master/kubernetes/README.md

あとはCloud Functionsにデプロイして良しなに。

今回は関数が実行できたら良いだけので、トリガを--trigger-http にしています。

> gcloud functions deploy create_gke_job --trigger-http --runtime=python37

※いつのまにかgcloud functions コマンドで、--runtime=python37 の指定ができるようになっていました。(Google Cloud SDK 216.0.0)


参考

GKEを使ったバッチジョブ実行

http://otiai10.hatenablog.com/entry/2017/12/19/162430

Google Kubernetes EngineでUnity ML-Agentsを動かしてみる(V0.5.0対応)

https://qiita.com/kai_kou/items/3a4d860f8353ff1b3110

kubernetes-client/python

https://github.com/kubernetes-client/python

python/kubernetes/README.md

https://github.com/kubernetes-client/python/blob/master/kubernetes/README.md

サーバー間での本番環境アプリケーションの認証の設定

https://cloud.google.com/docs/authentication/production#auth-cloud-implicit-python

Cloud FunctionsでPython利用記事まとめ

https://qiita.com/kai_kou/items/2f65db5305ba280ad81e