Always-Try(정보보안 및 일상)

EKS Starter - 2. eksctl을 이용한 AWS EKS 운영 본문

AWS

EKS Starter - 2. eksctl을 이용한 AWS EKS 운영

Always-Try 2021. 9. 1. 23:25
https://www.udemy.com/course/amazon-eks-starter-kubernetes-on-aws/ 참고

 

지난 시간에 이어 이제 EKS 운영 중 아래 사항에 대해서 알아보자.

 

1. 노드 그룹과 스팟 인스턴스

 

- 노드그룹 스케일링

eksctl get cluster

 

eksctl get nodegroup --cluster EKS-course-cluster

 

eksctl scale nodegroup --cluster=EKS-course-cluster --nodes=5 --name=ng-1 --nodes-min=3 --nodes-max=5

이후 노드가 5개로 들어난 것을 확인할 수 있다. (원래 3개였고, 2개가 Initializing 되고 있는 것을 확인)

 

eksctl get nodegroup --cluster EKS-course-cluster를 통해서도 노드가 5개로 늘어난 것을 확인 할 수 있다.

스케일링 되는걸 봤으니 돈을 아끼기 위해 콘솔에서 2개는 종료하자.

 

 

- 노드그룹 추가

지난 포스팅에서 클러스터를 생성했던 yaml 파일에 아래와 같이 추가한다.

추가된 부분

기존에 보지 못한 파라미터에 대한 설명은 다음과 같다.

maxPrice는 스팟인스턴스의 가격에 대한 설정이다. 금액 때문에 설정하는 것 같은데 아직 얼만큼의 금액이 적당한지 감이 오지 않는다. 스팟 인스턴스 메뉴에 가면 여기서 설정한 값이 나온다.

onDemandBaseCapacity 는 온디맨드 인스턴스로 프로비저닝될 최소 노드 그룹 용량이고, onDemandPercentageAboveBaseCapacity  온디맨드 인스턴스로 프로비저닝될 기준 이상의 인스턴스 비율이다. 둘 다 0으로 설정하면 모든 노드가 스팟 인스턴스로 모두 구성된다. 

 

eksctl create nodegroup --config-file=eks-course.yaml --include='ng-mixed'

이미 노드 그룹 ng-1은 실행되어지고 있기 때문에 --include 파라미터로 ng-mixed 라는 새로운 노드 그룹을 지정해줬다.

이후 내용을 보면 이와 관련된 내용이 확인되며, CloudFormation 스택으로 클러스터 내 노드그룹이 생성되는 것을 확인할 수 있다. 물론 CloudFormation 대시보드에서도 확인 가능하다.

위 캡쳐 2개를 자세히 보면 새로 생성 된 3개의 인스턴스 중 2번째는 스팟인스턴스라는 것을 알 수 있다.

 

eksctl get nodegroup --cluster EKS-course-cluster

 

- 노드그룹 삭제

eksctl delete nodegroup --config-file=eks-course.yaml --include=ng-mixed --approve

위 캡쳐에서 drain ~~ 는 해당 노드의 파드 스케쥴링을 막고 실행중인 파드들을 삭제하는 것이다. 그리고 cordon node ~~는 특정 노드에 있는 파드들을 다른 노드로 옮기거나 일정 시간동안 파드 스케쥴링을 막을때 사용한다.

 

위 명령어 실행 결과이다.

eksctl get nodegroup --cluster EKS-course-cluster

 

 

 

2. 클러스터 오토스케일러 이론

이 부분은 강의에 별 내용이 없다. 그래서 구글링해서 필요한 걸 간단하게 정리해봤다.

- 스케일 아웃 vs 스케일 인

 . 스케일 아웃 : 기존 서버와 비슷한 서버를 추가하는 것

 . 스케일 인: 기존 서버의 사양을 높이는 것

- VPA vs HPA

 . VPA(Vertical Pod Autoscaler) : 파드에 리소스를 더 할당 하는 것

 . HPA(Horizon Pod Autoscaler) : 파드의 수를 늘리는 것

 

 

 

3. 클러스터 오토스케일 Part 1

오토스케일링이 적용된 노드그룹들을 생성하는 실습을 진행한다.

먼저 워크로드라는 용어부터 알아보자.

클라우드 워크로드는 클라우드 리소스에서 실행할 수 있는 특정한 애플리케이션, 서비스, 기능 또는 특정한 작업량입니다. 가상 머신, 데이터베이스, 컨테이너, Hadoop 노드 및 애플리케이션이 모두 클라우드 워크로드로 간주됩니다. https://www.delltechnologies.com/ko-kr/learn/cloud/cloud-workloads.htm

