~/infra-dev.md
INFRA_DEV

Kubernetes Pod 리사이즈는 왜 “재배포”가 아니라 운영 조정일까

10분 읽기·2026.07.14·출처 3·00
오늘의 질문

CPU·메모리 설정이 잘못된 Pod를 꼭 죽이고 다시 띄워야 할까, 아니면 실행 중인 Pod의 리소스를 안전하게 조정할 수 있을까?

infra-dev.md
Pod resize runbook

Kubernetes Pod 리사이즈는 왜 “재배포”가 아니라 운영 조정일까

1. 왜 지금 봐야 하나

Kubernetes에서 CPU·메모리 request/limit은 오래도록 “Pod를 만들 때 정하는 값”에 가까웠다. 값을 바꾸려면 Deployment template을 수정하고, 새 ReplicaSet이 생기고, 기존 Pod가 종료되고, 새 Pod가 뜬다. stateless API 서버라면 받아들일 수 있지만, 긴 연결을 가진 서비스, warm cache를 가진 worker, local state가 큰 ML inference 서버, 장애 중 임시 증설이 필요한 Pod에는 이 교체 비용이 꽤 크다.

Kubernetes는 이 빈틈을 줄이기 위해 In-place Pod Resize를 발전시켜 왔다. v1.33 릴리스 노트는 이 기능이 beta로 승격되었고, 기존에는 Pod spec의 container resources가 사실상 immutable이라 변경하면 Pod replacement가 필요했지만 이제 실행 중 Pod의 resource configuration을 동적으로 바꾸는 길이 열렸다고 설명한다. 현재 Kubernetes 문서에서는 이 기능 상태를 v1.35 stable, 기본 활성화로 표시한다.

오늘의 핵심은 “오토스케일러를 대체한다”가 아니다.

In-place Pod Resize는 수평 확장 전에, 또는 재배포 없이, 이미 떠 있는 Pod의 리소스 계약을 조정하는 운영 레버다.

작은 팀 입장에서는 장애 대응과 비용 최적화의 언어가 달라진다. “Pod를 죽이고 크게 다시 띄울까?”가 아니라 “실행 중인 Pod가 감당할 수 있는 범위에서 CPU·메모리를 조정할 수 있을까?”를 물어볼 수 있다.

2. 핵심 개념

In-place Pod Resize는 Pod를 재생성하지 않고 container의 CPU·memory request/limit을 변경하는 기능이다. 문서 기준으로 핵심 필드는 세 층으로 나뉜다.

첫째, desired resources다. spec.containers[*].resources에 있는 CPU·memory 값이며, resize 요청 이후 “원하는 값”을 나타낸다. 이 값은 Pod의 resize subresource를 통해 갱신한다.

둘째, actual resources다. status.containerStatuses[*].resources는 현재 실행 중인 container에 실제로 적용된 resource 값을 보여준다. 아직 시작하지 않았거나 재시작된 container라면 다음 시작 시 할당될 값을 반영한다.

셋째, allocated resources다. status.containerStatuses[*].allocatedResources는 kubelet이 확인한 할당 값을 추적한다. 일반적인 운영 확인은 actual resources를 보되, scheduler는 resize가 pending/incomplete인 Pod가 있을 때 desired, allocated, actual request의 최대값을 사용해 스케줄링 판단을 한다.

요청은 대략 이런 모양이다.

zsh — 생존확인.sh
kubectl patch pod api-0 \
  --subresource=resize \
  --type='merge' \
  -p '{"spec":{"containers":[{"name":"api","resources":{"requests":{"cpu":"1000m","memory":"1Gi"},"limits":{"cpu":"2000m","memory":"2Gi"}}}]}}'

여기서 중요한 것은 “patch가 성공했다”와 “container에 실제 반영됐다”가 다르다는 점이다. kubelet은 상태 조건으로 resize 진행 상황을 알려준다.

  • PodResizePending: kubelet이 즉시 반영할 수 없다. Infeasible이면 현재 노드에서 불가능하고, Deferred이면 지금은 어렵지만 나중에 가능해질 수 있어 재시도된다.
  • PodResizeInProgress: kubelet이 resize를 받아들였고 적용 중이다. 적용 중 오류는 condition message와 Error reason으로 보고된다.

