쿠버네티스에서는 컨테이너 단위로 리소스 제한 설정이 가능하다.
서비스에 맞는 성능을 내기 위해서도 리소스 제한 설정은 필요하다.
제한이 가능한 리소스는 CPU, 메모리, Ephemeral 스토리이지만, Device Plugins 를 사용하면 GPU 등의 다른 리소스에 대해서도 제한 설정을 할 수 있다.
CPU는 클럭 수로 지정하지 않고, 1vCPU(가상 CPU)를 1,000m(millicores)단위로 지정한다. 그래서 3GHz CPU라고 해도 1코어 정도를 지정할 경우, 3000m가 아닌 1000m가 된다.
리소스 유형 | 단위 |
---|---|
CPU | 1 = 1000m = 1 vCPU |
메모리 | 1G = 1000M (1Gi = 1024Mi) |
리소스 제한은 파드 정의 내부의 각 컨테이너 정의 부분에 포함되고, spec.containers[].resources의 requests.cpu/requests.memory 또는 limits.cpu/limits.memory를 지정하는 형태로 제한한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-healthcheck
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
# command: ["/bin/bash", "-c", "--"]
# args: ["while true; do sleep 30; done;"]
ports:
- containerPort: 80
resources:
requests:
memory: "1024Mi"
cpu: "500m"
limits:
memory: "2048Mi"
cpu: "1000m"
kubectl get nodes -o yaml 로 확인할 수 있는 것은 노드의 총 리소스 양 (capacity)과 할당 가능한 리소스 양 (allocatable) 뿐이므로, 현재 리소스 사용량을 확인할 때는 kubectl describe node를 사용해야 한다.
Requests만 설정한 경우 Limits는 자동으로 설정되지 않고, 호스트 측의 부하가 최대로 상승할 때 까지 리소스를 계속 소비하려고 한다. 그 때문에 이런 파드가 많이 기동하는 노드에서 리소스 뺏기가 발생하고, 메모리의 경우 OOM(Out Of Memory)으로 인해 프로세스 정지로 이어지게 된다.
반대로, Limits만 설정한 경우에는 Limits와 같은 값이 Requests에 설정되게 되어있다. 오버커밋되는 경우 Limits뿐만 아니라 명시적으로 Requests도 설정하도록 하자.
일반적으로 스토리지는 용량 문제나 영속성 관점에서 영구 볼륨을 사용하여 그곳에 데이터를 쓰는 것이 바람직하지만, 컨테이너 재기동 시 삭제되어도 좋은 데이터의 경우에는 컨테이너 내부의 디스크 영역(간접적으로 노드 디스크 영역)을 사용할 수도 있다.
또 애플리케이션이 로그 데이터를 대량으로 출력하는 경우에도 예상치 못하게 쿠버네티스 노드의 디스크 영역을 많이 차지하는 경우가 있다.
이때 사용하는 것이 Ephemeral 스토리지 리소스 제한이다.
쿠버네티스 노드에서 기동 중인 시스템 구성 요소의 kubelet이 디스크 사용 현황을 정기적으로 모니터링하고, 초과한 경우 파드는 축출(Evict)되게 되어있다.
Ephemeral 스토리지 용량으로 계산되는 것은 다음 세가지이다.
컨테이너에서 쓰기로 소비되는 양은 emptyDir에 기록된 데이터와 컨테이너의 쓰기 가능한 레이어에 기록된 데이터의 합계이다.
쓰기 가능한 레이어의 데이터양은 간단히 말하면 영구 볼륨/hostPath/nfs 등이 마운트된 영역을 제외한 모든 영역에 대한 쓰기와 거의 동등하다고 보면 된다.
Ehpemeral 스토리지도 CPU나 메모리와 마찬가지로 Requests와 Limits에 의해 제한을 설정할 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-healthcheck
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
# command: ["/bin/bash", "-c", "--"]
# args: ["while true; do sleep 30; done;"]
ports:
- containerPort: 80
resources:
requests:
ephemeral-storage: "1024Mi"
limits:
ephemeral-storage: "2048Mi"
위의 경우, 2048Mi를 초과하는 데이터를 쓰면 파드는 자동으로 Evict된다.
기본적으로 설정에 따라 시스템용으로 여분 리소스가 확보되거나 빠듯하게 Evict되지 않게 여분의 리소스가 확보되기도 하지만,
ephemeral-storage 사용 제한을 하지 않으면, 예상치 못한 데이터 쓰기로 인해 쿠버네티스 노드의 디스크 용량을 초과하여, 그 노드의 모든 파드에 영향을 줄 가능성도 있음로 주의하여야 한다.
쿠버네티스 1.8 이후 Device Plugins 기능이 지원되어 GPU(NVIDIA/AMD)나 그 외 리소스도 CPU나 메모리와 마찬가지로 Requests/Limits 제한을 설정할 수 있게 되었다.
NVIDIA GPU 의 경우에는 requests와 limits에 nvidia.com/gpu 리소스로 지정한다.
resources:
requests:
nvidia.com/gpu: 2
limits:
nvidia.com/gpu: 2
NVIDIA GPU는 requests에 nvidia.com/gpu를 지정해도 GPU를 점유하지 않기 떄문에 프로그램에 따라서는 경합을 일으킬 수 있다.
특별한 상황이 아니라면, reqeusts와 limits 값을 함께 설정하여 사용하는 것을 추천한다.
그리고 limits만 지정한 경우 자동으로 같은 값이 reqeusts에 설정되기 떄문에 limits만 지정할 수도 있다.