개요
karpenter 이란 ?
karpenter은 WorkerNode(노드)의 수를 조절하는 기능이다
- Watching : 예약 불가능한 (Pending) pod를 감시한다.
- Provisioning : Pending pod의 요구사항에 맞는 노드를 배포하고 배포된 노드에 pod를 스케쥴링 해준다.
- Removing : 노드가 더 이상 필요하지 않을 때 노드 제거한다.
- AWS 환경만 지원
ClusterAutoscaler(CA) 차이점
- ClusterAutoscaler은 ASG를 사용하기 때문에 nodegroup을 구성/관리 해야하고, 노드 증설/축소 시 많은 단계가 필요해서 속도가 느리다.
- ClusterAutoscaler은 예약 불가능한 pod를 감시하고, AWS 리소스를 생성 요청하기 때문에 노드 확장하는대 시간이 오래 걸림.
- Karpenter은 ASG을 사용하지 않고 POD의 요구사항에 맞는 노드를 증설/축소 하기 때문에 속도가 빠르다.
(group-less auto scaling)
- karpenter은 빠른 프로비저닝 가능
ClusterAutoscaler는 Node생성되는데 5분이상 걸림
Karpenter는 Node생성되는데 1~2분 걸림
- https://aws.amazon.com/ko/blogs/korea/introducing-karpenter-an-open-source-high-performance-kubernetes-cluster-autoscaler/
- https://aws.amazon.com/ko/about-aws/whats-new/2021/11/aws-karpenter-v0-5/
- https://aws.amazon.com/ko/blogs/aws/introducing-karpenter-an-open-source-high-performance-kubernetes-cluster-autoscaler/
- https://karpenter.sh/v0.27.1/getting-started/
[ 아키텍처 ]
[ karpenter 프로세스 ]
Node Provisioning (Scale-out) 정책
- Unschedulable pod, pending 상태의 POD가 발생하면 Resource Request량 기준으로 Node가 증설됨.
- 신규 노드가 15분 동안 NotReady 상태면 종료하고 재생성.
Node Removing (Sale-in) 정책
- 예약된 Pod가 없는 Node가 있으면 cordon & drain 이후 terminate 진행.
- karpenter.sh/do-not-evict 설정으로 삭제 방지.
[ Required 작업 ]
- AWS Infra 구성
- EKS Cluster 설치
- IAM OIDC 생성
[ karpenter IAM 설정 ]
IAM Role 내용 정리
- KarpenterControllerRole은 karpenter가 WorkerNode를 생성할 수 있는 AWS 권한 설정
- KarpenterInstanceNodeRole은 Karpenter가 생성한 WorkerNode가 EKS에 조인될 수 있는 Role 권한 설정
1. iam role 생성 - KarpenterInstanceNodeRole
- "KarpenterInstanceNodeRole" IAM 역할 생성
- KarpenterInstanceNodeRole 이란?
- karpenter로 생성한 NODE에 연결 할 IAM 역할입니다.
- EKS에서 NODE를 관리하기 위해서는 IAM 역할이 필요합니다.
- KarpenterInstanceNodeRole 이란?
echo '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}' > node-trust-policy.json
aws iam create-role --role-name KarpenterInstanceNodeRole \
--assume-role-policy-document file://node-trust-policy.json
2. iam role에 policy 연결
- "KarpenterInstanceNodeRole" IAM 역할에 Policy을 연결합니다.
- AmazonEKSWorkerNodePolicy
- AmazonEKS_CNI_Policy
- AmazonEC2ContainerRegistryReadOnly
- AmazonSSMManagedInstanceCore
aws iam attach-role-policy --role-name KarpenterInstanceNodeRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy --role-name KarpenterInstanceNodeRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy --role-name KarpenterInstanceNodeRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam attach-role-policy --role-name KarpenterInstanceNodeRole \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
3. iam Policy 생성 - KarpenterControllerPolicy
- "KarpenterControllerRole" IAM 역할 생성
- KarpenterControllerRole 이란?
- karpenter가 AWS의 EC2(NODE)를 생성할 수 있는 권한을 설정합니다.
- karpenter가 AWS의 EC2(NODE)를 생성할 수 있는 권한을 설정합니다.
- KarpenterControllerRole 이란?
- controller-policy.json 파일 생성
echo '{
"Statement": [
{
"Action": [
"ssm:GetParameter",
"iam:PassRole",
"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/Name": "*karpenter*"
}
},
"Effect": "Allow",
"Resource": "*",
"Sid": "ConditionalEC2Termination"
}
],
"Version": "2012-10-17"
}' > controller-policy.json
- controller-policy.json 파일을 참조해서 IAM Policy 생성
aws iam create-policy --policy-name KarpenterControllerPolicy --policy-document file://controller-policy.json
4. iam Role 생성 - KarpenterControllerRole
- oidc 추출
cluster=${eks-cluster}
aws eks describe-cluster --name $cluster --query "cluster.identity.oidc.issuer" --output text
- rust-policy.json 파일 생성
- xxx으로 되어 있는 값을 채워야합니다.
- oidc, accountid
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123xxx:oidc-provider/oidc.eks.ap-southeast-1.amazonaws.com/id/EXAM1234"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.ap-southeast-1.amazonaws.com/id/EXAM1234:sub": "system:serviceaccount:karpenter:karpenter",
"oidc.eks.ap-southeast-1.amazonaws.com/id/EXAM1234:aud": "sts.amazonaws.com"
}
}
}
]
}
- Role 생성 - KarpenterControllerRole
- trust-policy.json 파일을 참조해서 IAM Role 생성
aws iam create-role --role-name KarpenterControllerRole \
--assume-role-policy-document file://trust-policy.json
- IAM Role에 Policy 연결
- "KarpenterControllerRole" IAM 역할에 Policy을 연결합니다.
- KarpenterControllerPolicy
- "KarpenterControllerRole" IAM 역할에 Policy을 연결합니다.
aws iam attach-role-policy --role-name KarpenterControllerRole \
--policy-arn arn:aws:iam:xxx:aws:policy/KarpenterControllerPolicy
5. subnet에 TAG 추가
- NODE에 설정된 subnet TAG 추가
- Key = karpenter.sh/discovery
- Value = ${Cluster-name}
# 공식 홈페이지에서 subnet에 자동으로 tag 넣기
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
6. SecurityGroup에 TAG 추가
- NODE에 연결된 SG TAG 추가
- Key = karpenter.sh/discovery
- Value = ${Cluster-name}
# 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)
aws ec2 create-tags \
--tags "Key=karpenter.sh/discovery,Value=${CLUSTER_NAME}" \
--resources ${SECURITY_GROUPS}
7. EC2 Instance profile 생성 및 ROLE 연결
- karpenter 설치할 때 Instance profile 지정이 필요합니다.
- Instance profile은 karpenter가 NODE을 생성할 때 IAM Role을 설정이 필요합니다.
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 "KarpenterInstanceNodeRole"
8. ConfigMap "aws-auth" 내용 추가
- karpenter가 만든 NODE가 EKS 권한을 얻을 수 있도록 "aws-auth"에 내용 추가
- KarpenterInstanceNodeRole
data:
mapRoles:
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::xxx:role/KarpenterInstanceNodeRole
username: system:node:{{EC2PrivateDNSName}}
kubectl edit cm aws-auth -n kube-system
apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::xxx:role/xxx-eks-node-group
username: system:node:{{EC2PrivateDNSName}}
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::xxx:role/KarpenterInstanceNodeRole
username: system:node:{{EC2PrivateDNSName}}
mapUsers: |
- groups:
- system:masters
userarn: arn:aws:iam::xxx:user/xxx@xxx.com
username: xxx@xxx.com
... 중간 생략 ...
[ karpenter 설치 ]
- helm repository URL : https://github.com/aws/karpenter/tree/main/charts/karpenter
1. karpenter 설치
설치 변수
- ${KARPENTER_IAM_ROLE_ARN}
- 위에서 생성한 KarpenterControllerRole 입력
- arn:aws:iam::xxx:role/KarpenterControllerRole
- ${CLUSTER_ENDPOINT}
- clustern endpoint 정보
- aws eks describe-cluster --name ${cluster_name} --query "cluster.endpoint" --output text
- KarpenterNodeInstanceProfile-${CLUSTER_NAME}
- KarpenterNodeInstanceProfile 정보 입력
helm upgrade --install --namespace karpenter --create-namespace \
karpenter oci://public.ecr.aws/karpenter/karpenter \
--version v0.27.1 \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \
--set settings.aws.clusterName=${CLUSTER_NAME} \
--set settings.aws.clusterEndpoint=${CLUSTER_ENDPOINT} \
--set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \
--set nodeSelector.nodegroupname=infra-ng
# --set settings.aws.interruptionQueueName=${CLUSTER_NAME} \
2. Provisioner 설치
- Provisioner은 Karpenter가 Node를 생성할 때 참조하는 내용이 들어있다.
- node Type, subnet, 등등
- Provisioner 메뉴얼 링크 : https://karpenter.sh/v0.20.0/concepts/provisioning/
- karpenter-provisioner.yaml 파일 생성
vi karpenter-provisioner.yaml
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: karpenter-provisioner
spec:
requirements:
- key: node.kubernetes.io/instance-type
operator: In
values: ["t2.small"]
- key: "topology.kubernetes.io/zone"
operator: In
values: ["ap-southeast-1a", "ap-southeast-1b", "ap-southeast-1c"]
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"]
- key: nodegroupname
operator: In
values:
- test-ng
limits:
resources:
cpu: "500"
memory: 1000Gi
ttlSecondsAfterEmpty: 30
labels:
role: ops
provision: karpenter
provider:
securityGroupSelector:
karpenter.sh/discovery: ${cluster-name}
subnetSelector:
karpenter.sh/discovery: ${cluster-name}
tags:
Name: karpenter.sh/provisioner-name/karpenter-provisioner
karpenter.sh/discovery: ${cluster-name}
- karpenter-provisioner.yaml 배포
kubectl apply -f karpenter-provisioner.yaml
[ karpenter 테스트 ]
1. Pod 생성
- php-apache pod 생성
- nodeSelector을 "nodegroupname: test-ng" 설정
vi php-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache-dw
spec:
selector:
matchLabels:
run: php-apache-dw
template:
metadata:
labels:
run: php-apache-dw
spec:
containers:
- name: php-apache-dw
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
nodeSelector:
nodegroupname: test-ng
# php-apache 배포
kubectl apply -f php-apache.yaml
2. Pod Pending
- "nodegroupname: test-ng" node가 존재하지 않아서 Pending 상태
- 에러 메세지
- Warning FailedScheduling 29m (x4 over 33m) default-scheduler 0/14 nodes are available: 14 node(s) didn't match Pod's node affinity/selector.
3. Node 생성
- karpenter가 node 생성 프로세스
- karpenter가 Pending POD를 감지
- Pending POD가 provisioner에 설정한 내용가 일치하면 Node 생성
- Node NotReady 상태
- Node Ready 상태
- POD가 Node에 배포됨
- node 생성 및 pod 배포까지 약 2분 30초 소요
- karpenter log 메세지
INFO controller.provisioner found provisionable pod(s) {"commit": "7131be2-dirty", "pods": 1}
INFO controller.provisioner computed new machine(s) to fit pod(s) {"commit": "7131be2-dirty", "machines": 1, "pods": 1}
INFO controller.provisioner launching machine with 1 pods requesting {"cpu":"355m","memory":"120Mi","pods":"7"} from types t2.small {"commit": "7131be2-dirty", "provisioner": "karpenter-provisioner"}
- Karpenter가 Node 증설 후 POD가 배포됨

