Deploy two web server replicas and delete one Pod to observe how the Deployment restores the declared replica count. Run the commands on cp01 and place ordinary application Pods on the workers. The same workload then provides a way to inspect rolling updates and recovery.
Table of Contents
1. Namespace and Deployment
mkdir -p ~/k8s-lab/app
cd ~/k8s-lab/app
kubectl create namespace lab
The file name is web-deployment.yaml. I use nginx-unprivileged which opens port 8080 as an unprivileged user. In the example, the digest of stable-alpine was specified at the time of confirmation. The content of the same tag may change, and digest fixation does not automatically apply security updates, so the timing of replacement of new images is also managed separately.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: lab
spec:
replicas: 2
revisionHistoryLimit: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
securityContext:
runAsNonRoot: true
runAsUser: 101
runAsGroup: 101
seccompProfile:
type: RuntimeDefault
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: web
containers:
- name: nginx
image: nginxinc/nginx-unprivileged:stable-alpine@sha256:782bb89768cc87b7f95c18b95baa1af250e5d451f26794f59363540161147c01
ports:
- name: http
containerPort: 8080
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 3
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 15
periodSeconds: 10
kubectl apply --dry-run=server -f web-deployment.yaml
kubectl apply -f web-deployment.yaml
kubectl -n lab rollout status deployment/web --timeout=180s
kubectl -n lab get deployment,replicaset,pods -o wide
2. Requests·limits and scheduling
CPU 100m is 0.1 of one core. The scheduler compares requests with the node’s allocatable resources, etc. This is not a setting that pins actual usage to requests. Exceeding the CPU limit may result in throttling and exceeding the memory limit may result in OOM termination. Even if the current CPU is free, it may be pending due to the total number of requests.
The scheduler’s Filter filters candidates based on resources, taints, selection conditions, etc. The remaining nodes select their placement locations by reflecting the plugin’s Score. The topology spread in the example causes the app to spread out. ScheduleAnyway allows placement even when distribution is difficult, so if there is only one worker, two replicas can run on the same node.
3. readiness·liveness
Readiness determines whether the request can be accepted, and liveness determines whether the request has stopped enough to require a restart. Pods that fail readiness are excluded from normal service delivery. In real apps, separate preparation of dependent services and process survival into separate designs. The DB is briefly slow, but restarting all web servers may increase the load. For apps with long startups, also consider startupProbe.
kubectl -n lab describe deployment web
kubectl -n lab get pods -l app=web
4. Deleting and recreating pods
POD=$(kubectl -n lab get pods -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl -n lab delete pod "$POD"
kubectl -n lab get pods -l app=web -w
After checking whether the Pod with the new name becomes Ready, end monitoring with Ctrl+C. It is the ReplicaSet controller that is directly responsible for Pod regeneration, while Deployment manages ReplicaSet replacement and replica count. The Pod IP is not fixed to the app’s connection destination, as the name and IP may change.
5. Rolling update/rollback
# 기능은 바꾸지 않고 Pod 템플릿 annotation을 바꿔 롤아웃을 관찰
kubectl -n lab patch deployment web --type=merge -p \
'{"spec":{"template":{"metadata":{"annotations":{"lab.maruops.com/release":"exercise-2"}}}}}'
kubectl -n lab rollout status deployment/web --timeout=180s
kubectl -n lab rollout history deployment/web
kubectl -n lab rollout undo deployment/web
kubectl -n lab rollout status deployment/web --timeout=180s
maxUnavailable: 0 is a setting that intentionally does not reduce available replicas. You will also need space for a third Pod to run briefly for maxSurge: 1. If resources are scarce or new Pods do not pass readiness, the rollout awaits. This example only observes template changes, excluding the download impact, but image changes follow the same path.
Rollback reverts the Deployment’s Pod template. It does not restore DB schema or external data. We also compare Git’s final state and actual resources. When finished, adjust it again to the example standard with kubectl apply -f web-deployment.yaml.
reference material
- Deployment behavior and rolling updates
- Scheduling Framework
- Container resource requests and limits
- Container health check
- NGINX Non-privileged image official repository
official documents and distribution files confirmed: October 18, 2026. The output is an example to determine completion and may vary depending on the environment.



