티스토리 뷰
EKS는 컨트롤 플레인을 자동 관리해주고, 추가 기능으로 클러스터 관리의 편의성까지 제공해준다.
하지만 데이터플레인 관리는 사용자의 몫이다.
EKS는 AWS 환경이다보니 온프레미스 환경보다 자유로운 자원의 확장과 축소 설정이 가능하다.
이러한 기능을 노드 오토스케일링이라고 하는데 대표적으로 CA(Cluster Autoscaler)와 Karpenter가 있다.
Karpenter가 CA 비해 빠르고 비용 절감효과가 있어서, 본 포스팅은 Karpenter를 정리해보려고 한다.
그래도 차근차근 알아가는게 중요하니 CA부터 정리해보자.
Cluster Autoscaler (CA)
Cluster Autoscaler는 AWS의 Auto Scaling Group(ASG)을 이용하여 EKS의 노드를 관리합니다. ASG는 EKS와 관련없는 별도의 AWS 자원으로 ASG와 EKS 노드 간의 데이터 동기화 작업이 필요하여 추가 시간이 소요됩니다. CA가 Karpenter에 비하여 오래된 기술이라 기술적 성숙도가 있으나 비용과 속도 측면에서 Karpenter가 유리합니다.
https://jennifersoft.com/ko/blog/kubernetes/2023-10-18-kubernetes-8/ 에서 발췌
- Horizontal Pod AutoScaler(HPA)에 의한 수평적 확장이 한계에 다다르면, pod는 적절한 Node를 배정받지 못하고 pending 상태가 됨
- CA는 Pod의 상태를 관찰하다가 지속해서 할당에 실패하면 Node Group의 ASG Desired Capacity 값을 수정하여 Worker Node 개수를 증가하도록 설정(pod를 감시하는 방식이 주기적인 pulling 방식이라 Node가 추가 되는 속도가 느림)
- 이를 인지한 ASG 가 새로운 Node를 추가여유 공간이 생기면 kube-scheduler 가 Pod를 새 Node에 할당.
CA 방식은 AWS 리소스인 ASG 에 의존도가 높고, Node가 추가 되는데 비교적 오랜 시간이 걸린다는 단점이 있다.
구성 방법이나 세부요소 정리는 따로 진행하지 않을 예정.
Karpenter와 CA를 비교하는 작업에서 진행할 수도 있다
Karpenter란?
Karpenter는 AWS 가 개발한 Kubernetes 의 Worker Node 자동 확장 기능을 수행하는 오픈소스 프로젝트입니다. Cluster Autoscaler (CA)와 비슷한 역할을 수행하지만, AWS 리소스에 의존성이 없어 JIT(Just In-Time) 배포가 가능하다는 점에서 다른 확장 시나리오를 가지고 있습니다
- Horizontal Pod AutoScaler(HPA)에 의한 수평적 확장이 한계에 다다르면, pod는 적절한 Node를 배정받지 못하고 pending 상태가 됨 - CA와 동일한 상황
- 이때 Karpenter 는 지속해서 unscheduled Pod 를 관찰하고 있다가, 새로운 Node 추가를 결정하고 직접 배포
(Karpenter는 pub/sub 방식으로 파드를 모니터링하고 있어서, pending 상태에 빠진 pod를 빠르게 감지) - 가장 적합한 스펙의 인스턴스를 만들기 위해서 Pod의 스펙을 체크
- 가장 적합한 스펙의 Node 인스턴스를 Provisioning
- 추가된 Node가 Ready 상태가 되면 Karpenter 는 kube-scheduler 를 대신하여 pod 의 Node binding 요청도 수행
- Pod가 없는 Node를 Deprovisioning 시키는 기능도 있음
가장 적합한 스펙의 Node를 Provisioning/Deprovisioning 하는 기능을 통해서 거의 30% 이상의 비용절감 효과를 얻을 수 있으면서, AWS 자원인 ASG와 독립되서 빠른 속도의 노드 Provisioning 기능까지 제공한다.
이 기능을 Terraform으로 구성해보자.
1. Provider
AWS Provider의 추가 지정이 필요하다.
Amazon Elastic Container Registry Public (ECR Public)에서 제공하는 karpenter의 Helm 차트 저장소가 us-east-1, virgina에 위치하기 때문이다.
대부분의 소스코드는 여기서 참고했다 : https://dev.to/segoja7/scaling-an-aws-eks-with-karpenter-using-helm-provider-with-terraform-kubernetes-series-episode-4-1dp6
# Configure the AWS Provider
provider "aws" {
region = "ap-northeast-2"
profile = terraform.workspace
# Make it faster by skipping something
skip_metadata_api_check = true
skip_region_validation = true
skip_credentials_validation = true
default_tags {
tags = {
Stage = terraform.workspace
}
}
}
provider "aws" {
region = "us-east-1"
alias = "virginia"
}
data "aws_ecrpublic_authorization_token" "token" {
provider = aws.virginia
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
# -------------------------------------------------------------------------------
# Provider
# -------------------------------------------------------------------------------
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
# This requires the awscli to be installed locally where Terraform is executed
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name, "--profile", terraform.workspace]
}
}
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
# This requires the awscli to be installed locally where Terraform is executed
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name, "--profile", terraform.workspace]
}
}
}
provider "kubectl" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
load_config_file = false
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
# This requires the awscli to be installed locally where Terraform is executed
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name, "--profile", terraform.workspace]
}
}
2. EKS Module
Fargate profile과 태그에 karpenter를 선언해준다.
module "eks" {
...
# Fargate
fargate_profiles = {
karpenter = {
selectors = [{ namespace = "karpenter" }]
}
kube-system = {
selectors = [
{
namespace = "kube-system"
labels = {
"eks.amazonaws.com/component" = "coredns"
}
}
]
}
}
tags = {
"karpenter.sh/discovery" = local.name
}
}
3. karpenter Module
https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest/submodules/karpenter
module "karpenter" {
source = "terraform-aws-modules/eks/aws//modules/karpenter"
cluster_name = module.eks.cluster_name
irsa_oidc_provider_arn = module.eks.oidc_provider_arn
version = "19.13"
policies = {
AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
tags = local.tags
}
karpenter 모듈은 eks 모듈의 서브모듈이다. 최신버전은 20 버전인데, IAM 권한을 지정하는 방식이 조금 다르니 주의해야한다.
4. helm chart release
helm_release 리소스를 통해 helm 차트를 배포한다.
resource "helm_release" "karpenter" {
namespace = var.karpenter_namespace
create_namespace = true
name = "karpenter"
repository = "oci://public.ecr.aws/karpenter"
repository_username = data.aws_ecrpublic_authorization_token.token.user_name
repository_password = data.aws_ecrpublic_authorization_token.token.password
chart = "karpenter"
version = var.karpenter_version
set {
name = "settings.aws.clusterName"
value = module.eks.cluster_name
}
set {
name = "settings.aws.clusterEndpoint"
value = module.eks.cluster_endpoint
}
set {
name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
value = module.karpenter.irsa_arn
}
set {
name = "settings.aws.defaultInstanceProfile"
value = module.karpenter.instance_profile_name
}
set {
name = "settings.aws.enablePodENI"
value = true
}
set {
name = "settings.aws.interruptionQueueName"
value = module.karpenter.queue_name
}
}
5. AWS Node Template 정의
Karpenter가 노드를 생성할 때 필요한 AWS 리소스의 구체적인 설정 정보를 정의하는 템플릿이다.
EBS, 서브넷, 보안 그룹 등을 정의한다.
resource "kubectl_manifest" "karpenter_node_template" {
yaml_body = <<-YAML
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
name: default
spec:
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100
volumeType: gp3
subnetSelector:
karpenter.sh/discovery: ${module.eks.cluster_name}
securityGroupSelector:
karpenter.sh/discovery: ${module.eks.cluster_name}
tags:
karpenter.sh/discovery: ${module.eks.cluster_name}
YAML
depends_on = [
helm_release.karpenter
]
}
6. karpenter provisioner 정의
Karpenter가 노드를 생성할 때 리소스 유형과 제한을 정의한다.
resource "kubectl_manifest" "karpenter_provisioner" {
yaml_body = <<-YAML
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
labels:
role: webapp
requirements:
- key: "node.kubernetes.io/instance-type"
operator: In
values: ["m6i.large", "r6i.large"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
limits:
resources:
cpu: 50
memory: 192Gi
providerRef:
name: default
ttlSecondsUntilExpired: 2592000 # 30d
ttlSecondsAfterEmpty: 30
YAML
depends_on = [helm_release.karpenter]
}
여기까지 작성하고 terraform apply를 하고 성공하면 끝이다.
> kubectl get provisioner
NAME AGE
default 17d
> kubectl get awsnodetemplate
NAME AGE
default 17d
> kubectl get pods -n karpenter
NAME READY STATUS RESTARTS AGE
karpenter-658655764d-7h27w 1/1 Running 0 17d
배포한 내용들과 카펜터 파드가 잘 검색되면 배포에 성공한 것이다.
쿠버네티스와 카펜터에 대해 100% 인지한 상태에서 진행한게 아니다보니
머리속으로나 포스팅 내용적으로나 정리해야할 것들이 더 있어보인다.
무엇보다 아직 태그의 사용법을 잘 모르는 것 같아서 이 쪽도 조금 더 알아봐야할 것 같다.
마치며
카펜터 설정에 대한 내용만 정리했는데, 다른 포스팅을 보니 CA와 비교하는 실습과정이 있었다.
https://jennifersoft.com/ko/blog/kubernetes/2023-10-18-kubernetes-8/
현재 작업하는 환경이 윈도우라 wsl로 옮기고, 위 테스트를 따라서 진행해 볼 예정이다.
그리고 다음은 클러스터와 인터넷을 연결하기 위한 로드밸런서 컨트롤러 설정을 해야한다.
이 후엔 실제 프로덕션 환경에서 사용한 istio Gateway와 배포를 위한 ArgoCD까지하면 큰 사이클은 정리한거지 싶다.
갈길이 참 멀다.
참고자료
https://devblog.kakaostyle.com/ko/2022-10-13-1-karpenter-on-eks/
https://jennifersoft.com/ko/blog/kubernetes/2023-10-18-kubernetes-8/
'개발 > 인프라' 카테고리의 다른 글
Terraform으로 EKS 배포하기 8. 서비스메시와 Istio (0) | 2024.05.28 |
---|---|
Terraform으로 EKS 배포하기 7. AWS 로드밸런서 컨트롤러 (0) | 2024.05.23 |
Terraform으로 EKS 배포하기 5. EKS 추가 기능(add-ons) (0) | 2024.05.05 |
Terraform으로 EKS 배포하기 4. EKS 클러스터 셋업 (0) | 2024.05.04 |
Terraform으로 EKS 배포하기 3. Provider와 AWS 인증 (0) | 2024.04.25 |
- Total
- Today
- Yesterday
- lambda
- cache
- openAI API
- MySQL
- 람다
- JWT
- Elastic cloud
- terraform
- CloudFront
- Spring
- GIT
- 오블완
- 티스토리챌린지
- elasticsearch
- S3
- Log
- ChatGPT
- AOP
- AWS
- OpenAI
- Kotlin
- OpenFeign
- 후쿠오카
- java
- EKS
- serverless
- springboot
- docker
- AWS EC2
- 스프링부트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |