<p>I am trying to perform a <a href="https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/" rel="nofollow noreferrer" title="Kubernetes Performing a Rolling Update">Kubernetes Rolling Update</a> using <a href="https://v2.helm.sh/docs/" rel="nofollow noreferrer" title="Helm v2 Docs">Helm v2</a>; however, I'm unable to.</p>
<p>When I perform a <code>helm upgrade</code> on a <a href="https://hub.docker.com/r/hqasem/slow-tomcat" rel="nofollow noreferrer" title="Slow Tomcat Docker Image">slow Tomcat image</a>, the original pod is destroyed.</p>
<p>I would like to figure out how to achieve zero downtime by incrementally updating Pods instances with new ones, and draining old ones.</p>
<p>To demonstrate, I created a sample <a href="https://hub.docker.com/r/hqasem/slow-tomcat" rel="nofollow noreferrer" title="Slow Tomcat Docker Image">slow Tomcat Docker image</a>, and a <a href="https://github.com/h-q/slowtom/" rel="nofollow noreferrer" title="Slow Tomcat Helm v2 deployment chart">Helm chart</a>.</p>
<h2>To install:</h2>
<pre><code>helm install https://github.com/h-q/slowtom/raw/master/docs/slowtom.tgz --name slowtom \
     -f https://github.com/h-q/slowtom/raw/master/docs/slowtom/environments/initial.yaml
</code></pre>
<p>You can follow the logs by running <code>kubectl logs -f slowtom-sf-0</code>, and once ready you can access the application on <code>http://localhost:30901</code></p>
<h2>To upgrade:</h2>
<h3>(and that's where I need help)</h3>
<pre><code>helm upgrade slowtom https://github.com/h-q/slowtom/raw/master/docs/slowtom.tgz \
     -f https://github.com/h-q/slowtom/raw/master/docs/slowtom/environments/upgrade.yaml
</code></pre>
<p>The <a href="https://github.com/h-q/slowtom/blob/master/docs/slowtom/environments/upgrade.yaml" rel="nofollow noreferrer" title="Initial Helm Deployment Yaml file"><code>upgrade.yaml</code></a> is identical to the <a href="https://github.com/h-q/slowtom/blob/master/docs/slowtom/environments/initial.yaml" rel="nofollow noreferrer" title="Upgrad Helm Deployment Yaml file"><code>initial.yaml</code></a> deployment file with the exception of the tag version number.</p>
<p>Here the original pod is destroyed, and the new one starts. Meanwhile, users are unable to access the application on <code>http://localhost:30901</code></p>
<h3>To Delete:</h3>
<pre><code>helm del slowtom --purge
</code></pre>
<h1>Reference</h1>
<h2>Local Helm Chart</h2>
<h3>Download helm chart:</h3>
<pre><code>curl -LO https://github.com/h-q/slowtom/raw/master/docs/slowtom.tgz
tar vxfz ./slowtom.tgz
</code></pre>
<h3>Install from local helm-chart:</h3>
<pre><code>helm install --debug ./slowtom --name slowtom -f ./slowtom/environments/initial.yaml
</code></pre>
<h3>Upgrade from local helm-chart:</h3>
<pre><code>helm upgrade --debug slowtom ./slowtom -f ./slowtom/environments/upgrade.yaml
</code></pre>
<h2>Docker Image</h2>
<h3><code>Dockerfile</code></h3>
<pre><code>FROM tomcat:8.5-jdk8-corretto

RUN mkdir /usr/local/tomcat/webapps/ROOT &amp;&amp; \
    echo '&lt;html&gt;&lt;head&gt;&lt;title&gt;Slow Tomcat&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Slow Tomcat Now Ready&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;' &gt;&gt; /usr/local/tomcat/webapps/ROOT/index.html

RUN echo '#!/usr/bin/env bash' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo 'x=2' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo 'secs=$(($x * 60))' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo 'while [ $secs -gt 0 ]; do' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo '   &gt;&amp;2 echo -e &quot;Blast off in $secs\033[0K\r&quot;' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo '   sleep 1' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo '   : $((secs--))' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo 'done' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo '&gt;&amp;2 echo &quot;slow cataline done. will now start real catalina&quot;' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    echo 'exec catalina.sh run' &gt;&gt; /usr/local/tomcat/bin/slowcatalina.sh &amp;&amp; \
    chmod +x /usr/local/tomcat/bin/slowcatalina.sh 

ENTRYPOINT [&quot;/usr/local/tomcat/bin/slowcatalina.sh&quot;]
</code></pre>
<h2>Helm Chart Content</h2>
<h3><code>slowtom/Chart.yaml</code></h3>
<pre><code>apiVersion: v1
description: slow-tomcat Helm chart for Kubernetes
name: slowtom
version: 1.1.2  # whatever
</code></pre>
<h3><code>slowtom/values.yaml</code></h3>
<pre><code># Do not use this file, but ones from environmments folder
</code></pre>
<h3><code>slowtom/environments/initial.yaml</code></h3>
<pre><code># Storefront
slowtom_sf:
  name: &quot;slowtom-sf&quot;
  hasHealthcheck: &quot;true&quot;
  isResilient: &quot;false&quot;
  replicaCount: 2
  aspect_values:
    - name: y_aspect
      value: &quot;storefront&quot;

image:
  repository: hqasem/slow-tomcat
  pullPolicy: IfNotPresent
  tag: 1
env:
  - name: y_env
    value: whatever
</code></pre>
<h3><code>slowtom/environments/upgrade.yaml</code></h3>
<pre><code># Storefront
slowtom_sf:
  name: &quot;slowtom-sf&quot;
  hasHealthcheck: &quot;true&quot;
  isResilient: &quot;false&quot;
  replicaCount: 2
  aspect_values:
    - name: y_aspect
      value: &quot;storefront&quot;

image:
  repository: hqasem/slow-tomcat
  pullPolicy: IfNotPresent
  tag: 2
env:
  - name: y_env
    value: whatever
</code></pre>
<h3><code>slowtom/templates/deployment.yaml</code></h3>
<pre><code>---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Values.slowtom_sf.name }} 
  labels:
    chart: &quot;{{ .Chart.Name | trunc 63 }}&quot;
    chartVersion: &quot;{{ .Chart.Version | trunc 63 }}&quot; 
    visualize: &quot;true&quot; 
    app: {{ .Values.slowtom_sf.name }} 
