EKS-NodeLess-06-AWS-Karpenter-Install

이번 포스팅은 Karpenter 설치다. 설치하다 막히면 가이드를 보자. https://karpenter.sh/v0.27.3/getting-started/migrating-from-cas/ karpenter 를 설치하기 전에 먼저 셋팅해야 할것들이 있다. CLUSTER_NAME=myeks # your clouster name AWS_PARTITION="aws" # aws or aws-gov or aws-cn 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) export KARPENTER_VERSION=v0.27.3 # latast version ```bash 환경 변수 설정이다. 클러스터 이름 / 리전 / OIDC ENDPOINT / 어카운트 넘버 / karpenter 버전이 그것이다. Karpenter 를 설치할때는 많은 권한을 요구로 한다. ```bash 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 "KarpenterNodeRole-${CLUSTER_NAME}" \\ --assume-role-policy-document file://node-trust-policy.json 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 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}" 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 aws iam create-role --role-name KarpenterControllerRole-${CLUSTER_NAME} \\ --assume-role-policy-document file://controller-trust-policy.json 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 ```bash 환경 설정과 적절한 권한이 주어져 있다면 이과정에서 에러는 나지 않는다. IAM까지 했다면 거의 다한거다. IAM에는 KarpenterNodeRole 을 만들고 권한부여하고 KarpenterNodeInstanceProfile 을 Role에 추가한다. 이름과도 같이 프로비저닝된 Karpenter Node가 가지게 될 Role 이다. 또 KarpenterControllerRole 은 IRSA로 Karpenter Pod에 부여될 Role이다. 그다음에 필수로 있어야하는건 서브넷과 보안그룹이다. 인스턴스가 프로비저닝 되기위한 필수 조건이 바로 이것이다. 이 실습에선 Karpenter의 기본설정을 따라가지만 이해를 돕기위해 직접 태깅을 추가한다. 만일 NodeGroup를 사용하고 있고 전환하길 원한다면 가이드에 나온 스크립트를 사용해도 좋다. ![](/images/2023/05/image-4.png) 나는 이렇게 추가했다 **karpenter.sh/discovery = myeks** 다 그다음엔 보안그룹에 태그를 추가해준다 ![](/images/2023/05/image-5.png) 서브넷과 동일하게 했다. 실제로 사용할때에 AWSNodeTemplate 을 작성할때 사용할 태그이다. 이렇게 진행했다면 이제 Karpenter 에서 프로비저닝한 노드가 클러스터에 Join이 가능하도록 허용해줘야 한다. ```bash 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/KarpenterNodeRole-${CLUSTER_NAME} username: system:node:{{EC2PrivateDNSName}} ```bash mapRoles 아래에 넣는다. 변수부분 수정해서 넣어야한다. 이제 드디어 카펜터를 설치한다. 이과정에는 헬름이 필수다. ```bash helm template karpenter oci://public.ecr.aws/karpenter/karpenter \\ --version ${KARPENTER_VERSION} \\ --namespace karpenter \\ --set clusterName=${CLUSTER_NAME} \\ --set settings.aws.clusterName=${CLUSTER_NAME} \\ --set clusterEndpoint=${CLUSTER_ENDPOINT} \\ --set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${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 ```bash settings.aws.clusterName / clusterName 이두가지 옵션은 다른옵션이다. 헷갈리지 말자. 우리는 NodeLess 를 진행중이기 때문에 여기서 Karpneter 가이드와 다르게 간다. ```bash aws eks create-fargate-profile --fargate-profile-name karpenter --cluster-name myeks --pod-execution-role-arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/AmazonEKSFargatePodExecutionRole --subnets "subnet-1" "subnet-2" "subnet-3" ```bash 이렇게 karpenter Fargate Profile을 생성하였다면 이제 Karpenter의 컴포넌트와 CRD를 같이 배포해줄 때다. ```bash kubectl create namespace karpenter 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 apply -f karpenter.yaml ```bash 이렇게 배포하면 파게이트에 배포된 Karpenter 를 만날수 있다. ```bash k get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES karpenter-5bffc6f5d8-p2pxh 1/1 Running 0 9d 192.168.12.183 fargate-ip-192-168-12-183.ap-northeast-2.compute.internal <none> <none> karpenter-5bffc6f5d8-qgcwn 1/1 Running 0 9d 192.168.13.157 fargate-ip-192-168-13-157.ap-northeast-2.compute.internal <none> <none> ```bash Karpenter는 버전에 따라 Pod내에 Container 가 2개인 경우가 있다. 이경우엔 컨트롤러와 웹훅용도의 컨테이너가 두개가 동작한다. 일정버전 이상에서만 Fargate에 프로비저닝 된다. 그냥 v0.27.3버전 이상쓰자. 하다가 안되면 대부분 유저 문제다. <https://karpenter.sh/v0.27.3/troubleshooting/> 을보자. 설치가 드디어 완료됬다. 다음은 Karpenter 의 두가지 CRD에 대한 설명을 할것이다.