그리고 stateful workloads와 stateless workloads라는 용어가 나온다. 이것도 알아보자.

간단히 설명하자면 stateful workloads는 이전 트랜잭션의 기록을 기반으로 다음 트랜잭션을 진행하는 워크로드를 의미하며, stateless workloads는 이전 트랜잭션의 기록이 필요 없이 1회성 또는 단기간에 처리되는 워크로드를 의미한다. 비유하자면 stateful workloads는 카카오 대출 서비스, stateless workloads는 네이버 검색창 같은 것이라고 할 수 있다.

자 이제 아래의 노드그룹들을 생성하는 yaml 파일을 만들어보자

1) 단일 가용영역에 있는 2개의 노드그룹 (for stateful workloads)

2) 스팟인스턴스를 사용하면서 2개의 가용영역에 걸쳐있는 1개의 노드그룹 (for stateless workloads)

현재 지난 포스팅에서 생성한 ng-1 그룹은 그대로 있는 상태이다. 혹시 ng-1 그룹에 변화가 있는지 보기 위해 그대로 둔 상태에서 방금 생성한 yaml 파일을 이용하여 노드 그룹을 생성해보자. (몇분 소요된다.)

 

eksctl create nodegroup --config-file=eks-course.yaml 

근데 에러가 좀 발생한다. 흠

먼저 Error: couldn't find public subnets: mapping doesn't have subnet with AZ ap-northeast-2d가 발생해서 yaml의 가용영역을 c,d 에서 a,c로 변경 후 재실행했다.

이후 잘 실행되더니 Cloudformation이 실패했다. 실패 이벤트를 보니 지정한 가용 영역에는 프리티어 이미지를 사용하지 못하는 것 같다. 눈물을 머금고 yaml의 이미지 타입을 micro에서 small로 올린다.

이후 eksctl create nodegroup --config-file=eks-course.yaml 재실행

그리고 kubectl get nodes

 

ng-1 노드 그룹은 별다른 점이 없다. 더이상 이 노드 그룹은 필요가 없기에 삭제하자.

 

eksctl delete nodegroup -f eks-course.yaml --include="ng-1"

노드 그룹을 삭제하기 위해서는 노드 그룹을 생성한 yaml 파일이 꼭 있어야 되나 하는 생각을 잠시해본다.

그리고 본 명령어를 자세히 보면 아까 다른 노드 그룹을 삭제할 때 줬었던 --approve라를 파라미터가 없다. 이는 dry mode로 삭제 명령에 대한 결과를 보기 위함이다. 즉, 실제 삭제 전 테스트를 해보기 위함이다.

이제 진짜 삭제를 해보자.

eksctl delete nodegroup -f eks-course.yaml --include="ng-1" --approve

 

여기서 궁금증이 하나 생겼다. 이미 생성한 노드 그룹의 인스턴스 타입을 변경할 수 있을까??

답은 No. EKS 노드 그룹 인스턴스 유형은 생성 후에 변경할 수 없다. 새 인스턴스 유형을 원할 때마다 새 노드 그룹을 생성해야 한다.

 

 

이제 오토스케일러를 배포해보자

- deployment 생성

kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml 

 

- evicted(쫓아내다. 퇴거하다)를 방지하기 위한 deployment 주석 달기

kubectl -n kube-system annotate deployment.apps/cluster-autoscaler cluster-autoscaler.kubernetes.io/safe-to-evict="false" --overwrite

