EKS를 운영하면서 진행한 비용 절감 전략 몇가지를 소개합니다.
EKS는 싸지만 비쌉니다. 클러스터 비용은 표준 버전에 대해서 클러스터당 0.1$(월 10만원 안팍)으로 개인 입장에서는 다소 비싸지만, 회사 입장에서는 충분히 수용 가능한 비용입니다.
물론 컨트롤 플레인을 프로비저닝 한다면 다소 비용이 올라가긴 합니다만 자주 있는 일은 아닙니다.
컨트롤플레인은 꽤나 저렴하지만 데이터 플레인(노드)에 대해서는 결코 저렴하다고 할 수 없습니다. 물론 이것은 비단 EKS의 문제만은 아닙니다.
쿠버네티스 시스템은 운영하기 위한 부수적인 컴포넌트들이 다수 필요하며, 오히려 반대로 쿠버네티스 이기 때문에 비용을 줄일 수 있는 방법도 존재합니다.
여기서는 제가 적용한 쿠버네티스 데이터 플레인 비용 절감 방법을 몇가지 소개합니다.
저희 회사는 데이터독(Datadog)을 활용하고 있습니다.
데이터독의 비용을 줄이는 방법은 많지만 오늘은 EKS Dataplane에 대해서만 다룹니다.
Infrastructure, APM, Security 등 데이터독의 대다수의 코어 피처들은 호스트 기준으로 비용을 청구합니다.

하지만 동시에 청구된 호스트에 포함되어 별도로 비용을 지불하지 않아도 되는 기능들도 많습니다. 이런 서비스의 경우 청구되는 Host가 많은 수록 해당 서비스에 대해서는 오히려 비용이 절감되는 효과가 있습니다.

