<p>After a recent upgrade to GKE 1.26, I began encountering an issue related to a Kubernetes job that has been historically running without issue.</p>
<p>The job itself consists two components:</p>
<ul>
<li>A simple <code>initContainer</code> that just functions as a health check against an API/service that can sometimes take some time to respond when spinning up (~10 minutes at times)</li>
<li>A script that handles logic and a variety of calls to said API service</li>
</ul>
<p>It looks something like the following in a nutshell (some things omitted for brevity):</p>
<pre><code>apiVersion: batch/v1
kind: Job
metadata:
  name: my-job-{{ now | date &quot;20060102150405&quot; }}
  labels:
    app: my-job
spec:
  backoffLimit: 0
  template:
    metadata:
      labels:
        app: my-job
      annotations:
        &quot;cluster-autoscaler.kubernetes.io/safe-to-evict&quot;: &quot;true&quot;
    spec:
      restartPolicy: Never
      ...
      initContainers:
      - name: wait-service
        ...
        command: ['bash', '-c', 'while [[ &quot;$(curl -s -o /dev/null -w ''%{http_code}'' http://someService/api/v1/status)&quot; != &quot;200&quot; ]]; do echo waiting for service; sleep 2s; done']
      containers:
        - name: run-job
          ...
      volumes:
          ...
      tolerations: 
          ...
</code></pre>
<p><strong>The problem I’m encountering is that after ~5 minutes after a deployment, while the <code>initContainer</code> is running and awaiting the service, Kubernetes will create a new instance of the job (complete with its own <code>initContainer</code> etc.)</strong> This is problematic primarily because two instances of the script being run in the primary container (run-job) could easily cause the operations within it to get out of sync/into a bad state (the script involves the suspension and restoration of various services via the API in a specific order).</p>
<p>I can verify this within the logs of the original job:</p>
<pre><code>│ wait-service waiting for service 
| failed container &quot;run-job&quot; in pod &quot;my-job-20230721165715-rh6s2&quot; is waiting to start: PodInitializing for .../my-job-20230721165715-rh6s2 (run-job)                            
| wait-service waiting for service   
</code></pre>
<p>So roughly ~5 minutes after a new deployment of this job, I have two instances of it running (aligning with the failed container message above). This typically ends with one or both of them in bad states.</p>
<p>I’ve attempted a few configuration changes with little success and I’m wondering what the best way to handle this would be? Essentially I need to allow an adequate toleration for the <code>initContainer</code> such that it doesn’t trigger the above failure and recreate a new job (but rather continue forth with the original instance).</p>

Rion Williams
<p>Since you're using helm, and you've named the job using timestamped name (<code>my-job-{{ now | date &quot;20060102150405&quot; }}</code>), this will create a fresh job each time you do the helm install, but this makes no connection with the existing job(s) that may or may not be running at the time you do the upgrade.</p>
<p>If you want to ensure existing jobs are terminated when you deploy, you should consider using <a href="https://helm.sh/docs/topics/charts_hooks/#the-available-hooks" rel="nofollow noreferrer">pre-upgrade hooks</a> to delete any existing jobs in the application namespace before the upgrade is applied.</p>
<hr />
<p>UPDATE 1</p>
<p>I've spun up a 1.26 cluster and used your example (with a few tweaks in order to get it to run), left it for 10 minutes, and got no additional job or pods.</p>
<p>What you can do in the meanwhile however, is trace the pods backwards to find out what &quot;owns&quot; them. If you <code>kubectl describe {pod}</code>, you'll see within the output a line reading &quot;Controlled by&quot;. For example:</p>
<pre><code>Controlled By:  Job/example-service-deploy-jobs-20230722170514
</code></pre>
<p>If you see two pods, describe both and see if the same job is referenced or not. If you have both pointing at the same job, then the job has spawned two pods -- this normally means it considered the first pod as failed and has spawned the second to try again.</p>
<p>If you see a different job referenced, it means another job has been deployed without deleting the first one.</p>
<p>Describe the jobs and see they it also have a &quot;controlled by&quot; field (they shouldn't if they were installed by Helm or manually deployed using <code>kubectl apply</code> or similar) -- my reason for this check is to see if something (like a cronjob) is triggering a job.</p>
<p>Separate question: how is your cluster being hosted, is it bare metal or hosted (AKS, EKS, GKE, etc?)</p>
<p>Another possibility, if you're running on hosted is that you're running on Spot/Preemptible instances, or the node is having some other issue. You can watch the nodes (<code>watch kubectl get nodes</code>) to see if any of them terminate while you're watching the init container -- and if they do, you can start investigating the reason for the node termination.</p>
<p>In short, it is not the job itself that is the issue, but something else around it (or in the cluster).</p>