May 17, 2023 · 3 min · 📁 AWS, Kubernetes · 🏷️ EKS, nodeless, karpenter

EKS-NodeLess-05-AWS-Karpenter-component

이제야 드디어 Karpenter까지 왔다. Karpenter의 구성요소부터 살펴보자! PodDisruptionBudget: PodDisruptionBudget은 클러스터의 안정성을 보장하기 위해 사용된다. 특정 서비스를 중단하지 않고 동시에 종료할 수 있는 Pod의 최대 수를 지정한다. ServiceAccount: Karpenter가 동작하려면 해당 권한을 가진 Kubernetes의 ServiceAccount가 필요하다. ServiceAccount는 Kubernetes 리소스에 대한 API 접근 권한을 제공한다. Secret-webhook-cert: Karpenter의 웹훅에 사용되는 TLS 인증서를 저장하는 Secret이다. 이를 통해 웹훅이 안전하게 통신할 수 있다. ConfigMap-logging: Karpenter의 로깅 설정을 저장하는 ConfigMap이다. 로깅 수준, 출력 형식 등을 지정할 수 있다. ...

May 15, 2023 · 3 min · 📁 AWS, Kubernetes · 🏷️ EKS, nodeless, karpenter

EKS-NodeLess-04-AWS-LoadBalancer-Controller

AWS LoadBalancer Controller 도 Fargate에 올려야 한다. 비교적 간단한데, Controller Pod에 annotations 한줄만 추가하면된다. 먼저 추가할때 Policy 를 생성한다. VPC_NAME=myeks-VPC // VPC NAME 으로 변경 CLUSTER_NAME=myeks REGION=ap-northeast-2 curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.7/docs/install/iam_policy.json aws iam create-policy \\ --policy-name AWSLoadBalancerControllerIAMPolicy \\ --policy-document file://iam_policy.json POLICY_ARN=`aws iam list-policies | grep Arn | grep AWSLoadBalancerControllerIAMPolicy | awk -F\\" '{print $4}'` VPC_ID=$(aws ec2 describe-vpcs --query 'Vpcs[?contains(Tags[?Key==`Name`].Value[], `'$VPC_NAME'`) == `true`].[VpcId]' --output text) ```bash 이 Policy를 이용하여 eksctl에서 사용할거다. POLICY_ARN은 전체 Policy 에서 AWSLoadBalancerControllerIAMPolicy 의 arn을 추출한다. ```bash eksctl create iamserviceaccount \\ --cluster=myeks \\ --namespace=kube-system \\ --name=aws-load-balancer-controller \\ --role-name AmazonEKSLoadBalancerControllerRole \\ --attach-policy-arn=$POLICY_ARN \\ --approve ```bash ```bash helm install aws-load-balancer-controller eks/aws-load-balancer-controller \\ -n kube-system \\ --set clusterName=$CLUSTER_NAME \\ --set serviceAccount.create=false \\ --set serviceAccount.name=aws-load-balancer-controller \\ --set region=$REGION \\ --set vpcId=$VPC_ID ```bash 로 보통 AWS LoadBalancer Controller 를 설치해 줘야 하지만 우리는 Fargate annotations 추가 한단계를 더 거쳐야 한다. ```bash kubectl patch deployment aws-load-balancer-controller -n kube-system --type=json -p='[{"op": "add", "path": "/spec/template/metadata/annotations/eks.amazonaws.com~1fargate-profile", "value":"kube-system"}]' kubectl rollout restart deployment aws-load-balancer-controller -n kube-system ```bash 다음과 같이 patch 를 하고 rollout restart 까지 하면 pod가 Fargate 로 생성된다. ```bash k get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES aws-load-balancer-controller-76db948d9b-qzpsd 1/1 Running 0 46s 192.168.11.65 fargate-ip-192-168-11-65.ap-northeast-2.compute.internal <none> <none> aws-load-balancer-controller-76db948d9b-t26qt 1/1 Running 0 88s 192.168.11.180 fargate-ip-192-168-11-180.ap-northeast-2.compute.internal <none> <none> ```bash 시간날때마다 Fargate 로 추가되어야 하는 에드온들을 Fargate 로 생성하는 방법을 작성하겠다. 읽어줘서 감사하다!

May 14, 2023 · 2 min · 📁 AWS, Kubernetes

EKS-NodeLess-03-Karpenter-01-intro