즉, 이런 per-host allotment 되는 서비스들을 고려해서 작은 사이즈의 많은 노드를 큰 사이즈의 적은 노드로 변경하는것도 충분히 고려해 볼만 합니다.
물론 이 경우 심각하게 따져봐야 할 문제가 있습니다.
이 포스팅에서 이 문제를 깊게 다루기는 어렵습니다. 미래의 제가 아마 기회가 되면 깊게 다룰 수도 있을것 같습니다.
위의 내용만 보면 마치 적은 숫자의 큰 노드를 운영하는게 무조건적으로 유리할것 같지만 그렇게 단순한 문제는 아닙니다.
고려해야 할 여러가지 문제중에 간단한 문제 몇가지만 소개하자면,
큰 장애 영향범위
일명 Blast Radius라고 부르는, 노드 수준의 장애가 일어났을때 영향받는 서비스가 너무 많아집니다.
노드 수준의 장애는 여러 요인으로 발생합니다. AWS EC2 인스턴스 수준의 장애, 데몬셋(주로 네트워크 관련)의 문제 등등
노드 수준의 공유 자원
CPU, Memory는 직관적이라서 놓치기 쉽지 않지만 디스크와 네트워크 등의 I/O는 놓치기 쉽습니다.
AWS의 많은 인스턴스 타입은 스펙이 올라가더라도 이 두 자원의 성능 또는 한계가 늘어나지 않는 경우가 많습니다. 하나의 노드에서 네트워크 요구량이 많은 서비스들이 과밀집하게 배치하는 행위는 노드수준의 장애를 촉발합니다
물론 cross node network 발생 확률을 줄인다거나, kubelet, daemonset 등으로 인한 api server의 부하도 줄이는 등의 적은 숫자의 큰 노드 자체가 가지고 오는 다른 장점들도 많습니다.
여러가지 문제를 고려해야 하긴 하겠지만, 문제가 없다면 적은 숫자의 노드를 운영하는것은 Datadog(그리고 이와 비슷하게 호스트당 비용을 청구하는) 비용 절감에 분명 효과가 있습니다.
오버 프로비저닝은 흔히 scale out이 일어날때 노드가 뜨는 시간을 기다리지 않기 위해 사용하는 쿠버네티스 운영 방식 중 하나입니다.
하지만 over provisioning으로 인해 노드가 예상한것보다 과하게 준비됨으로 인해 비용이 더 발생하기도 합니다.
이 부분은 정말 예상하기 힘든데, pod의 scale out뿐만 아니라 배포로 인한 pod의 증가로 인한 노드 변경도 일어날 수 있기 때문입니다.
이 문제는 Datadog을 결합하면 더 큰 문제가 됩니다. Datadog은 unique host로 비용이 청구됩니다.
즉, node 하나가 1시간동안 100번 생겼다가 사라졌다가를 반복하면 100대의 호스트 비용이 청구됩니다.
그래서 over provisioning을 하되 Karpenter의 기능을 이용해서 매번 다른 노드를 띄우는것은 막는 방법이 몇가지 있습니다.
아직 Datadog 섹션입니다. 다소 이상할 수 있는 내용들이지만, 모두 Datadog에 포커스를 맞춘 비용 절감 전략이라는걸 잊지 말아주세요
consolidateAfter 조절실제로 disruption 시킬 수 있는 노드라 할지라도 그냥 더 오래 띄워두는 겁니다.
어떠한 이유로 한번 노드가 생성되면 빠르게 지우지 않고 조금 더 기다려 보면서 노드 생성이 일어나는 비율 자체를 줄일 수 있습니다.
최소 노드 스펙을 조절하여 scale out 또는 배포가 일어나더라도 노드의 빈 공간을 활용하여 node가 늘어나는것을 최소화 하는 것도 선택지가 될 수 있습니다.
karpenter 1.8 버전부터 추가된 static nodepool 기능은 실제로 전혀 필요 없는 빈 노드라 할지라도 replica를 지정해서 노드를 강제로 띄워둘 수 있는 기능입니다.
노드 수준의 오버프로비저닝을 하는게 다소 이상하게 보일 수 있습니다. 하지만 배포와 Scale out 등의 이유로 노드 생성이 잦은 경우 차라리 이 경우가 비용적으로는 이득인 경우도 많습니다.
노드 자체의 단가를 낮추는 방법입니다. spot instance는 RI, SP와 대비해도 수 배 이상 저렴하기도 합니다.
하지만 spot instance는 갑작스럽게 종료될 수 있다는 문제점이 있습니다.
그렇기에 pod를 spot과 on-demand instance에 분할 배치하는것이 중요합니다.
예를 들어 replica를 4대 운용한다면 on-demand와 spot에 각각 2대씩 띄워서 운영할 수 있습니다.
하지만 spot이 모두 갑자기 종료되어 2대만 운영된다면 서비스 품질에 영향을 미칠 수 있습니다. 이 경우 replica를 늘릴수도 있습니다.
on-demand에 2대, spot에 4대를 운영하면 spot이 4대중 2대가 예상치 못한 이유로 종료된다고 하더라도 여전히 4대를 healthy하기에 서비스 품질에는 영향을 미치지 않습니다.
심지어 spot instance는 아주 저렴하기에 이렇게 변경하더라도 기존 ondemand 4대를 사용할때보다 저렴한 경우가 많습니다!
이 글을 작성하는 시간 기준 각 인스턴스의 시간 당 비용을 보면
c6g.8xlarge : 1.232$ (코어당 0.058$)12xlarge : 0.3746$ (코어당 0.007)코어당 비용으로 계산하면 9배 정도 저렴하고 RI 또는 SP를 적용하더라도 3배 이상 저렴합니다.
karpenter에서 pod를 on-demadn와 spot에 분배하는 방법은 링크를 참고하시면 되겠습니다
의식의 흐름대로 계속 쓰다보니 너무 길어져서 1편은 여기서 마무리 하겠습니다.
2편에서는 QOS를 고려한 비용 최적화 내용을 더 다뤄보겠습니다.
수정이 필요한 내용, 다양한 의견 모두 환영합니다