--- title: Tanzu Application PlatformでCronJobのWorkloadを作成する tags: ["Kubernetes", "Cartographer", "kind", "Tanzu", "TAP"] categories: ["Dev", "CaaS", "Kubernetes", "TAP"] date: 2023-04-10T20:01:15Z updated: 2023-04-11T01:16:49Z --- Tanzu Application Platform (1.4時点)では、[こちらのドキュメント](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.4/tap/workloads-workload-types.html)に記載されているように、Out of the Box (OOTB) Supply Chainsにて以下のWorkload Typeがサポートサポートされています。 * `type=web` ... スケーラブルなWebアプリケーションを想定したもの。KnativeのServiceリソースをが作成される。Scale to Zero、Zero to Nがサポートされる。 * `type=server` ... トラディショナルなWebアプリケーションを想定したもの。K8s標準のDeployment、Serviceリソースが作成される。 * `type=worker` ... キューを処理するバックグラウンドアプリケーションを想定したもの。K8s標準のDeploymentが作成される。 今回はここに`type=cronjob`を追加して、K8s標準のCronJobリソースを作成できるようにします。 TAPのWorkloadは[Cartographer](https://cartographer.sh/)によって管理されています。 Workloadによって作成されるリソースをカスタマイズは、通常はClusterSupplyChainリソースを追加することで行えます。 ただし、1からSupply Chainを作る場合は、 * ソースコードの取得 * ソースコードの脆弱性スキャン * ソースコードのテスト * コンテナイメージの取得 * コンテナイメージの脆弱性スキャン * マニフェストの作成 * マニフェストのパッケージング などなど、Supply Chainを構成するコンポーネントを定義していく必要があります。(チュートリアルは[こちら](https://cartographer.sh/docs/v0.7.0/tutorials/first-supply-chain/)) TAPのOOTB Supply Chainで定義されているものを再度定義するのは面倒くさいですね。 TAPではOOTB Supply Chainのうち、"マニフェストの作成"の部分だけをカスタマイズできるようになっています。 ドキュメントは[こちら](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.4/tap/workloads-server.html#define-a-workload-type-that-exposes-server-workloads-outside-the-cluster-5)です。 ドキュメントでは`type=server`のリソースに加えてIngressリソースを作る例を説明しています。 Supply Chainによって生成させたいマニフェストのテンプレートをCartographerのClusterConfigTemplateで定義すれば良いです。 [こちらの記事](https://ik.am/entries/733)で作成した環境で試します。 **目次** ### ClusterConfigTemplateの定義 CronJobのテンプレートを次のようにClusterConfigTemplateに定義します。 ```yaml cat < cronjob-template.yaml apiVersion: carto.run/v1alpha1 kind: ClusterConfigTemplate metadata: name: cronjob-template spec: configPath: .data lifecycle: mutable ytt: | #@ load("@ytt:data", "data") #@ load("@ytt:yaml", "yaml") #@ def merge_labels(fixed_values): #@ labels = {} #@ if hasattr(data.values.workload.metadata, "labels"): #@ labels.update(data.values.workload.metadata.labels) #@ end #@ labels.update(fixed_values) #@ return labels #@ end #@ def update_config(config): #@ values = {} #@ values.update(config) #@ spec = dict(values["spec"]) #@ spec.update({"restartPolicy": data.values.params.restartPolicy if hasattr(data.values.params, "restartPolicy") else "Never"}) #@ workload = dict(spec["containers"][0]) #@ if hasattr(data.values.params, "command"): #@ workload.update({"command": data.values.params.command}) #@ end #@ if hasattr(data.values.params, "args"): #@ workload.update({"args": data.values.params.args}) #@ end #@ spec["containers"][0] = workload #@ values["spec"] = spec #@ return values #@ end #@ def delivery(): apiVersion: batch/v1 kind: CronJob metadata: name: #@ data.values.workload.metadata.name annotations: kapp.k14s.io/update-strategy: "fallback-on-replace" ootb.apps.tanzu.vmware.com/servicebinding-workload: "true" kapp.k14s.io/change-rule: "upsert after upserting servicebinding.io/ServiceBindings" labels: #@ merge_labels({ "app.kubernetes.io/component": "run", "carto.run/workload-name": data.values.workload.metadata.name }) spec: schedule: #@ data.values.params.schedule if hasattr(data.values.params, "schedule") else "0 15 * * *" successfulJobsHistoryLimit: 1 failedJobsHistoryLimit: 3 concurrencyPolicy: Forbid jobTemplate: metadata: labels: #@ data.values.config.metadata.labels spec: backoffLimit: 0 template: #@ update_config(data.values.config) #@ end --- apiVersion: v1 kind: ConfigMap metadata: name: #@ data.values.workload.metadata.name + "-cronjob" labels: #@ merge_labels({ "app.kubernetes.io/component": "config" }) data: delivery.yml: #@ yaml.encode(delivery()) EOF ``` > K8s標準のCronJobではなく、[Argo Workflows](https://argoproj.github.io/argo-workflows/cron-workflows/)や[Furiko](https://furiko.io/docs/execution/jobconfig/sample-configuration)のような拡張スケジューラを使いたい場合もこのClusterConfigTemplateを変更すれば良いです。 このCronJobのmanifestは最終的にDeliverableによってデプロイされるので、Deliverableを管理するService AccountがCronJobを作成する権限を持つ必要があります。 `apps.tanzu.vmware.com/aggregate-to-deliverable: "true"`というラベルをClusterRoleにつければ、Deliverableを管理するService Accountにバインドされます。 ```yaml cat < deliverable-with-cronjob.yml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: deliverable-with-cronjob labels: apps.tanzu.vmware.com/aggregate-to-deliverable: "true" rules: - apiGroups: - batch resources: - cronjobs verbs: - get - list - watch - create - patch - update - delete - deletecollection EOF ``` これらをapplyします。 ``` # Muti Cluster構成の場合はBuild Clusterにて kubectl apply -f cronjob-template.yaml ``` ``` # Muti Cluster構成の場合はRun Clusterにて kubectl apply -f deliverable-with-cronjob.yml ``` 最後にWorkload Typeを追加するための設定を`tap-values.yaml`に追加します。 ```yaml ootb_supply_chain_basic: # supply_chainの値がbasicの場合 # or ootb_supply_chain_testing: supply_chainの値がtestingの場合 # or ootb_supply_chain_testing_scanning: supply_chainの値がtesting_scanningの場合 supported_workloads: - type: web cluster_config_template_name: config-template - type: server cluster_config_template_name: server-template - type: worker cluster_config_template_name: worker-template - type: cronjob cluster_config_template_name: cronjob-template # <--- ``` `tap-values.yaml`の変更を反映させます。 ``` tanzu package installed update -n tap-install tap --values-file tap-values.yaml ``` 更新が完了すると、source-to-url Supply Chainに`type=cronjob`が追加されていることがわかります。 ``` $ tanzu apps cluster-supply-chain get source-to-url --- # source-to-url: Ready --- Supply Chain Selectors TYPE KEY OPERATOR VALUE expressions apps.tanzu.vmware.com/workload-type In web expressions apps.tanzu.vmware.com/workload-type In server expressions apps.tanzu.vmware.com/workload-type In worker expressions apps.tanzu.vmware.com/workload-type In cronjob ``` 現状はService Bindingの機能が使えません。CronJobへのBindに対応していません。 ### (Optional) Overlaysによる設定変更 TAPをインストールした後に ``` kubectl apply -f cronjob-template.yaml kubectl apply -f deliverable-with-cronjob.yml ``` を実行してTAPをアップデートするという手順が、宣言的でなくて好みでない場合は、overlay fileとしてClusterConfigTemplateとClusterRoleを追加すれば、 `tanzu package install`あるいは`tanzu package installed update`でTAPをインストール/更新する際に同時にClusterConfigTemplateとClusterRoleも作成されます。 この場合は、次のようにoverlayとしてClusterConfigTemplateとClusterRoleを作成します。 ``` # Muti Cluster構成の場合はBuild Clusterにて kubectl -n tap-install create secret generic ootb-templates-cronjob-template \ -o yaml \ --dry-run=client \ --from-file=cronjob-template.yaml \ | kubectl apply -f- ``` ``` # Muti Cluster構成の場合はRun Clusterにて kubectl -n tap-install create secret generic tap-auth-deliverable-with-cronjob \ -o yaml \ --dry-run=client \ --from-file=deliverable-with-cronjob.yml \ | kubectl apply -f- ``` `tap-values.yaml`に以下の設定を追加。 ```yaml package_overlays: - name: ootb-templates secrets: - name: ootb-templates-cronjob-template # Muti Cluster構成の場合はBuild Clusterにて - name: tap-auth secrets: - name: tap-auth-deliverable-with-cronjob # Muti Cluster構成の場合はRun Clusterにて ``` 初回インストールの場合、 ``` tanzu package install tap -p tap.tanzu.vmware.com -v 1.4.2 --values-file tap-values.yaml -n tap-install ``` 更新の場合 ``` tanzu package installed update -n tap-install tap --values-file tap-values.yaml ``` で`type=cronjob`が使えるようになります。 ### CronJob Workloadの作成 いろいろなCronJobを作成してみます。 #### シンプルなCronJob [Kubernetesの公式ドキュメント](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/)に載っているサンプルを作成しいてみます。 次のコマンドでCronJobを作るためのWorkloadを作成します。今回は `--image` でCronJobで実行するコンテナイメージを指定します。 ``` tanzu apps workload apply \ -n demo \ --type cronjob \ --image ghcr.io/making/busybox \ --param-yaml 'command=["/bin/sh", "-c", "date; echo Hello from TAP"]' \ --param schedule="* * * * *" \ --app cronjob-demo \ cronjob-demo ``` > 公式ドキュメントと同じように`--image busybox:1.28`で実行するとImageRepositoryリソースで次のようなエラーが発生しました。 > `unable to pull image "busybox:1.28": Expected an Image but got: application/vnd.docker.distribution.manifest.list.v2+json` > 次のようなRelocationが必要でした。 > ``` > docker pull busybox > docker tag busybox ghcr.io/making/busybox > docker push busybox > ``` しばらくするとCronJobが作成され、さらにJobが実行されます。 ``` $ tanzu apps workload get cronjob-demo --namespace demo 📡 Overview name: cronjob-demo type: cronjob namespace: demo 💾 Source type: image image: ghcr.io/making/busybox 📦 Supply Chain name: basic-image-to-url NAME READY HEALTHY UPDATED RESOURCE image-provider True True 10m imagerepositories.source.apps.tanzu.vmware.com/cronjob-demo config-provider True True 10m podintents.conventions.carto.run/cronjob-demo app-config True True 10m configmaps/cronjob-demo-cronjob service-bindings True True 10m configmaps/cronjob-demo-with-claims api-descriptors True True 10m configmaps/cronjob-demo-with-api-descriptors config-writer True True 10m runnables.carto.run/cronjob-demo-config-writer 🚚 Delivery name: delivery-basic NAME READY HEALTHY UPDATED RESOURCE source-provider True True 9m34s imagerepositories.source.apps.tanzu.vmware.com/cronjob-demo-delivery deployer True True 60s apps.kappctrl.k14s.io/cronjob-demo 💬 Messages No messages found. 🛶 Pods NAME READY STATUS RESTARTS AGE cronjob-demo-28018560-zdp85 0/1 Completed 0 4s cronjob-demo-config-writer-l68rw-pod 0/1 Completed 0 10m To see logs: "tanzu apps workload tail cronjob-demo --namespace demo --timestamp --since 1h" ``` 作成されたCronJobとJobを確認します。 ``` $ kubectl get cronjob,job -n demo NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/cronjob-demo * * * * * False 0 23s 81s NAME COMPLETIONS DURATION AGE job.batch/cronjob-demo-28018560 1/1 7s 23s ``` ログを確認します。時刻が表示されています。 ``` $ kubectl logs -n demo cronjob-demo-28018560-zdp85 Mon Apr 10 08:00:04 UTC 2023 Hello from TAP ``` `schedule`が`* * * * *`なので、このJobは毎分実行されます。 確認できたらworkloadを削除します。 ``` tanzu apps workload delete -n demo cronjob-demo ``` #### curlを実行するだけのCronJob 次のコマンドでCronJobを作るためのWorkloadを作成します。 ``` tanzu apps workload apply \ -n demo \ --type cronjob \ --image ghcr.io/making/curl \ --param-yaml 'command=["curl"]' \ --param-yaml 'args=["-s", "https://httpbin.org/get"]' \ --param schedule="* * * * *" \ --app hello-curl \ hello-curl ``` しばらくするとCronJobが作成され、さらにJobが実行されます。 ``` $ tanzu apps workload get hello-curl --namespace demo 📡 Overview name: hello-curl type: cronjob namespace: demo 💾 Source type: image image: ghcr.io/making/curl 📦 Supply Chain name: basic-image-to-url NAME READY HEALTHY UPDATED RESOURCE image-provider True True 106s imagerepositories.source.apps.tanzu.vmware.com/hello-curl config-provider True True 102s podintents.conventions.carto.run/hello-curl app-config True True 102s configmaps/hello-curl-cronjob service-bindings True True 102s configmaps/hello-curl-with-claims api-descriptors True True 102s configmaps/hello-curl-with-api-descriptors config-writer True True 91s runnables.carto.run/hello-curl-config-writer 🚚 Delivery name: delivery-basic NAME READY HEALTHY UPDATED RESOURCE source-provider True True 44s imagerepositories.source.apps.tanzu.vmware.com/hello-curl-delivery deployer True True 42s apps.kappctrl.k14s.io/hello-curl 💬 Messages No messages found. 🛶 Pods NAME READY STATUS RESTARTS AGE hello-curl-28018564-2rlgc 0/1 Completed 0 11s hello-curl-config-writer-k76bd-pod 0/1 Completed 0 101s To see logs: "tanzu apps workload tail hello-curl --namespace demo --timestamp --since 1h" ``` 作成されたCronJobとJobを確認します。 ``` $ kubectl get cronjob,job -n demo NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/hello-curl * * * * * False 0 42s 76s NAME COMPLETIONS DURATION AGE job.batch/hello-curl-28018564 1/1 8s 42s ``` ログを確認します。curlの実行結果が出力されています。 ``` $ kubectl logs -n demo hello-curl-28018564-2rlgc { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin.org", "User-Agent": "curl/8.0.1-DEV", "X-Amzn-Trace-Id": "Root=1-6433c2f5-5f649b191de9f1ea4e83fb8f" }, "origin": "220.242.176.124", "url": "https://httpbin.org/get" } ``` 確認できたらworkloadを削除します。 ``` tanzu apps workload delete -n demo hello-curl ``` #### PythonのScriptを実行するCronJob 次はCronJobで実行するコンテナイメージをソースコードから作成します。 https://github.com/making/hello-python のPythonコードをCloud Native Buildpacksでコンテナイメージ化してCronJob実行します。 次のコマンドでCronJobを作るためのWorkloadを作成します。今回は`--git-repo`でソースコードのURLを指定します。 ``` tanzu apps workload apply \ -n demo \ --type cronjob \ --git-repo https://github.com/making/hello-python \ --git-branch main \ --param schedule="* * * * *" \ --app hello-python \ --label apps.tanzu.vmware.com/has-tests=true \ hello-python ``` しばらくするとCronJobが作成され、さらにJobが実行されます。 ``` $ tanzu apps workload get hello-python --namespace demo 📡 Overview name: hello-python type: cronjob namespace: demo 💾 Source type: git url: https://github.com/making/hello-python branch: main 📦 Supply Chain name: source-to-url NAME READY HEALTHY UPDATED RESOURCE source-provider True True 4m58s gitrepositories.source.toolkit.fluxcd.io/hello-python image-provider True True 3m58s images.kpack.io/hello-python config-provider True True 3m52s podintents.conventions.carto.run/hello-python app-config True True 3m52s configmaps/hello-python-cronjob service-bindings True True 3m52s configmaps/hello-python-with-claims api-descriptors True True 3m52s configmaps/hello-python-with-api-descriptors config-writer True True 3m38s runnables.carto.run/hello-python-config-writer 🚚 Delivery name: delivery-basic NAME READY HEALTHY UPDATED RESOURCE source-provider True True 2m54s imagerepositories.source.apps.tanzu.vmware.com/hello-python-delivery deployer True True 2m52s apps.kappctrl.k14s.io/hello-python 💬 Messages No messages found. 🛶 Pods NAME READY STATUS RESTARTS AGE hello-python-28018837-25db8 0/1 Completed 0 32s hello-python-build-1-build-pod 0/1 Completed 0 4m57s hello-python-config-writer-ch8z4-pod 0/1 Completed 0 3m50s ``` 作成されたCronJobとJobを確認します。 ``` $ kubectl get cronjob,job -n demo NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/hello-python * * * * * False 0 45s 3m6s NAME COMPLETIONS DURATION AGE job.batch/hello-python-28018837 1/1 5s 45s ``` ログを確認します。 ``` $ kubectl logs -n demo hello-python-28018837-25db8 { "args": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "httpbin.org", "User-Agent": "python-requests/2.28.2", "X-Amzn-Trace-Id": "Root=1-643402ed-0e6ea59220b36d3636bd2a41" }, "origin": "220.242.176.124", "url": "https://httpbin.org/get" } ``` 確認できたらworkloadを削除します。 ``` tanzu apps workload delete -n demo hello-python ``` #### Spring BatchのJobを実行するCronJob 今後はSpring Batchで実装されたバッチ処理のソースコード https://github.com/making/billing-job をCloud Native Buildpacksでコンテナイメージ化してCronJob実行します。 次のコマンドでCronJobを作るためのWorkloadを作成します。 ``` tanzu apps workload apply \ -n demo \ --type cronjob \ --git-repo https://github.com/making/billing-job \ --git-branch master \ --param schedule="0 15 * * *" \ --app billing-job \ --label apps.tanzu.vmware.com/has-tests=true \ --build-env BP_JVM_VERSION=17 \ --env BPL_JVM_THREAD_COUNT=8 \ --env JAVA_TOOL_OPTIONS=-Dmanagement.health.probes.enabled=false \ billing-job ``` > `--env JAVA_TOOL_OPTIONS=-Dmanagement.health.probes.enabled=false` はSpring Boot Actuatorを使った場合に自動で追加されるProbeの設定を向こうにするために追加しています。
> ドキュメントは[こちら](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.4/tap/spring-boot-conventions-reference-CONVENTIONS.html#spring-boot-actuator-probes-convention-5) しばらくするとCronJobが作成されます。00:00 JSTに実行されるようにScheduleしたのでまだJobは作成されません。 ``` $ tanzu apps workload get billing-job --namespace demo 📡 Overview name: billing-job type: cronjob namespace: demo 💾 Source type: git url: https://github.com/making/billing-job branch: master 📦 Supply Chain name: source-to-url NAME READY HEALTHY UPDATED RESOURCE source-provider True True 4m51s gitrepositories.source.toolkit.fluxcd.io/billing-job image-provider True True 3m39s images.kpack.io/billing-job config-provider True True 3m34s podintents.conventions.carto.run/billing-job app-config True True 3m34s configmaps/billing-job-cronjob service-bindings True True 3m33s configmaps/billing-job-with-claims api-descriptors True True 3m33s configmaps/billing-job-with-api-descriptors config-writer True True 3m17s runnables.carto.run/billing-job-config-writer 🚚 Delivery name: delivery-basic NAME READY HEALTHY UPDATED RESOURCE source-provider True True 2m48s imagerepositories.source.apps.tanzu.vmware.com/billing-job-delivery deployer True True 2m46s apps.kappctrl.k14s.io/billing-job 💬 Messages No messages found. 🛶 Pods NAME READY STATUS RESTARTS AGE billing-job-build-1-build-pod 0/1 Completed 0 4m52s billing-job-config-writer-mlhff-pod 0/1 Completed 0 3m33s To see logs: "tanzu apps workload tail billing-job --namespace demo --timestamp --since 1h" ``` 作成されたCronJobを確認します。 ``` $ kubectl get cronjob,job -n demo NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/billing-job 0 15 * * * False 0 3m48s ``` 手動でJobを作成します。 ``` kubectl create job -n demo --from cronjob/billing-job test-run ``` 作成されたCronJobとJobを確認します。 ``` $ kubectl get cronjob,job -n demo NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/billing-job 0 15 * * * False 0 5m12s NAME COMPLETIONS DURATION AGE job.batch/test-run 1/1 13s 26s ``` ログを確認します。 ``` $ kubectl logs -n demo test-run-c9r5d Setting Active Processor Count to 8 Calculating JVM memory based on 4528180K available memory For more information on this calculation, see https://paketo.io/docs/reference/java-reference/#memory-calculator Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx4191438K -XX:MaxMetaspaceSize=72549K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 4528180K, Thread Count: 8, Loaded Class Count: 10395, Headroom: 0%) Enabling Java Native Memory Tracking Adding 124 container CA certificates to JVM truststore Spring Cloud Bindings Enabled Picked up JAVA_TOOL_OPTIONS: -Dmanagement.health.probes.enabled="false" -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=8 -XX:MaxDirectMemorySize=10M -Xmx4191438K -XX:MaxMetaspaceSize=72549K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.0.5) 2023-04-10T16:38:45.371Z INFO 1 --- [ main] lol.maki.billing.BillingJobApplication : Starting BillingJobApplication v0.0.1-SNAPSHOT using Java 17.0.6 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace) 2023-04-10T16:38:45.376Z INFO 1 --- [ main] lol.maki.billing.BillingJobApplication : No active profile set, falling back to 1 default profile: "default" 2023-04-10T16:38:46.207Z INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2023-04-10T16:38:46.436Z INFO 1 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:b918459b-19ff-41d4-8f50-d482bba0dee8 user=SA 2023-04-10T16:38:46.440Z INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2023-04-10T16:38:46.829Z INFO 1 --- [ main] lol.maki.billing.BillingJobApplication : Started BillingJobApplication in 1.968 seconds (process running for 2.419) 2023-04-10T16:38:46.832Z INFO 1 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: [] 2023-04-10T16:38:46.844Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.845Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?] 2023-04-10T16:38:46.860Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.860Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE I1 where I1.JOB_NAME = ? and I1.JOB_INSTANCE_ID in (SELECT max(I2.JOB_INSTANCE_ID) from BATCH_JOB_INSTANCE I2 where I2.JOB_NAME = ?)] 2023-04-10T16:38:46.868Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.869Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?] 2023-04-10T16:38:46.871Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.871Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?] 2023-04-10T16:38:46.872Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.872Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?] 2023-04-10T16:38:46.878Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.879Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT into BATCH_JOB_INSTANCE(JOB_INSTANCE_ID, JOB_NAME, JOB_KEY, VERSION) values (?, ?, ?, ?)] 2023-04-10T16:38:46.889Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.889Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT into BATCH_JOB_EXECUTION(JOB_EXECUTION_ID, JOB_INSTANCE_ID, START_TIME, END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME, LAST_UPDATED) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)] 2023-04-10T16:38:46.892Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing SQL batch update [INSERT into BATCH_JOB_EXECUTION_PARAMS(JOB_EXECUTION_ID, PARAMETER_NAME, PARAMETER_TYPE, PARAMETER_VALUE, IDENTIFYING) values (?, ?, ?, ?, ?)] with a batch size of 100 2023-04-10T16:38:46.893Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT into BATCH_JOB_EXECUTION_PARAMS(JOB_EXECUTION_ID, PARAMETER_NAME, PARAMETER_TYPE, PARAMETER_VALUE, IDENTIFYING) values (?, ?, ?, ?, ?)] 2023-04-10T16:38:46.901Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.902Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT INTO BATCH_JOB_EXECUTION_CONTEXT (SHORT_CONTEXT, SERIALIZED_CONTEXT, JOB_EXECUTION_ID) VALUES(?, ?, ?)] 2023-04-10T16:38:46.904Z INFO 1 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=BillingJob]] launched with the following parameters: [{'run.id':'{value=1, type=class java.lang.Long, identifying=true}'}] 2023-04-10T16:38:46.922Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.923Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?] 2023-04-10T16:38:46.928Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.928Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT COUNT(*) FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?] 2023-04-10T16:38:46.932Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.932Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_JOB_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ?, LAST_UPDATED = ? where JOB_EXECUTION_ID = ? and VERSION = ?] 2023-04-10T16:38:46.936Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.936Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT SE.STEP_EXECUTION_ID, SE.STEP_NAME, SE.START_TIME, SE.END_TIME, SE.STATUS, SE.COMMIT_COUNT, SE.READ_COUNT, SE.FILTER_COUNT, SE.WRITE_COUNT, SE.EXIT_CODE, SE.EXIT_MESSAGE, SE.READ_SKIP_COUNT, SE.WRITE_SKIP_COUNT, SE.PROCESS_SKIP_COUNT, SE.ROLLBACK_COUNT, SE.LAST_UPDATED, SE.VERSION, SE.CREATE_TIME, JE.JOB_EXECUTION_ID, JE.START_TIME, JE.END_TIME, JE.STATUS, JE.EXIT_CODE, JE.EXIT_MESSAGE, JE.CREATE_TIME, JE.LAST_UPDATED, JE.VERSION from BATCH_JOB_EXECUTION JE join BATCH_STEP_EXECUTION SE on SE.JOB_EXECUTION_ID = JE.JOB_EXECUTION_ID where JE.JOB_INSTANCE_ID = ? and SE.STEP_NAME = ? order by SE.CREATE_TIME desc, SE.STEP_EXECUTION_ID desc] 2023-04-10T16:38:46.940Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.940Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT COUNT(*) from BATCH_JOB_EXECUTION JE JOIN BATCH_STEP_EXECUTION SE on SE.JOB_EXECUTION_ID = JE.JOB_EXECUTION_ID where JE.JOB_INSTANCE_ID = ? and SE.STEP_NAME = ?] 2023-04-10T16:38:46.942Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.942Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT into BATCH_STEP_EXECUTION(STEP_EXECUTION_ID, VERSION, STEP_NAME, JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, COMMIT_COUNT, READ_COUNT, FILTER_COUNT, WRITE_COUNT, EXIT_CODE, EXIT_MESSAGE, READ_SKIP_COUNT, WRITE_SKIP_COUNT, PROCESS_SKIP_COUNT, ROLLBACK_COUNT, LAST_UPDATED, CREATE_TIME) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)] 2023-04-10T16:38:46.943Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.943Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT INTO BATCH_STEP_EXECUTION_CONTEXT (SHORT_CONTEXT, SERIALIZED_CONTEXT, STEP_EXECUTION_ID) VALUES(?, ?, ?)] 2023-04-10T16:38:46.945Z INFO 1 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [BilliProcessing] 2023-04-10T16:38:46.946Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.947Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, COMMIT_COUNT = ?, READ_COUNT = ?, FILTER_COUNT = ?, WRITE_COUNT = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, READ_SKIP_COUNT = ?, PROCESS_SKIP_COUNT = ?, WRITE_SKIP_COUNT = ?, ROLLBACK_COUNT = ?, LAST_UPDATED = ? where STEP_EXECUTION_ID = ? and VERSION = ?] 2023-04-10T16:38:46.948Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:46.948Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?] 2023-04-10T16:38:46.955Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:46.955Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ?] 2023-04-10T16:38:47.023Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing SQL batch update [INSERT INTO BILL_STATEMENTS (id, first_name, last_name, minutes, data_usage,bill_amount) VALUES (?, ?, ?, ?, ?, ?)] 2023-04-10T16:38:47.023Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT INTO BILL_STATEMENTS (id, first_name, last_name, minutes, data_usage,bill_amount) VALUES (?, ?, ?, ?, ?, ?)] 2023-04-10T16:38:47.027Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.028Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ?] 2023-04-10T16:38:47.029Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.029Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, COMMIT_COUNT = ?, READ_COUNT = ?, FILTER_COUNT = ?, WRITE_COUNT = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, READ_SKIP_COUNT = ?, PROCESS_SKIP_COUNT = ?, WRITE_SKIP_COUNT = ?, ROLLBACK_COUNT = ?, LAST_UPDATED = ? where STEP_EXECUTION_ID = ? and VERSION = ?] 2023-04-10T16:38:47.030Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:47.030Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?] 2023-04-10T16:38:47.034Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing SQL batch update [INSERT INTO BILL_STATEMENTS (id, first_name, last_name, minutes, data_usage,bill_amount) VALUES (?, ?, ?, ?, ?, ?)] 2023-04-10T16:38:47.035Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT INTO BILL_STATEMENTS (id, first_name, last_name, minutes, data_usage,bill_amount) VALUES (?, ?, ?, ?, ?, ?)] 2023-04-10T16:38:47.037Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.038Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ?] 2023-04-10T16:38:47.039Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.039Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, COMMIT_COUNT = ?, READ_COUNT = ?, FILTER_COUNT = ?, WRITE_COUNT = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, READ_SKIP_COUNT = ?, PROCESS_SKIP_COUNT = ?, WRITE_SKIP_COUNT = ?, ROLLBACK_COUNT = ?, LAST_UPDATED = ? where STEP_EXECUTION_ID = ? and VERSION = ?] 2023-04-10T16:38:47.040Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:47.040Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?] 2023-04-10T16:38:47.042Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.042Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE STEP_EXECUTION_ID = ?] 2023-04-10T16:38:47.045Z INFO 1 --- [ main] o.s.batch.core.step.AbstractStep : Step: [BilliProcessing] executed in 99ms 2023-04-10T16:38:47.045Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.045Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_STEP_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, COMMIT_COUNT = ?, READ_COUNT = ?, FILTER_COUNT = ?, WRITE_COUNT = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, READ_SKIP_COUNT = ?, PROCESS_SKIP_COUNT = ?, WRITE_SKIP_COUNT = ?, ROLLBACK_COUNT = ?, LAST_UPDATED = ? where STEP_EXECUTION_ID = ? and VERSION = ?] 2023-04-10T16:38:47.046Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:47.046Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?] 2023-04-10T16:38:47.048Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.048Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_JOB_EXECUTION_CONTEXT SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? WHERE JOB_EXECUTION_ID = ?] 2023-04-10T16:38:47.051Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:47.052Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?] 2023-04-10T16:38:47.055Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query 2023-04-10T16:38:47.056Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT COUNT(*) FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?] 2023-04-10T16:38:47.057Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update 2023-04-10T16:38:47.057Z DEBUG 1 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [UPDATE BATCH_JOB_EXECUTION set START_TIME = ?, END_TIME = ?, STATUS = ?, EXIT_CODE = ?, EXIT_MESSAGE = ?, VERSION = ?, CREATE_TIME = ?, LAST_UPDATED = ? where JOB_EXECUTION_ID = ? and VERSION = ?] 2023-04-10T16:38:47.069Z INFO 1 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=BillingJob]] completed with the following parameters: [{'run.id':'{value=1, type=class java.lang.Long, identifying=true}'}] and the following status: [COMPLETED] in 129ms 2023-04-10T16:38:47.082Z INFO 1 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2023-04-10T16:38:47.088Z INFO 1 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. Native Memory Tracking: ... ``` 確認できたらworkloadを削除します。 ``` tanzu apps workload delete -n demo billing-job ``` --- TAPからCronJobを作成されるようになりました。TAPをカスタマイズすることで可能性が広がりますね。 ちなみに、このブログをbackupしてS3に保存するためのWorkloadは[こちら](https://github.com/categolj/k8s-manifests/blob/main/lime-build/config/app/blog-api/backup-db.yaml)です。