kubernetes: activeDeadlineSeconds not working correctly for Jobs in 1.24.0

What happened?

Prior to 1.24.0 setting spec.adctiveDeadlineSeconds in a Job object (batch/v1) would kill the Job and Pods if they ran longer than the integer specified. I tested today with 1.24.0 and it’s not working. The Job defined below (for testing) should be killed 10 seconds, but isn’t. It’s actually being terminated after about 55 seconds.

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  activeDeadlineSeconds: 10
  ttlSecondsAfterFinished: 120
  completions: 5
  parallelism: 1
  backoffLimit: 4
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: ctr
        image: alpine:latest
        command: ['sh', '-c', 'echo "TEST" && sleep 60']

What did you expect to happen?

The Job to be killed after 10 seconds as per activeDeadlineSeconds: 10. It’s worked like this in 1.23.x.

How can we reproduce it (as minimally and precisely as possible)?

On a cluster running 1.24.0 with the following YAML file called job.yml.

job.yml

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  activeDeadlineSeconds: 10
  ttlSecondsAfterFinished: 120
  completions: 5
  parallelism: 1
  backoffLimit: 4
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: ctr
        image: alpine:latest
        command: ['sh', '-c', 'echo "TEST" && sleep 60']

Create the Job. kubectl apply -f job.yml

On Kubernetes clusters earlier than 1.24.0 it would fail after 10 seconds and the following command should show Warning DeadlineExceeded Xs job-controller Job was active longer than specified deadline in the events 10 seconds after the Pod is created.

kubectl describe job test

<SNIP>
Events:
  Type     Reason            Age   From            Message
  ----     ------            ----  ----            -------
  Normal   SuccessfulCreate  16s   job-controller  Created pod: ckad1-kk6jt
  Normal   SuccessfulDelete  6s    job-controller  Deleted pod: ckad1-kk6jt
  Warning  DeadlineExceeded  6s    job-controller  Job was active longer than specified deadline

In K8s 1.24.0 it’s terminated after about a minute instead of 10 seconds. It works as expected in 1.23.6 and other point versions of 1.23.

Anything else we need to know?

It works as expected, and documented, in all versions of 1.23 I’ve tested on.

Docs: https://kubernetes.io/docs/concepts/workloads/controllers/job/#job-termination-and-cleanup

Kubernetes version

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.0", GitCommit:"4ce5a8954017644c5420bae81d72b09b735c21f0", GitTreeState:"clean", BuildDate:"2022-05-03T13:46:05Z", GoVersion:"go1.18.1", Compiler:"gc", Platform:"darwin/arm64"}
Kustomize Version: v4.5.4
Server Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.0", GitCommit:"4ce5a8954017644c5420bae81d72b09b735c21f0", GitTreeState:"clean", BuildDate:"2022-05-03T13:38:19Z", GoVersion:"go1.18.1", Compiler:"gc", Platform:"linux/arm64"}

Cloud provider

All and also local clusters.

OS version

N/A

Install tools

N/A

Container runtime (CRI) and version (if applicable)

N/A

Related plugins (CNI, CSI, …) and versions (if applicable)

N/A

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 16 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I think I have figured out why this happened. It is a side effect of JobReadyPods feature gate (thanks @harshanarayana ).

  1. background: when we call queue.AddAfter(key, duration) with duration > 0 multiple times, the workqueue will only keep the duration that will be triggered nearest from now.

  2. previously (when there is no JobReadyPods feature gate or do not enable it): job-controller mainly relies on the first time sync to add the job after its ActiveDeadlineSeconds:

https://github.com/kubernetes/kubernetes/blob/92263ee0dd2588978dd2d99a952a1d463e3a88a3/pkg/controller/job/job_controller.go#L751-L760

(unless the ActiveDeadlineSeconds field has been changed then it will be add after here).

  1. now: the JobReadyPods feature gate makes jm.podUpdateBatchPeriod to be 1s and it will be add after for the job when a pod of it has been updated. Then the ActiveDeadlineSeconds duration which has been added after in the first time sync will be overwrite to 1s. And after the next syncJob, there will be no one to addAfter the job again.

https://github.com/kubernetes/kubernetes/blob/92263ee0dd2588978dd2d99a952a1d463e3a88a3/pkg/controller/job/job_controller.go#L482-L506

WDYT @harshanarayana @liggitt @alculquicondor

just add it back to the queue every time there is a job sync. It’s a noop if the item is already there.

@harshanarayana Emm… Usually it is not suggested to have multiple active queues in one controller, which will cause an object to be handled by multiple workers at the same time and also make the progress more complicated.

My suggestion is do queue.AddAfter at the end of syncJob every time an unfinished job is reconciled, the duration should be ActiveDeadlineSeconds - time.Since(job.Status.StartTime). This is clear for everyone to understand, brings less change and no extra burden on the controller.

The job controller for sure has the code for cleanup on active deadline still in place https://github.com/kubernetes/kubernetes/blob/f3264dd0b33ba4450c453436e3ebd5a287712a1a/pkg/controller/job/job_controller.go#L762-L799

+1 from me as well. The behavior for sure is not the same on 1.23.x vs 1.24.0 using the same job manifest. And the documentation v/s the behavior is not the same.