aws eks --region ap-northeast-2 update-kubeconfig --name ws-eks-cluster
Shell
복사
kubectl create ns karpenter
Shell
복사
private_a=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=ws-private-a" --query "Subnets[].SubnetId[]" --region ap-northeast-2 --output text)
private_b=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=ws-private-b" --query "Subnets[].SubnetId[]" --region ap-northeast-2 --output text)
private_subnet_name=("$private_a" "$private_b")
for name in "${private_subnet_name[@]}"
do
aws ec2 create-tags --resources $name --tags Key=karpenter.sh/discovery,Value=ws-eks-cluster
done
cluster_sg=$(aws ec2 describe-security-groups --filters "Name=tag:aws:eks:cluster-name,Values=ws-eks-cluster" --query "SecurityGroups[].GroupId[]" --region ap-northeast-2 --output text)
aws ec2 create-tags --resources $cluster_sg --tags Key=karpenter.sh/discovery,Value=ws-eks-cluster
Shell
복사
export KARPENTER_NAMESPACE=karpenter
export CLUSTER_NAME=ws-eks-cluster
export KARPENTER_VERSION="1.3.3"
export TEMPOUT="$(mktemp)"
export AWS_PARTITION="aws"
export CLUSTER_ENDPOINT=$(aws eks describe-cluster --name ws-eks-cluster --query "cluster.endpoint" --output text)
export AWS_DEFAULT_REGION=ap-northeast-2
export OIDC_ENDPOINT="$(aws eks describe-cluster --name "${CLUSTER_NAME}" \
--query "cluster.identity.oidc.issuer" --output text)"
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export K8S_VERSION=$(aws eks describe-cluster --name "${CLUSTER_NAME}" --query "cluster.version" --output text)
export ALIAS_VERSION="$(aws ssm get-parameter --name "/aws/service/eks/optimized-ami/${K8S_VERSION}/amazon-linux-2023/x86_64/standard/recommended/image_id" --query Parameter.Value | xargs aws ec2 describe-images --query 'Images[0].Name' --image-ids | sed -r 's/^.*(v[[:digit:]]+).*$/\1/')"
oidc_id=$(aws eks describe-cluster --name $CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
Shell
복사
eksctl utils associate-iam-oidc-provider \
--region ${AWS_DEFAULT_REGION} \
--cluster ${CLUSTER_NAME} \
--approve
Shell
복사
curl -fsSL https://raw.githubusercontent.com/aws/karpenter-provider-aws/v"${KARPENTER_VERSION}"/website/content/en/preview/getting-started/getting-started-with-karpenter/cloudformation.yaml > "${TEMPOUT}" \
&& aws cloudformation deploy \
--stack-name "Karpenter-${CLUSTER_NAME}" \
--template-file "${TEMPOUT}" \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides "ClusterName=${CLUSTER_NAME}"
Shell
복사
cat << EOF > karpenter-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/nodepool": "*"
}
},
"Effect": "Allow",
"Resource": "*",
"Sid": "ConditionalEC2Termination"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::${AWS_ACCOUNT_ID}:role/ws-eks-node-role",
"Sid": "PassNodeIAMRole"
},
{
"Effect": "Allow",
"Action": "eks:DescribeCluster",
"Resource": "arn:aws:eks:ap-northeast-2:${AWS_ACCOUNT_ID}:cluster/${CLUSTER_NAME}",
"Sid": "EKSClusterEndpointLookup"
},
{
"Sid": "AllowScopedInstanceProfileCreationActions",
"Effect": "Allow",
"Resource": "*",
"Action": [
"iam:CreateInstanceProfile"
],
"Condition": {
"StringEquals": {
"aws:RequestTag/kubernetes.io/cluster/${CLUSTER_NAME}": "owned",
"aws:RequestTag/topology.kubernetes.io/region": "ap-northeast-2"
},
"StringLike": {
"aws:RequestTag/karpenter.k8s.aws/ec2nodeclass": "*"
}
}
},
{
"Sid": "AllowScopedInstanceProfileTagActions",
"Effect": "Allow",
"Resource": "*",
"Action": [
"iam:TagInstanceProfile"
],
"Condition": {
"StringEquals": {
"aws:ResourceTag/kubernetes.io/cluster/${CLUSTER_NAME}": "owned",
"aws:ResourceTag/topology.kubernetes.io/region": "ap-northeast-2",
"aws:RequestTag/kubernetes.io/cluster/${CLUSTER_NAME}": "owned",
"aws:RequestTag/topology.kubernetes.io/region": "ap-northeast-2"
},
"StringLike": {
"aws:ResourceTag/karpenter.k8s.aws/ec2nodeclass": "*",
"aws:RequestTag/karpenter.k8s.aws/ec2nodeclass": "*"
}
}
},
{
"Sid": "AllowScopedInstanceProfileActions",
"Effect": "Allow",
"Resource": "*",
"Action": [
"iam:AddRoleToInstanceProfile",
"iam:RemoveRoleFromInstanceProfile",
"iam:DeleteInstanceProfile"
],
"Condition": {
"StringEquals": {
"aws:ResourceTag/kubernetes.io/cluster/${CLUSTER_NAME}": "owned",
"aws:ResourceTag/topology.kubernetes.io/region": "ap-northeast-2"
},
"StringLike": {
"aws:ResourceTag/karpenter.k8s.aws/ec2nodeclass": "*"
}
}
},
{
"Sid": "AllowInstanceProfileReadActions",
"Effect": "Allow",
"Resource": "*",
"Action": "iam:GetInstanceProfile"
},
{
"Sid": "AllowInterruptionQueueActions",
"Effect": "Allow",
"Resource": "*",
"Action": [
"sqs:DeleteMessage",
"sqs:GetQueueUrl",
"sqs:ReceiveMessage"
]
}
],
"Version": "2012-10-17"
}
EOF
Shell
복사
aws iam create-policy \
--policy-name "ws-karpenter-controller-policy" \
--policy-document file://karpenter-controller-policy.json
Shell
복사
cat << EOF > trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/${oidc_id}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.ap-northeast-2.amazonaws.com/id/${oidc_id}:aud": "sts.amazonaws.com",
"oidc.eks.ap-northeast-2.amazonaws.com/id/${oidc_id}:sub": "system:serviceaccount:karpenter:karpenter"
}
}
}
]
}
EOF
Shell
복사
aws iam create-role \
--role-name "ws-karpenter-controller-role" \
--assume-role-policy-document file://trust-policy.json
Shell
복사
aws iam attach-role-policy \
--role-name "ws-karpenter-controller-role" \
--policy-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:policy/ws-karpenter-controller-policy"
Shell
복사
helm repo add karpenter https://charts.karpenter.sh/
helm repo update
helm template karpenter oci://public.ecr.aws/karpenter/karpenter --version "${KARPENTER_VERSION}" --namespace "${KARPENTER_NAMESPACE}" \
--set "settings.clusterName=${CLUSTER_NAME}" \
--set "settings.interruptionQueue=${CLUSTER_NAME}" \
--set "serviceAccount.annotations.eks\.amazonaws\.com/role-arn=arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/ws-karpenter-controller-role" \
--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
Shell
복사
karpenter.yaml 파일 수정 및 배포
# 위 명령어를 수행하면 karpenter.yaml 파일이 실행되는데, 해당 파일을 열어
# 아래 부분에서 values를 Karpenter에 의해 생성되지 않은 워커 노드그룹 이름으로
# 꼭 바꿔주어야 한다.
vim karpenter.yaml
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: karpenter.sh/nodepool
operator: DoesNotExist
- key: eks.amazonaws.com/nodegroup
operator: In
values:
- ${Karpenter에 생성되지 않은 현재 Worker NodeGroup Name ex. ws-addon}
- key: topology.kubernetes.io/region
operator: In
values:
- ap-northeast-2
# karpenter만 올리기 위해 toleration섹션도 찾아서 추가
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- key: "node-role.kubernetes.io/ws-addon"
operator: "Exists"
effect: "NoSchedule"
Shell
복사
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: karpenter-global-settings
namespace: karpenter
data:
clusterName: ${CLUSTER_NAME}
clusterEndpoint: ${CLUSTER_ENDPOINT}
aws.defaultInstanceProfile: "KarpenterInstanceProfile"
EOF
Shell
복사
kubectl create -f \
"https://raw.githubusercontent.com/aws/karpenter-provider-aws/v${KARPENTER_VERSION}/pkg/apis/crds/karpenter.sh_nodepools.yaml"
kubectl create -f \
"https://raw.githubusercontent.com/aws/karpenter-provider-aws/v${KARPENTER_VERSION}/pkg/apis/crds/karpenter.k8s.aws_ec2nodeclasses.yaml"
kubectl create -f \
"https://raw.githubusercontent.com/aws/karpenter-provider-aws/v${KARPENTER_VERSION}/pkg/apis/crds/karpenter.sh_nodeclaims.yaml"
kubectl apply -f karpenter.yaml
Shell
복사
cat > nodepool.yaml << 'EOF'
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
namespace: karpenter
spec:
template:
metadata:
labels:
nodegroup: emr
eks.amazonaws.com/compute-type: emr
spec:
taints:
- key: eks.amazonaws.com/compute-type
value: emr
effect: NoSchedule
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: kubernetes.io/os
operator: In
values: ["linux"]
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"]
- key: "node.kubernetes.io/instance-family"
operator: In
values: ["m5", "m5d", "c5", "c5d", "c4", "r4"]
- key: "node.kubernetes.io/instance-cpu"
operator: In
values: ["4", "8", "16", "32"]
- key: "topology.kubernetes.io/zone"
operator: In
values: ["ap-northeast-2a", "ap-northeast-2b"]
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: 720h # 30 * 24h = 720h
limits:
cpu: 200
memory: 800Gi
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 90s
---
#ec2nodeclass(Karpenter가 노드 생성시 참고할 EC2 설정)
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
namespace: karpenter
spec:
role: "ws-eks-node-role" # replace with your cluster name
amiSelectorTerms:
- alias: "al2023@latest"
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "ws-eks-cluster" # replace with your cluster name
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "ws-eks-cluster" # replace with your cluster name
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100Gi
volumeType: gp3
tags:
nodegroup: emr
eks.amazonaws.com/compute-type: emr
EOF
Shell
복사
kubectl apply -f nodepool.yaml
Shell
복사
