Realtime Resizing
Realtime Resizing은 Smart Sizing 추천과 클러스터 사이의 루프를 닫아줍니다. 10분마다 Wave가 추천을 자동으로 적용할 수 있습니다. **기본값은 꺼짐(off)**입니다. 자동 리사이즈는 워크로드 단위 (Apply Mode)와 컨테이너 단위 (auto-apply) 양쪽에서 opt-in해야만 동작합니다. 이 페이지는 auto-apply가 실제로 무엇을 하는지, 추천 값이 적용할 만큼 "충분히 다른지" 판단하는 임계값, 그리고 프로덕션에서 켜기 전에 알아야 할 운영상 주의점을 다룹니다.
아직 Smart Sizing을 설정하지 않았다면 Smart Sizing Overview부터 시작하세요.
VPA보다 나은 점
수직 스케일링을 위한 Kubernetes 네이티브 옵션은 Vertical Pod Autoscaler(VPA)입니다. VPA는 원래 Pod를 축출하고 재시작하는 방식으로 추천 값을 적용했습니다. 이후 VPA 프로젝트는 InPlaceOrRecreate 업데이트 모드를 추가했습니다. 현재 베타이며, VPA updater와 admission controller의 기능 게이트로 활성화하고, in-place pod resize를 지원하는 클러스터가 필요합니다 (K8s 1.33에서 베타, 1.35에서 GA). Wave가 사용하는 것과 동일한 /resize subresource를 호출하며, in-place 변경을 적용할 수 없을 때는 축출 후 재생성으로 대체됩니다.
즉 두 프로젝트 모두 최신 클러스터에서는 Pod 재시작을 피할 수 있습니다. 차이는 resize 호출 이전 단계에서 갈립니다: 추천 값을 어떻게 정하는지, 언제 실제로 적용하는지, 운영자가 결과를 어떻게 확인하는지입니다. Wave Smart Sizing이 추천 쪽을 담당하고, Realtime Resizing은 아래와 같은 파이프라인으로 적용 경로를 연결합니다.
Wave가 공유된 in-place 기본 동작 위에 추가하는 것
| 항목 | VPA (InPlaceOrRecreate, 베타) | Wave Realtime Resizing |
|---|---|---|
| 히스테리시스 | Priority 비율만 사용 (--pod-update-threshold, 기본값 10%) | Priority OR CPU 절대값 변화 (≥ 50 mCPU) OR 메모리 절대값 변화 (≥ 64 MiB). VPA의 비율 전용 임계값이 놓치는 대형 컨테이너의 드리프트를 잡아냅니다 |
| 노드 리소스 부족 시 동작 | 자동으로 축출 후 재생성으로 대체 | 세 가지 명시적 모드: Off, In-Place (해당 Pod를 건너뛰고 다음 주기에 재시도, 조용한 재시작 없음), Manifest Patch (롤아웃으로 관리). 암묵적인 폴백 없음 |
| 컨테이너별 제어 | VPA 오브젝트의 minAllowed / maxAllowed | Container Settings를 통한 컨테이너별 buffer / min / max, 매 주기마다 상속됨 |
| 지원 워크로드 종류 | Deployment, StatefulSet, DaemonSet (VPA의 targetRef가 지원하는 모든 것) | 여기에 Argo Rollout과 OpenShift DeploymentConfig 추가 |
| 다른 writer와의 조율 | 없음: 운영자가 직접 충돌을 피해야 함 | Deployment가 Autopilot으로 전환되면 자동으로 해제됨. Argo CD auto-sync 관련 주의사항은 문서화되어 있음 (아래 참고) |
| 운영자 가시성 | VPA 이벤트 + kubectl describe vpa | Wave Web Console의 Apply History 패널: 워크로드별, 컨테이너별, 주기별로 이전 → 새 request/limit과 결과를 보여줌 |
클러스터가 지원한다면 VPA와 Wave 모두 in-place 기본 동작을 사용할 수 있습니다. Wave의 가치는 그 주변 파이프라인에 있습니다: 추천 분석, 더 안전한 히스테리시스, 명시적인 apply-mode 모델, 운영자가 볼 수 있는 이력입니다.
Apply Modes
각 워크로드 (Deployment, StatefulSet, DaemonSet, Argo Rollout, OpenShift DeploymentConfig)는 세 가지 Apply Mode 중 하나로 설정됩니다. 워크로드 상세 페이지의 Info 패널에서 현재 모드를 확인할 수 있으며, Realtime Resizing을 클릭하면 변경할 수 있습니다:
| 모드 | Wave가 하는 일 | 사용 시점 |
|---|---|---|
| Off | 추천 값만 생성하고 워크로드는 건드리지 않습니다. | 평가 모드: 아무것도 바꾸지 않고 Smart Sizing이 무엇을 할지 확인합니다. |
| In-Place Pod Resize | 실행 중인 각 Pod에 대해 Kubernetes 1.27+의 /resize subresource를 호출합니다. Pod 재시작, 롤아웃, 다운타임이 없습니다. | Kubernetes 1.27+ 환경의 대부분의 프로덕션 워크로드. 사용자 영향이 가장 적습니다. |
| Manifest Patch | 워크로드 스펙 (spec.template.spec.containers[*].resources)을 패치합니다. 새 Pod는 다음 롤아웃에서 새 리소스 값을 받습니다. | in-place를 지원하지 않는 클러스터, 또는 변경 사항이 일반 롤아웃 경로로 반영되길 원하는 워크로드. |
기본 Apply Mode는 Off입니다. 명시적으로 모드를 선택하기 전까지 Wave는 절대 자동 적용하지 않습니다. 자동 적용은 추가로 컨테이너 단위에서도 opt-in해야 합니다. 워크로드의 Apply Mode가 Manifest나 In-Place여도, 해당 컨테이너의 Container Settings에서 Apply recommendations automatically를 활성화하기 전까지 Wave는 아무것도 적용하지 않습니다.
기본적으로 auto-apply는 request만 갱신합니다. CPU/메모리 limit을 적용하는 것은 컨테이너별로 별도 opt-in해야 합니다 (Apply CPU limit / Apply memory limit). 꺼둔 채로 두면 limit은 설정한 값 그대로 유지되어, 메모리 상한이 자동으로 낮아져 OOMKill에 노출되는 상황을 막아줍니다.
메모리 limit은 Manifest 모드에서만 적용됩니다. In-Place 모드는 메모리 request만 적용합니다. Kubernetes의 in-place resize 경로는 메모리 limit을 바꾸지 않기 때문입니다. 따라서 In-Place를 선택하면 Apply memory limit 옵션은 아무 효과가 없습니다.
In-Place를 위한 클러스터 사전 요구사항
In-Place Pod Resize는 기능 게이트 뒤에 있는 Kubernetes 기능입니다:
| Kubernetes 버전 | In-Place 상태 |
|---|---|
| < 1.27 | 사용 불가. Manifest 모드를 사용하세요. |
| 1.27~1.32 | Alpha: InPlacePodVerticalScaling 기능 게이트를 수동으로 활성화해야 합니다. |
| 1.33~1.34 | Beta (기본 활성화). |
| ≥ 1.35 | GA. |
Wave는 런타임에 클러스터를 조회해 Web Console의 In-Place 옵션을 그에 맞게 제어합니다. 클러스터가 in-place resize를 지원하지 않으면, 라디오 옵션이 설명 툴팁과 함께 비활성화됩니다.
스킵 임계값: VPA 스타일 히스테리시스
10분마다 Wave는 각 컨테이너에 대해 새 추천 값을 마지막으로 적용된 스냅샷과 비교합니다. 새 추천 값이 마지막 적용 값과 너무 비슷하면, Wave는 해당 컨테이너의 적용을 건너뜁니다. K8s API 호출도, 롤아웃도, 감사 로그 기록도 없습니다.
다음 중 하나라도 해당하면 (OR 조합) 컨테이너에 의미 있는 변화가 있다고 판단해 Wave가 적용합니다:
| 가드 | 임계값 |
|---|---|
| Priority (리소스 변화의 누적 비율) | ≥ 10% |
| CPU 절대값 변화 | ≥ 50 mCPU (0.05 core) |
| 메모리 절대값 변화 | ≥ 64 MiB |
워크로드에서 Aggressive Recommendations가 켜져 있으면 게이트가 달라집니다: priority 비율 검사는 비활성화되고, 절대값 변화 기준은 ≥ 10 mCPU (0.01 core)와 ≥ 10 MiB로 좁아집니다. Aggressive 모드는 최근 사용량을 촘촘히 따라가기 위한 것이므로 히스테리시스가 훨씬 가볍습니다. 작은 변화도 그대로 적용됩니다.
이 숫자들을 선택한 이유
- Priority 10%: Kubernetes VPA Updater의
--pod-update-threshold기본값과 동일합니다. K8s VPA 컴포넌트가 사용하는 업계 표준 참고값을 그대로 채택해, 프로덕션에서 VPA를 운영해본 사람이라면 익숙하게 느끼도록 했습니다. - CPU 50 mCPU: K8s 운영자는 관례적으로 CPU request/limit을 50 mCPU의 배수 (50 / 100 / 250 / 500 / 1000)로 설정합니다. 50 mCPU 미만의 변화는 노이즈이며 재적용할 이유가 되지 않습니다. 50 mCPU라는 하한선은 HPA의 10% 허용 오차와도 같은 맥락입니다. 둘 다 비슷한 규모에서 "사소한 변화는 무시"하는 가드입니다.
- 메모리 64 MiB: 실제 컨테이너 메모리 request (보통 128 MiB
1 GiB) 기준으로 64 MiB는 650%의 변화이며, 의미상 10% priority 가드와 같은 스케일입니다. jemalloc arena나 JVM region 같은 allocator 내부 청킹에서 나오는 노이즈도 흡수합니다.
VPA와 다른 점
VPA의 Updater는 priority만 봅니다. Pod 안의 모든 컨테이너로부터 계산된 누적 비율입니다. Wave는 priority에 절대값 가드 두 개를 OR로 결합합니다. 이 안전장치는 VPA가 놓치는 한 가지 경우를 잡아냅니다: 비율은 10% 미만이지만 절대값 변화는 운영상 의미 있는 대형 컨테이너입니다.
예시: 컨테이너가 4.00 CPU에서 4.05 CPU로 바뀌었습니다. 비율은 1.25%로 VPA의 10% 기준에 한참 못 미칩니다. 하지만 절대값 변화가 정확히 50 mCPU이므로, Wave는 그래도 적용합니다.
HPA와 Autopilot에서 Realtime Resizing이 비활성화되는 이유
워크로드가 (HPA나 Wave Autopilot에 의해) 수평으로 오토스케일링되면, Pod가 동적으로 생성되고 종료됩니다. 이 상태에서의 자동 리사이즈는 두 apply mode 모두에서 문제를 일으킵니다:
- In-place 모드는 지금 실행 중인 Pod만 업데이트합니다. 잠시 후 scale-up으로 생성되는 Pod는 이전 값이 담긴 워크로드 스펙에서 시작하므로, 그룹 안에 서로 다른 크기의 Pod가 섞이게 됩니다. round robin 같은 단순한 로드밸런싱 알고리즘에서는 크기가 다른 Pod 사이에 트래픽이 고르게 분배되지 않아 워크로드가 불안정해질 수 있습니다.
- Manifest 모드는 워크로드 스펙을 패치하므로, 기존 Pod 전체가 종료되고 다시 생성됩니다. 오토스케일링 도중에 전체 롤아웃이 일어나는 셈이라 프로덕션에 큰 영향을 줍니다.
이런 이유로 HPA와 Autopilot 워크로드에서는 Realtime Resizing 컨트롤을 사용할 수 없습니다. 탭은 Smart Sizing with HPA / Autopilot으로 바뀌고 워크로드 성능 모델을 사용합니다. 추천 값을 검토한 뒤 Resize Now로 수동 적용하세요. 권장 기준선 워크플로우는 Aggressive Recommendations에서 설명합니다.
Monitoring Mode의 Autopilot은 워크로드를 스케일링하지 않으므로, 이 경우에는 Realtime Resizing을 계속 사용할 수 있습니다.
운영상 주의할 점: 프로덕션에서 auto-apply를 켜기 전에 읽어보세요
In-Place는 Pod당 fire-and-forget으로 동작합니다
In-Place 모드는 실행 중인 각 Pod에 /resize 호출을 보내고 넘어갑니다. Wave는 요청 제출 결과 (API 호출이 제출 시점에 수락되었는지 거부되었는지)만 기록하며, 이후 kubelet의 비동기 resize 상태는 폴링하지 않습니다.
in-place resize가 제출 시점에 거부되는 가장 흔한 이유는 Node 리소스 부족입니다. 새 request가 해당 Node에 들어가지 않는 경우입니다. Wave는 Pod별로 이 거부를 기록하지만 롤아웃이나 축출을 트리거하지는 않습니다. 다음 Smart Sizing 주기 (10분 후)에서 다시 평가하고, 추천 값이 아직 수렴하지 않았다면 재시도합니다.
resize가 제출 시점에는 수락되었지만 이후 kubelet이 해당 Pod를 resource-deferred로 표시하는 경우 (예: resize가 반영되기 전에 Node가 가득 차는 경우), Wave는 이를 비동기적으로 알아차리지 못합니다. 다음 주기에서 워크로드의 실제 리소스가 여전히 추천 값과 다를 때 드러납니다.
적합한 Node로의 재스케줄링을 보장받아야 한다면 Manifest 모드를 사용하세요. 이 경로는 일반적인 Pod 교체 흐름을 거칩니다.
Manifest Patch는 ArgoCD auto-sync와 충돌합니다
워크로드가 auto-sync가 켜진 Argo CD로 관리되고 있다면, Manifest 모드는 Argo CD와 충돌합니다: Wave가 리소스를 패치하면 Argo CD가 drift를 감지해 되돌립니다. 몇 분 안에 적용 이전 상태로 돌아가고, Wave는 다시 적용을 시도합니다.
Wave의 Manifest 모드가 리소스 값의 source of truth가 되길 원하는 워크로드에서는 Argo CD auto-sync를 끄세요. Wave Autopilot에도 이미 동일한 제약이 적용됩니다.
In-Place 모드는 Argo CD와 함께 사용해도 안전합니다. in-place resize 호출은 워크로드 스펙을 바꾸지 않고 Pod 상태를 직접 갱신하므로, Argo CD가 drift를 감지하지 않습니다.
Autopilot으로 전환되면 Deployment의 auto-apply가 해제됩니다
Deployment가 나중에 Autopilot 관리로 전환되면, Smart Sizing auto-apply는 자동으로 해제(꺼짐)됩니다. Autopilot이 관리하는 워크로드의 리소스 결정은 Autopilot이 갖게 되며, Wave는 같은 필드를 두 writer가 놓고 다투게 두지 않습니다.
Autopilot을 거친 워크로드에서 Smart Sizing auto-apply를 다시 켜려면 먼저 Autopilot을 꺼야 합니다.
컨테이너별 buffer / min / max가 매 주기를 제한합니다
각 컨테이너의 Container Settings (buffer 비율, min CPU/메모리 하한, max CPU/메모리 상한)는 스킵 임계값 검사를 거치기 전에 추천 값을 제한합니다.
이력을 확인하는 곳
스킵 임계값을 통과해 K8s API까지 도달한 적용 시도는 워크로드 상세 페이지의 Smart Sizing → Apply History에 기록됩니다. 테이블에는 시각, 모드 (in-place / manifest), 컨테이너 이름, 이전 → 새 CPU/메모리 request와 limit, 결과 (applied / failed)가 표시됩니다.
스킵 임계값에 의해 건너뛴 추천은 이 테이블에 나타나지 않습니다. 설계상 K8s API 호출도, 감사 로그 기록도 만들지 않기 때문입니다. 작은 드리프트가 반영될 것으로 기대했는데 반영되지 않았다면, 대개 이것이 이유입니다. 마지막으로 적용된 행을 기준으로 변화량을 다시 계산하고 priority / CPU / 메모리 가드와 비교해보세요.
컨테이너를 Wave 적용 이전 값으로 완전히 되돌리려면 Restore Original을 사용하세요.
권장 롤아웃 순서
- 모든 워크로드에서 Off로 시작합니다. 며칠 동안 추천 값을 관찰합니다.
- 중요하지 않은 워크로드 하나를 골라 In-Place로 전환합니다 (K8s 1.27+가 없거나 Argo CD 제약이 있다면 Manifest).
- 그 워크로드의 컨테이너 한두 개에서 auto-apply를 활성화합니다.
- 이력 테이블에서 성공한 적용 행 몇 개를 확인하고, 몇 주기 동안 리소스 추이를 지켜봅니다.
- 더 많은 워크로드로 확대합니다.