spec:
  replicas: {{ .Values.slowtom_sf.replicaCount }} 
  selector: 
    matchLabels:
      app: {{ .Values.slowtom_sf.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.slowtom_sf.name }}
        visualize: &quot;true&quot; 
    spec:
      dnsPolicy: ClusterFirstWithHostNet
      containers: 
        - name: {{ .Values.slowtom_sf.name }} 
          image: &quot;{{ .Values.image.repository }}:{{ .Values.image.tag }}&quot;
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          command: [&quot;/usr/local/tomcat/bin/slowcatalina.sh&quot;]
          args: [&quot;whatever&quot;]
          env:
{{ toYaml .Values.env | indent 12 }}
{{ toYaml .Values.slowtom_sf.aspect_values | indent 12 }}
          resources: 
{{ toYaml .Values.resources | indent 12 }}
---
</code></pre>
<h3><code>slowtom/templates/service.yaml</code></h3>
<pre><code>kind: Service
apiVersion: v1
metadata:
  name: {{.Values.slowtom_sf.name}} 
  labels:
    chart: &quot;{{ .Chart.Name | trunc 63 }}&quot;
    chartVersion: &quot;{{ .Chart.Version | trunc 63 }}&quot;
    app: {{.Values.slowtom_sf.name}}
    visualize: &quot;true&quot; 
    hasHealthcheck: &quot;{{ .Values.slowtom_sf.hasHealthcheck }}&quot; 
    isResilient: &quot;{{ .Values.slowtom_sf.isResilient }}&quot;
spec:
  type: NodePort
  selector:
    app: {{.Values.slowtom_sf.name}}
  sessionAffinity: ClientIP
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
      name: http
      nodePort: 30901
---
</code></pre>

<p>Unlike <code>Deployment</code>, <code>StatefulSet</code> does not start a new pod before destroying the old one during a rolling update. Instead, the expectation is that you have multiple pods, and they will be replaced one-by-one. Since you only have 1 replica configured, it must destroy it first. Either increase your replica count to 2 or more, or switch to a <code>Deployment</code> template.</p>
<p><a href="https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#rolling-update" rel="nofollow noreferrer">https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#rolling-update</a></p>
