<p>I have a Kubernetes cluster and I'm deploying my app there with Helm. Everything works fine, but one aspect, the Job update. As I've read, the Jobs are immutable and that's why they can't be updated, but I don't get, why is helm not creating a new job as it does for the Pods?</p>
<p>In the end, I want to achieve that my app code is deployed as a job, that runs DB migrations. I tried to do it as a Pod, but for pods, the restart policy can be only &quot;Always&quot;, &quot;never&quot; is not supported, even though the doc says otherwise. How can I achieve this, so the Migration can be updated with every deployment (new image tag) and it runs once and not restarts?</p>

<p>You can use helm hooks here.
Official Link: <a href="https://helm.sh/docs/topics/charts_hooks/" rel="nofollow noreferrer">https://helm.sh/docs/topics/charts_hooks/</a></p>
<p>Once job is completed with &quot;helm install&quot;, helm hook should delete it. Once you perform &quot;helm upgrade&quot;, a new job should be triggered. Application logic should handle install and upgrade scenarios.</p>
<p>Below are some concepts related to helm hooks.</p>
<h1>Types of Helm Hooks</h1>
<ul>
<li>pre-install   : hooks run after templates are rendered and before any resources are created in a Kubernetes cluster</li>
<li>post-install  : hooks run after all Kubernetes resources have been loaded</li>
<li>pre-delete    : hooks run before any existing resources are deleted from Kubernetes</li>
<li>post-delete   : hooks run after all Kubernetes resources have been deleted</li>
<li>pre-upgrade   : hooks run after chart templates have been rendered and before any resources are loaded into Kubernetes</li>
<li>post-upgrade  : hooks run after all Kubernetes resources have been upgraded</li>
<li>pre-rollback  : hooks run after templates have been rendered and before any resources are rolled back</li>
<li>post-rollback : hooks run after all resources have been modified</li>
<li>test          : hooks run when helm test subcommand is executed</li>
</ul>
<p>NOTE: One resource can implement multiple hooks:</p>
<p>Eg:
annotations:
&quot;helm.sh/hook&quot;: post-install,post-upgrade</p>
<h1>How Helm Chart Hooks Are Executed</h1>
<ul>
<li>When a Helm chart containing hooks is executed, components like pods or jobs pertaining to hooks are not directly applied in a Kubernetes environment.
Instead when a hook is executed, a new pod is created corresponding to the hook.
If successfully run, they will be in &quot;Completed&quot; state.</li>
<li>Any resources created by a Helm hook are un-managed Kubernetes objects.
In other words, uninstalling a Helm chart using &quot;helm uninstall&quot; will not remove the underlying resources created by hooks.
A separate deletion policy needs to be defined in the form of annotation if those resources need to be deleted.</li>
<li>Any hook resources that must never be deleted should be annotated with &quot;helm.sh/resource-policy: keep&quot;.</li>
</ul>
<h1>Helm Hook Annotations</h1>
<ul>
<li>&quot;helm.sh/hook&quot;: post-install</li>
<li>&quot;helm.sh/hook-weight&quot;: &quot;-5&quot;                       ## NOTE: This MUST be string</li>
<li>&quot;helm.sh/hook-delete-policy&quot;: hook-succeeded</li>
<li>&quot;helm.sh/resource-policy&quot;: keep</li>
</ul>
<h1>Hook Deletion Policies</h1>
<ul>
<li>“helm.sh/hook-delete-policy&quot; annotation to be used.</li>
</ul>
<h2>Three different deletion policies are supported which will decide when to delete the resources:</h2>
<ul>
<li>before-hook-creation  : Delete the previous resource before a new hook is launched</li>
<li>hook-succeeded        : Delete the resource after the hook is successfully executed</li>
<li>hook-failed           : Delete the resource if the hook failed during execution</li>
</ul>
<p>NOTE: If no hook deletion policy annotation is specified, the before-hook-creation behavior is applied by default.</p>
<h1>Hook Weights</h1>
<ul>
<li>&quot;helm.sh/hook-weight&quot; annotation to be used.</li>
<li>Hook weights can be positive or negative numbers but must be represented as strings.</li>
<li>When Helm starts the execution cycle of hooks of a particular Kind it will sort those hooks in ascending order.</li>
</ul>
<h2>Hook weights ensure below:</h2>
<ul>
<li>execute in the right weight sequence</li>
<li>block each other</li>
<li>all block main K8s resource from starting</li>
</ul>
<h1>Complete Execution Flow Example</h1>
<ol>
<li>Step-1: Create post-install and post-install hook YAML files</li>
</ol>
<hr />
<p>pre-install.yaml</p>
<pre><code>apiVersion: v1
 kind: Pod
 metadata:
   name: hook-preinstall
   annotations:
     &quot;helm.sh/hook&quot;: &quot;pre-install&quot;          ## Without this line, this becomes a normal K8s resource.
 spec:
   containers:
   - name: hook1-container
     image: busybox
     imagePullPolicy: IfNotPresent
     command: ['sh', '-c', 'echo The pre-install hook Pod is running  - hook-preinstall &amp;&amp; sleep 15']
   restartPolicy: Never
   terminationGracePeriodSeconds: 0
</code></pre>
<hr />
<p>post-install.yaml</p>
<pre><code>apiVersion: v1
 kind: Pod
 metadata:
   name: hook-postinstall
   annotations:
     &quot;helm.sh/hook&quot;: &quot;post-install&quot;         ## Without this line, this becomes a normal K8s resource.
 spec:
   containers:
   - name: hook2-container
     image: busybox
     imagePullPolicy: IfNotPresent
     command: ['sh', '-c', 'echo post-install hook Pod is running - hook-postinstall &amp;&amp; sleep 10']
   restartPolicy: Never
   terminationGracePeriodSeconds: 0
</code></pre>
<hr />
<ol start="2">
<li>Step-2: Install Helm Chart (Assuming other K8s resources are defined under /templates/ directory)</li>
</ol>
<hr />
<ol start="3">
<li>Get Pods:</li>
</ol>
<hr />
<pre><code>$ kubectl get pods
NAME                                 READY   STATUS      RESTARTS   AGE
demohook-testhook-5ff88bb44b-qc4n2   1/1     Running     0          5m45s
hook-postinstall                     0/1     Completed   0          5m45s
hook-preinstall                      0/1     Completed   0          6m2s
$
</code></pre>
<hr />
<ol start="4">
<li>Describe Pods and notice Started &amp; Finished time of the pods:</li>
</ol>
<hr />
<pre><code>$ kubectl describe pod demohook-testhook-5ff88bb44b-qc4n2 | grep -E 'Anno|Started:|Finished:'
$ kubectl describe pod hook-postinstall | grep -E 'Anno|Started:|Finished:'              
$ kubectl describe pod hook-preinstall | grep -E 'Anno|Started:|Finished:'
</code></pre>
<hr />
