컨테이너에 메모리 리소스 할당하기
컨테이너에 메모리 리소스 할당하기
이 페이지에서는 컨테이너에 메모리 request(요청)와 메모리 limit(상한)을 할당하는 방법을 보여줘요. 컨테이너는 요청한 만큼의 메모리를 보장받지만, 상한 이상의 메모리는 사용할 수 없습니다.
출처: 문서
본문
시작하기 전에
클러스터의 각 노드에는 최소 300 MiB의 메모리가 있어야 해요.
이 페이지의 몇몇 단계는 클러스터에서 metrics-server 서비스를 실행해야 해요. metrics-server가 실행 중이라면 그 단계들을 건너뛸 수 있습니다.
Minikube를 사용 중이라면 다음 명령으로 metrics-server를 활성화해요:
minikube addons enable metrics-server
metrics-server나 리소스 메트릭 API(metrics.k8s.io)의 다른 제공자가 실행 중인지 확인하려면 다음 명령을 실행해요:
kubectl get apiservices
리소스 메트릭 API가 사용 가능하다면 출력에 metrics.k8s.io 참조가 포함됩니다.
NAME
v1beta1.metrics.k8s.io
네임스페이스 만들기
이 연습에서 만드는 리소스가 클러스터의 다른 부분과 격리되도록 네임스페이스를 만들어요.
kubectl create namespace mem-example
메모리 request와 limit 지정하기
컨테이너에 메모리 request를 지정하려면 컨테이너 리소스 매니페스트에 resources.requests.memory 필드를 넣고, 메모리 limit을 지정하려면 resources.limits.memory를 넣어요.
이 연습에서는 컨테이너 하나를 가진 파드를 만들어요. 컨테이너의 메모리 request는 100 MiB, 메모리 limit은 200 MiB입니다. 파드의 구성 파일은 다음과 같아요:
구성 파일의 args 섹션은 컨테이너가 시작될 때 사용할 인자를 제공해요. "--vm-bytes", "150M" 인자는 컨테이너가 150 MiB의 메모리를 할당하려 시도하라고 알려줍니다.
파드를 만들어요:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example
파드 컨테이너가 실행 중인지 확인해요:
kubectl get pod memory-demo --namespace=mem-example
파드에 대한 상세 정보를 확인해요:
kubectl get pod memory-demo --output=yaml --namespace=mem-example
출력은 파드의 컨테이너 하나가 메모리 request 100 MiB, limit 200 MiB를 가진 것을 보여줍니다.
...
resources:
requests:
memory: 100Mi
limits:
memory: 200Mi
...
kubectl top을 실행해 파드의 메트릭을 가져와요:
kubectl top pod memory-demo --namespace=mem-example
출력은 파드가 약 162,900,000 바이트(약 150 MiB)의 메모리를 사용 중임을 보여줘요. 이는 파드의 100 MiB request보다 많지만 200 MiB limit 안에 들어옵니다.
NAME CPU(cores) MEMORY(bytes)
memory-demo <something> 162856960
파드를 삭제해요:
kubectl delete pod memory-demo --namespace=mem-example
컨테이너의 메모리 limit 초과하기
노드에 사용 가능한 메모리가 있다면 컨테이너는 메모리 request를 초과할 수 있어요. 하지만 컨테이너는 메모리 limit 이상을 사용할 수 없습니다. 컨테이너가 limit보다 많은 메모리를 할당하면 종료 후보가 되고, 계속해서 limit을 넘는 메모리를 소비하면 컨테이너는 종료됩니다. 종료된 컨테이너를 다시 시작할 수 있다면, kubelet은 다른 런타임 실패와 마찬가지로 컨테이너를 다시 시작해요.
이 연습에서는 limit보다 많은 메모리를 할당하려 시도하는 파드를 만들어요. 메모리 request 50 MiB, limit 100 MiB인 컨테이너 하나를 가진 파드의 구성 파일은 다음과 같아요:
구성 파일의 args 섹션에서 컨테이너가 100 MiB limit을 훨씬 넘는 250 MiB의 메모리를 할당하려 시도할 것임을 알 수 있어요.
파드를 만들어요:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example
파드에 대한 상세 정보를 확인해요:
kubectl get pod memory-demo-2 --namespace=mem-example
이 시점에 컨테이너는 실행 중이거나 종료됐을 수 있어요. 컨테이너가 종료될 때까지 앞선 명령을 반복해요:
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
컨테이너 상태를 더 자세히 확인해요:
kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example
출력은 컨테이너가 메모리 부족(OOM)으로 종료됐음을 보여줍니다:
lastState:
terminated:
containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null
이 연습의 컨테이너는 다시 시작할 수 있으므로 kubelet이 다시 시작해요. 컨테이너가 반복해서 종료·재시작되는 걸 보려면 이 명령을 여러 번 반복해요:
kubectl get pod memory-demo-2 --namespace=mem-example
출력은 컨테이너가 종료되고, 다시 시작되고, 또 종료되고, 또 다시 시작되는 식으로 계속됨을 보여줍니다:
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s
파드 히스토리에 대한 상세 정보를 확인해요:
kubectl describe pod memory-demo-2 --namespace=mem-example
출력은 컨테이너가 시작과 실패를 반복함을 보여줍니다:
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container
클러스터 노드에 대한 상세 정보를 확인해요:
kubectl describe nodes
출력에는 메모리 부족 상태로 인해 컨테이너가 종료된 기록이 포함됩니다:
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child
파드를 삭제해요:
kubectl delete pod memory-demo-2 --namespace=mem-example
노드 용량보다 큰 메모리 request 지정하기
메모리 request와 limit은 컨테이너와 연결되어 있지만, 파드가 메모리 request와 limit을 가진다고 생각하는 게 유용해요. 파드의 메모리 request는 파드 안 모든 컨테이너의 메모리 request의 합이고, 파드의 메모리 limit 역시 파드 안 모든 컨테이너의 limit 합입니다.
파드 스케줄링은 request를 기준으로 해요. 파드는 노드에 스케줄되기 위해 노드가 파드의 메모리 request를 충족할 만큼 충분한 메모리를 가져야 해요.
이 연습에서는 클러스터의 어떤 노드 용량도 초과하는 큰 메모리 request를 가진 파드를 만들어요. 클러스터의 어떤 노드 용량도 초과할 가능성이 있는 1000 GiB 메모리를 요청하는 컨테이너 하나를 가진 파드의 구성 파일은 다음과 같아요:
파드를 만들어요:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example
파드 상태를 확인해요:
kubectl get pod memory-demo-3 --namespace=mem-example
출력은 파드 상태가 PENDING임을 보여줘요. 즉 파드가 어떤 노드에도 스케줄되지 않았고, 계속 PENDING 상태로 남아 있습니다:
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
이벤트를 포함한 파드에 대한 상세 정보를 확인해요:
kubectl describe pod memory-demo-3 --namespace=mem-example
출력은 노드의 메모리가 부족해 컨테이너를 스케줄할 수 없음을 보여줍니다:
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
메모리 단위
메모리 리소스는 바이트 단위로 측정돼요. 메모리는 일반 정수나 E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki 접미사가 붙은 고정 소수점 정수로 표현할 수 있습니다. 예를 들어 다음은 모두 거의 같은 값을 나타냅니다:
128974848, 129e6, 129M, 123Mi
파드를 삭제해요:
kubectl delete pod memory-demo-3 --namespace=mem-example
메모리 limit을 지정하지 않으면
컨테이너에 메모리 limit을 지정하지 않으면 다음 중 하나가 적용돼요:
-
컨테이너가 사용하는 메모리 양에 상한이 없다. 컨테이너는 실행 중인 노드의 사용 가능한 모든 메모리를 사용할 수 있고, 이로 인해 OOM Killer가 호출될 수 있어요. 또한 OOM Kill이 발생하면 리소스 limit이 없는 컨테이너가 종료될 확률이 더 높아요.
-
컨테이너가 기본 메모리 limit이 있는 네임스페이스에서 실행 중이며, 컨테이너에 자동으로 기본 limit이 할당된다. 클러스터 관리자는 LimitRange를 사용해 메모리 limit의 기본값을 지정할 수 있어요.
메모리 request와 limit의 동기
클러스터에서 실행되는 컨테이너에 메모리 request와 limit을 구성하면 클러스터 노드의 메모리 리소스를 효율적으로 사용할 수 있어요. 파드의 메모리 request를 낮게 유지하면 파드가 스케줄될 가능성이 높아지고, 메모리 limit을 request보다 크게 하면 두 가지를 얻을 수 있습니다:
- 파드는 우연히 사용 가능한 메모리를 활용하는 버스트 활동을 할 수 있다.
- 버스트 동안 파드가 사용할 수 있는 메모리 양이 합리적인 수준으로 제한된다.
정리하기
네임스페이스를 삭제해요. 이러면 이 작업을 위해 만든 모든 파드가 삭제됩니다:
kubectl delete namespace mem-example
더 알아보기 (Learn more)
앱 개발자용
- 컨테이너와 파드에 CPU 리소스 할당하기
- 파드 레벨 CPU·메모리 리소스 할당하기
- 파드에 대한 Quality of Service 구성하기
- 컨테이너에 할당된 CPU·메모리 리소스 크기 조정하기