현재 요구사항 : Scale In&Out이 빠르면서 비용을 절감할 수 있는 autoscaling 방침이 필요
사전 준비
- 기존 EKS 클러스터를 사용합니다.
- 기존 VPC와 서브넷을 사용합니다.
- 기존 보안 그룹을 사용합니다.
- 노드가 하나 이상의 노드 그룹에 속해 있습니다.
- 워크로드에 EKS 모범 사례를 준수하는 포드 중단 예산이 있습니다.
- 클러스터에 서비스 계정에 대한 OIDC 제공업체 가 있습니다.
클러스터 이름에 대한 변수 지정
CLUSTER_NAME=<your cluster name>
클러스터 구성에서 다른 변수 설정 (아래 명령어 그냥 복붙하면 알아서 설정됨)
AWS_PARTITION="aws"
AWS_REGION="$(aws configure list | grep region | tr -s " " | cut -d" " -f3)"
OIDC_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} \
--query "cluster.identity.oidc.issuer" --output text)"
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' \
--output text)
변수 설정 잘됐는지 아래 명령어로 확인
echo $CLUSTER_NAME $AWS_PARTITION $AWS_REGION
Karpenter 및 Karpenter 컨트롤러로 프로비저닝된 노드에 대해 두 개의 새로운 IAM 역할을 생성해야 합니다.
echo '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}' > node-trust-policy.json
node-trust-policy.json
의 내용을 그대로 적용합니다.aws iam create-role --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--assume-role-policy-document file://node-trust-policy.json
KarpenterNodeRole에 연결한 4개의 IAM Policy는 모두 AWS 관리형 정책입니다.
- AmazonEKSWorkerNodePolicy
- AmazonEKS_CNI_Policy
- AmazonEC2ContainerRegistryReadOnly
- AmazonSSMManagedInstanceCore
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:${AWS_PARTITION}:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:${AWS_PARTITION}:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:${AWS_PARTITION}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:${AWS_PARTITION}:iam::aws:policy/AmazonSSMManagedInstanceCore
aws iam create-instance-profile \
--instance-profile-name "KarpenterNodeInstanceProfile-${CLUSTER_NAME}"
aws iam add-role-to-instance-profile \
--instance-profile-name "KarpenterNodeInstanceProfile-${CLUSTER_NAME}" \
--role-name "KarpenterNodeRole-${CLUSTER_NAME}"
IAM Role의 신뢰관계를 생성합니다.
cat << EOF > controller-trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_ENDPOINT#*//}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_ENDPOINT#*//}:aud": "sts.amazonaws.com",
"${OIDC_ENDPOINT#*//}:sub": "system:serviceaccount:karpenter:karpenter"
}
}
}
]
}
EOF
Karpenter 컨트롤러에서 사용할 IAM Role을 생성합니다.
aws iam create-role --role-name KarpenterControllerRole-${CLUSTER_NAME} \
--assume-role-policy-document file://controller-trust-policy.json
Karpenter 컨트롤러용 IAM Policy를 생성합니다.
cat << EOF > controller-policy.json
{
"Statement": [
{
"Action": [
"ssm:GetParameter",
"ec2:DescribeImages",
"ec2:RunInstances",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeLaunchTemplates",
"ec2:DescribeInstances",
"ec2:DescribeInstanceTypes",
"ec2:DescribeInstanceTypeOfferings",
"ec2:DescribeAvailabilityZones",
"ec2:DeleteLaunchTemplate",
"ec2:CreateTags",
"ec2:CreateLaunchTemplate",
"ec2:CreateFleet",
"ec2:DescribeSpotPriceHistory",
"pricing:GetProducts"
],
"Effect": "Allow",
"Resource": "*",
"Sid": "Karpenter"
},
{
"Action": "ec2:TerminateInstances",
"Condition": {
"StringLike": {
"ec2:ResourceTag/karpenter.sh/provisioner-name": "*"
}
},
"Effect": "Allow",
"Resource": "*",
"Sid": "ConditionalEC2Termination"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME}",
"Sid": "PassNodeIAMRole"
},
{
"Effect": "Allow",
"Action": "eks:DescribeCluster",
"Resource": "arn:${AWS_PARTITION}:eks:${AWS_REGION}:${AWS_ACCOUNT_ID}:cluster/${CLUSTER_NAME}",
"Sid": "EKSClusterEndpointLookup"
}
],
"Version": "2012-10-17"
}
EOF
aws iam put-role-policy --role-name KarpenterControllerRole-${CLUSTER_NAME} \
--policy-name KarpenterControllerPolicy-${CLUSTER_NAME} \
--policy-document file://controller-policy.json
for 반복문 형태로 여러 서브넷에 한 번에 태그가 추가됩니다.
for NODEGROUP in $(aws eks list-nodegroups --cluster-name ${CLUSTER_NAME} \
--query 'nodegroups' --output text); do aws ec2 create-tags \
--tags "Key=karpenter.sh/discovery,Value=${CLUSTER_NAME}" \
--resources $(aws eks describe-nodegroup --cluster-name ${CLUSTER_NAME} \
--nodegroup-name $NODEGROUP --query 'nodegroup.subnets' --output text )
done
추가되는 태그 정보는 다음과 같습니다.
karpenter.sh/discovery
보안 그룹에도 태그를 추가해야합니다.
이 명령은 클러스터의 첫 번째 노드 그룹에 대한 보안 그룹에만 태그를 지정합니다.
만약, 여러 보안 그룹을 사용하고 있는 경우 Karpenter가 노드별로 사용해야 할 보안 그룹을 결정해야 합니다.
NODEGROUP=$(aws eks list-nodegroups --cluster-name ${CLUSTER_NAME} \
--query 'nodegroups[0]' --output text)LAUNCH_TEMPLATE=$(aws eks describe-nodegroup --cluster-name ${CLUSTER_NAME} \
--nodegroup-name ${NODEGROUP} --query 'nodegroup.launchTemplate.{id:id,version:version}' \
--output text | tr -s "\t" ",")
# If your EKS setup is configured to use only Cluster security group, then please execute -
# 클러스터에서 하나의 보안그룹만 사용한다면 아래 명령어 사용
SECURITY_GROUPS=$(aws eks describe-cluster \
--name ${CLUSTER_NAME} --query "cluster.resourcesVpcConfig.clusterSecurityGroupId" --output text)
# If your setup uses the security groups in the Launch template of a managed node group, then :
# 노드그룹의 시작 템플릿에 있는 보안그룹을 사용한다면 아래 명령어 사용
SECURITY_GROUPS=$(aws ec2 describe-launch-template-versions \
--launch-template-id ${LAUNCH_TEMPLATE%,*} --versions ${LAUNCH_TEMPLATE#*,} \
--query 'LaunchTemplateVersions[0].LaunchTemplateData.[NetworkInterfaces[0].Groups||SecurityGroupIds]' \
--output text)
aws ec2 create-tags \
--tags "Key=karpenter.sh/discovery,Value=${CLUSTER_NAME}" \
--resources ${SECURITY_GROUPS}
aws-auth
이를 위해서는 클러스터에서 ConfigMap을 수정해야 합니다 .kubectl edit configmap aws-auth -n kube-system
apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::111122223333:role/dev-global-eks-node-iam-role
username: system:node:{{EC2PrivateDNSName}}
kind: ConfigMap
metadata:
...
mapRoles를 보면 기존 ASG로 관리되는 노드그룹이 등록되어 있습니다.apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::111122223333:role/dev-global-eks-node-iam-role
username: system:node:{{EC2PrivateDNSName}}
+ - groups:
+ - system:bootstrappers
+ - system:nodes
+ rolearn: arn:aws:iam::111122223333:role/KarpenterNodeRole-YOUR_CLUSTER_NAME_HERE
+ username: system:node:{{EC2PrivateDNSName}}
kind: ConfigMap
metadata:
...
위와 같이 추가되면 전체 aws-auth configmap에는 두개의 그룹이 있게 됩니다. 하나는 Karpenter 노드 역할용이고 다른 하나는 기존 노드 그룹용입니다.카펜터의 버전을 지정해줍니다.
export KARPENTER_VERSION=v0.31.0
helm 차트 배포 명령어를 수행해줍니다.
helm template karpenter oci://public.ecr.aws/karpenter/karpenter --version ${KARPENTER_VERSION} --namespace karpenter \
--set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \
--set settings.aws.clusterName=${CLUSTER_NAME} \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"="arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/KarpenterControllerRole-${CLUSTER_NAME}" \
--set controller.resources.requests.cpu=1 \
--set controller.resources.requests.memory=1Gi \
--set controller.resources.limits.cpu=1 \
--set controller.resources.limits.memory=1Gi > karpenter.yaml
nodeAffinity
를 사용해 기존 ASG로 운영되는 노드그룹에 배치하는 걸 권장하고 있습니다. 파드 배치의 예시는 다음과 같습니다.위와 같은 배포 원칙으로 인해 karpenter.yaml 파일을 편집하여 karpenter node affinity를 변경할 겁니다. 변경되면 karpenter는 기존 노드 그룹 노드 중 하나에서 실행될겁니다.
규칙은 다음과 같아야 합니다. $NODEGROUP
은 기존에 클러스터에서 사용하던 노드그룹 중 하나의 이름을 넣으면 됩니다.
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: karpenter.sh/provisioner-name
operator: DoesNotExist
+ - matchExpressions:
+ - key: eks.amazonaws.com/nodegroup
+ operator: In
+ values:
+ - YOUR_NODE_GROUP_NAME # 노드그룹 이름은 현재 사용중인 노드 그룹으로 수정하기
이제 Karpenter 배포가 준비되었습니다.
Karpenter 네임스페이스를 생성합니다.
kubectl create namespace karpenter
Karpenter가 새 노드를 프로비저닝할 때 사용하는 CRD(Custom Resource Definition)인 provisioners
와 awsnodetemplates
을 생성합니다.
kubectl create -f \
https://raw.githubusercontent.com/aws/karpenter/${KARPENTER_VERSION}/pkg/apis/crds/karpenter.sh_provisioners.yaml
kubectl create -f \
https://raw.githubusercontent.com/aws/karpenter/${KARPENTER_VERSION}/pkg/apis/crds/karpenter.k8s.aws_awsnodetemplates.yaml
kubectl create -f \
https://raw.githubusercontent.com/aws/karpenter/${KARPENTER_VERSION}/pkg/apis/crds/karpenter.sh_machines.yaml
kubectl apply -f karpenter.yaml
생성 후에는 kubectl api-resources
명령어로 CRD 목록을 확인합니다.
kubectl api-resources \
--categories karpenter \
-o wide
awsnodetemplates
과 provisioners
리소스가 새로 추가된 걸 확인할 수 있습니다.
NAME SHORTNAMES APIVERSION NAMESPACED KIND VERBS CATEGORIES
awsnodetemplates karpenter.k8s.aws/v1alpha1 false AWSNodeTemplate delete,deletecollection,get,list,patch,create,update,watch karpenter
provisioners karpenter.sh/v1alpha5 false Provisioner delete,deletecollection,get,list,patch,create,update,watch karpenter
Worker Node를 생성하려면 Provisioner와 AWS Node template, 두개가 필요합니다.
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: <<<provisioner name>>>
spec:
providerRef:
name: <<node template name>>
# taint 설정 및 labels 설정을 추가할 수 있다.
# taints:
# - key: purpose
# value: monitoring
# effect: NoExecute
# labels:
# purpose: monitoring
requirements:
# instance type을 정의 여러개를 한번에 정의할 수 있습니다.
- key: node.kubernetes.io/instance-type
operator: In
values: [ c6i.8xlarge, c6i.4xlarge ]
# WorkerNode를 생성할 Zone
- key: topology.kubernetes.io/zone
operator: In
values: [ ap-northeast-2a, ap-northeast-2c ]
# on-demand, spot 중 원하는 인스턴스를 선언, 둘다 정의할 수 있습니다.
- key: karpenter.sh/capacity-type
operator: In
values: [ on-demand ]
- key: kubernetes.io/os
operator: In
values:
- linux
- key: kubernetes.io/arch
operator: In
values:
- amd64 # or arm64
# pod를 적극적으로 이동하고 노드를 삭제하거나 더 저렴한 인스턴스 타입으로 교체하는 노드 통합 기능
consolidation:
enabled: true
# launch Template 사용시(권장하지 않음)
# providerRef:
# name: <<<AWSNodeTemplasteName>>>
# consolidation.enabled 가 false인 경우 사용
# ttlSecondsAfterEmpty: 30
ttlSecondsUntilExpired: 2592000
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: prometheus-provisioner
spec:
labels:
purpose: prometheus
nodegroup: prometheus
requirements:
# instance type을 정의 여러개를 한번에 정의할 수 있습니다.
- key: node.kubernetes.io/instance-type
operator: In
values: [ t4g.medium ]
# WorkerNode를 생성할 Zone
- key: topology.kubernetes.io/zone
operator: In
values: [ ap-northeast-2a, ap-northeast-2c ]
# on-demand, spot 중 원하는 인스턴스를 선언, 둘다 정의할 수 있습니다.
- key: karpenter.sh/capacity-type
operator: In
values: [ on-demand ]
- key: kubernetes.io/os
operator: In
values:
- linux
- key: kubernetes.io/arch
operator: In
values:
- arm64
consolidation:
enabled: true
providerRef:
name: prometheus-node-template
ttlSecondsUntilExpired: 2592000
설정 방식)
ttlSecondsAfterEmpty는 현재 Karpenter에 의해 생성된 WorkerNode에 DaemonSet 이외에 모든 POD들이 삭제되어 있는 상태라면 해당 WorkerNode를 해당 시간만큼 기다렸다가 삭제하라는 의미 입니다. 즉 불필요해진 WorkerNode로 판단되었기 때문에 해당 시간만큼 기다렸다가 삭제하는 것입니다.
ttlSecondsUntilExpired는 Karpenter에 의해 WorkerNode가 생성되었을 때 해당 WorkerNode의 수명을 의미합니다. 즉, 위에서 설정한 시간만큼 WorkerNode가 살아 있었다면 신규 WorkerNode로 교체하라는 것을 의미합니다. 시간은 “초”로 설정할 수 있으며 위의 값이 의미하는 것은 다음과 같습니다. 60sec 60min 24hour 30days = 2592000*
마지막으로 consolidation인데 이 옵션이 아주 중요합니다. consolidation은 WorkerNode의 상태를 감시하며 Node에 현재 배포되어 있는 POD들의 spec을 확인하여 해당 POD를 이동했을 때 WorkerNode를 삭제할 수 있다면 POD를 이동시킵니다. 결국 자원효율성을 최대한으로 사용하기 위한 옵션입니다. 주의 사항으로는 원하지 않는 POD의 이동이 자주 발생할 수 있으며 위에서 설명한 ttlSecondsAfterEmpty 옵션과 동시에 사용이 불가능하다는 점이 있습니다. 2개의 옵션 중 1개만 사용해야 합니다. 제가 위에서 사용한 Sample에도 consolidation을 false로 설정해 놓은 것을 보실 수 있을 겁니다.
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
name: <<<AWSNodeTemplateName>>>
spec:
# subnet, securityGroup tag
subnetSelector:
karpenter.sh/discovery: <<<subnet_tag_value>>>
securityGroupSelector:
karpenter.sh/discovery: <<<securityGroup_tag_value>>>
# WorkerNode Role Name, 미설정시 karpenter에서 생성한 instance role로 자동 할당
# eksctl로 자동생성한 IAM은 설정시 에러 발생할 가능성이 있음, 추가 생성한 IAM 으로는 가능
instanceProfile: <<<Instance_Role_Name>>>
# WorkerNode AMI
# amiFamily 사용 시 자동으로 최신버전의 AmazonLinux2 WorkerNode image 사용
# AL2, Bottlerocket, Ubuntu, Windows2019, Windows2022 등을 사용할 수 있습니다.
amiFamily: AL2
# 주석 처리 되어 있지만 amiSelector를 사용하여 특정 AMI 를 지정해줄 수도 있습니다.
# amiSelector:
# aws-ids: <<<AMI ID>>>
# 노드그룹 사용시, instance에 연결된 볼륨을 확인 후 값을 맞춰줘야 합니다.
# 아래 blockDeviceMapping 찾는법 토글 참조
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 10G
volumeType: gp3
iops: 3000
throughput: 125
deleteOnTermination: true
# WorkerNode tag
tags:
Name : <<<instance_name_tag>>>
# 아래는 필요시 사용
# WorkerNode userdata
# userData: <<<instance_userdata>>>
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
name: prometheus-node-template
spec:
# subnet, securityGroup tag
subnetSelector:
Name: "subnet-private-a,subnet-private-c"
securityGroupSelector:
karpenter.sh/discovery: "devops"
amiFamily: AL2
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 50G
volumeType: gp3
iops: 3000
throughput: 125
deleteOnTermination: true
tags:
Name: prometheus
nodegroup-role: worker
Team: devops
// 앱의 yaml 파일이나 helm에서 annotation을 수정하면 됨.
spec:
template:
metadata:
labels:
annotations:
# 아래가 추가되어야 함
karpenter.sh/do-not-evict: "true"
Pod Disruption Budget(PDB)은 애플리케이션의 복제본 수가 선언된 임계값 미만으로 떨어지면 퇴거 프로세스를 일시적으로 중단할 수 있습니다. 사용 가능한 복제본 수가 임계값을 초과하면 제거 프로세스가 계속됩니다. minAvailable
, maxUnavailable
를 사용하여 PDB의 복제본 수 를 선언할 수 있습니다. 예를 들어 앱 복사본을 3개 이상 사용하려면 PDB를 만들면 됩니다.
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: my-svc-pdb
spec:
minAvailable: 3
selector:
matchLabels:
app: my-svc
위의 PDB 정책은 3개 이상의 복제본을 사용할 수 있을 때까지 제거 프로세스를 중단하도록 Kubernetes에 지시합니다. PodDisruptionBudgets
은 노드의 draining을 존중합니다. EKS 관리형 노드 그룹 업그레이드 중에 노드는 15분의 시간 초과로 드레이닝됩니다 . 15분 후 업데이트가 강제 실행되지 않으면(EKS 콘솔에서는 롤링 업데이트 옵션이라고 함) 업데이트가 실패합니다. 업데이트가 강제 실행되면 pod 삭제됩니다.
자체 관리형 노드의 경우 AWS 노드 종료 핸들러 와 같은 도구를 사용할 수도 있습니다 . 이 도구는 EC2 유지 관리 이벤트 및 EC2 스팟 중단 과 같이 EC2 인스턴스를 사용할 수 없게 만드는 이벤트에 Kubernetes 제어 플레인이 적절하게 응답하도록 보장합니다 . Kubernetes API를 사용하여 노드를 차단하여 새 포드가 예약되지 않았는지 확인한 다음 노드를 비워 실행 중인 모든 포드를 종료합니다.
pod anti-affinity를 사용하여 여러 노드에 배포 포드를 예약하고 노드 업그레이드 중에 PDB 관련 지연을 방지할 수 있습니다.
initialDelaySeconds
첫 번째 프로브를 지연하는 데 사용할 수 있습니다 . Liveness Probe를 사용할 때 Kubernetes가 모든 Pod를 교체하려고 시도하여 애플리케이션을 오프라인으로 렌더링하므로 모든 Pod가 동시에 Liveness Probe에 실패하는 상황이 발생하지 않도록 해야 합니다. 또한 Kubernetes는 Liveness Probe에도 실패하는 새로운 Pod를 계속 생성하여 제어 플레인에 불필요한 부담을 줄 것입니다. Pod 외부 요소(예: 외부 데이터베이스)에 의존하도록 Liveness Probe를 구성하지 마세요. 즉, 포드 외부의 응답하지 않는 데이터베이스로 인해 포드가 활성 프로브에 실패하게 해서는 안 됩니다. Sandor Szücs의 게시물 LIVENESS PROBES ARE DANGEROUS에서는 잘못 구성된 프로브로 인해 발생할 수 있는 문제에 대해 설명합니다.• 컨테이너가 보통 초기 지연 시간 + 실패 임계 값 * 대기 초(initialDelaySeconds + failureThreshold * periodSeconds)
이후에 기동된다면, 스타트업 프로브가 활성화 프로브와 같은 엔드포인트를 체크하도록 명시해야 한다.
앱을 시작하는 데 추가 시간이 필요한 경우 시작 프로브를 사용하여 활성 및 준비 프로브를 지연할 수 있습니다. 예를 들어, 데이터베이스에서 캐시를 하이드레이션해야 하는 Java 앱이 완전히 작동하려면 최대 2분이 걸릴 수 있습니다. 완전히 작동할 때까지 모든 활성 또는 준비 프로브는 실패할 수 있습니다. 시작 프로브를 구성하면 활성 또는 준비 프로브가 실행되기 전에 Java 앱이 정상 상태가 될 수 있습니다 .
시작 프로브가 성공할 때까지 다른 모든 프로브는 비활성화됩니다. Kubernetes가 애플리케이션 시작을 기다려야 하는 최대 시간을 정의할 수 있습니다. 구성된 최대 시간 후에도 포드가 여전히 시작 프로브에 실패하면 포드가 종료되고 새 포드가 생성됩니다.
Startup Probe는 Liveness Probe와 유사합니다. 실패하면 Pod가 다시 생성됩니다. Ricardo A.가 자신의 게시물 인 환상적인 프로브 및 구성 방법 에서 설명했듯이 , 시작 프로브는 애플리케이션의 시작 시간을 예측할 수 없을 때 사용해야 합니다. 애플리케이션을 시작하는 데 10초가 걸린다는 것을 알고 있다면 대신 Liveness/Readiness Probe를 사용해야 합니다 initialDelaySeconds
.
Limit을 걸지 않으면 노드에 다중 포드가 예약 되어 OOM 에러가 발생할 수 있습니다.
설정 귀찮을땐 limit range를 namespace 별로 걸수도 있으니 확인
https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/memory-default-namespace/
주의사항)
동일한 태그를 사용하는 리소스들은 두개 이상 정의 금지
Karpenter provisioner yaml 수정 후 다시 apply 해도 적용이 되지 않기 때문에, 바로 적용하려면 별도의 롤링 업데이트를 해야함.
https://younsl.github.io/blog/k8s/karpenter/
무신사 유튜브 참조: https://www.youtube.com/watch?v=FPlCVVrCD64
카카오 스타일 블로그 참조 : https://devblog.kakaostyle.com/ko/2022-10-13-1-karpenter-on-eks/
감사합니다!