103 lines
4.5 KiB
Markdown
103 lines
4.5 KiB
Markdown
# Assignment
|
||
|
||
An application deployed on the Kubernetes cluster requires an update with new features developed by the Nautilus application development team. The existing setup includes a deployment named nginx-deployment and a service named nginx-service. Below are the necessary changes to be implemented without deleting the deployment and service:
|
||
|
||
|
||
1.) Modify the service nodeport from 30008 to 32165
|
||
|
||
2.) Change the replicas count from 1 to 5
|
||
|
||
3.) Update the image from nginx:1.19 to nginx:latest
|
||
|
||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||
|
||
# Solution
|
||
|
||
# Update Deployment + Service (no delete, all patches) — `nginx-deployment` / `nginx-service`
|
||
|
||
Three in-place changes, each as a surgical `kubectl patch`: replicas `1 → 5`, image
|
||
`nginx:1.19 → nginx:latest`, service nodePort `30008 → 32165`. No object is deleted and no
|
||
full manifest is reproduced.
|
||
|
||
## Patches
|
||
|
||
```bash
|
||
# 1) Replicas 1 -> 5 (strategic-merge patch)
|
||
kubectl patch deployment nginx-deployment \
|
||
-p '{"spec":{"replicas":5}}'
|
||
|
||
# 2) Image nginx:1.19 -> nginx:latest (strategic-merge, container matched by name)
|
||
kubectl patch deployment nginx-deployment \
|
||
-p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx-container","image":"nginx:latest"}]}}}}'
|
||
|
||
# 3) NodePort 30008 -> 32165 (JSON patch, precise field replace)
|
||
kubectl patch service nginx-service \
|
||
--type=json \
|
||
-p='[{"op":"replace","path":"/spec/ports/0/nodePort","value":32165}]'
|
||
|
||
# Wait for the image change to roll out
|
||
kubectl rollout status deployment/nginx-deployment
|
||
```
|
||
|
||
## How it works
|
||
|
||
### Two patch types, chosen per change
|
||
|
||
`kubectl patch` supports different strategies; each change uses the one that's cleanest for it.
|
||
|
||
**Strategic-merge patch (default)** — used for replicas and image. It deep-merges the JSON
|
||
fragment into the live object, and it understands Kubernetes list semantics.
|
||
|
||
- **Replicas** — `{"spec":{"replicas":5}}` merges a single scalar field; nothing else in the
|
||
spec is touched.
|
||
- **Image** — `{"spec":{"template":{"spec":{"containers":[{"name":"nginx-container","image":"nginx:latest"}]}}}}`.
|
||
The `containers` list is merged **by the `name` key**, so including `name: nginx-container`
|
||
tells Kubernetes to patch *that* existing container's image rather than replace the whole
|
||
list or add a second container. This is why the correct container name matters — a wrong
|
||
name would append a new container instead of updating the existing one.
|
||
|
||
**JSON patch (`--type=json`)** — used for the nodePort. It's an ordered list of explicit
|
||
operations (RFC 6902). `replace` on `/spec/ports/0/nodePort` targets exactly one field of the
|
||
first port entry. JSON patch is the right tool for editing **one element of a list** like
|
||
`ports` — a strategic-merge patch on a ports array is ambiguous about how to match entries,
|
||
whereas `ports/0` is unambiguous. `32165` is inside the valid NodePort range
|
||
(`30000–32767`), so the API accepts it.
|
||
|
||
### Why the image patch triggers a rolling update
|
||
|
||
Changing the container image mutates the pod template. The Deployment controller detects the
|
||
template change, creates a new ReplicaSet, and rolls `nginx:latest` pods in while retiring the
|
||
`nginx:1.19` pods incrementally — governed by the live `RollingUpdate` strategy
|
||
(`maxSurge/maxUnavailable 25%`). `rollout status` blocks until that completes. The replicas
|
||
patch simply scales the ReplicaSet to 5.
|
||
|
||
### Nothing gets deleted
|
||
|
||
All three are `patch` operations that mutate existing objects in place. The service keeps its
|
||
ClusterIP; the deployment keeps its identity and rollout history. "Without deleting" is
|
||
satisfied by construction — a delete + recreate would drop the ClusterIP and history.
|
||
|
||
### Equivalent shortcuts
|
||
|
||
The same results are achievable with purpose-built verbs, if you prefer them over raw patches:
|
||
|
||
```bash
|
||
kubectl scale deployment nginx-deployment --replicas=5
|
||
kubectl set image deployment/nginx-deployment nginx-container=nginx:latest
|
||
# (nodePort still needs a patch/edit — there's no dedicated verb for it)
|
||
```
|
||
|
||
## Verify
|
||
|
||
```bash
|
||
kubectl get deployment nginx-deployment
|
||
kubectl get deployment nginx-deployment \
|
||
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
|
||
kubectl get service nginx-service \
|
||
-o jsonpath='{.spec.ports[0].nodePort}{"\n"}'
|
||
```
|
||
|
||
Expected — deployment `READY 5/5`, image `nginx:latest`, nodePort `32165`.
|
||
|
||
> If the rollout hangs with new pods in `ImagePullBackOff`, the `nginx:latest` pull failed
|
||
> (node offline / rate-limited); `kubectl describe pod <name>` shows the cause. |