- pod log 메세지
Normal Nominated 12m karpenter Pod should schedule on node: ip-10-223-70-189.ap-southeast-1.compute.internal
5. Node 축소
- POD를 삭제하면 karpenter가 생성한 node에 배포된 pod가 없어서 자동으로 축소됨
- karpenter log 메세지
Provisioner 옵션
[ Provisioner - spec.requirements 옵션 ]
- 옵션 링크 : https://karpenter.sh/v0.27.1/concepts/provisioners/
key | 설명 |
node.kubernetes.io/instance-type | AWS Node Type 설정하는 옵션 |
topology.kubernetes.io/zone | a,b,c zone 선택하는 옵션 |
karpenter.sh/capacity-type | on-demand, spot 옵션 선택 |
nodegroupname | NodeSelector 내용과 일치했을 때 생성하는 옵션 |
key | 설명 |
spec.provider.securityGroupSelector | AWS NODE 생성할 때 SG설정 옵션 (values에 지정한 tag 설정된 SG그룹) |
spec.provider.subnetSelector | AWS NODE 생성할 때 subnet 설정 옵션 (values에 지정한 tag 설정된 subnet) |
spec.provider.tags | AWS NODE 생성할 때 TAG 내용 추가 (karpenter가 생성한 EC2 TAG NAME 설정) |
spec.labels | AWS NODE 생성할 때 labels 내용 추가 |
spec.annotations | AWS NODE 생성할 때 annotations 내용 추가 |
spec.taints | AWS NODE 생성할 때 taints 내용 추가 |
spec.ttlSecondsAfterEmpty | Karpenter가 생성한 Node가 사용하지 않으면 Node를 축소합니다. 값은 초 단위 설정 생략시 node 축소를 하지 않습니다. |
spec.ttlSecondsUntilExpired | Karpenter가 생성한 Node 만료일을 설정합니다. 만료가되면 Node가 삭제됩니다. 값은 초 단위 설정 |
spec.providerRef | Node Template을 사용해서 더 다양한 옵션을 할때 사용한다. https://karpenter.sh/v0.27.1/concepts/node-templates/ |
spec.limits.resources.cpu spec.limits.resources.memory |
Karpenter가 AWS Node를 무한대로 생성하지 못하도록 제한한다. (AWS Node 생성할 수 있는 개수 limit(제한) 설정합니다.) |
'인프라 > 시스템 구축' 카테고리의 다른 글
[ istio ] Install (0) | 2023.04.13 |
---|---|
[ istio ] istio 이란? (0) | 2023.04.13 |
[ EKS ] ClusterAutoscaler (CA) (0) | 2023.04.06 |
[ EKS ] VPA (0) | 2023.04.06 |
[ EKS ] HPA (0) | 2023.04.04 |