많은 기사에서도 접할 수 있듯이 올해 스타트업의 시장이 좋지 않다.
그래서 현재 재직중인 회사에서도 불필요한 또는 비효율적인 AWS 인프라 비용을 줄이라는 특명이 내려왔다.
그래서 AWS 인프라 비용에서 가장 많은 부분을 차지하는 EKS Node 비용을 먼저 줄여보기로 했다.
가장 좋은 방법은 각 Deployment의 Request/Limit 사이즈를 조절하는 것이다.
하지만 이것은 개발팀에서 조절하는 부분이고 데브옵스팀에서는 관여하기 어렵기에 그럼 노드를 효율적으로 사용할 수 있는 부분을 찾아보기로 했다. 그러던 중 팀원이 좋은? 괜찮은? 오픈소스인 Karpenter를 공유해주었고 당사에 적용한 내용을 기술해보고자 한다.
먼저 대부분의 EKS를 운영하는 회사에서는 Cluster Auto Scaler(이하 CAS)를 사용하고 있을것 같다.
하지만 CAS에는 아래의 치명적인 단점이 존재한다.
- EKS Node Group을 설정하고 해당 Group을 선택하기 때문에 필요한 Pod Request와는 약간 별개다.
- Spot, On-demand를 혼용해서 사용할 때 Spot이 사용 가능함에도 On-demand Group을 사용하는 경우가 많다.
- 그래서 당사도 Spot, On-demand의 비율이 50:50이상 잘 올라가지 않는다.
- Spot이 사용 가능하다면 Spot을 사용하는것이 비용 효율적인 측면에서는 더 좋은데..(운영 환경 제외)
- Spot 노드에 Daemonset만 있더라도, 노드 삭제를 하지 않는다.
- 이것은 CAS의 스펙이라고 한다. Spot 노드를 삭제하지 않기 때문에 불필요하게 비용이 나간다.
- Spot 사용이 불가능할 때 즉시 Fail-over가 되지 않는다.
하지만 Karpenter를 도입하면 위와 문제점 중 상당부분을 해결할 수 있다. 그렇다면 Karpenter란 무엇인가?
Karpenter란?
2020년 11월에 출시된 오픈소스 솔루션이며, AWS에서 2021년 12월에 소개된 아주 따끈따끈한 신규 오픈소스 솔루션이다.
Karpenter의 가장 큰 이념은 "노드 타입을 선정할 때 필요한 용량에 따라 가장 비용 효율적인 노드를 선택한다." 이다.
비용 효율화를 고민하는 나로서는 더할나위 없는 솔루션이다!!
Karpenter는 크게 위의 2가지 기능을 한다고 볼 수 있다.
- Provisioning : Unschedulable Pods이 있으면 schedule 한다. 그리고 필요에 따라서 노드를 띄운다.
- Deprovisioning : 정해진 시간에 따라서 비용 효율화를 위해 노드를 통/폐합한다.
기존에는 kube-scheduler(Pod schedule)가 있고, CAS(노드 생성)가 각자의 역할을 하였다.
그런데 Karpenter는 스스로 2가지의 역할을 모두 한다. 그렇기 때문에 CAS를 이용할때보다 노드 생성 및 Pod schedule 시간이 짧다.
Provisioning을 위한 구성요소는 무엇일까?
Provisioning 하기 위해서는 Provisioners와 AWSNodeTemplate이 필요하다.
Provisioners
쉽게 말하면 Karpenter가 노드를 만들때 생성하는 스펙이다. 인스턴스 타입/스펙/용량 등에 대한 전반적인 설정이 있다.
기본적으로 spec.requirements 아래 옵션을 통해 Karpenter가 생성할 노드 스펙을 정할 수 있다.
- 아래 옵션 외 eviction, pod density 등의 다양한 옵션을 제공한다.
key: karpenter.sh/capacity-type
spot, on-demand 선택이 가능하고, Karpenter가 만드는 노드의 타입을 정하는 부분이다.
Karpenter는 비용 효율을 먼저 생각하기 때문에 기본적으로 Spot을 먼저 생성한다.
그리고 Spot 생성이 불가능하면 거의 바로? On-demand로 Fail-over가 가능하다.
Fail-over가 되기에 Spot을 안정적으로 사용할 수 있는 이유가 되기도 한다.
key: karpenter.k8s.aws/instance-category
t계열을 사용할지, c/m 계열의 인스턴스를 사용할지 인스턴스 타입을 지정할 수 있다.
key: node.kubernetes.io/instance-type
t3.2xlarge와 같이 Karpenter로 특정 인스턴스 타입을 지정할 수 있다.
권장하는 방법은 아니지만, 설정하지 않을 경우 작은 노드를 생성하여 노드 개수가 늘어나는 위험이 있다.
key: karpenter.k8s.aws/instance-cpu
4, 8, 16과 같이 인스턴스에 대한 CPU 사양을 정할 수 있다.
4로 입력하면 인스턴스 중에서 4vCPU를 제공하는 인스턴스 타입만 선택한다.
key: karpenter.k8s.aws/instance-generation
인스턴스 세대를 뜻한다. 이건 크게 의미 없는것 같다.
key : kubernetes.io/os
Karpenter가 만드는 노드 운영체제를 정하는 것이며, 기본값은 linux이다.
kye : kubernetes.io/arch
amd64, arm64 선택이 가능한대, 노드의 어떤 아키텍처를 정할 지 선택할 수 있다.
기본값은 amd64이며, arm64가 조금 더 저렴하긴 하나 운영하는 서비스에서 해당 아키텍처 호환이 가능해야 한다.
key : topology.kubernetes.io/zone
노드를 만들 때 특정 region에 생성할 때 사용하는 옵션이다. 기본값은 현재 EKS가 존재하는 region이다.
그리고 휴먼에러? 잘못된 코드로 인해 무한정으로 Pod이 재생성될 때 이를 막아주는 옵션도 존재한다.
limits:
resources:
cpu: 1000
memory: 1000Gi
AWSNodeTemplate
위 Provisioner에서 노드 타입을 결정했다면, AWSNodeTemplate은 시작 템플릿와 유사하게 tag, subnet 등을 정한다.
Node를 생성할 때 필요한 Subnet, SG, Tag등 EKS node groupe의 시작템플릿와 유사하다.
만약 기존 CAS 환경에서 마이그레이션하는거라면 subnet, securitygroup selector를 기존과 동일하게 설정하는 것이 중요하다.
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
name: default
spec:
subnetSelector: { ... } # required, discovers tagged subnets to attach to instances
securityGroupSelector: { ... } # required, discovers tagged security groups to attach to instances
instanceProfile: "..." # optional, overrides the node's identity from global settings
amiFamily: "..." # optional, resolves a default ami and userdata
amiSelector: { ... } # optional, discovers tagged amis to override the amiFamily's default
userData: "..." # optional, overrides autogenerated userdata with a merge semantic
tags: { ... } # optional, propagates tags to underlying EC2 resources
metadataOptions: { ... } # optional, configures IMDS for the instance
blockDeviceMappings: [ ... ] # optional, configures storage devices for the instance
detailedMonitoring: "..." # optional, configures detailed monitoring for the instance
status:
subnets: { ... } # resolved subnets
securityGroups: { ... } # resolved security groups
최근에 Karpenter 이미지 업데이트를 하고 난 다음에 장애가 났었는데, 원인은 userData를 넣는 방법이 달라서 장애가 났었다.
Karpenter는 이미지 업데이트가 아주 빠르게 되는 편이다. 그리고 종종 메타데이터가 변경되기 때문에 이미지 업데이트만 했을 때 장애가 날 수 있다.
다음 게시물에서는 schedule와 Deprovisioning에 대해서 알아볼 예정이다!!
끄읏!!
'기술 이모저모 > [Ops] Devops' 카테고리의 다른 글
[SLA] 서비스 안전성의 주요 지표 SLI, SAO + SLA (0) | 2023.04.02 |
---|---|
[Karpenter] Karpenter vs Cluster AutoScaler 장/단점 비교 (0) | 2023.03.26 |
[Github] Container Image 취약점 점검 Trivy[1/2] (0) | 2022.11.26 |
[Ansible] Ansible을 이용한 서버 점검 스크립트 실행 자동화 구현 (0) | 2022.05.29 |
[Ansible] 서버 스크립트 자동 점검 Ansible 사용 방법 [2/2] (0) | 2022.05.29 |