🚀 Resource Request & Limit

Docker에서 --cpu, --memory 옵션을 통해 컨테이너가 실제로 사용할 수 있는 리소스 양을 제한했던 것과 같은 기능을 쿠버네티스에서도 할 수 있다.
파드를 생성할 때 별도로 제한을 걸지 않으면 호스트에 있는 모든 CPU, Memory 자원을 독점해서 사용할 수 있다.
그래서 반드시 적절하게 용량을 지정할 필요가 있다.
- 요청 : request
- 제한 : limit
파드에서 요청이나 제한 또는 모두를 설정할 수 있다. 요청과 제한 모두를 설정하는 것을 권장한다.
🚀 Request (요청)
요청이라는 것은 파드가 리소스를 사용할 때 특정 용량을 요청하는 것이다.
ex) cpu : 1개 memory : 1G 사용할 것이다.
요청을 하게되면 스케줄러(정확하게는 컨테이너를 제어하는 kubelet)이 요청한 만큼을 사용할 수 있도록 보장해준다.
파드가 요청한 양을 모두 사용하던 적게 사용하던 상관없다.
kubelet은 요청한 만큼의 용량을 확보해서 파드에게 제공한다.
만약 호스트가 가진 memory가 3G라고 하고 1번 파드가 memory를 1G 요청하고 2번 파드도 1G를 요청했다고 해보자kubelet은 요청한 만큼을 확보시켜 준다.
필요한 다른 프로세스를 실행하는 것은 고려하지 않고 순수하게 파드만 생각해보면 남은 공간은 1G이다.
만약 3번째 파드가 memory를 1.5G 요청한다면 리소스 용량이 남아있지 않아 할당해줄 수 없다.
그러면 파드의 요청은 실행될 수 없다.
즉, 요청이라고 하는 것은 호스트에게 나에게 요청량만큼을 확보해달라고 하는 것이다.
🚀 Limit (제한)
요청과 제한은 같을 수 있다. 또는 요청보다 제한이 더 클 수 있다.
제한이라고 하는 것은 예를 들자면 파드는 memory 1G를 요청했고 2G로 제한을 걸었을 때
최소한 memory 3G 중에서 1G는 확보해서 무조건 할당해주고 최대 2G까지 늘려서 쓸 수 있다는 것이다.
우선 기본적으로 파드가 start할 때는 1G만큼을 무조건 확보해서 제공한다.
하지만 (제한 - 요청)만큼의 용량은 미리 확보해놓지 않는다.
최대 2G까지 사용할 수 있다는 것이지 실제로 그 용량을 사용할 수 있는가의 여부는 다른 파드의 요청량과 연관이 있다.
vagrant@k8s-node1 ~ kubectl describe pod
QoS Class: BestEffort
QoS(Quality of Service) Class
BestEffort: 가장 나쁨BurstableGuaranteed: 가장 좋음
- 요청/제한이 설정되어 있지 않으면 :
BestEffort - 요청 < 제한 :
Burstable - 요청 = 제한 :
Guranteed
만약 특정 호스트에 파드가 여러개 떠있다면 cpu, memory 자원을 경합하게 될 것이다.
경합시 우선순위는 Guranteed가 제일 높다. 그다음이 Burstable이며 BestEffort가 가장 마지막이다.
그래서 BestEffort는 실제로 리소스를 아예 할당 못받는 경우도 있다.
더 심하게는 RS이 있을 때 삭제되는 제일 첫번째 대상이 BestEffort이다.
리소스가 더 이상없어서 누군가가 죽어야 한다면 그것이 BestEffort가 된다.
이름 그대로 Guranteed는 항상 실행하는 것을 보장한다.Guranteed로 설정되어 있는 것이 너무 많으면 가장 최근에 생성된 것은 또 안될 수도 있다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl explain pod.spec.containers.resources
- request : 용량을 지정한다. map 형식을 사용한다.
- cpu
- memory
- limits
- cpu
- memory
CPU 요청 & 제한 : milicore(m) 단위 사용
ex) 1500m -> cpu 1.5개, 1000m -> cpu 1개 (정확히는 core 1개)
ex) 1.5, .0.1
Memory 요청 & 제한 : M, G, T, Mi, Gi, Ti
myweb-reqlit.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-reqlit
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
resources:
requests:
cpu: 200m
memory: 200M
limits:
cpu: 200m
memory: 200M
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl get po
NAME READY STATUS RESTARTS
myweb-reqlit 1/1 Running 0 4s
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl describe pod myweb-reqlit
QoS Class: Guaranteed
값이 같으면 Guaranteed이다.
resources:
requests:
cpu: 100m
memory: 100M
limits:
cpu: 200m
memory: 200M
limits가 더 큰 경우 기본적으로 requests와 limits값은 수정될 수 없다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl replace -f myweb-reqlim.yaml --force
pod "myweb-reqlit" deleted
pod/myweb-reqlit replaced
--force 옵션을 붙이면 가능한데 기존의 것을 삭제하고 새로 만든다.
📌 만약 특정 필드를 수정하고 싶은데 수정이 안될 때
kubectl explain pod.spec.containers.resources
KIND: Pod
VERSION: v1
RESOURCE: resources <Object>
DESCRIPTION:
Compute Resources required by this container. Cannot be updated.
Cannot be updated.라고 되어있으면 기본적으로 수정할 수 없다.--force 옵션을 붙이면 삭제했다가 다시 만들며 엄밀히 update는 아니다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl describe pod myweb-reqlit
QoS Class: Burstable
Burstable는 requests한 만큼 자유자재로 사용하다가 최대치는 limits까지 올라갈 수 있음을 의미한다.
물론 다른 파드들이 requests로 확보하고 있는 경우에는 못 쓸수도 있다.
더 이상 할당할 수 있는 양이 없으면 Burst할 수 없다.
apiVersion: v1
kind: Pod
metadata:
name: myweb-reqlit
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
resources:
requests:
memory: 100M
limits:
memory: 200M
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl describe pod myweb-reqlit
QoS Class: Burstable
cpu 값을 지워도 Burstable이다.
cpu와 memory 둘 중에 하나라도 세팅되어 있으면 Burstable로 작동한다.
apiVersion: v1
kind: Pod
metadata:
name: myweb-reqlit
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl describe pod myweb-reqlit
QoS Class: BestEffort
requests, limits 어떠한 설정도 가지지 않으면 BestEffort로 작동한다.
나중에 리소스에 대한 경합이 있을 때 리소스를 아예 받지 못하거나 복제본 컨트롤러에서 아예 삭제할 수 있다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node1 151m 8% 1922Mi 59%
node2 100m 5% 1291Mi 50%
node3 95m 5% 1375Mi 53%
top 명령을 사용하면 각 노드가 사용하는 리소스 양을 볼 수 있다.
나는 VM을 생성할 때 cpu : 2개, node1의 memory : 4G node2, 3의 memory : 3G로 세팅했다.
cpu가 2개라는 것은 2000m를 의미하며 현재 node1이 사용하는 양인 151m가 약 7% 정도여야 하지만
메모리에서 커널이 확보해서 사용하는 영역을 제외하고 나머지 영역에 대해서만 계산하기 때문에
전체 용량 중 8%를 말하는 것은 아니다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl get po -A -o wide | grep node1 | wc -l
12
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl get po -A -o wide | grep node2 | wc -l
12
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl get po -A -o wide | grep node3 | wc -l
11
노드마다 떠 있는 파드 개수를 확인할 수 있다.
파드의 개수가 많을 수록 리소스를 더 많이 사용하는 경향을 띈다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl describe node node1
...
Capacity:
cpu: 2
ephemeral-storage: 40593612Ki
hugepages-2Mi: 0
memory: 3927804Ki
pods: 110 # 노드 당 파드 개수는 110개로 제한
Allocatable:
cpu: 1800m
ephemeral-storage: 37411072758
hugepages-2Mi: 0
memory: 3301116Ki
pods: 110
Non-terminated Pods: (12 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 1420m (78%) 400m (22%)
memory 835859200 (24%) 1066231040 (31%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
describe로 노드 정보를 확인하면 Capacity와 Allocatable : 할당할 수 있는 양,
Non-terminated Pods : 실행 중인 파드들
각 파드의 NS와 이름 및 각 파드들의 요청과 제한량을 확인할 수 있다.
0으로 세팅되어 있는 것은 요청과 제한량이 세팅되어 있지 않은 것이며 BestEffort 타입이다.
Allocated resources는 총 cpu의 요청, 제한량 memory의 요청, 제한량을 볼 수 있다.
Requests는 실제로 사용하는 양과 상관없이 미리 확보해놓은 양이므로 스케줄러에의해 할당할 수 없는 영역이다.
ephemeral-storage : emptyDir, configMap, Secret와 같은 임시 스토리지 공간을 의미한다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl top pods -A
NAMESPACE NAME CPU(cores) MEMORY(bytes)
-A 옵션을 붙이면 모든 파드들의 cpu, memory 사용량을 볼 수 있다.
kubectl top명령으로 사용량을 볼 수 있는 이유는 add-on인 metrics-server에 의한 것이다.
해당 add-on이 없을 때 kubectl top명령을 실행하면 오류가 발생한다.
myweb-big.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb-reqlit
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
resources:
limit bnhs:
cpu: 3000m
memory: 4000M
너무 큰 리소스를 요구하여 실행할 수 없는 리소스
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl describe pod myweb-big
Containers:
myweb:
Image: ghcr.io/c1t1d0s7/go-myweb
Port: <none>
Host Port: <none>
Limits:
cpu: 3
memory: 4G
Requests:
cpu: 3
memory: 4G
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2s default-scheduler 0/3 nodes are available: 3 Insufficient cpu, 3 Insufficient memory.
limits만 설정하면 limits양과 똑같은 requests가 자동으로 설정된다.
하지만 requests만 설정하는 경우 limits는 설정되지 않는다.
Events를 보면 FailedScheduling이다.
3개의 노드 중에서 아무것도 가능하지 않다. 즉, 스케줄링 가능한 노드가 하나도 없다는 것이다.
3개의 노드 모두 cpu, memory가 부족하다. 호스트가 가진 양보다 더 많기 때문에 당연히 할당할 수 없다.
vagrant@k8s-node1 ~/autoscaling/reqlim kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-big 0/1 Pending 0 2m15s
Pending상태임을 확인할 수 있다.
파드의 라이프 사이클에서 Pending라는 의미는
- 이미지를 받고 있거나
- 볼륨을 연결하는 중이거나
- 스케줄링 되기 전
순서대로 보면 스케줄링되고 볼륨을 찾았을 때 볼륨이 있어야 하며 그다음 이미지를 받는다.
Pending 상태가 너무 오랫동안 지속되면 다음 세가지 중에 하나를 의심해봐야 한다.
'DevOps > Kubernetes' 카테고리의 다른 글
| [Kubernetes] Pod Scheduling ( + kube-scheduler, nodeName, nodeSelector) (0) | 2022.06.05 |
|---|---|
| [Kubernetes] HPA : Horisontal Pod AutoScaler (파드의 오토 스케일링) (0) | 2022.06.04 |
| [Kubernetes] StatefulSet (스테이트풀)과 Headless Service (헤드리스 서비스) (0) | 2022.06.04 |
| [Kubernetes] TLS/SSL Termination with Ingress (0) | 2022.06.01 |
| [Kubernetes] Nginx HTTPs 서버 구성하기 (0) | 2022.06.01 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!