즉 In-place resize는 단순 YAML 변경이 아니라 “원하는 리소스, 할당된 리소스, 실제 적용 리소스, 지연/불가능 상태”를 관측해야 하는 운영 플로우다.

3. 최신 이슈와 연결

v1.33 beta 블로그에서 눈에 띄는 변화는 status.resize 대신 Pod condition을 통해 상태를 표현하도록 정리했다는 점이다. PodResizePendingPodResizeInProgress는 resize를 이벤트 한 줄이 아니라 상태 머신으로 다루게 만든다.

현재 문서에서 실무적으로 중요한 항목은 세 가지다.

  1. 버전과 기능 게이트: 문서는 Kubernetes server가 1.33 이상이어야 하고, control plane과 node에서 InPlacePodVerticalScaling feature gate가 활성화되어야 한다고 설명한다. kubectl --subresource=resize는 kubectl v1.32 이상이 필요하다.
  2. restart 정책: resizePolicy로 resource별 재시작 필요 여부를 정할 수 있다. 기본은 NotRequired지만, memory 변경은 많은 애플리케이션과 런타임이 동적으로 조정하지 못하므로 RestartContainer가 필요할 수 있다고 문서는 설명한다.
  3. 재시도 우선순위: Deferred resize는 kubelet이 주기적으로 다시 시도한다. 여러 resize가 밀려 있으면 PriorityClass가 높은 Pod가 먼저 재시도되고, 같은 priority라면 QoS class가 높은 Pod가 먼저 재시도된다.

여기서 개발자가 가져갈 메시지는 분명하다. In-place resize는 “무중단으로 아무 값이나 바꾸는 기능”이 아니다. node 여유 자원, container runtime, 애플리케이션의 memory 적응 능력, priority, QoS, restart policy가 함께 맞아야 안전하다.

4. 개발자 관점 해석

운영에서 리소스 조정은 보통 세 가지 상황에서 발생한다.

첫째, 장애 중 임시 증설이다. 특정 Pod가 CPU throttling이나 memory pressure로 느려지는데 horizontal scale-out은 cold start, shard ownership, connection rebalancing 때문에 곧바로 효과가 나지 않을 수 있다. 이때 실행 중 Pod의 CPU request/limit을 올릴 수 있다면 재배포보다 빠른 완충 장치가 된다.

둘째, 비용 회수다. 장애 대응 때문에 크게 올린 request를 나중에 줄이지 않으면 cluster bin-packing이 나빠진다. In-place resize는 “새 배포를 굴려서 줄이기”보다 더 작은 단위로 리소스를 회수할 수 있는 길을 준다.

셋째, 상태ful 워크로드 보호다. StatefulSet, cache-heavy service, inference server처럼 재시작 자체가 비용인 워크로드는 Pod 교체가 곧 사용자 지연이나 재처리 비용으로 이어질 수 있다. In-place resize는 이런 워크로드에서 “재시작 없이 가능한 조정”과 “재시작이 필요한 조정”을 분리하게 해준다.

하지만 이 기능을 HPA/VPA의 만능 대체재처럼 쓰면 위험하다. HPA는 replica 수를 조정해 부하를 분산하고, VPA는 권장 request를 계산하거나 Pod 재생성을 통해 리소스를 맞추는 역할을 해왔다. In-place resize는 그 사이에서 “이미 실행 중인 Pod의 vertical adjustment”를 담당한다. 따라서 자동화하려면 다음 질문부터 정해야 한다.

  • resize를 누가 결정하는가? 사람, runbook, controller, VPA 연동?
  • 어떤 metric이 resize trigger인가? CPU throttling, RSS, p95 latency, queue lag?
  • 얼마까지 올릴 수 있는가? namespace quota, node allocatable, budget guardrail?
  • 실패하면 무엇을 할 것인가? horizontal scale-out, Pod replacement, traffic drain?
  • 줄이는 작업은 언제 할 것인가? 장애 종료 후 자동 회수, 수동 승인, 예약 작업?