방금 위에서 한 명령어가 정확히 뭔지 모를수도 있다. 설명하자면 클러스터는 요청 수가 감소하면 파드들을 삭제할 수도 있는데, 이때 특정 파드를 삭제하지 않기 위해서 위와 같은 safe-to-evict="false" 라는 주석을 추가한다. 클러스터에 해당 내용을 추가하면 클러스터 자체의 속성이 될 것이고, 특정 파드에 위 주석을 추가하면 클러스터는 파드를 삭제하려고 할 때 해당 주석이 있는 파드는 삭제하지 않고 다른 파드를 삭제하려고 할 것이다. (https://stackoverflow.com/questions/63871413/how-to-make-sure-kubernetes-autoscaler-not-deleting-the-nodes-which-runs-specifi)

 

- deployment에 이미지 버전을 매칭하고 클러스터 이름을 설정

AWS 콘솔에서 쿠버네티스 버전을 확인해보자. 

그리고 https://github.com/kubernetes/autoscaler/releases 에서 해당 버전의 가장 최근 릴리즈 된 버전을 찾는다. 필자의 경우 1.20.0 이다.

 

이후 해당 정보를 kubenetes에 업데이트한다.

kubectl -n kube-system edit deployment.apps/cluster-autoscaler

 

업데이트된 정보를 확인해보자.

kubectl -n kube-system describe deployment cluster-autoscaler

 

 

4. 클러스터 오토스케일 Part 2

nginx deployment와 scale it in/out
nginx를 배포하기 위해 nginx-deployment.yaml 파일을 생성하자.

위 캡처에서 네모박스 친 부분을 하나씩 살펴보자.

replicas부터 보자.

레플리카셋은 실행되는 파드 개수에 대한 가용성을 보증 하며 지정한 파드 개수만큼 항상 실행될 수 있도록 관리 합니다. 즉 5개의 파드를 항상 실행 하도록 설정하면 이후 파드 1개가 삭제될 경우 다시 파드 1개가 실행되어 5개를 유지할 수 있도록 해줍니다. (https://nirsa.tistory.com/136)

그 다음 resources 부분의 limit과 requests이다. 이 또한 잘 정리된 블로그를 참고하자.

request는 컨테이너가 생성될때 요청하는 리소스 양이고, limit은 컨테이너가 생성된 후에 실행되다가 리소스가 더 필요한 경우 (CPU가 메모리가 더 필요한 경우) 추가로 더 사용할 수 있는 부분이다. (https://bcho.tistory.com/1291)

그리고 생성한 인스턴스 타입과 limit을 비교하면 최대 몇개의 파드를 물리적인 1개의 인스턴스에서 실행할 수 있는지 확인할 수 있다. 예를들어 t3.small은 2GB의 메모리를 지원하는데 우리는 nginx를 512M로 리밋을 정했으니 4개까지는 생성할 수 있다. 

 

마지막으로 nodeSelector를 보자. 참고로 실습에서는 스팟 인스턴스로 파드를 구성하기 위해 인스턴스 타입을 spot 이라고 지정했다.

특정한 노드(들) 집합에서만 동작하도록 파드를 제한할 수 있다. 이를 수행하는 방법에는 여러 가지가 있으며 권장되는 접근 방식은 모두 레이블 셀렉터를 사용하여 선택을 용이하게 한다. 보통 스케줄러가 자동으로 합리적인 배치(예: 자원이 부족한 노드에 파드를 배치하지 않도록 노드 간에 파드를 분배하는 등)를 수행하기에 이러한 제약 조건은 필요하지 않지만 간혹 파드가 배포할 노드를 제어해야 하는 경우가 있다. 예를 들어 SSD가 장착된 머신에 파드가 연결되도록 하거나 또는 동일한 가용성 영역(availability zone)에서 많은 것을 통신하는 두 개의 서로 다른 서비스의 파드를 같이 배치할 수 있다. (https://kubernetes.io/ko/docs/concepts/scheduling-eviction/assign-pod-node/)

 

 

그 다음 파드를 배포해보자.

kubectl apply -f nginx-deployment.yaml

그리고 생성된 파드를 보자.

kubectl get pod

kubectl get nodes -l instance-type=spot (-l을 옵션을 주면 라벨링을 이용한 필터링이 가능하다)

 

파드를 스케일링 해보자.

kubectl scale --replicas=3 deployment/test-autoscaler

 

다시 파드 정보를 보면, 3개의 파드가 생성되어 있다.

kubectl get po

여기서 kubectl get nodes -l instance-type=spot 를 해보면 !! 스팟인스턴스가 2개인 것을 확인할 수 있다.

파드의 request와 limit 정책으로 인해 1개의 노드로는 감당이 안되서 자동으로 1개의 노드를 더 띄워준 것이다. 실제로 콘솔에서 스팟 인스턴스를 확인해보면 2개가 떠있다.

t3.micro로 생성된 것으로 보아 위에서 생성한 scale-spot 노드 그룹에 포함된 것이라고 유추할 수 있다.

하지만 파드를 배포할 때 scale-spot이라는 노드 그룹을 지정하지는 않았다. 그럼 어떻게 저 노드 그룹으로 들어갔을까? 추측컨데 labels의 용도가 이와 같이 특정 그룹이나 파드를 지정하기 위함이라고 했으니 lables에 있는 instance-type을 따라 간것으로 보인다. (이 부분은 명확하진 않으니 참고)

 

다시 파드를 줄여보자.

kubectl scale --replicas=1 deployment/test-autoscaler

그리고 파드 정보를 불러와보자. 엄청 빠르게 적용되는 것을 알 수 있다.

kubectl get po

그럼 추가로 생성된 스팟 인스턴스도 바로 없어질까?

kubectl get nodes -l instance-type=spot

아니다. 바로 없어지진 않고 약 5분 뒤에 사라진다. 어떻게 알 수 있을까? 오토스케일링 그룹의 휴지기간(Default cooldown)을 보면 알 수 있다.

 

이제 클러스터의 오토스케일 관련 로그를 한번 보자.

kubectl -n kube-system logs deployment.apps/cluster-autoscaler (로그가 너무 많이 나와서 보기 힘들다.)

필터를 걸어서 보고 싶은 로그만 보자.

kubectl -n kube-system logs deployment.apps/cluster-autoscaler | grep -A5 "Expanding Node Group"

 

 

 

5. 클라우드와치 로깅

컨트롤 플레인 로그 유형은 아래와 같다. (https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/control-plane-logs.html)

1) Kubernetes API 서버 구성 요소 로그 (api)

2) 감사 (audit)

3) 인증자 (authenticator)

4) 컨트롤러 관리자 (controllerManager)

