v1.33 "Octarine" 릴리스 핵심 변경 사항
Kubernetes v1.33은 2025년 4월 23일에 릴리스되었으며, 코드명은 "Octarine: The Color of Magic"이다. 64개의 개선 사항이 포함되어 있고, 그 중 18개가 Stable로 졸업, 20개가 Beta 진입, 24개가 새로운 Alpha 기능이다.
이 플레이북은 v1.33으로 업그레이드하는 운영팀이 **알아야 할 것, 해야 할 것, 주의해야 할 것**을 실행 가능한 단위로 정리한 문서다.
Stable로 졸업한 핵심 기능
| 기능 | KEP | 운영 영향도 | 필요 조치 |
| ------------------------- | -------- | ----------- | -------------------------------------------------------------------------------------------- |
| Sidecar Containers | KEP-753 | 높음 | initContainers에 `restartPolicy: Always` 사용 가능. 기존 sidecar injection 워크어라운드 정리 |
| User Namespaces | KEP-127 | 높음 | Pod에서 `hostUsers: false` 기본 활성화. 보안 격리 강화 |
| nftables kube-proxy | KEP-3866 | 중간 | iptables에서 nftables로 전환 가능. 대규모 Service 환경에서 성능 향상 |
| CRD Validation Ratcheting | KEP-4008 | 중간 | 기존 CRD 필드값이 새 스키마에 안 맞아도 변경 안 하면 통과 |
Beta로 진입한 주요 기능
| 기능 | KEP | 운영 영향도 | 설명 |
| ------------------------- | -------- | ----------- | ------------------------------------------------- |
| In-Place Pod Resize | KEP-1287 | 높음 | Pod 재시작 없이 CPU/Memory 조정 가능. 기본 활성화 |
| DRA Driver-owned Status | KEP-4817 | 중간 | DRA 드라이버가 ResourceClaim 상태를 직접 업데이트 |
| Pod-level Resource Limits | KEP-2837 | 중간 | 컨테이너 단위가 아닌 Pod 단위로 리소스 상한 설정 |
Deprecated/Removed
| 항목 | 상태 | 대응 |
| ------------------------------------- | ---------- | -------------------------------- |
| Endpoints API | Deprecated | EndpointSlice API로 마이그레이션 |
| flowcontrol.apiserver.k8s.io/v1beta3 | Removed | v1으로 업데이트 |
| Node Status `conditions` 필드 중 일부 | 변경 | 모니터링 쿼리 수정 확인 |
플레이 1: 업그레이드 사전 준비
Step 1. 현재 클러스터 상태 점검
#!/bin/bash
pre-upgrade-check.sh - 업그레이드 전 클러스터 상태 점검
echo "=== 1. 현재 버전 확인 ==="
kubectl version --short 2>/dev/null || kubectl version
echo ""
echo "=== 2. 노드 상태 확인 ==="
kubectl get nodes -o wide
NOT_READY=$(kubectl get nodes --no-headers | grep -v " Ready " | wc -l)
if [ "$NOT_READY" -gt 0 ]; then
echo "WARNING: $NOT_READY 개 노드가 NotReady 상태입니다. 업그레이드 전 해결 필요."
fi
echo ""
echo "=== 3. Deprecated API 사용 확인 ==="
v1.33에서 제거된 API를 사용하는 리소스 탐색
kubectl get --raw /metrics | grep -E 'apiserver_requested_deprecated_apis'
echo ""
echo "=== 4. PodDisruptionBudget 확인 ==="
kubectl get pdb --all-namespaces -o wide
echo "PDB가 없는 critical 워크로드가 있으면 업그레이드 중 downtime 발생 가능"
echo ""
echo "=== 5. etcd 상태 확인 ==="
kubectl -n kube-system exec -it etcd-$(hostname) -- \
etcdctl endpoint health --cluster \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
echo ""
echo "=== 6. 버전 skew 확인 ==="
echo "Control Plane:"
kubectl get nodes -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}'
echo ""
echo "Workers:"
kubectl get nodes -l '!node-role.kubernetes.io/control-plane' -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}'
Step 2. Deprecated API 마이그레이션
v1.33에서 가장 중요한 API 변경은 Endpoints API의 deprecation이다. 기존에 Endpoints를 직접 읽고 있는 컨트롤러나 스크립트가 있다면 EndpointSlice로 전환해야 한다.
Endpoints API를 사용하는 리소스 찾기
kubectl get endpoints --all-namespaces -o name | wc -l
EndpointSlice로 읽는 방법
kubectl get endpointslices --all-namespaces -o wide
코드에서 Endpoints를 직접 참조하는 경우 변경 예시:
Before: Endpoints API
from kubernetes import client
v1 = client.CoreV1Api()
endpoints = v1.read_namespaced_endpoints("my-service", "default")
for subset in endpoints.subsets:
for address in subset.addresses:
print(address.ip)
After: EndpointSlice API
discovery_v1 = client.DiscoveryV1Api()
slices = discovery_v1.list_namespaced_endpoint_slice(
"default",
label_selector="kubernetes.io/service-name=my-service"
)
for ep_slice in slices.items:
for endpoint in ep_slice.endpoints:
for address in endpoint.addresses:
print(address)
Step 3. etcd 백업
업그레이드 전 반드시 etcd 스냅샷을 생성한다. 이것이 최후의 롤백 수단이다.
etcd 스냅샷 생성
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-pre-v133-$(date +%Y%m%d%H%M).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
스냅샷 검증
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-pre-v133-*.db --write-out=table
플레이 2: Control Plane 업그레이드
kubeadm 기반 클러스터에서의 업그레이드 절차다. 관리형 서비스(EKS, GKE, AKS)는 콘솔이나 CLI에서 버전을 지정하면 자동 처리된다.
Control Plane 노드 업그레이드
1. kubeadm 업그레이드
sudo apt-get update
sudo apt-get install -y kubeadm=1.33.0-1.1
2. 업그레이드 계획 확인
sudo kubeadm upgrade plan v1.33.0
3. 업그레이드 실행 (첫 번째 control plane 노드)
sudo kubeadm upgrade apply v1.33.0
4. kubelet과 kubectl 업그레이드
sudo apt-get install -y kubelet=1.33.0-1.1 kubectl=1.33.0-1.1
sudo systemctl daemon-reload
sudo systemctl restart kubelet
5. 추가 control plane 노드 (두 번째, 세 번째)
sudo kubeadm upgrade node
업그레이드 후 Control Plane 검증
API Server 버전 확인
kubectl version
컴포넌트 상태 확인
kubectl get componentstatuses 2>/dev/null || \
kubectl get --raw /readyz?verbose
etcd 클러스터 상태
kubectl -n kube-system exec -it etcd-cp-01 -- \
etcdctl member list --write-out=table \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
플레이 3: Worker 노드 롤링 업그레이드
Worker 노드는 한 번에 하나씩 업그레이드하여 서비스 가용성을 유지한다.
#!/bin/bash
worker-upgrade.sh <node-name>
NODE=$1
echo "=== $NODE 업그레이드 시작 ==="
1. 노드 cordon (새 Pod 스케줄링 차단)
kubectl cordon "$NODE"
2. 노드 drain (기존 Pod 퇴거)
kubectl drain "$NODE" \
--ignore-daemonsets \
--delete-emptydir-data \
--timeout=300s \
--grace-period=120
3. 노드에서 패키지 업그레이드 (SSH)
ssh "$NODE" "sudo apt-get update && \
sudo apt-get install -y kubeadm=1.33.0-1.1 && \
sudo kubeadm upgrade node && \
sudo apt-get install -y kubelet=1.33.0-1.1 && \
sudo systemctl daemon-reload && \
sudo systemctl restart kubelet"
4. 노드 uncordon
kubectl uncordon "$NODE"
5. 노드 상태 확인
kubectl get node "$NODE" -o wide
echo "=== $NODE 업그레이드 완료 ==="
롤링 업그레이드 병렬도 결정
| 클러스터 규모 | 동시 업그레이드 노드 수 | 근거 |
| ------------- | ----------------------- | -------------------------------- |
| 3-10 노드 | 1 | 여유 노드가 적으므로 보수적 진행 |
| 10-50 노드 | 2-3 | PDB 준수 확인 후 병렬화 |
| 50-200 노드 | 5-10 | 노드 그룹별 순차 진행 |
| 200+ 노드 | 노드 풀 단위 | Blue-green 노드 풀 교체 권장 |
플레이 4: In-Place Pod Resize 활용
v1.33에서 Beta로 승격된 In-Place Pod Resize는 운영팀에게 가장 실용적인 기능이다. Pod를 재시작하지 않고 CPU/Memory를 조정할 수 있다.
리사이즈 실행
현재 리소스 확인
kubectl get pod my-app-xyz -o jsonpath='{.spec.containers[0].resources}'
리사이즈 요청 (resize subresource 사용)
kubectl patch pod my-app-xyz --subresource=resize --type=merge -p '{
"spec": {
"containers": [{
"name": "app",
"resources": {
"requests": {"cpu": "500m", "memory": "512Mi"},
"limits": {"cpu": "1000m", "memory": "1Gi"}
}
}]
}
}'
리사이즈 상태 확인
kubectl get pod my-app-xyz -o jsonpath='{.status.resize}'
"Proposed" → "InProgress" → "Completed" 순서로 전환
Resize Policy 설정
Container spec에서 리사이즈 정책을 지정할 수 있다:
apiVersion: v1
kind: Pod
metadata:
name: resizable-app
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: '250m'
memory: '256Mi'
limits:
cpu: '500m'
memory: '512Mi'
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # CPU는 재시작 없이 조정
- resourceName: memory
restartPolicy: RestartContainer # Memory는 컨테이너 재시작 필요
자동 리사이즈 연동 (VPA + In-Place Resize)
VerticalPodAutoscaler가 In-Place Resize를 활용하도록 설정:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: 'InPlaceOrRecreate' # v1.33에서 추가된 모드
resourcePolicy:
containerPolicies:
- containerName: app
minAllowed:
cpu: '100m'
memory: '128Mi'
maxAllowed:
cpu: '2000m'
memory: '4Gi'
플레이 5: User Namespaces 보안 강화
v1.33에서 User Namespaces가 기본 활성화되었다. 컨테이너 내부에서 root로 실행되더라도 호스트에서는 비권한(unprivileged) UID로 매핑되어 보안이 강화된다.
User Namespaces 적용
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
hostUsers: false # User Namespaces 활성화
containers:
- name: app
image: myapp:v2.0
securityContext:
runAsUser: 0 # 컨테이너 내부에서는 root
하지만 hostUsers: false이므로 호스트에서는 고유 UID로 매핑
보안 정책과 결합
User Namespaces와 Pod Security Standards를 함께 사용:
Namespace에 Pod Security 레벨 적용
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Kyverno로 User Namespaces 강제화:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-user-namespaces
spec:
validationFailureAction: Enforce
rules:
- name: require-hostusers-false
match:
any:
- resources:
kinds: ['Pod']
namespaces: ['production', 'staging']
validate:
message: '프로덕션/스테이징 Pod는 hostUsers: false를 설정해야 합니다.'
pattern:
spec:
hostUsers: false
플레이 6: nftables kube-proxy 전환
v1.33에서 nftables 기반 kube-proxy가 Stable이 되었다. iptables보다 성능이 좋고, 특히 Service 수가 많은 클러스터에서 큰 차이가 난다.
전환 전 확인
현재 kube-proxy 모드 확인
kubectl -n kube-system get configmap kube-proxy -o yaml | grep mode
nftables 지원 확인 (노드에서)
nft --version
nftables v1.0.6 이상 필요
kube-proxy ConfigMap 수정
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-proxy
namespace: kube-system
data:
config.conf: |
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: nftables # iptables → nftables
nftables:
masqueradeAll: false
syncPeriod: 30s
minSyncPeriod: 1s
전환 후 kube-proxy를 롤링 재시작:
kubectl -n kube-system rollout restart daemonset kube-proxy
kubectl -n kube-system rollout status daemonset kube-proxy
플레이 7: 업그레이드 후 검증
업그레이드가 완료되었다고 끝이 아니다. 아래 검증 단계를 반드시 거친다.
자동화된 검증 스크립트
#!/bin/bash
post-upgrade-verify.sh
ERRORS=0
echo "=== Post-Upgrade Verification ==="
1. 모든 노드 Ready 확인
echo "[1/7] Node Status..."
NOT_READY=$(kubectl get nodes --no-headers | grep -v " Ready " | wc -l)
if [ "$NOT_READY" -gt 0 ]; then
echo "FAIL: $NOT_READY nodes not ready"
ERRORS=$((ERRORS + 1))
else
echo "PASS: All nodes ready"
fi
2. 모든 시스템 Pod Running 확인
echo "[2/7] System Pods..."
FAILING=$(kubectl -n kube-system get pods --no-headers | grep -v "Running\|Completed" | wc -l)
if [ "$FAILING" -gt 0 ]; then
echo "FAIL: $FAILING system pods not running"
kubectl -n kube-system get pods | grep -v "Running\|Completed"
ERRORS=$((ERRORS + 1))
else
echo "PASS: All system pods healthy"
fi
3. CoreDNS 동작 확인
echo "[3/7] DNS Resolution..."
kubectl run dns-test --image=busybox:1.36 --restart=Never --rm -it -- \
nslookup kubernetes.default.svc.cluster.local 2>/dev/null
if [ $? -eq 0 ]; then
echo "PASS: DNS working"
else
echo "FAIL: DNS resolution failed"
ERRORS=$((ERRORS + 1))
fi
4. API Server 버전 확인
echo "[4/7] API Server Version..."
SERVER_VERSION=$(kubectl version -o json | jq -r '.serverVersion.gitVersion')
echo "Server version: $SERVER_VERSION"
if [[ "$SERVER_VERSION" == *"1.33"* ]]; then
echo "PASS: Correct version"
else
echo "FAIL: Unexpected version"
ERRORS=$((ERRORS + 1))
fi
5. 핵심 워크로드 상태 확인
echo "[5/7] Critical Workloads..."
for ns in production staging; do
UNAVAIL=$(kubectl -n "$ns" get deployments --no-headers 2>/dev/null | \
awk '{if ($2 != $4) print $1}')
if [ -n "$UNAVAIL" ]; then
echo "FAIL: Unavailable deployments in $ns: $UNAVAIL"
ERRORS=$((ERRORS + 1))
fi
done
echo "PASS: Critical workloads healthy"
6. Ingress/Service 동작 확인
echo "[6/7] Service Connectivity..."
kubectl get svc -A --no-headers | awk '{print $1"/"$2}' | head -5 | while read svc; do
echo " Checking $svc..."
done
echo "PASS: Services enumerated"
7. 메트릭 파이프라인 확인
echo "[7/7] Metrics Pipeline..."
kubectl top nodes 2>/dev/null
if [ $? -eq 0 ]; then
echo "PASS: Metrics working"
else
echo "WARN: Metrics pipeline may need time to recover"
fi
echo ""
echo "=== Verification Complete: $ERRORS errors ==="
exit $ERRORS
Conformance Test 실행
업그레이드 후 Kubernetes Conformance Test를 실행하여 클러스터가 스펙을 준수하는지 확인:
Sonobuoy로 Conformance Test 실행
sonobuoy run --mode=certified-conformance --wait
결과 확인
sonobuoy status
sonobuoy results $(sonobuoy retrieve)
업그레이드 롤백 절차
문제가 발견되면 즉시 롤백할 수 있어야 한다.
Worker 노드 롤백
Worker 노드를 이전 버전으로 다운그레이드
ssh worker-node-01 "sudo apt-get install -y \
kubeadm=1.32.x-1.1 kubelet=1.32.x-1.1 && \
sudo kubeadm upgrade node && \
sudo systemctl daemon-reload && \
sudo systemctl restart kubelet"
Control Plane 롤백 (최후의 수단)
Control Plane 롤백은 etcd 복원을 동반하므로 위험하다. 반드시 사전에 백업을 확인한 상태에서만 진행한다.
etcd 스냅샷에서 복원
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-pre-v133-*.db \
--data-dir=/var/lib/etcd-restored
etcd 데이터 디렉토리 교체 (모든 control plane 노드에서)
sudo systemctl stop etcd
sudo mv /var/lib/etcd /var/lib/etcd-broken
sudo mv /var/lib/etcd-restored /var/lib/etcd
sudo systemctl start etcd
정답: ||EndpointSlice API. v1.21부터 사용 가능했으며, dual-stack 네트워킹 등 새로운 기능을
지원한다.||
정답: ||CPU는 컨테이너 재시작 없이(NotRequired) 조정 가능하지만, Memory는 경우에 따라 컨테이너
재시작(RestartContainer)이 필요하다.||
정답: ||컨테이너 내부에서 root(UID 0)로 실행되더라도 호스트에서는 비권한 UID로 매핑되어, 컨테이너
탈출(container escape) 시에도 호스트 권한을 얻지 못한다.||
정답: ||Control Plane 롤백은 API Server 바이너리만 되돌리면 안 되고, etcd에 저장된 클러스터 상태도
함께 복원해야 한다. etcd 스냅샷이 없으면 이전 상태로 돌아갈 방법이 없다.||
정답: ||iptables는 규칙이 선형 체인으로 평가되어 Service 수에 비례하여 지연이 증가하지만,
nftables는 맵/셋 기반으로 O(1)에 가까운 룩업이 가능하다.||
정답: ||cordon 없이 drain만 하면, drain 중에 새로운 Pod가 해당 노드에 스케줄링될 수 있다.
cordon으로 먼저 새 Pod 배치를 차단한 후 drain으로 기존 Pod를 퇴거해야 한다.||
정답: ||CRD 스키마를 강화해도, 기존에 저장된 리소스가 변경되지 않는 한 새 스키마 규칙에 걸리지
않는다. 이것은 기존 리소스를 깨뜨리지 않으면서 점진적으로 스키마를 개선할 수 있게 해준다.||
참고 자료
- [Kubernetes v1.33 릴리스 블로그](https://kubernetes.io/blog/2025/04/23/kubernetes-v1-33-release/)
- [Kubernetes v1.33 DRA 업데이트](https://kubernetes.io/blog/2025/05/01/kubernetes-v1-33-dra-updates/)
- [Kubernetes v1.33 주요 변경사항 미리보기](https://kubernetes.io/blog/2025/03/26/kubernetes-v1-33-upcoming-changes/)
- [kubeadm 업그레이드 공식 문서](https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/)
- [Kubernetes 릴리스 페이지](https://kubernetes.io/releases/)
- [Kyverno 정책 엔진](https://kyverno.io/docs/)
현재 단락 (1/331)
Kubernetes v1.33은 2025년 4월 23일에 릴리스되었으며, 코드명은 "Octarine: The Color of Magic"이다. 64개의 개선 사항이 포함되어 있고,...