|
| 1 | +--- |
| 2 | +title: 컨테이너에 할당된 CPU 및 메모리 리소스 리사이즈 |
| 3 | +content_type: task |
| 4 | +weight: 30 |
| 5 | +min-kubernetes-server-version: 1.33 |
| 6 | +--- |
| 7 | + |
| 8 | + |
| 9 | +<!-- overview --> |
| 10 | + |
| 11 | +{{< feature-state feature_gate_name="InPlacePodVerticalScaling" >}} |
| 12 | + |
| 13 | +이 페이지는 *파드를 재생성하지 않으면서* 컨테이너에 할당된 CPU 및 메모리 리소스 |
| 14 | +요청량과 제한량을 변경하는 방법을 설명한다. |
| 15 | + |
| 16 | +전통적으로 파드의 리소스 요구사항을 변경하려면 기존 파드를 삭제하고 |
| 17 | +[워크로드 컨트롤러](/docs/concepts/workloads/controllers/)에 의해 관리되는 대체 파드를 생성해야 했다. |
| 18 | +인플레이스(In-place) 파드 리사이즈를 사용하면 실행 중인 파드 내에서 컨테이너의 CPU/메모리 할당량을 변경할 수 있으며, |
| 19 | +애플리케이션 중단을 피할 수 있다. 파드 리소스 리사이즈에 대한 프로세스는 [파드에 할당된 CPU 및 메모리 리소스 리사이즈](/docs/tasks/configure-pod-container/resize-pod-resources)에서 다룬다. |
| 20 | + |
| 21 | +**핵심 개념:** |
| 22 | + |
| 23 | +* **원하는 리소스(Desired Resources):** 컨테이너의 `spec.containers[*].resources`는 |
| 24 | + 해당 컨테이너가 *원하는* 리소스를 나타내며, CPU와 메모리에 대해 변경 가능하다. |
| 25 | +* **실제 리소스(Actual Resources):** `status.containerStatuses[*].resources` |
| 26 | + 필드는 실행 중인 컨테이너에 *현재 구성된* 리소스를 반영한다. |
| 27 | + 아직 시작되지 않았거나 재시작된 컨테이너의 경우, |
| 28 | + 다음 시작 시 할당될 리소스를 반영한다. |
| 29 | +* **리사이즈 트리거(Triggering a Resize):** 파드 명세에서 원하는 `requests`와 |
| 30 | + `limits`를 업데이트하여 리사이즈를 요청할 수 있다. |
| 31 | + 이는 일반적으로 파드의 `resize` 서브리소스를 대상으로 하는 `kubectl patch`, |
| 32 | + `kubectl apply`, 또는 `kubectl edit`을 사용하여 수행된다. |
| 33 | + 원하는 리소스와 할당된 리소스가 일치하지 않으면 kubelet이 |
| 34 | + 컨테이너 크기를 조정하려고 시도한다. |
| 35 | +* **할당된 리소스(고급):** |
| 36 | + `status.containerStatuses[*].allocatedResources` 필드는 kubelet에서 확인된 |
| 37 | + 리소스 값을 추적하며, 주로 내부 스케줄링 로직에 사용된다. 대부분의 모니터링 및 |
| 38 | + 검증 목적에서는 `status.containerStatuses[*].resources`에 집중하면 된다. |
| 39 | + |
| 40 | +노드에 보류 중이거나 불완전한 리사이즈가 있는 파드가 있는 경우([파드 리사이즈 상태](#파드-리사이즈-상태) 참조), |
| 41 | +{{< glossary_tooltip text="스케줄러" term_id="kube-scheduler" >}}는 |
| 42 | +스케줄링 결정을 내릴 때 컨테이너의 원하는 요청량, 할당된 요청량, 상태의 실제 |
| 43 | +요청량 중 *최대값*을 사용한다. |
| 44 | + |
| 45 | +## {{% heading "prerequisites" %}} |
| 46 | + |
| 47 | + |
| 48 | +{{< include "task-tutorial-prereqs.md" >}}{{< version-check >}} |
| 49 | + |
| 50 | +컨트롤 플레인과 클러스터의 모든 노드에서 |
| 51 | +`InPlacePodVerticalScaling` [기능 게이트](/docs/reference/command-line-tools-reference/feature-gates/)가 |
| 52 | +활성화되어 있어야 한다. |
| 53 | + |
| 54 | +`--subresource=resize` 플래그를 사용하려면 `kubectl` 클라이언트 버전이 최소 v1.32 이상이어야 한다. |
| 55 | + |
| 56 | +## 파드 리사이즈 상태 |
| 57 | + |
| 58 | +kubelet은 리사이즈 요청의 상태를 나타내기 위해 파드의 상태 조건을 업데이트한다. |
| 59 | + |
| 60 | +* `type: PodResizePending`: kubelet이 요청을 즉시 승인할 수 없다. |
| 61 | + `message` 필드에서 이유에 대한 설명을 제공한다. |
| 62 | + * `reason: Infeasible`: 요청된 리사이즈가 현재 노드에서 불가능하다(예: 노드가 가진 것보다 더 많은 리소스 요청). |
| 63 | + * `reason: Deferred`: 요청된 리사이즈가 |
| 64 | + 현재는 불가능하지만, 나중에 가능할 수 있다 |
| 65 | + (예: 다른 파드가 제거된 경우). |
| 66 | + kubelet이 리사이즈를 재시도한다. |
| 67 | +* `type: PodResizeInProgress`: kubelet이 리사이즈를 승인하고 리소스를 |
| 68 | + 할당했지만, 변경사항이 아직 적용 중이다. |
| 69 | + 이는 보통 짧은 시간이지만 리소스 유형과 런타임 동작에 따라 더 오래 걸릴 수 있다. |
| 70 | + 실행 중 오류는 `message` 필드에 (`reason: Error`와 함께) 보고된다. |
| 71 | + |
| 72 | +### Kubelet의 지연된 리사이즈 재시도 방식 |
| 73 | + |
| 74 | +요청된 리사이즈가 _Deferred_ 으로 표시되면, kubelet은 주기적으로 리사이즈를 재시도한다. |
| 75 | +예를 들어, 다른 파드가 제거되거나 스케일 다운되는 경우에 해당한다. 지연된 리사이즈가 |
| 76 | +여러 개인 경우, 다음 우선순위에 따라 재시도를 한다. |
| 77 | + |
| 78 | +* 우선순위가 높은 파드(PriorityClass 기준)의 리사이즈 요청이 먼저 재시도된다. |
| 79 | +* 두 파드의 우선순위가 같은 경우, Guaranteed 파드의 리사이즈가 Burstable 파드의 리사이즈보다 먼저 재시도된다. |
| 80 | +* 다른 모든 조건이 동일한 경우, 지연 상태에 더 오래 있었던 파드가 우선적으로 재시도된다. |
| 81 | + |
| 82 | +우선순위가 높은 리사이즈가 보류 중으로 표시되더라도 나머지 보류 중인 리사이즈 시도가 차단되지는 않는다. |
| 83 | +우선순위가 높은 리사이즈가 다시 지연되더라도 나머지 모든 보류 중인 리사이즈는 계속 재시도된다. |
| 84 | + |
| 85 | + |
| 86 | +### `observedGeneration` 필드 활용 |
| 87 | + |
| 88 | +{{< feature-state feature_gate_name="PodObservedGenerationTracking" >}} |
| 89 | + |
| 90 | +* 최상위 `status.observedGeneration` 필드는 kubelet이 승인한 최신 파드 사양에 해당하는 `metadata.generation`을 보여준다. 이 필드를 사용하여 kubelet이 처리한 가장 최근의 리사이즈 요청을 확인할 수 있다. |
| 91 | +* `PodResizeInProgress` 상태에서 `conditions[].observedGeneration` 필드는 현재 진행 중인 리사이즈가 시작되었을 때의 파드 사양에서 `metadata.generation`을 나타낸다. |
| 92 | +* `PodResizePending` 상태에서 `conditions[].observedGeneration` 필드는 보류 중인 리사이즈에 대한 할당이 마지막으로 시도되었을 때의 파드 사양에서 `metadata.generation`을 나타낸다. |
| 93 | + |
| 94 | +## 컨테이너 리사이즈 정책 |
| 95 | + |
| 96 | +컨테이너 명세에서 `resizePolicy`를 설정하여 크기를 조정할 때 컨테이너를 |
| 97 | +재시작해야 하는지 여부를 제어할 수 있다. |
| 98 | +이를 통해 리소스 유형(CPU 또는 메모리)에 따른 세밀한 제어가 가능하다. |
| 99 | + |
| 100 | +```yaml |
| 101 | + resizePolicy: |
| 102 | + - resourceName: cpu |
| 103 | + restartPolicy: NotRequired |
| 104 | + - resourceName: memory |
| 105 | + restartPolicy: RestartContainer |
| 106 | +``` |
| 107 | +
|
| 108 | +* `NotRequired`: (기본값) 컨테이너를 재시작하지 않고 실행 중인 컨테이너에 리소스 변경을 적용한다. |
| 109 | +* `RestartContainer`: 새로운 리소스 값을 적용하기 위해 컨테이너를 재시작한다. |
| 110 | + 많은 애플리케이션과 런타임이 메모리 할당을 동적으로 조정할 수 없기 때문에 |
| 111 | + 메모리 변경 시 종종 필요하다. |
| 112 | + |
| 113 | +리소스에 대해 `resizePolicy[*].restartPolicy`가 지정되지 않은 경우, 기본값은 `NotRequired`이다. |
| 114 | + |
| 115 | +{{< note >}} |
| 116 | +파드의 전체 `restartPolicy`가 `Never`인 경우, 모든 리소스에 대해 컨테이너 `resizePolicy`는 `NotRequired`여야 한다. |
| 117 | +그런 파드에서는 재시작이 필요한 리사이즈 정책을 구성할 수 없다. |
| 118 | +{{< /note >}} |
| 119 | + |
| 120 | +**예시 시나리오:** |
| 121 | + |
| 122 | +CPU에 대해 `restartPolicy: NotRequired`로, 메모리에 대해 `restartPolicy: RestartContainer`로 구성된 컨테이너를 고려해보자. |
| 123 | +* CPU 리소스만 변경된 경우, 컨테이너는 인플레이스에서 크기가 조정된다. |
| 124 | +* 메모리 리소스만 변경된 경우, 컨테이너가 재시작된다. |
| 125 | +* CPU와 메모리 리소스가 *동시에* 변경된 경우, (메모리 정책으로 인해) 컨테이너가 재시작된다. |
| 126 | + |
| 127 | +## 제한사항 |
| 128 | + |
| 129 | +쿠버네티스 {{< skew currentVersion >}}에서 파드 리소스의 인플레이스 리사이즈에는 다음 제한사항이 있다. |
| 130 | + |
| 131 | +* **리소스 유형:** CPU와 메모리 리소스만 크기를 조정할 수 있다. |
| 132 | +* **메모리 감소:** 메모리 리사이즈 후 재시작 정책이 `NotRequired`(또는 지정되지 않음)인 경우, kubelet은 메모리 제한을 줄일 때 |
| 133 | + oom-kill을 방지하기 위해 최선을 다하지만, 어떠한 보장도 제공하지 않는다. |
| 134 | + 컨테이너의 메모리 제한을 줄이기 전에 메모리 사용량이 요청된 제한을 초과하면 리사이즈가 건너뛰어지고 |
| 135 | + 상태는 "진행 중"으로 유지된다. 이는 검사 직후 메모리 사용량이 급증할 수 있는 |
| 136 | + 경쟁 조건에 여전히 취약하기 때문에 최선을 다하는 것으로 간주한다. |
| 137 | +* **QoS 클래스:** 파드의 원래 [서비스 품질(QoS) 클래스](/docs/concepts/workloads/pods/pod-qos/)(Guaranteed, Burstable, 또는 BestEffort)는 |
| 138 | + 생성 시 결정되며 리사이즈로 **변경할 수 없다**. 리사이즈된 리소스 값은 |
| 139 | + 여전히 원래 QoS 클래스의 규칙을 준수해야 한다. |
| 140 | + * *Guaranteed*: 리사이즈 후에도 CPU와 메모리 모두에 대해 요청량이 제한량과 계속 같아야 한다. |
| 141 | + * *Burstable*: CPU와 메모리 *모두*에 대해 요청량과 제한량이 동시에 같아질 수 없다 |
| 142 | + (이는 Guaranteed로 변경될 것이므로). |
| 143 | + * *BestEffort*: 리소스 요구사항(`requests` 또는 `limits`)을 추가할 수 없다 |
| 144 | + (이는 Burstable 또는 Guaranteed로 변경될 것이므로). |
| 145 | +* **컨테이너 유형:** 재시작할 수 없는 {{< glossary_tooltip text="초기화 컨테이너" term_id="init-container" >}}와 |
| 146 | + {{< glossary_tooltip text="임시 컨테이너" term_id="ephemeral-container" >}}는 크기를 조정할 수 없다. |
| 147 | + [사이드카 컨테이너](/docs/concepts/workloads/pods/sidecar-containers/)는 크기를 조정할 수 있다. |
| 148 | +* **리소스 제거:** 리소스 요청량과 제한량은 한 번 설정되면 |
| 149 | + 완전히 제거할 수 없으며, 다른 값으로만 변경할 수 있다. |
| 150 | +* **운영 체제:** 윈도우 파드는 인플레이스 리사이즈를 지원하지 않는다. |
| 151 | +* **노드 정책:** [정적 CPU 또는 메모리 관리자 정책](/docs/tasks/administer-cluster/cpu-management-policies/)에 의해 관리되는 파드는 |
| 152 | + 인플레이스에서 크기를 조정할 수 없다. |
| 153 | +* **스왑:** [스왑 메모리](/docs/concepts/architecture/nodes/#swap-memory)를 활용하는 파드는 메모리에 대한 |
| 154 | + `resizePolicy`가 `RestartContainer`가 아닌 경우 메모리 요청량을 리사이즈할 수 없다. |
| 155 | + |
| 156 | +이러한 제한사항은 향후 쿠버네티스 버전에서 완화될 수 있다. |
| 157 | + |
| 158 | +## 네임스페이스 생성 |
| 159 | + |
| 160 | +이 연습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다. |
| 161 | + |
| 162 | +```shell |
| 163 | +kubectl create namespace qos-example |
| 164 | +``` |
| 165 | + |
| 166 | +## 예시 1: 재시작 없는 CPU 리사이즈 |
| 167 | + |
| 168 | +먼저, 인플레이스 CPU 리사이즈와 재시작이 필요한 메모리 리사이즈를 위해 설계된 파드를 생성한다. |
| 169 | + |
| 170 | +{{% code_sample file="pods/resource/pod-resize.yaml" %}} |
| 171 | + |
| 172 | +파드를 생성한다. |
| 173 | + |
| 174 | +```shell |
| 175 | +kubectl create -f pod-resize.yaml -n qos-example |
| 176 | +``` |
| 177 | + |
| 178 | +이 파드는 Guaranteed QoS 클래스에서 시작된다. 초기 상태를 확인한다. |
| 179 | + |
| 180 | +```shell |
| 181 | +# 파드가 실행될 때까지 잠시 기다린다 |
| 182 | +kubectl get pod resize-demo --output=yaml -n qos-example |
| 183 | +``` |
| 184 | + |
| 185 | +`spec.containers[0].resources`와 `status.containerStatuses[0].resources`를 관찰한다. |
| 186 | +이들은 매니페스트와 일치해야 한다(700m CPU, 200Mi 메모리). `status.containerStatuses[0].restartCount`를 확인한다(0이어야 함). |
| 187 | + |
| 188 | +이제 CPU 요청량과 제한량을 `800m`로 증가시킨다. `--subresource resize` 커맨드라인 인수와 함께 `kubectl patch`를 사용한다. |
| 189 | + |
| 190 | +```shell |
| 191 | +kubectl patch pod resize-demo -n qos-example --subresource resize --patch \ |
| 192 | + '{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}' |
| 193 | +
|
| 194 | +# 다른 방법: |
| 195 | +# kubectl -n qos-example edit pod resize-demo --subresource resize |
| 196 | +# kubectl -n qos-example apply -f <수정된-매니페스트> --subresource resize --server-side |
| 197 | +``` |
| 198 | + |
| 199 | +{{< note >}} |
| 200 | +`--subresource resize` 커맨드라인 인수는 `kubectl` 클라이언트 버전 v1.32.0 이상이 필요하다. |
| 201 | +이전 버전은 `invalid subresource` 오류를 보고한다. |
| 202 | +{{< /note >}} |
| 203 | + |
| 204 | +패치 후 파드 상태를 다시 확인한다. |
| 205 | + |
| 206 | +```shell |
| 207 | +kubectl get pod resize-demo --output=yaml --namespace=qos-example |
| 208 | +``` |
| 209 | + |
| 210 | +다음을 확인할 수 있어야 한다. |
| 211 | +* `spec.containers[0].resources`는 이제 `cpu: 800m`를 보여준다. |
| 212 | +* `status.containerStatuses[0].resources`도 `cpu: 800m`를 보여주며, 노드에서 리사이즈가 성공했음을 나타낸다. |
| 213 | +* `status.containerStatuses[0].restartCount`는 `0`으로 유지된다. CPU `resizePolicy`가 `NotRequired`였기 때문이다. |
| 214 | + |
| 215 | +## 예시 2: 재시작이 있는 메모리 리사이즈 |
| 216 | + |
| 217 | +이제 *동일한* 파드의 메모리를 `300Mi`로 증가시켜 크기를 조정한다. |
| 218 | +메모리 `resizePolicy`가 `RestartContainer`이므로 컨테이너가 재시작될 것으로 예상된다. |
| 219 | + |
| 220 | +```shell |
| 221 | +kubectl patch pod resize-demo -n qos-example --subresource resize --patch \ |
| 222 | + '{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"memory":"300Mi"}, "limits":{"memory":"300Mi"}}}]}}' |
| 223 | +``` |
| 224 | + |
| 225 | +패치 직후 파드 상태를 확인한다. |
| 226 | + |
| 227 | +```shell |
| 228 | +kubectl get pod resize-demo --output=yaml --namespace=qos-example |
| 229 | +``` |
| 230 | + |
| 231 | +이제 다음을 관찰할 수 있어야 한다. |
| 232 | +* `spec.containers[0].resources`는 `memory: 300Mi`를 보여준다. |
| 233 | +* `status.containerStatuses[0].resources`도 `memory: 300Mi`를 보여준다. |
| 234 | +* `status.containerStatuses[0].restartCount`가 `1`로 증가했다(또는 이전에 재시작이 발생했다면 더 많이), |
| 235 | + 메모리 변경을 적용하기 위해 컨테이너가 재시작되었음을 나타낸다. |
| 236 | + |
| 237 | +## 문제 해결: 실행 불가능한 리사이즈 요청 |
| 238 | + |
| 239 | +다음으로, 노드 용량을 초과할 가능성이 높은 1000개의 전체 코어(`"1000m"` 밀리코어 대신 `"1000"`으로 작성)와 같은 비합리적인 양의 CPU를 요청해 본다. |
| 240 | + |
| 241 | +```shell |
| 242 | +# 과도하게 큰 CPU 요청으로 패치 시도 |
| 243 | +kubectl patch pod resize-demo -n qos-example --subresource resize --patch \ |
| 244 | + '{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"1000"}, "limits":{"cpu":"1000"}}}]}}' |
| 245 | +``` |
| 246 | + |
| 247 | +파드의 세부사항을 조회한다. |
| 248 | + |
| 249 | +```shell |
| 250 | +kubectl get pod resize-demo --output=yaml --namespace=qos-example |
| 251 | +``` |
| 252 | + |
| 253 | +문제를 나타내는 변경사항을 확인할 수 있다. |
| 254 | + |
| 255 | +* `spec.containers[0].resources`는 *원하는* 상태(`cpu: "1000"`)를 반영한다. |
| 256 | +* `type: PodResizePending`과 `reason: Infeasible`이 있는 조건이 파드에 추가되었다. |
| 257 | +* 조건의 `message`는 이유를 설명한다(`Node didn't have enough capacity: cpu, requested: 800000, capacity: ...`). |
| 258 | +* 중요한 것은, 실행 불가능한 리사이즈가 kubelet에 의해 적용되지 않았기 때문에 `status.containerStatuses[0].resources`는 |
| 259 | + *여전히 이전 값*(`cpu: 800m`, `memory: 300Mi`)을 보여준다는 것이다. |
| 260 | +* 이 실패한 시도로 인해 `restartCount`는 변경되지 않는다. |
| 261 | + |
| 262 | +이를 해결하려면 실행 가능한 리소스 값으로 파드를 다시 패치해야 한다. |
| 263 | + |
| 264 | +## 정리 |
| 265 | + |
| 266 | +네임스페이스를 삭제한다. 이렇게 하면 이 작업을 위해 생성한 모든 파드를 삭제한다. |
| 267 | + |
| 268 | +```shell |
| 269 | +kubectl delete namespace qos-example |
| 270 | +``` |
| 271 | + |
| 272 | +## {{% heading "whatsnext" %}} |
| 273 | + |
| 274 | + |
| 275 | +### 애플리케이션 개발자를 위한 추가 자료 |
| 276 | + |
| 277 | +* [컨테이너 및 파드 메모리 리소스 할당](/docs/tasks/configure-pod-container/assign-memory-resource/) |
| 278 | + |
| 279 | +* [컨테이너 및 파드 CPU 리소스 할당](/docs/tasks/configure-pod-container/assign-cpu-resource/) |
| 280 | + |
| 281 | +* [파드 수준 CPU 및 메모리 리소스 할당](/docs/tasks/configure-pod-container/assign-pod-level-resources/) |
| 282 | + |
| 283 | +### 클러스터 관리자를 위한 추가 자료 |
| 284 | + |
| 285 | +* [네임스페이스에 대한 기본 메모리 요청량과 제한량 구성](/docs/tasks/administer-cluster/manage-resources/memory-default-namespace/) |
| 286 | + |
| 287 | +* [네임스페이스에 대한 기본 CPU 요청량과 제한량 구성](/docs/tasks/administer-cluster/manage-resources/cpu-default-namespace/) |
| 288 | + |
| 289 | +* [네임스페이스에 대한 최소 및 최대 메모리 제약 조건 구성](/docs/tasks/administer-cluster/manage-resources/memory-constraint-namespace/) |
| 290 | + |
| 291 | +* [네임스페이스에 대한 최소 및 최대 CPU 제약 조건 구성](/docs/tasks/administer-cluster/manage-resources/cpu-constraint-namespace/) |
| 292 | + |
| 293 | +* [네임스페이스에 대한 메모리 및 CPU 쿼터 구성](/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/) |
0 commit comments