서론
우리가 kubernetes를 사용하는 목적은 많지만, 가장 큰 목적은 "효율적인 자원의 관리"라고 생각합니다. 쿠버네티스 deployment 오브젝트를 통해 pod를 생성할 때 파드의 리소스를 효율적으로 관리하는 방법을 알아보도록 하겠습니다.
본론
1.. spec.replicas
디플로이먼트에서는. spec.replicas 스펙을 통해서 replicasets을 조절 가능합니다. 아래와 같이 spec 하위에 replicas의 개수로 배포되는 파드의 레플리카 수를 조절할 수 있는 건 다들 아실 텝니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
그렇다면, 각 파드들은 어떻게 노드로부터 리소스(cpu, memory 등)를 할당받아서 사용할 수 있을까요??
2. 파드 및 컨테이너 리소스 관리하기
사실 저희는 파드를 지정할 때, 컨테이너에 필요한 각 리소스의 양을 선택적으로 지정할 수 있습니다. 가장 일반적인 리소스는 CPU와 메모리(RAM)입니다. 파드에서 컨테이너에 대한 리소스 요청(request)을 지정하게 되면, kube-scheduler는 이 정보를 사용하여 파드가 배치될 노드를 결정합니다.
컨테이너에 대한 리소스 제한(limit)을 지정하면, kubelet은 실행 중인 컨테이너가 설정한 제한보다 많은 리소스를 사용할 수 없도록 해당 제한을 적용하여 줍니다.
2-1. 요청 및 제한하는 방법
파드가 실행 중인 노드에 사용 가능한 리소스가 충분하다면, 컨테이너가 해당 리소스에 지정한 request보다 더 많은 리소스를 사용할 수 있도록 허용하는 게 기본이고, 컨테이너는 limit보다 더 많은 리소스를 사용할 수 없게 됩니다. 예를 들어서, 컨테이너에 대해 256 Mib의 memory 요청을 설정하고, 해당 컨테이너가 8 Gib의 메모리를 가진 노드로 스케줄 된 파드에 있고 다른 파드는 없는 경우, 컨테이너는 더 많은 RAM을 사용할 수 있게 되는 것입니다.
해당 컨테이너에 4 Gib 메모리 제한을 설정하면 kubelet, 컨테이너 런타임들이 제한을 적용하게 됩니다. 런타임은 컨테이너가 구성된 리소스 제한을 초과하여 사용하지 못하게 막는데, 예를 들어서 컨테이너의 프로세스가 허용된 양보다 많은 메모리를 사용하려고 한다면 시스템 커널은 out of memory (OOM) 오류와 함께 할당을 시도한 프로세스를 종료시키게 됩니다.
때문에 제한은 반응적 혹은 강제적으로 구현할 수 있고, 런타임마다 다른 방식으로 동일한 제약을 구현하는 것도 가능합니다.
2-2. 파드와 컨테이너의 리소스 요청 제한
각 컨테이너에 대해, 다음과 같은 리소스 제한(limit) 및 요청(request)을 지정할 수 있습니다.
- spec.containers[].resources.limits.cpu
- spec.containers[].resources.limits.memory
- spec.containers[].resources.limits.hugepages-<size>
- spec.containers[].resources.requests.cpu
- spec.containers[].resources.requests.memory
- spec.containers[].resources.requests.hugepages-<size>
apiVersion: apps/v1
kind: Deployment
metadata:
name: mingyu-api-deployment # deployment의 이름
namespace: test
labels:
app: mingyu-api-deployment # deployment의 라벨
spec:
replicas: 2
selector:
matchLabels:
app: mingyu-api-deployment
template:
metadata:
labels:
app: mingyu-api-deployment
spec:
containers:
- name: mingyu-api
image: hub.docker.com/mingyu-api-dev:latest
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
위처럼 deployment.yaml을 작성할 경우, 컨테이너 리소스에 대해 cpu는 250m (1 코어 = 1000m), 메모리는 256 Mib를 요청하여 생성하기에 최소 자원으로 보장받게 됩니다. 다만 사용량이 많아질 경우에는 각 2배씩 향상된 500m cpu에 512 Mib 메모리까지 유동적으로 가용 가능한 리소스가 있다면 사용 가능하게 하겠다는 의미입니다.
2-3. 0/3 nodes are available 오류
클러스터들의 리소스들을 request 하여 최소 필요 용량을 점유하다 보면, 분명 아래와 같은 오류를 맞닥뜨리게 될 것입니다.
0/3 nodes are available: 3 Insufficient cpu. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod.
이 오류는 새로운 파드가 요청한 CPU 리소스를 클러스터 내 어떤 노드에서도 충족시킬 수 없기 때문에 발생합니다. 구체적으로:
- Insufficient cpu: 새 파드가 정의한 CPU 요청량(requests)이 클러스터의 노드들에 남아있는 가용 CPU보다 많습니다.
- No preemption victims found: 스케줄러가 자원을 확보하기 위해 낮은 우선순위의 파드를 강제로 종료(preemption)하려 했지만, 강제로 종료할 만한 후보 파드를 찾지 못했다는 의미입니다.
즉, 파드가 요청한 CPU 리소스가 현재 클러스터(3개 노드)에 남아있는 자원보다 많아서 스케줄링이 불가능한 상태입니다.
해결 방법으로는
- 파드의 CPU 리소스 요청을 줄이거나,
- 클러스터에 더 많은 CPU 자원을 가진 노드를 추가하여 용량을 확장하는 방법이 있습니다.
결론
쿠버테니스에서 파드 및 컨테이너 리소스를 관리하는 방법은 쿠버네티스 공식 문서에 자세히 나와있습니다. 아래 사이트를 참고하여 원하는 방향성에 맞게 애플리케이션 컨테이너의 리소스를 제한하여 안전한 k8s 환경을 운영해 보아요 :)
파드 및 컨테이너 리소스 관리
파드를 지정할 때, 컨테이너에 필요한 각 리소스의 양을 선택적으로 지정할 수 있다. 지정할 가장 일반적인 리소스는 CPU와 메모리(RAM) 그리고 다른 것들이 있다. 파드에서 컨테이너에 대한 리소...
kubernetes.io
댓글