原文はこちら
このブログポストではKubernetes CronJobでOracle Cloud InfrastructureのCLIコマンドをスケジュールで定期的に自動的に実行する方法についてご説明します。
例として使うソリューションでは、Oracle Serverless Functionの呼び出しをスケジュール化します。
Kubernetes CronJobsとは
バックグラウンドで様々なタスクをスケジュール実行するのは、開発者、また、運用オペレーターにとってよくあるニーズです。典型的には、"CronJobs"というスケジュール実行方法が知られています。
KubernetesはCronJobsをサポートしており、これはKubernetesがタスクをコンテナ化された環境でスケジュール実行するように設定するというものです。この自動化されたジョブは、UNIXやLinuxシステム上でのCronタスクのように実行されます。
Cronジョブは、たとえばバックアップを取ったりメールを送るなどの周期、定期実行されるタスクを作成するのに便利です。Cronジョブはまた、たまにしか行わないようなアクションを指定した時間に一度だけ実行する、というようなことにも使えます。
OCI CLIとは
Oracle Cloud Infrastructure CLIは多機能で簡単に使えるツールで、Oracle Cloud Infrastructureのコンソールと同様の機能を提供している他、コンソールではできない機能もいくつかコマンドとして提供されています。このCLIは開発者にとって、また、GUIよりもコマンドラインインターフェースを好むひとにとって、便利です。
このCLIは多くのOCIサービスの構成やオーケストレーションをサポートしており、コアサービス(ネットワーク、コンピュート、ブロックボリューム)やデータベース、ロードバランシング、サーバレスファンクションなどなどに対応しています。全サポート状況はこちらのリストをご覧ください。
Oracle Functionsとは
Oracle Functionsはフルマネージドで高いスケーラビリティを備えた、オンデマンドのFunction as a Service(FaaS)プラットフォームです。オープンソースのエンジンであるFnプロジェクトをベースとしてエンタープライズグレードのOracle Cloud Infrastructure上に構築されています。
Oracle Functionsを使って、あなたのコードをデプロイし、それを直接呼び出したりなにかのイベントをトリガーとして起動したりできます。そして費用がかかるのは実行されている時間についてだけです。
Oracle Functionsはコンテナネイティブです。これはすなわち、各ファンクションは完全に自己充足したOCIR Dockerレジストリ上のDockerイメージであり、ファンクションを呼び出したときにプルされ、デプロイされて実行されるということです。
チュートリアルの概要
まず、OCI CLIを含んだコンテナイメージを構築します。その後CLIの設定パラメータと認証情報を格納するKubernetes Secretを構成します。
そしてそのコンテナイメージをOCI Registryにプッシュします。その後、Kubernetes CronJobsでコンテナ化されたOCI CLIコマンドでServerless Functionを呼び出すようにスケジュールを定義します。
事前準備
まず、OCI CLIコマンドをOracle Container Engine for Kubernetes(OKE)上のスケジュール化されたCronJobとして実行するために必要となるコンポーネントの実装と設定を行っていきます。
必要となるのは:
- Oracle Container Engine for Kubernetesクラスターが起動されていること
- Oracle Cloud FunctionがOCIテナンシー内でプロビジョニングされていること
- Oracle Cloud Infrastructure CLIとkubectlコマンドラインがあなたの開発端末にインストールされ、構成されていること
デプロイ手順
1. Kubernetes Secretの設定
この事前準備の前提として、あなたの開発端末にOCI CLIがインストールされ構成されていることが必要です。このプロセスではそのCLI設定ファイルとOCI API秘密鍵の構成が必要になります。
そしてこれらのアーティファクトをKuberenetes Secretの中にコピーしていきます。これはスケジュールされたタスクが実行されるたびに、CLIがあなたのOCIテナンシーにアクセスするのに使われます。
あなたの開発端末から、以下のコマンドを実行しましょう:
1 | kubectl create secret generic oci-cli-config --from-file=<oci-config-file> --from-file=<rsa-private-key> |
<oci-config-file>の値と<rsa-private-key>の値はあなたの開発端末の適切なパスに置き換えてくださいね。例えば以下のようになります:
1 | kubectl create secret generic oci-cli-config --from-file=./.oci/config --from-file=./.oci/ssh/id_rsa_pri.pem |
OCI CLI設定ファイルとRSA秘密鍵が、コンテナの実行環境ファイルシステム内でパス/root/.ociへ自動的にマウントされます。
これはOCI CLI設定ファイルのデフォルトのファイルシステム格納位置なので、特に設定をしなくてもCLIはスケジュールタスクが起動されるたびにこれらのファイルを使ってあなたのOCIテナンシーに認証をしにいきます。
2. CLIコンテナイメージのビルド
あなたの開発端末でoci-fn-cronというディレクトリを作成し、そこにDockerfileという名前のファイルを以下の内容で作成してください:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | FROM oraclelinux:7-slim ENV OCI_CLI_SUPPRESS_FILE_PERMISSIONS_WARNING=True ENV PATH= "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/rh/rh-python36/root/usr/bin:${PATH}" ENV LC_ALL=en_US.utf8 ENV LANG=en_US.utf8 ARG CLI_VERSION=2.6.14 RUN mkdir /oci-cli WORKDIR /oci-cli RUN yum -y install oracle-release-el7 && \ yum -y install oracle-softwarecollection-release-el7 && \ yum-config-manager --enable software_collections && \ yum-config-manager --enable ol7_latest ol7_optional_latest ol7_addons && \ yum-config-manager --disable ol7_ociyum_config && \ yum -y install scl-utils && \ yum -y install rh-python36 && \ yum -y install gcc && \ yum -y install wget && \ yum -y install unzip && \ rm -rf / var /cache/yum RUN wget -qO- -O oci-cli.zip "https://github.com/oracle/oci-cli/releases/download/v${CLI_VERSION}/oci-cli-${CLI_VERSION}.zip" && \ unzip -q oci-cli.zip -d .. && \ rm oci-cli.zip && \ pip3 install oci_cli-*-py2.py3-none-any.whl && \ yes | oci setup autocomplete ENTRYPOINT [ "/opt/rh/rh-python36/root/usr/bin/oci" ] |
oci-fn-cronディレクトリに移動し、以下のコマンドを実行してCLIコンテナイメージをビルドしましょう。
1 | docker build -t oci-fn-cron . |
3. コンテナイメージをOCIレジストリにプッシュ
次のステップでは、ビルドしたコンテナイメージをクラウドにプッシュします。OCIレジストリサービスの使い方の一連のガイドについては、こちらの記事をチェックしてくださいね。
Oracle Cloud Infrastructureのコンソールにログインしていただく必要があります。また、その際のユーザーは、テナンシーの管理者グループに所属しているか、REPOSITORY_CREATEの権限が付与されたグループに所属している必要があります。
適切な権限があることを確認いただき、ユーザーの認証トークンを生成してください。あとで使うので、このトークンはどこかにコピーしておいてください。
OCIコンソールで、Developer Servies -> Registry(OCIR)タブへと移動し、イメージをプッシュしたいOCIリージョンを選択してください。このリージョンはあなたのOKEクラスターがプロビジョニングされているリージョンと同一のものを選びます。
OCIレジストリへのログイン
あなたの開発端末からdocker loginコマンドでOCIレジストリにログインします。
1 | docker login <region-key>.ocir.io |
<region-key>はお使いのOCIリージョンごとのコードを表しています。使用可能なリージョンと対応するコードはこちらをご覧ください。
プロンプトが出るので、<テナンシー名>/<ユーザー名>のフォーマットでユーザー名を入力します。パスワードのプロンプトが出たら、先程コピーしておいた認証トークンを入力してください。
コンテナイメージのタグ付け
OCIレジストリにプッシュするOCI CLIイメージにタグを付けます。
1 | docker tag oci-fn-cron:latest <region-code>.ocir.io/<tenancy-name>/oci-cron/oci-fn-cron:latest |
OCIレジストリへのイメージのプッシュ
docker pushコマンドを使ってコンテナイメージをOCIレジストリにプッシュします。
1 | docker push <region-code>.ocir.io/<tenancy-name>/oci-cron/oci-fn-cron:latest |
OCIコンソールから、新たに作成されたリポジトリとイメージが見えるようになっているはずです。
4. Kubernetes CronJobのスケジュール
あなたの開発端末でoci-fn-cron.yamlというの名前のファイルを以下の内容で作成してください:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | kind: CronJob apiVersion: batch/v1beta1 metadata: name: oci-functions-cron spec: schedule: "*/5 * * * *" jobTemplate: spec: template: spec: containers: - name: oci-functions-cron image: <region-code>.ocir.io/<tenancy-name>/oci-cron/oci-fn-cron:latest command: [ "/opt/rh/rh-python36/root/usr/bin/oci" ] args: [ "--debug" , "fn" , "function" , "invoke" , "--function-id" , "<function-ocid>" , "--file" , "-" , "--body" , "-" ] imagePullPolicy: Always volumeMounts: - name: oci-cli-config mountPath: "/root/.oci" readOnly: true ports: - containerPort: 9081 restartPolicy: Never volumes: - name: oci-cli-config secret: secretName: oci-cli-config items: - key: config path: config - key: id_rsa_pri.pem path: ssh/id_rsa_pri.pem |
以下の置き換えが必要です:
- 13行目ではあなたのOCIリージョンコードとテナンシー名
- 15行目では起動したいあなたのOracle FunctionのOCID
ファイルを保存して、以下のコマンドでこのCronJobを送信しましょう:
1 | kubectl apply -f oci-fn-cron.yaml |
CronJobオペレーションの確認
以下の手順でCronJobが正しく機能していることを確認できます:
1. ジョブ実行履歴を以下のコマンドで確認:
1 | kubectl get jobs --watch |
以下のような出力になります:
1 2 3 4 | NAME COMPLETIONS DURATION AGE oci-functions-cron-1575886560 1/1 43s 4m45s oci-functions-cron-1575886680 1/1 34s 2m44s oci-functions-cron-1575886800 1/1 35s 44s |
2. 以下のコマンドでスケジュールジョブに関連したPod名称を取得します。<job-name>は前述のコマンドの出力から持ってきましょう:
1 | kubectl get pods --selector=job-name=<job-name> --output=jsonpath={.items[*].metadata.name} |
3. 以下のコマンドで実行されたCLIコマンドのログを取得できます。<pod-name>は前述のコマンドの出力から持ってきましょう:
1 | kubectl logs <pod-name> |
あなたのファンクションが正しく実行されていれば、以下のような出力になります。これはKuberenetes CronJobとして定義したfn function invokeコマンドをCLIが実行した結果生成されたデータです:
1 2 3 4 5 6 7 8 9 10 11 12 13 | INFO:oci.base_client.140263433586560: 2019-12-09 21:54:04.502876: Request: GET https: //functions.us-ashburn-1.oci.oraclecloud.com/20181201/functions/ocid1.fnfunc.oc1.iad.aaaaaaaaadfmkqscppi63jistu4t7au2veexg5in6lykzovzmvaja6vqmwsa DEBUG:oci.base_client.140263433586560: 2019-12-09 21:54:04.601030: time elapsed for request 4AFF967835C440009D15F3CFAAC404D2: 0.0978535171598196 DEBUG:oci.base_client.140263433586560: 2019-12-09 21:54:04.601216: time elapsed in response: 0:00:00.092832 DEBUG:oci.base_client.140263433586560: 2019-12-09 21:54:04.601319: Response status: 200 DEBUG:oci.base_client.140263433586560: 2019-12-09 21:54:04.603549: python SDK time elapsed for deserializing: 0.0020453811157494783 DEBUG:oci.base_client.140263433586560: 2019-12-09 21:54:04.603681: Response returned DEBUG:oci.base_client.140263433586560:time elapsed for request: 0.1009602730628103 INFO:oci.base_client.140263433271056: 2019-12-09 21:54:04.608421: Request: POST https: //newg3h4jqoq.usashburn1.functions.oci.oraclecloud.com/20181201/functions/ocid1.fnfunc.oc1.iad.aaaaaaaaadfmkqscppi63jistu4t7au2veexg5in6lykzovzmvaja6vqmwsa/actions/invoke DEBUG:oci.base_client.140263433271056: 2019-12-09 21:54:37.288483: time elapsed for request 7C625DE5724D4C3B8E26A771D3F7F87B: 32.679952513892204 DEBUG:oci.base_client.140263433271056: 2019-12-09 21:54:37.288662: time elapsed in response: 0:00:32.676453 DEBUG:oci.base_client.140263433271056: 2019-12-09 21:54:37.288778: Response status: 200 DEBUG:oci.base_client.140263433271056: 2019-12-09 21:54:37.288893: Response returned DEBUG:oci.base_client.140263433271056:time elapsed for request: 32.68057371187024 |
CronJobスケジュールの変更
Kuberenetesでは、ひとつのCronJobオブジェクトはctontabにおける一行のようなものです。CronJobはCronのフォーマットで指定されたスケジュールでジョブを実行します。例として、上の例のCronオブジェクトはOracle Functionを5分ごとに実行します。
違うスケジュールであなたのファンクションを実行するには、単純にあなたのoci-fn-cron.yamlファイルのscheduleの部分を修正し、そのCronJobを再送信すればOKです。
別のCLIオペレーションのスケジュール化
ここでの例では、OCI CLIにOracle Serverless Functionを周期的に実行させました。
ここまでで使い方はわかったと思うので、別のCLIコマンドをKubernetes CronJobsにスケジュール実行させるのはとても簡単でしょう。
別のCronJob定義yamlファイルを作成し、ジョブname(前述のoci-fn-cron.yamlでは4行目)とargs(15行目)のOCI CLIコマンドを要件に応じて修正するだけでOKです。
OCI CLIがサポートしているすべてのサービスのリストはこちらで確認できます。ユースケースはほとんど無限大です!