1. 유틸리티 설치
카펜터는 헬름 차트를 사용하여 클러스터로 설치된다.
- AWS CLI (v2.22.6)
- kubectl (v1.31.1)
- eksctl (v0.192.0)
- helm (v3.16.2)
- karpenter (v1.0.5)
사용한 버전은 다음과 같다.
2. 환경 변수 설정
카펜터, 쿠버네티스 버전 설정
export KARPENTER_NAMESPACE="kube-system"
export KARPENTER_VERSION="1.0.5"
export K8S_VERSION="1.31"
환경 변수 설정
export AWS_PARTITION="aws"
export CLUSTER_NAME="eks"
export AWS_REGION="ap-northeast-2"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export NODEGROUP_NAME="karpenter-ng"
export POLICY_ARN="arn:aws:iam::<AWS_ACCOUNT_ID>:policy/KarpenterControllerPolicy-eks"
export ROLE_ARN="arn:aws:iam::<AWS_ACCOUNT_ID>:role/KarpenterControllerRole-eks"
# 임시 파일 지정
export TEMPOUT="$(mktemp)"
# EKS에 최적화된 AMI ID 가져오기 (Amazon Linux 2)
export ARM_AMI_ID="$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2-arm64/recommended/image_id --query Parameter.Value --output text)"
export AMD_AMI_ID="$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2/recommended/image_id --query Parameter.Value --output text)"
export GPU_AMI_ID="$(aws ssm get-parameter --name /aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2-gpu/recommended/image_id --query Parameter.Value --output text)"
값을 기억하기
echo "${KARPENTER_NAMESPACE}" "${KARPENTER_VERSION}" "${K8S_VERSION}" "${CLUSTER_NAME}" "${AWS_REGION}" "${AWS_ACCOUNT_ID}" "${TEMPOUT}" "${ARM_AMI_ID}" "${AMD_AMI_ID}" "${GPU_AMI_ID}"
3. IAM 권한 준비
KarpenterControllerRole : Karpenter 컨트롤러에 필요한 역할
echo '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}' > karpenter-trust-policy.json
KarpenterNodeRole : Karpenter가 생성하는 노드에 할당할 역할
aws iam create-role --role-name KarpenterControllerRole \
--assume-role-policy-document file://karpenter-trust-policy.json
KarpenterNodeRole에 EKS 노드에게 필수적으로 필요한 권한 4개
- AmazonEKSWorkerNodePolicy
- AmazonEKS_CNI_Policy
- AmazonEC2ContainerRegistryReadOnly
- AmazonSSMManagedInstanceCore
aws iam attach-role-policy \
--role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy \
--role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy \
--role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam attach-role-policy \
--role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Karpenter가 배포한 EC2에서 해당 Role을 사용할 수 있도록 EC2 Instance Profile을 생성한다.
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}"
1. Karpenter 컨트롤러용 IAM Role
이제 Karpenter 컨트롤러가 새 인스턴스를 프로비저닝 하는 데 사용할 IAM 역할을 생성해야 한다.
Karpenter 컨트롤러는 IRSAIAM Role for Service Account 방식으로 IAM 권한을 얻어 EC2 생성, 삭제를 수행한다.
IAM Role의 신뢰 관계 생성
cat << EOF > controller-trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws: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/Name": "*karpenter*"
}
},
"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
Inline Policy를 Karpenter Controller용 IAM Role에 연결한다.
aws iam put-role-policy \
--role-name KarpenterControllerRole-${CLUSTER_NAME} \
--policy-name KarpenterControllerPolicy-${CLUSTER_NAME} \
--policy-document file://controller-policy.json
2. EKS 클러스터의 서브넷에 태그를 추가하는 AWS CLI 명령어
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 ts-eks --query 'nodegroup.subnets' --output text )
done
3. 보안 그룹에 태그를 추가하는 CLI 명령어
이 명령은 클러스터의 첫 번째 노드 그룹에 대한 보안 그룹에만 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" ",")
SECURITY_GROUPS=$(aws eks describe-cluster \
--name ${CLUSTER_NAME} --query "cluster.resourcesVpcConfig.clusterSecurityGroupId" --output text)
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}
4. aws-auth configMap 업데이트
방금 생성한 노드 IAM 역할을 사용하는 EC2 노드가 EKS 클러스터에 가입하도록 허용해 준다.
관련 설정은 aws-auth ConfigMap에서 관리된다.
kubectl edit configmap aws-auth -n kube-system
# 변경 전
apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/dev-global-eks-node-iam-role
username: system:node:{{EC2PrivateDNSName}}
kind: ConfigMap
metadata:
...
# 변경 후
apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/dev-global-eks-node-iam-role
username: system:node:{{EC2PrivateDNSName}}
+ - groups:
+ - system:bootstrappers
+ - system:nodes
+ rolearn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/KarpenterNodeRole-eks
+ username: system:node:{{EC2PrivateDNSName}}
kind: ConfigMap
metadata:
...
참고로, ControllerRole이 아니라 NodeRole을 써야 한다.
4. Karpenter 설치
helm registry logout public.ecr.aws
Helm을 사용하여 Public ECR에서 Karpenter 이미지를 설치할 때 인증 없이(unauthenticated) 접근이 가능하도록 하기 위함이다.
Public ECR은 기본적으로 공개되어 있으므로 인증 없이 이미지를 받을 수 있다. 하지만 인증 세션이 활성화되어 있으면 인증 관련 문제가 발생할 가능성이 있으므로 이를 방지한다.
로그아웃되면 이후의 Helm 명령어는 인증 없이 Public ECR에서 이미지를 다운로드하게 된다.
helm 차트에서 Karpenter 배포 yaml을 생성할 수 있다.
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"="${ROLE_ARN}" \
--set controller.resources.requests.cpu=0.5 \
--set controller.resources.requests.memory=512Mi \
--set controller.resources.limits.cpu=0.5 \
--set controller.resources.limits.memory=512Mi \
--set replicas=2 > karpenter.yaml
OCI Helm 차트는 릴리스 프로세스의 일부로 Cosign 에 의해 서명되었으므로 다음 명령을 실행하여 설치하기 전에 차트를 확인할 수 있다.
Sigstore의 Cosign 도구를 사용하여 컨테이너 이미지의 서명을 검증하는 과정이다.
이 예에서는 Karpenter 컨테이너 이미지의 서명을 검증하고, 이 이미지가 신뢰할 수 있는 소스에서 빌드되었음을 확인한다.
프로덕션 환경에서 신뢰할 수 없는 이미지를 사용하는 위험을 줄이기 위해 실행한다.
cosign verify public.ecr.aws/karpenter/karpenter:1.0.5 \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity-regexp='https://github\.com/aws/karpenter-provider-aws/\.github/workflows/release\.yaml@.+' \
--certificate-github-workflow-repository=aws/karpenter-provider-aws \
--certificate-github-workflow-name=Release \
--certificate-github-workflow-ref=refs/tags/v1.0.5 \
--annotations version=1.0.5
'Kubernetes' 카테고리의 다른 글
[k8s] EKS에서 Karpenter 사용하기 (2) (1) | 2025.01.05 |
---|---|
[k8s] karpenter란? (2) | 2025.01.04 |