<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>PriorityClass on jyukki's Blog</title><link>https://jyukki.com/tags/priorityclass/</link><description>Recent content in PriorityClass on jyukki's Blog</description><generator>Hugo -- 0.147.0</generator><language>ko-KR</language><lastBuildDate>Mon, 14 Sep 2026 10:06:00 +0900</lastBuildDate><atom:link href="https://jyukki.com/tags/priorityclass/index.xml" rel="self" type="application/rss+xml"/><item><title>2026 개발 트렌드: Kubernetes v1.37 In-Place Resize Preemption, 무중단 확장보다 퇴출 예산을 먼저 설계하자</title><link>https://jyukki.com/posts/2026-09-14-kubernetes-inplace-resize-preemption-budget-trend/</link><pubDate>Mon, 14 Sep 2026 10:06:00 +0900</pubDate><guid>https://jyukki.com/posts/2026-09-14-kubernetes-inplace-resize-preemption-budget-trend/</guid><description>Kubernetes v1.37의 in-place Pod resize scheduler preemption Alpha를 계기로, restart 없는 scale-up을 목표로 삼지 않고 어떤 workload를 언제 퇴출해도 되는지 priority·PDB·capacity·rollback 예산으로 설계하는 기준을 정리합니다.</description><content:encoded><![CDATA[<p>Pod의 CPU나 memory request가 부족해졌을 때 기존 선택지는 불편했다. Pod를 재생성해 더 큰 노드에 배치하거나, 노드에 여유가 생길 때까지 기다리거나, VPA 권고를 사람이 해석해 rollout했다. Kubernetes의 in-place Pod resize는 실행 중인 container 자원을 조정할 수 있게 하면서 이 간극을 줄였다. 하지만 노드의 allocatable headroom이 부족하면 kubelet은 resize를 <code>Deferred</code>로 남긴다. Pod는 살아 있지만 필요한 자원을 얻지 못한 채 기다린다.</p>
<p>Kubernetes v1.37은 이 deferred 상태를 위한 <strong>scheduler preemption for in-place Pod resize</strong>를 Alpha로 추가했다. <code>InPlacePodVerticalScalingSchedulerPreemption</code> feature gate를 켜면 scheduler가 높은 우선순위 Pod의 resize를 만족시키기 위해 같은 node의 낮은 우선순위 Pod를 preempt할 수 있다. 공식 발표의 핵심도 “resize가 자동으로 안전해졌다”가 아니라, 정적 배치 이후 생기는 자원 부족을 scheduler가 해소할 수 있는 경로가 열렸다는 것이다.</p>
<p>이 글은 <a href="/learning/deep-dive/deep-dive-kubernetes-rollouts/">Kubernetes Rollout 전략</a>, <a href="/learning/deep-dive/deep-dive-capacity-planning-littles-law-saturation/">Capacity Planning·Little&rsquo;s Law·Saturation</a>, <a href="/learning/deep-dive/deep-dive-priority-load-shedding-bulkhead/">Priority Load Shedding·Bulkhead</a>, <a href="/posts/2026-09-11-kubernetes-node-lifecycle-conditions-trend/">Node Lifecycle Conditions</a>를 resize 관점으로 연결한다. 중요한 질문은 “API Pod가 restart 없이 커질 수 있는가”가 아니라, <strong>어느 workload를 얼마나 자주, 어떤 복구 증거가 있을 때 중단시켜도 되는가</strong>다.</p>
<p>공식 자료는 <a href="https://kubernetes.io/blog/2026/09/10/kubernetes-v1-37-scheduler-preemption-for-in-place-pod-resize-alpha/">Kubernetes v1.37의 Scheduler Preemption for In-Place Pod Resize 발표</a>, <a href="https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/">container resource resize 문서</a>, <a href="https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/">Pod Priority and Preemption 문서</a>, <a href="https://kubernetes.io/docs/tasks/run-application/configure-pdb/">PodDisruptionBudget 문서</a>를 기준으로 확인했다. Alpha 기능의 세부 동작과 feature gate는 이후 release에서 달라질 수 있으므로, 문서의 example을 production 정책으로 복사하지 않는다.</p>
<h2 id="이-글에서-얻는-것">이 글에서 얻는 것</h2>
<ul>
<li><code>ResizeDeferred</code>가 의미하는 node headroom 문제와, v1.37이 scheduler preemption으로 메우려는 범위를 이해합니다.</li>
<li>resize를 받는 high-priority Pod와 preempt되는 low-priority Pod의 가용성 비용을 분리해서 계산합니다.</li>
<li>PriorityClass, PDB, termination grace, queue lease, checkpoint를 하나의 <strong>퇴출 예산(eviction budget)</strong> 으로 묶는 기준을 얻습니다.</li>
<li>staging → 단일 pool → 제한 canary로 승격하기 위한 지표와 rollback 조건을 숫자로 정합니다.</li>
</ul>
<h2 id="핵심-개념이슈">핵심 개념/이슈</h2>
<h3 id="1-deferred-resize는-더-큰-request가-아니라-node-local-capacity-문제다">1) Deferred resize는 &ldquo;더 큰 request&quot;가 아니라 node-local capacity 문제다</h3>
<p>실행 중인 Pod의 resource request를 늘리면 kubelet은 해당 node에 추가 allocation을 수용할 여유가 있는지 본다. 여유가 없으면 resize 요청은 <code>ResizeDeferred</code> 상태가 될 수 있다. 이 상태가 곧 애플리케이션이 실패했다는 뜻은 아니지만, latency가 이미 악화됐거나 OOM 위험을 줄이려는 resize라면 기다리는 시간 자체가 SLO 비용이다.</p>
<p>v1.37의 Alpha 기능은 scheduler가 이 신호를 보고 lower-priority Pod를 preempt해 공간을 만든 뒤, deferred resize가 진행되도록 한다. 이것은 새 Pod를 우선 배치할 때의 preemption과 비슷해 보이지만 이미 실행 중인 workload가 resource를 키우는 상황이라는 점이 다르다. high-priority Pod에는 restart 없는 resize일 수 있어도 low-priority Pod에는 명시적인 중단·재시작·재처리 비용이 생긴다.</p>
<p>따라서 용량 문제를 다음처럼 나눠 관찰해야 한다.</p>
<table>
  <thead>
      <tr>
          <th>관측값</th>
          <th>해석</th>
          <th>먼저 확인할 것</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>ResizeDeferred</code> 횟수</td>
          <td>해당 node의 resize headroom 부족</td>
          <td>request 증가량, node allocatable, 기존 reserved request</td>
      </tr>
      <tr>
          <td>deferred 지속 시간</td>
          <td>scheduler/용량이 부족한 시간</td>
          <td>scale-out 가능 여부, autoscaler delay, victim 후보</td>
      </tr>
      <tr>
          <td>preemption 횟수</td>
          <td>다른 workload에 전가된 가용성 비용</td>
          <td>victim class, PDB, retry/중복 처리 결과</td>
      </tr>
      <tr>
          <td>resize 완료 뒤 p99/오류율</td>
          <td>resize가 실제로 SLO를 회복했는지</td>
          <td>application bottleneck이 CPU/memory였는지</td>
      </tr>
  </tbody>