In-place resize는 “리소스 값을 바꾸는 명령”이 아니라 “운영자가 재배포 없이 조정할 수 있는 권한”에 가깝다. 권한에는 관측, 승인, 롤백, 비용 한도가 따라와야 한다.

5. 내 프로젝트에 적용할 체크포인트

Kubernetes를 쓰는 팀이라면 바로 적용하기보다 아래부터 확인하자.

  • 클러스터 버전과 node 버전이 In-place Pod Resize를 지원하는가?
  • 관리형 Kubernetes라면 해당 feature gate가 실제로 활성화되어 있는가?
  • kubectl 버전이 --subresource=resize를 지원하는가?
  • resize 대상 workload가 CPU 변경을 재시작 없이 받아들일 수 있는가?
  • memory 변경 시 애플리케이션 런타임이 heap, cache, allocator limit을 동적으로 재조정하는가?
  • resizePolicy를 CPU와 memory에 각각 다르게 둘 필요가 있는가?
  • PodResizePending, PodResizeInProgress condition을 dashboard/alert에서 볼 수 있는가?
  • Deferred가 오래 지속될 때 node 여유 자원 부족인지, priority/QoS 문제인지 확인할 수 있는가?
  • resize 후 실제 status.containerStatuses[*].resources가 원하는 값으로 바뀌었는지 검증하는 runbook이 있는가?
  • 임시 증설 후 request를 줄이는 비용 회수 절차가 있는가?

특히 memory는 조심해야 한다. CPU limit 증가는 상대적으로 runtime이 즉시 이득을 볼 수 있지만, memory limit 변경은 애플리케이션이 이미 잡은 heap, cache, mmap, allocator 동작과 맞물린다. “Pod는 안 죽었지만 앱은 새 limit을 제대로 활용하지 못하는” 상태가 생길 수 있다.

6. 오늘 10분 액션

오늘은 운영 자동화까지 만들지 말고, resize 후보 하나를 찾는 데 집중하자.

  1. 최근 장애나 성능 이슈에서 “request/limit을 올렸으면 좋았겠다” 싶은 workload 하나를 고른다.
  2. 그 workload의 현재 request/limit, 실제 사용량, HPA 설정, PDB, restart 비용을 한 줄로 적는다.
  3. staging cluster에서 feature 지원 여부를 확인한다.
zsh — 생존확인.sh
kubectl version
kubectl get pod <pod-name> -o jsonpath='{.status.conditions}'
  1. CPU만 작은 폭으로 올리는 resize draft runbook을 만든다.
  2. runbook 마지막 줄에 반드시 “actual resources 확인”과 “원복/축소 시점”을 넣는다.

오늘의 목표는 기능을 켜는 것이 아니다. “재배포 없이 리소스를 조정할 수 있는 상황과, 여전히 재배포가 더 안전한 상황을 구분하는 기준”을 만드는 것이다.

7. 더 볼 자료

중복 회피 메모

로컬 content/generated와 Supabase 최근 infra_dev 글을 확인했다. 최근 글은 Docker Compose pre_start init lifecycle, Terraform state secret, GitHub Actions step-level 병렬화, OpenTelemetry semantic convention 카디널리티, RDS delayed replica, GitHub secret scanning triage, Vercel AI Gateway routing, GitHub Actions pull_request_target 보안, OIDC subject/audience, Kubernetes Indexed Job 실패 예산, Cloudflare Queues backlog/DLQ를 다뤘다. 이번 글은 Kubernetes를 다시 다루지만 batch Job 실패 예산이나 GKE capacity buffer가 아니라, 실행 중 Pod의 CPU·memory request/limit을 resize subresource와 Pod condition으로 조정하는 In-place Pod Resize 운영 절차에 집중해 중복을 피했다.

오늘 10분 액션+5%

댓글 0

최신순 ▾
한 줄 남기기

혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)