export CLUSTER_NAME=[EKS Cluster Name]
# 실습 기준 버전 v0.29.0 -> export KARPENTER_VERSION=v0.29.0
export KARPENTER_VERSION=[Karpenter Version]
export AWS_DEFAULT_REGION="ap-northeast-2"
# CLUSTER_ENDPOINT는 EKS Cluster 개요 탭의 API 서버 엔드포인트와 동일한지 확인
export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text)"
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
export TEMPOUT=$(mktemp)
# 변수에 값이 잘 저장되어 있는지 확인
echo $CLUSTER_NAME $KARPENTER_VERSION $AWS_DEFAULT_REGION $CLUSTER_ENDPOINT $AWS_ACCOUNT_ID $TEMPOUT
웹에서 자원 생성에 필요한 cloudformation 소스를 받아오는데, 혹시 소스를 구하기 어려운 경우 아래 파일을 활용하자
cloudformation.yaml
IAM - Role에 KarpenterNodeRole-[EKS CLUSTER 이름] 형식의 Role이 생성된다
curl -fsSL https://raw.githubusercontent.com/aws/karpenter/"${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}"
eksctl utils associate-iam-oidc-provider --cluster ${CLUSTER_NAME} --approve
eksctl create iamserviceaccount \
--cluster "${CLUSTER_NAME}" --name karpenter --namespace karpenter \
--role-name "KarpenterControllerRole-${CLUSTER_NAME}" \
--attach-policy-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME}" \
--role-only \
--approve
# --role-only 옵션에 의해 Service Account는 생성하지 않고, IAM Role만 생성된다
# --approve 옵션은 OIDC 공급자와의 연결을 자동으로 승인한다
# IAM OIDC 공급자를 생성하면, 사용자는 이를 명시적으로 승인해야 한다
# K8s Service Account가 IAM 역할을 사용하도록 허용하는데, 이 과정을 자동으로 승인하게 해준다
태그의 Key, Value는 서브넷, 보안그룹에 동일하게 적용한다
key | Value |
---|---|
karpenter.sh/discovery | Karpenter를 활용할 EKS 클러스터 이름 |
# Subnet
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
# 복사 & 붙여넣기는 한 블럭씩 차례대로
# Security Group
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" ",")
# EKS에 적용된 보안 그룹이 단일로 구성되어 있을 경우
SECURITY_GROUPS=$(aws eks describe-cluster \
--name ${CLUSTER_NAME} --query cluster.resourcesVpcConfig.clusterSecurityGroupId | tr -d '"')
# Managed node group Launch template 사용한 경우..? 무슨 말인지 잘 모르겠다
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}
eksctl create iamidentitymapping \
--username system:node:{{EC2PrivateDNSName}} \
--cluster ${CLUSTER_NAME} \
--arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME} \
--group system:bootstrappers \
--group system:nodes
# 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.clusterEndpoint="${CLUSTER_ENDPOINT}" \
--set settings.aws.clusterName=${CLUSTER_NAME} \
--set settings.aws.interruptionQueueName=${CLUSTER_NAME} \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \
--wait > karpenter.yaml
# karpenter를 배치할 NameSpace 생성
kubectl create ns karpenter
# 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.sh_machines.yaml
kubectl create -f https://raw.githubusercontent.com/aws/karpenter/${KARPENTER_VERSION}/pkg/apis/crds/karpenter.k8s.aws_awsnodetemplates.yaml
# karpenter 설치
kubectl apply -f karpenter.yaml
kubectl get pod -n karpenter
Karpenter가 배치할 인스턴스 노드의 타입을 결정하고, 생성될 서브넷, 보안그룹 등을 지정한다
여기서 Provisioner의 spec.providerRef 필드는 Provisioner에 공통적으로 적용할 내용을 입력한 클라우드 공급자(NodeTemplate)를 참조할 때 사용하고, 만약 직접 클라우드 공급자를 참조하는 형식이 아닌 직접 지정하고자 하는 경우는 provider 필드를 사용한다
만약 requirements 필드에 karpenter.sh/capacity-type 키의 값을 spot, on-demand 두 개 다 줄 경우 가능한 spot 타입으로 띄우려고 한다(Spot을 사용할 경우 가능한 다양한 인스턴스를 쓰는 것이 유리하다)
-Provisioner의 Limits 필드는 CPU, Memory는 최대 인스턴스를 제한하는 데 사용한다. 병렬적으로 증설되기 때문에 약간의 OverCommit이 될 수 있다.
-인스턴스 개수 기반으로 제한을 걸지 못하는 이유는 다양한 인스턴스가 띄워질 수 있기 때문..
-BP는 중간 인스턴스 타입의 CPU, Memory Spec * 원하는 대수로 리소스 제한을 거는 걸 추천
-실제로 주어지는 자원의 양은 requests로 설정
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
requirements:
- key: karpenter.k8s.aws/instance-category
operator: In
values: [c, m, r]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["2"]
- key: kubernetes.io/arch
operator: In
values: [ "amd64" ]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: topology.kubernetes.io/zone
operator: In
values: ["ap-northeast-2a", "ap-northeast-2c"]
- key: karpenter.k8s.aws/instance-cpu
operator: In
values: ["4", "8", "16", "32"]
- key: karpenter.k8s.aws/instance-hypervisor
operator: In
values: ["nitro"]
limits:
resources:
cpu: 1000
memory: 1000Gi
providerRef:
name: default
provider:
deviceName: /dev/xvda
ebs:
deleteOnTermiation: true
volumeSize: 100Gi
volumeType: gp3
ttlSecondsAfterEmpty: 30
---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
name: default
spec:
subnetSelector:
karpenter.sh/discovery: "${CLUSTER_NAME}"
securityGroupSelector:
karpenter.sh/discovery: "${CLUSTER_NAME}"
tags:
karpenter.sh/discovery: "${CLUSTER_NAME}"
EOF
# 테스트를 위한 어플리케이션 php-apache 배포
kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
# Pod AutoScaling을 위한 HPA 구성
# 빠른 확장을 위해 CPU 기준을 30%로 설정
kubectl autoscale deployment php-apache --cpu-percent=30 --min=1 --max=50
# 테스트를 위한 부하 발생 어플리케이션
# 0.01초 마다 php-apache 서비스로 Request 송신
# default namespace에 load-generator 파드가 생성 및 동작
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
#위 명령을 우리 프로젝트에 적합하게 변경하면 아래와 같다
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.005; do if wget -q -O- http://houstagram.com > /dev/null; then echo 'Request was successful'; else echo 'Request failed'; fi; done"
kubectl get hpa -n [namespace]
kubectl get deployment metrics-server -n kube-system
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl top pods
kubectl top nodes
kubectl get hpa -n [namespace]
먼저 helm을 설치한다
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
helm version --short
#버전확인
그리고 아래 명령어로 설치해주면 끝이다!
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl patch svc -n kube-system kube-ops-view -p '{"spec":{"type":"LoadBalancer"}}'
우린 기존에 alb controller, ingress가 설치되어있기 때문에 loadbalancer만 변경해주면 들어갈 수 있다
포트 번호는 8080 입니다!!