When we update an app in Kubernetes — new image, config change, replica count Kubernetes needs to replace the old pods with new ones. The deployment strategy controls how that happens. Get it wrong and you either have downtime you didn’t expect, or two versions of your app running at the same time when they shouldn’t be.
https://kubernetes.io/docs/tutorials/kubernetes-basics/explore/explore-intro/
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
Two strategies: Recreate and RollingUpdate.
Node subnets in this cluster:
10.42.0.x → k3s-cp-01
10.42.1.x → k3s-worker-02
10.42.2.x → k3s-worker-01Step 1 — Create the Namespace
Every app gets its own namespace. It keeps things clean and resources are isolated, you can set permissions per namespace, and kubectl get pods only shows what’s relevant.
We create a dedicated namespace for this app rather than dumping everything into default.
kubectl create namespace newappSet it as default context so we don’t have to type -n newapp on every command:
k config set-context default --namespace=newappConfirm:
k config get-contextsExpected output:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* default default default newappStep 2 — Create the Deployment
Rather than writing the manifest from scratch, we use --dry-run=client to generate a valid base YAML and redirect it to a file.
kubectl create deployment my-newapp --image=httpd --replicas=10 --dry-run=client -o yaml > deploy.yamlEdit deploy.yaml and add the ports:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-newapp
name: my-newapp
namespace: newapp
spec:
replicas: 10
selector:
matchLabels:
app: my-newapp
template:
metadata:
labels:
app: my-newapp
spec:
containers:
- name: httpd
image: httpd
ports:
- containerPort: 80Apply it:
k apply -f deploy.yamlCheck pods — -o wide shows the node each pod landed on:
k get pods -o wideExpected output:
NAME READY STATUS RESTARTS AGE IP NODE
my-newapp-f6544cd7d-96r7n 1/1 Running 0 35s 10.42.0.155 k3s-cp-01
my-newapp-f6544cd7d-cdf94 1/1 Running 0 35s 10.42.0.154 k3s-cp-01
my-newapp-f6544cd7d-czq2v 1/1 Running 0 35s 10.42.1.230 k3s-worker-02
my-newapp-f6544cd7d-jmhrj 1/1 Running 0 35s 10.42.2.152 k3s-worker-01
my-newapp-f6544cd7d-pzqfz 1/1 Running 0 35s 10.42.2.153 k3s-worker-01
my-newapp-f6544cd7d-rdm4f 1/1 Running 0 35s 10.42.2.154 k3s-worker-01
my-newapp-f6544cd7d-rpx2c 1/1 Running 0 35s 10.42.0.157 k3s-cp-01
my-newapp-f6544cd7d-tx2ql 1/1 Running 0 35s 10.42.0.156 k3s-cp-01
my-newapp-f6544cd7d-xhcct 1/1 Running 0 36s 10.42.1.229 k3s-worker-02
my-newapp-f6544cd7d-zbdmv 1/1 Running 0 35s 10.42.1.231 k3s-worker-0210 pods spread automatically across all 3 nodes and the scheduler figured it out based on available resources on each node.
Check deployment:
k get deployments.appsExpected output:
NAME READY UP-TO-DATE AVAILABLE AGE
my-newapp 10/10 10 10 53sStep 3 — Exec Into a Pod
We exec into a pod to verify networking to see if they can talk to each other. This is important to understand because Kubernetes pod networking means every pod gets its own IP and can reach any other pod in the cluster regardless of which node it’s on.
k exec -ti my-newapp-f6544cd7d-96r7n -- /bin/bashThe base httpd image doesn’t include ping so install it:
apt update && apt install -y iputils-pingPing a pod on a different node and pick an IP from the output above that’s on a different node: by default all IP’s will communicate across pods.
ping 10.42.0.157Step 4 — Strategy: Recreate ( Parallel Remediation )
Recreate is the simpler of the two strategies. When you apply an update, Kubernetes kills every running pod immediately, waits for them all to be gone, then starts the new ones. The app is completely down during that gap.
strategy sits directly under spec same indent level as replicas, selector, and template:
spec:
replicas: 10
selector:
...
strategy: # 2 spaces — directly under spec
type: Recreate
template:
...Create deploy.recreate.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-newapp
name: my-newapp
namespace: newapp
spec:
replicas: 10
selector:
matchLabels:
app: my-newapp
strategy:
type: Recreate
template:
metadata:
labels:
app: my-newapp
spec:
containers:
- name: httpd
image: httpd:2.4-trixie
ports:
- containerPort: 80Apply it:
k apply -f deploy.recreate.yamlOpen a second terminal and watch pods to see the Recreate behaviour in action:
k get pods -wYou will see all 10 old pods terminate simultaneously, then 10 new ones start. There is no overlap.
Check pods after:
k get pods -o wideExpected output:
Step 5 — Strategy: RollingUpdate
RollingUpdate is the default strategy in Kubernetes and the right choice for production workloads. Instead of killing everything at once, it replaces pods gradually so our app stays available throughout the update.
Two settings control the pace:
maxUnavailable— how many pods can be down at once during the update. Default 25%.maxSurge— how many extra pods can run above your desired count during the update. Default 25%.
Create deploy.rollingupdate.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-newapp
name: my-newapp
namespace: newapp
spec:
replicas: 10
selector:
matchLabels:
app: my-newapp
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: my-newapp
spec:
containers:
- name: httpd
image: httpd:2.4-trixie
ports:
- containerPort: 80Apply it:
k apply -f deploy.rollingupdate.yamlWatch the rollout:
k rollout status deployment/my-newappExpected output:

With maxUnavailable: 1 and maxSurge: 1 on 10 replicas — at most 9 pods down, at most 11 pods running at any point. One old pod terminates, one new pod starts, repeat until all 10 are updated.
Check rollout history — every apply that changes the pod spec creates a new revision:
k rollout history deployment/my-newappExpected output:
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>Roll back to the previous revision if something goes wrong:
k rollout undo deployment/my-newappCommit to Git
git add .
git commit -m "tested recreate and rolling update"
git pushSummary
| Recreate | RollingUpdate | |
|---|---|---|
| Downtime | Yes | No |
| Old + new pods together | No | Yes briefly |
| Extra config | None | maxUnavailable, maxSurge |
| Use case | dev/test | Production, stateless |
| Default | No | Yes |


