ResourceQuota 적용기
우리 회사에서 운영하는 여러 서비스들은 각자 자신의 config repository 에서 values.yaml에 CPU와 Memory Rrequest 값을 정의하고 있다. 문제sms 개발자들은 인프라 설정을 잘 몰라 그냥 복붙해서 쓰다 보니, 이 값들이 실제 필요량보다 너무 크게 잡히거나 적게 잡히거나 하는 것이다.
특히 dev 환경에서 이게 심했다. m7g.xlarge 노드 3개를 띄워 놓았음에도 pod들이 memory 부족으로 스케줄링이 안 되고 대기하는 상황이 매번 발생했다.
0/3 nodes are available: 3 Insufficient memory. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod
실제로 해당 노드들은 CPU 자원은 넉넉했지만, 메모리가 꽉 차서 새로운 팟을 받을 수 없었다.
원인은 명확했다. 각 서비스의 리소스 요청이 실제 사용량보다 훨씬 크게 설정되어, 불필요하게 많은 메모리를 예약하고 있었던 것이다.
노드 리소스 현황 확인
k top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
[pod 내부 ip 1].ap-northeast-2.compute.internal 1667m 10% 22248Mi 77%
[pod 내부 ip 2].ap-northeast-2.compute.internal 1409m 8% 16378Mi 56%
[pod 내부 ip 3].ap-northeast-2.compute.internal 1282m 8% 16396Mi 56%
그라파나 모니터링과 리소스 요청 조정
그라파나 대시보드의 memory utilization from request 지표를 확인해보니 메모리 요청 대비 실제 사용률이 50% 미만인 서비스가 다수였다. 예상한대로 서비스들이 필요 이상으로 많은 메모리를 예약하고 있던 것이다.
과도한 자원을 차지하는 서비스들을 선별해 Resource Request 값을 수정했다.
이를 통해 불필요한 자원 예약을 줄이고, 실제 사용량에 맞춰 리소스 요청을 최적화했다.
ResourceQuota와 LimitRange
인프라 차원에서는 네임스페이스별로 CPU와 메모리 자원의 상한을 관리하기 위해 ResourceQuota와 LimitRange를 관리했다.
ResourceQuota
네임스페이스 내 전체 자원 요청 상한 설정
LimitRange
Pod 또는 컨테이너 단위의 기본 요청 및 제한 설정으로 과도한 자원 예약 방지
- values.yaml에서 네임스페이스별 CPU, 메모리 요청값을 정의
- Helm 템플릿을 이용해 네임스페이스별로 LimitRange와 ResourceQuota 생성
- 기본 CPU 요청과 한도를 LimitRange로 설정해 Pod의 과다 예약 방지
-ResourceQuota로 네임스페이스 전체 자원 요청 상한 설정
적용한 Helm 템플릿 예시
ResourceQuota와 LimitRange 템플릿을 만들고, values.yaml에서 namespace별 CPU, Memory Request 값을 정의하여 적용했다.
# resource-quota.yaml
{{- range .Values.namespaces }}
apiVersion: v1
kind: ResourceQuota
metadata:
name: {{ .name }}-quota
namespace: {{ .name }}
spec:
hard:
requests.cpu: {{ with .cpu }}{{ default $.Values.quota.cpu.request .request }}{{ else }}{{ $.Values.quota.cpu.request }}{{ end }}
{{- with .memory }}
{{- if .request }}
requests.memory: {{ .request | quote }}
{{- end }}
{{- end }}
---
{{- end }}
# limit-range.yaml
{{- range .Values.namespaces }}
apiVersion: v1
kind: LimitRange
metadata:
name: {{ .name }}-limitrange
namespace: {{ .name }}
spec:
limits:
- type: Container
default:
cpu: "1"
defaultRequest:
# 1/100 core
cpu: "10m"
---
{{- end }}
# values.yaml 예시
- name: silicon-scope-api-system
- name: silicon-scope-synchronizer-system
cpu:
request: "2"
- name: klayswap-front-system
memory:
request: "512Mi"
- name: launchpad-front-system
memory:
request: "256Mi"
quota:
cpu:
request: "1"