k8s pod 자원 배분에 대해 ..
k8s는 안다고 생각했는데 알고보니 몰랐던 것들이 계속 나온다 .. 이번엔 가장 기본적인 파드 자원 분배에 관한 이런 저런 얘기를 써놓을 예정 .. 계속 추가 예정 ,,
일단 기본적인 개념은 Request, Limit 일 것이다.
- Request : 파드가 노드 안에서 "나는 이만큼 노드의 자원을 쓸 것이다" 라고 선언해두는 값. CPU의 경우 100m 이런식으로 정의할 수 있고, 100m의 경우 0.1cpu라고 보면 된다. Memory는 메가 혹은 기가 단위 등으로 지정 가능.
Req의 특징은 노드에서 제공 가능한 자원 제공량의 제한을 받는다는 것. 예를 들어 하나의 노드에 남은 cpu가 100m 밖에 없다고 하면, 새로운 파드가 생성될 때 110m 짜리가 만들어져야 한다고 하면 그거는 안 만들어지고 pending상태가 유지된다. 이걸 만들려면 110m짜리를 줄여서 들어가거나 다른 파드를 줄이거나 해야 한다. 아니면 노드의 사이즈를 늘리던지. 이거에 대해 잘 모르면 배포할 때 스트레스를 엄청나게 받는다.
꼼수 : 예를 들어 하나의 노드에 파드를 많이 넣고 싶다면, 굳이 100m 이런 식으로 많이 할당해서 지정할 필요 없다. 그냥 10m으로 지정해서 수십개를 넣어놔도 이론상은 문제가 없다. 다만 이렇게 했을 경우, 노드가 과부하가 될 경우 각 파드들의 성능이 매우 느려질 것이다. (10m 씩만 할당되어 있으므로)
하지만 정석대로 200m 이런식으로 할당해 놓으면 노드의 cpu가 아무리 100%를 뚫어도 그 파드는 최소 0.2cpu는 무조건 할당을 받기에 노드의 부하와 상관없이 일정 이상의 성능을 확보할 수 있다.
그러니까 하나의 노드에 수십개의 파드를 넣는 것은 가능하지만, 그렇게 했을 때 노드 과부하 시에 개별 파드들의 성능 하락을 각오해야 한다. 그러므로 상황에 따라 적절하게 설정해야 한다.
- Limit : Request가 "이만큼 쓸 것이다" 라는 선언이라면, Limit 는 "이만큼 쓸 수 있다" 라는 제한이라고 볼 수 있다. 예를 들어 Req를 200m, Limit가 1000m이라고 설정해둔 상태에서 파드가 요청을 많이 받아서 200m을 넘겨야 할 경우 200m은 가볍게 넘기지만, 1000m은 절대 못넘긴다.
그리고 limit의 특징 : 몇으로 정의하든 request와는 다르게 node의 자원 현황에 상관없이 몇으로든 정의할 수 있다.
- GKE나 EKS 같은 Cloud의 Managed kubernetes를 사용할 경우? : 이 경우에는 기본적으로 해당 벤더에서 설치하는 파드들이 있다. 때문에 노드 사이즈를 너무 작게 가져갈 경우, 걔들이 기본적으로 설치하는 파드들만으로 자원 사용량이 꽉 찰 수 있다. 내가 해봤을 때는 벤더의 파드 + 최소한의 내 파드들을 운영하려면 최소한 2개의 vCPU와 4GB RAM은 필수라고 본다.
결론?
k8s의 파드에 대한 자원 분배는 상황에 따라 전략이 달라진다.
예시 1) 노드가 과부하 상태여도 반드시 일정 이상의 성능을 보장해야 하는 중요한 파드다? : Req와 limit 모두 높게 할당한다.
예시 2) 하나의 노드에 매우 많은 여러개의 파드를 넣고 싶다? : 각 파드의 req를 최소판으로 할당해서 넣는다. 근데 만약 그중의 하나가 필요할 때는 자원을 많이 써야 한다? (예를 들어 batching 작업) 그러면은 limit는 높게 설정해두면 평소에 적게 쓰다가도 필요할 때 많은 컴퓨팅 자원을 활용할 수 있다.
req를 많이 할당해 두면 다른 파드 공간이 아까운 거 같고 .. 그렇다고 적게 할당해 두면 노드 과부하 나면 서비스 느려지고 ... 중간점을 잘 찾는 것이 중요해 보인다.
TIP : 노드 과부하 상태를 만들어 보고 싶다면?
노드 과부하 때 Request를 높여 놓으면 과부하여도 그 파드는 잘 동작한다는 걸 테스트하고 싶으면, 아래처럼 하면 된다.
- 파드의 Request 낮춰두기 : 10m 등으로.
- 아래처럼 노드의 cpu를 갈구는 파드를 설치.
# ▼ YOUR_NODE_NAME을 꼭 실제 노드 이름으로 바꾸고 전체를 복사하세요 ▼
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: cpu-villain
spec:
nodeName: [node name] # <--- 여기에 노드 이름을 붙여넣으세요!
containers:
- name: stress
image: polinux/stress
# 5분(300초) 동안 CPU 코어 4개를 풀가동합니다.
command: ["stress"]
args: ["--cpu", "4", "--timeout", "300"]
resources:
requests:
cpu: "10m" # 잠입용: 적게 신고하고
limits:
cpu: "4000m" # 테러용: 엄청나게 씁니다
restartPolicy: Never
EOF- 10m짜리 파드가 속도가 느려지고 restart 하는 등 문제가 발생하는 것을 확인한다.
- 그리고 10m짜리 파드를 500m 등으로 늘리고, 다시 갈궈본다.
- 그러면 노드가 과부하되어도 파드는 정상적으로 동작하는 것을 확인할 수 있다.