</table>
<p>CPU utilization 40%라는 평균만 보고 “여유가 있다”고 결론 내리면 안 된다. scheduler는 실제 request와 node-local placement를 본다. 한 node에 특정 request가 몰렸거나 fragmentation이 크면 평균 사용률과 상관없이 deferred가 발생한다.</p>
<h3 id="2-priorityclass는-권리의-순서이지-희생의-안전-보증이-아니다">2) PriorityClass는 권리의 순서이지 희생의 안전 보증이 아니다</h3>
<p>PriorityClass는 scheduler에게 상대적 중요도를 알린다. 하지만 <code>priority=1000</code>인 Pod가 <code>priority=100</code>인 Pod를 밀어낼 수 있다는 사실은 낮은 priority Pod가 안전하게 종료된다는 증명이 아니다. preemption 후보에는 최소한 아래 다섯 사실이 있어야 한다.</p>
<ol>
<li>작업이 멈춰도 고객 데이터나 외부 부작용이 중복되지 않는다.</li>
<li><code>terminationGracePeriodSeconds</code> 안에 checkpoint, offset commit, lease release 또는 safe retry가 끝난다.</li>
<li>PDB가 보호해야 할 replica 수와 충돌하지 않는다.</li>
<li>다시 배치될 node/pool 또는 queue 처리 여력이 있다.</li>
<li>owner가 event와 job outcome을 보고 복구 여부를 판단할 수 있다.</li>
</ol>
<p>예를 들어 image thumbnail 생성 worker는 object key 기반 멱등성이 있고 결과를 overwrite할 수 있다면 좋은 초기 후보다. 반면 결제 capture worker, DB primary, migration job, in-memory session owner는 낮은 priority여도 자동 preemption 후보가 아니다. 비용을 줄이려고 priority를 낮게 준 것이 “강제 종료 승인”으로 해석되면 안 된다.</p>
<h3 id="3-pdb는-모든-중단을-막는-안전망이-아니다">3) PDB는 모든 중단을 막는 안전망이 아니다</h3>
<p>PodDisruptionBudget은 voluntary disruption에 대한 availability budget을 표현한다. scheduler preemption, node failure, application crash처럼 모든 경로에 동일하게 적용된다고 가정하면 위험하다. 기능을 켜기 전에 cluster 버전과 실제 preemption 흐름에서 PDB가 어떻게 관찰되는지 staging으로 검증하고, PDB만으로 stateful workload의 안전을 선언하지 않는다.</p>
<p>특히 <code>minAvailable</code>이나 <code>maxUnavailable</code> 값을 정할 때 replica 수만 세면 부족하다. traffic drain, readiness recovery, cache warm-up, leader election, downstream rate limit까지 포함한 <strong>실제 회복 시간</strong>을 budget에 넣어야 한다. 3 replica API에서 한 Pod가 종료된 뒤 readiness까지 p95 75초가 걸린다면, 30초마다 resize preemption이 반복되는 정책은 replicas가 3개여도 서비스에 압박을 준다.</p>
<h3 id="4-feature-gate-일관성은-최소-조건이다">4) feature gate 일관성은 최소 조건이다</h3>
<p>공식 안내에 따르면 이 기능은 Kubernetes v1.37 이상과 함께 control plane 구성요소(<code>kube-apiserver</code>, <code>kube-scheduler</code>) 및 kubelet에 feature gate를 켜야 한다. 일부 node만 다르거나 rollout 중 설정이 섞이면 resize가 특정 node에서만 다르게 보일 수 있다. Gate가 enabled라는 것은 scheduler action이 가능하다는 뜻이지, workload policy가 준비됐다는 뜻이 아니다.</p>
<p>기술 검증과 운영 승인 기준을 분리한다.</p>
<table>
  <thead>
      <tr>
          <th>층위</th>
          <th>통과 질문</th>
          <th>통과해도 아직 하지 말 일</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>기능성</td>
          <td>Deferred 뒤 scheduler event와 resize complete가 보이는가</td>
          <td>모든 namespace에 gate 적용</td>
      </tr>
      <tr>
          <td>안전성</td>
          <td>victim이 idempotent하게 재시작되고 PDB/SLO 위반이 없는가</td>
          <td>stateful/결제 workload 포함</td>
      </tr>
      <tr>
          <td>효과</td>
          <td>high-priority p99와 error budget이 실제 개선되는가</td>
          <td>capacity 부족을 preemption으로만 해결</td>
      </tr>
      <tr>
          <td>운영성</td>
          <td>on-call이 victim·reason·rollback을 10분 안에 판단하는가</td>
          <td>수동 승인 없는 전면 자동화</td>
      </tr>
  </tbody>
