当我手动触发它时,如何防止 Kubernetes cronjob 运行 同时发生?

How to prevent Kubernetes cronjob running concurrently when I trigger it manually?

我已设置 Kubernetes cronJob 以防止并发运行 like here 使用 parallelism: 1concurrencyPolicy: Forbidparallelism: 1。但是,当我尝试手动创建 cronJob 时,我可以这样做。

$ kubectl get cronjobs
...
$ kubectl create job new-cronjob-1642417446000 --from=cronjob/original-cronjob-name
job.batch/new-cronjob-1642417446000 created
$ kubectl create job new-cronjob-1642417446001 --from=cronjob/original-cronjob-name
job.batch/new-cronjob-1642417446001 created

我原以为不会创建新的 cronjob。或者它可以创建并失败,并显示引用 concurrencyPolicy 的状态。如果 属性 concurrencyPolicy 是 CronJob 规范的一部分,而不是 PodSpec,它应该会阻止创建新作业。为什么没有?

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cronjob-name
  annotations:
    argocd.argoproj.io/sync-wave: "1"
spec:
  schedule: "0 * * * *"
  suspend: false
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 3
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      parallelism: 1
      completions: 1
      backoffLimit: 3
      template:
        spec:
          restartPolicy: Never

阅读 official documentation 关于 kubectl create -f 的文章后,我没有找到防止这种情况发生的方法。这种行为是预期的吗?如果是,我想我应该检查我的 Docker 图像(用 Java 编写的应用程序)是否已经有一个 cronjob 运行。我该怎么做?

concurrencyPolicy: Forbidden 规范仅阻止 the same CronJob 的并发 pod 创建和执行。它不适用于单独的 CronJobs,即使它们使用相同的 Docker 图像有效地执行相同的命令。就 Kubernetes 而言,它们是不同的工作。如果这是 Java,Kubernetes 所做的是 if (stringA == stringB) 而不是 if (stringA.equals(stringB))

If it is, I think I should check inside my Docker image (app written in Java) if there is already a cronjob running. How would I do that?

一种使用方式是使用分布式锁机制,使用单独的组件,例如Redis。这是使用 Java Redis 库 redisson 的指南的 link:https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers。以下是从该页面获取的代码示例:

RLock lock = redisson.getLock("myLock");

// wait for lock aquisition up to 100 seconds 
// and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
    // do operation
} else {
    // some other execution is doing it so just chill
}