Skip to content

필사 모드: Kubernetes v1.33 운영 실전 플레이북: 업그레이드와 보안 자동화

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

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개의 개선 사항이 포함되어 있고,...

작성 글자: 0원문 글자: 11,842작성 단락: 0/331