</table>
<h2 id="실무-적용">실무 적용</h2>
<h3 id="1-resize와-퇴출을-같은-capacity-budget으로-모델링한다">1) resize와 퇴출을 같은 capacity budget으로 모델링한다</h3>
<p>resize request를 추가 CPU·memory, victim을 해제 가능한 request, node에 남겨야 할 headroom으로 표현한다. 예를 들어 node allocatable이 8 CPU이고, high-priority Pod가 4→6 CPU로 +2 CPU resize를 원하며 현재 headroom이 1 CPU라면 scheduler는 최소 1 CPU 이상의 victim request를 찾아야 한다. 그러나 여기서 “1 CPU짜리 아무 Pod”가 답은 아니다.</p>
<p>다음처럼 정책을 문서로 만든다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>high-priority resize 허용: API tier-0, request delta &lt;= 1 CPU 또는 2 GiB
</span></span><span style="display:flex;"><span>victim 후보: batch-low, checkpoint 완료 &lt;= 20초, external side effect 없음
</span></span><span style="display:flex;"><span>보호 대상: database, payment, migration, default-priority API
</span></span><span style="display:flex;"><span>node reserve: allocatable의 15% 또는 1 CPU 중 큰 값
</span></span><span style="display:flex;"><span>자동 preemption 상한: node당 1회 / 30분, pool당 3회 / 1시간
</span></span></code></pre></div><p>수치는 예시이며 workload의 recovery p95와 traffic pattern으로 조정해야 한다. 중요한 것은 <code>PriorityClass</code>만 남기지 않고 “resize request의 상한”, “희생 가능 작업”, “남겨 둘 여유”, “반복 횟수”를 한 정책에서 연결하는 점이다. preemption이 잦다면 feature가 잘 작동하는 것이 아니라 request 산정, node packing, HPA/VPA, pool isolation 중 하나가 틀렸다는 신호로 본다.</p>
<h3 id="2-먼저-preemption-없이-deferred를-관찰한다">2) 먼저 preemption 없이 deferred를 관찰한다</h3>
<p>production gate를 바로 활성화하지 말고 staging에서 high/low PriorityClass, 의도적으로 부족한 node headroom, resize subresource RBAC를 만든다. high-priority Pod의 request를 올려 <code>ResizeDeferred</code> event를 확인하고, 다음 이벤트 순서와 실제 cgroup allocation을 기록한다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ResizeDeferred
</span></span><span style="display:flex;"><span>  -&gt; scheduler가 victim 선택 또는 보류한 근거
</span></span><span style="display:flex;"><span>  -&gt; victim Preempted / termination event
</span></span><span style="display:flex;"><span>  -&gt; ResizeStarted
</span></span><span style="display:flex;"><span>  -&gt; ResizeCompleted 또는 다시 Deferred
</span></span></code></pre></div><p>그 다음 production에서는 gate 없이도 deferred 시간, candidate victim, autoscaler action, API SLO를 dashboard로 모은다. 2주 데이터를 보면 resize preemption이 실제로 필요한 희귀 spike인지, 예약 headroom과 node pool 분리로 더 싸게 해결할 구조적 부족인지 구분할 수 있다.</p>
<h3 id="3-단일-pool에서-48시간-제한-canary를-실행한다">3) 단일 pool에서 48시간 제한 canary를 실행한다</h3>
<p>canary는 high-priority API 하나와 재시작 가능한 batch/consumer 하나가 <strong>전용 node pool</strong>에 있는 경우로 제한한다. customer-facing API와 DB, migration, baseline web workload가 섞인 일반 pool은 첫 대상이 아니다. 48시간 동안 다음 기준을 동시에 통과해야 다음 대상으로 넓힌다.</p>
<table>
  <thead>
      <tr>
          <th>지표</th>
          <th>승격 기준</th>
          <th>즉시 중단/rollback 기준</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>의도하지 않은 victim</td>
          <td>0건</td>
          <td>보호 대상 또는 default priority가 1건이라도 victim</td>
      </tr>
      <tr>
          <td>PDB/SLO 위반</td>
          <td>0건</td>
          <td>availability SLO breach 또는 PDB 관련 unexpected event</td>
      </tr>
      <tr>
          <td>resize 완료 시간 p95</td>
          <td>2분 이하 또는 기존 대비 50% 개선</td>
          <td>10분 초과 deferred가 2회</td>
      </tr>
      <tr>
          <td>victim 복구 p95</td>
          <td>checkpoint 포함 2분 이하</td>
          <td>duplicate side effect, data repair 필요</td>
      </tr>
      <tr>
          <td>preemption 빈도</td>
          <td>pool당 3회/시간 미만</td>
          <td>5회/시간이 15분 지속</td>
      </tr>
      <tr>
          <td>high-priority p99</td>
          <td>baseline 대비 악화 없음</td>
          <td>+10%가 10분 지속</td>
      </tr>
  </tbody>