NodeLess 컨셉에서 제일 중요한 역할을 맡고 있는 Karpenter 다. Karpenter 의 기본적인 아키텍처 부터 리뷰해볼까 한다. 그렇다면 그전에 Cluster Autoscaler 부터 설명해야 한다. Cluster Autoscaler 는 보통 CA라 부른다. 간략하게 플로우를 설명하겠다. Kubernetes에 새로운 Pod 가 프로비저닝 되었을때 Pod는 노드그룹에 스케줄링 된다. 노드그룹에 자원이 부족하면 CA가 트리거 된다. CA는 AWS 의 ASG에 새로운 로드를 요청한다. ASG는 새로운노드를 생성하고 노드그룹에 추가한다. 새로 스케줄링된 노드에 Pod가 생성된다. 생략된 단계가 있지만 실제로 이 단계를 모두 거쳐야 인스턴스가 EKS에 연결되고 노드그룹에 인스턴스가 노출된다. 그렇다면 단순히 ASG에서 노드를 제거해본 경험이 있는가? 있다면 알것이다. 이건 가끔 커피한잔하고 와도 제거안된 인스턴스가 있는 경우도 있다. ...

May 12, 2023 · 1 min · 📁 AWS, Kubernetes · 🏷️ EKS, nodeless, karpenter

EKS-NodeLess-02-Fargate

# k get pod -A -o wide NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES default nginx-pod 1/1 Running 0 11m 192.168.12.217 ip-192-168-12-150.ap-northeast-2.compute.internal <none> <none> karpenter karpenter-5bffc6f5d8-6f779 1/1 Running 0 125m 192.168.12.99 fargate-ip-192-168-12-99.ap-northeast-2.compute.internal <none> <none> karpenter karpenter-5bffc6f5d8-84mjn 1/1 Running 0 130m 192.168.11.201 fargate-ip-192-168-11-201.ap-northeast-2.compute.internal <none> <none> kube-system aws-node-h5z8d 1/1 Running 0 11m 192.168.12.150 ip-192-168-12-150.ap-northeast-2.compute.internal <none> <none> kube-system coredns-fd69467b9-4nk6x 1/1 Running 0 127m 192.168.12.52 fargate-ip-192-168-12-52.ap-northeast-2.compute.internal <none> <none> kube-system coredns-fd69467b9-cqqpq 1/1 Running 0 125m 192.168.11.122 fargate-ip-192-168-11-122.ap-northeast-2.compute.internal <none> <none> kube-system kube-proxy-z8qlj 1/1 Running 0 11m 192.168.12.150 ip-192-168-12-150.ap-northeast-2.compute.internal <none> <none> ```bash 먼저 예제를 보여준다. NodeLess EKS 컨셉의 기반이다. nginx-pod / aws-node-h5z8d / kube-proxy-z8qlj 는 카펜터가 만든 노드위에 올라가 있다. NodeLess 의 컨셉은 두가지를 기반으로 한다. 쿠버네티스 컴포넌트 kube-system namespace Pod들은 Fargate에 올린다. 여기에 에드온이나 관리가 필요한 Pod도 포함된다. karpenter controller라던가..AWS ELB Controller 라던가 그런 에드온들이 그런 역할을 한다. Node가 필요한 Pod는 NodeGroup을 사용하지 않고 Karpenter를 사용한다. 그럼 NodeGroup이 없는 클러스터부터 만드는 방법이다. <https://eksctl.io/usage/fargate-support/> ```bash eksctl create cluster --fargate ```bash 간단하다 옵션으로 --fargate를 주면된다. Fargate profile 같은경우에는 사실 콘솔에서 손으로 만들면 편하다. subnet이나 iam role 넣어주는게....그렇지 않다면 먼저 aws cli 부터 학습해야 한다. eksctl이 자동으로 해주는 부분도 있지만 필수요소는 알아야 하기 때문이다. <https://awscli.amazonaws.com/v2/documentation/api/latest/reference/eks/create-fargate-profile.html> ```bash aws eks create-fargate-profile --fargate-profile-name kube-system --cluster-name myeks --pod-execution-role-arn arn:aws:iam::123456789:role/AmazonEKSFargatePodExecutionRole --subnets "subnet-1" "subnet-2" "subnet-3" ```bash <https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/pod-execution-role.html> 역할생성은 이링크를 참고한다. 이런식으로 만들고 파게이트는 네임스페이스로 지정하면 네임스페이스에 만들어지는 톨레이션이나 다른 노드 어피니티등을 가지지 않은 Pod를 Fargate로 프로비저닝 한다. 이때 일반적인 쿠버네티스와 다른 부분은 Fargate 스케줄러(fargate-scheduler)가 별도로 동작하여 Fargate를 프로비저닝한다. 일반적인 경우엔 (default-scheduler)가 Pod를 프로비저닝 한다. 이 차이를 알아두면 어떤 노드를 물고있는지 확인하기 편하다.

May 7, 2023 · 2 min · 📁 AWS, Kubernetes · 🏷️ EKS, nodeless, fargate