5) 스케줄러 (scheduler)

각각의 로그 타입은 자신만의 클라우드와치 로그 스트림을 생성한다. 그리고 /aws/eks/cluster-name/의 prefix를 가진다.

 

초기 ks-course.yaml 파일에 cloudwatch를 수정해서 다시 생성해보자.

그리고 배포해보자

 eksctl utils update-cluster-logging --config-file eks-course.yaml --approve

명령어 실행이 끝났으면 클라우드와치 콘솔에서 확인해보자.

그리고 AWS EKS 대시보드 콘솔에서도 로깅에 대한 설정을 변경할 수 있다.

 

그냥 두면 돈이 많이 나오니까 다시 원복하자. 먼저 --approve 명령어를 제외한 dry run 모드로 실행해본다.

eksctl utils update-cluster-logging --name=EKS-course-cluster --disable-types all

 

그리고 실제 로깅 비활성화를 수행하자.

eksctl utils update-cluster-logging --name=EKS-course-cluster --disable-types all --approve

이후 콘솔에서도 비활성화로 되어 있는 것을 볼 수 있다.

 

 

 

6. 클라우드와치 컨테이너 Insights

Container Insights란 뭘까? AWS에서 컨테이너를 사용하는 서비스(ECS, EKS 등)에 대해서 컨테이너 애플리케이션 및 마이크로서비스에 대한 상태를 빠르게 확인하고 빠른 대응을 할 수 있게 도와주는 서비스이다.

CloudWatch Container Insights를 사용하여 컨테이너식 애플리케이션 및 마이크로서비스의 지표 및 로그를 수집, 집계 및 요약할 수 있습니다. 컨테이너 인사이트는 Amazon ECAmazon EC2 Amazon Elastic Container Service (Amazon ECS), Amazon Elastic Kubernetes Service (Amazon EKS) 및 Kubernetes 플랫폼에서 사용할 수 있습니다. Amazon ECS 지원에는 Fargate 에 대한 지원이 포함되어 있습니다. (https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/ContainerInsights.html)

 

우선 Container Insights를 적용하기 위해 노드 그룹이 CloudWatch Agent에 접근할 수 있도록 IAM policy를 추가해줘야 하고, CloudWatch Agent를 배포한다. 그리고나서 메트릭을 확인해보자.

 

먼저 노드 인스턴스의 IAM 역할을 클릭해서 들어간다.

 

그리고 아래 정책을 연결한다. 이걸 원하는 노드 그룹에 다 넣어줘야 한다. 

다음으로 Cloudwatch Agent를 배포한다. 아래 테스트는 Fluentd를 이용해서 했지만, AWS에서는 더 성능이 좋은 Fluent Bit를 출시했다고 하므로 아래 docs를 참고해서 Fluent Bit를 이용하길 바란다. (실제로 아래 테스트는 잘 동작하지도 않았다.)

(https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html)

 

 curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml | sed "s/{{cluster_name}}/EKS-course-cluster/;s/{{region_name}}/ap-northeast-2/" | kubectl apply -f -

빨간 부분은 각자 환경에 맞게 수정한다.

kubectl get all -n amazon-cloudwatch

 

 

그리고 Container Insights를 제거하려면 다음 명령어를 입력한다.

 

curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml | sed "s/{{cluster_name}}/EKS-course-cluster/;s/{{region_name}}/ap-northeast-2/" | kubectl delete -f -

 

마지막 테스트는 잘 동작하지 않았다. 다음 링크를 참고해서 다시 테스트 해보면 좋을 것 같다. 단 다음 링크는 cloudwatch를 이용하지는 않는다.

https://aws.amazon.com/ko/premiumsupport/knowledge-center/eks-metrics-server-pod-autoscaler/

Comments