</table>
<p>“preemption 0건”도 성공적인 canary 결과일 수 있다. 실제로는 scheduler가 불필요하게 행동하지 않았고, headroom 또는 autoscaler가 충분했다는 뜻일 수 있다. 이 경우 feature를 더 넓히는 대신 deferred 원인이 node fragmentation인지 request inflation인지 점검하는 편이 좋다.</p>
<h3 id="4-event와-ownership을-runbook에-넣는다">4) event와 ownership을 runbook에 넣는다</h3>
<p>on-call이 high-priority Pod만 보고 “resize가 성공했다”고 끝내면 victim의 backfill·duplicate·queue lag를 놓친다. alert에는 최소한 resize 대상, request delta, node, victim list, PriorityClass, PDB 상태, queue lag, rollback flag가 함께 있어야 한다.</p>
<p>우선순위는 다음처럼 고정할 수 있다.</p>
<ol>
<li>data integrity와 customer action의 중복 여부를 확인한다.</li>
<li>victim workload의 recovery/queue lag가 SLO 안인지 확인한다.</li>
<li>high-priority Pod의 allocation과 p99가 회복됐는지 확인한다.</li>
<li>같은 node/pool에서 재발하면 preemption을 끄고 capacity·autoscaling·packing을 조사한다.</li>
</ol>
<p>이 순서는 high-priority API의 latency가 중요하지 않아서가 아니다. preemption으로 만든 숨은 부채가 늦게 나타나도 되돌릴 수 있도록, 먼저 irreversible side effect를 보는 것이다.</p>
<h2 id="트레이드오프주의점">트레이드오프/주의점</h2>
<h3 id="무중단이라는-단어가-비용을-가린다">&ldquo;무중단&quot;이라는 단어가 비용을 가린다</h3>
<p>in-place resize는 high-priority Pod의 restart를 피할 수 있다. 그러나 그 자원을 만들기 위해 victim이 종료된다면 cluster 전체 관점에서는 가용성 비용을 옮긴 것뿐이다. batch가 안전하게 재시작되는지, queue가 중복을 흡수하는지, downstream가 burst를 견디는지를 증명하지 못하면 무중단이라는 표현을 운영 결론으로 쓰지 않는다.</p>
<h3 id="preemption은-capacity-planning의-대체품이-아니다">preemption은 capacity planning의 대체품이 아니다</h3>
<p>지속적으로 deferred가 발생하는 pool은 피크 capacity가 부족하거나 request가 실제 사용량과 맞지 않거나, heterogeneous workload가 한 node에 섞였을 가능성이 크다. 이 경우 preemption을 자주 허용하면 high-priority 부하는 빨라질 수 있어도 batch starvation, queue lag, noisy-neighbor 문제가 늘어난다. headroom reservation, node pool 분리, HPA/VPA tuning, cluster autoscaler latency를 먼저 비교해야 한다.</p>
<h3 id="alpha-gate는-전체-제어면을-바꾼다">Alpha gate는 전체 제어면을 바꾼다</h3>
<p>기능이 Alpha이고 feature gate가 여러 component에 걸친다는 점도 중요하다. upgrade·rollback 시 gate 조합, node 교체, scheduler event schema, autoscaler와의 상호작용을 실제 버전에서 확인해야 한다. feature gate를 켠 상태에서 policy 오류가 나면 단순 application rollback으로 scheduler behavior가 사라지지 않을 수 있으므로, gate off 절차와 node rollout 영향을 runbook에 함께 둔다.</p>
<h2 id="체크리스트">체크리스트</h2>
<ul>
<li><input disabled="" type="checkbox"> v1.37 이상 control plane과 모든 대상 kubelet의 version/gate 조합을 inventory로 확인했는가?</li>
<li><input disabled="" type="checkbox"> <code>ResizeDeferred</code>, <code>ResizeStarted</code>, <code>ResizeCompleted</code>, <code>Preempted</code> event를 workload·node·PriorityClass별로 조회할 수 있는가?</li>
<li><input disabled="" type="checkbox"> resize 대상의 최대 delta와 node reserve를 숫자로 정했는가?</li>
<li><input disabled="" type="checkbox"> victim 후보가 idempotency, checkpoint/safe retry, termination 시간, queue lease 검증을 통과했는가?</li>
<li><input disabled="" type="checkbox"> PriorityClass 기본값을 암묵적으로 사용하는 Pod와 stateful·결제·migration workload를 자동 victim에서 제외했는가?</li>
<li><input disabled="" type="checkbox"> PDB를 실제 preemption 흐름과 cluster version에서 검증했으며, PDB만을 data integrity 보증으로 쓰지 않는가?</li>
<li><input disabled="" type="checkbox"> 1개 pool·1~2 deployment·48시간 canary의 preemption 상한과 abort 조건을 정했는가?</li>
<li><input disabled="" type="checkbox"> gate off, victim scale-out, high-priority resize 취소의 rollback owner와 10분 이내 판단 기준이 문서화됐는가?</li>
</ul>
<h3 id="연습-restart-없는-확장과-안전한-중단을-함께-증명하기">연습: restart 없는 확장과 안전한 중단을 함께 증명하기</h3>
<ol>
<li>constrained staging node에 4 CPU high-priority Pod와 3 CPU low-priority batch Pod를 배치해 1 CPU headroom을 남긴다.</li>
<li>high-priority Pod를 6 CPU로 resize해 <code>ResizeDeferred</code>가 발생하는지 확인한다.</li>
<li>feature gate를 시험 환경에만 켠 뒤, low-priority Pod가 preempt됐을 때 checkpoint·queue re-delivery·idempotency key가 중복 side effect 없이 복구되는지 검사한다.</li>
<li>high-priority Pod의 <code>allocatedResources</code>, p99, error rate와 low-priority job의 lag·완료 수를 같은 시간축에 놓는다.</li>
<li>마지막으로 victim을 보호 대상(PDB가 있는 stateful Pod 또는 non-idempotent worker)으로 바꾼 fixture에서 automation을 허용하지 않고 alert/abort로 끝나는지 테스트한다.</li>
</ol>
]]></content:encoded></item></channel></rss>