2024. 3. 31. 07:27ㆍEKS@CloudNet
- CloudNet에서 주관하는 EKS 스터디 2기 내용입니다
- 매번 좋은 스터디를 진행해 주시는 CloudNet 팀 감사드립니다
0. Setup
- 기존과 비슷하게 가시다님이 배포해주신 원클릭 배포 파일을 사용한다. 기존 베포 파일에서는 노드 스펙으로 t3.medium을 사용했었는데 이번에는 t3.xlarge 를 사용한다.
- bastion address로 접속해서 노드가 잘 배포되었는지 확인한다.

- 기본 설정을 위해 node IP 확인해서 PrivateIP 변수로 넣어주고, 노드 보안그룹 ID를 확인한다.
N1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address})
N2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address})
N3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address})
echo "export N1=$N1" >> /etc/profile
echo "export N2=$N2" >> /etc/profile
echo "export N3=$N3" >> /etc/profile
echo $N1, $N2, $N3
# 노드 보안그룹 ID 확인
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ng1* --query "SecurityGroups[*].[GroupId]" --output text)
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32
# 워커 노드 SSH 접속
for node in $N1 $N2 $N3; do ssh -o StrictHostKeyChecking=no ec2-user@$node hostname; done
- 모니터링 대시보드 사용을 위해 ExternalDNS에 내 도메인을 등록해주고 kube-ops-view를 설치해준다.
# ExternalDNS
MyDomain=<자신의 도메인>
echo "export MyDomain=<자신의 도메인>" >> /etc/profile
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text)
echo $MyDomain, $MyDnzHostedZoneId
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml
MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -
# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
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"}}'
kubectl annotate service kube-ops-view -n kube-system "external-dns.alpha.kubernetes.io/hostname=kubeopsview.$MyDomain"
echo -e "Kube Ops View URL = http://kubeopsview.$MyDomain:8080/#scale=1.5"
아래 캡처와 같이 ExternalDNS가 deploy 되었고, Route53에 등록된 내 도메인을 통해서 클러스터에 접근할 수 있게 되었다.

LoadBalancer/CSI Driver을 배포하고 kube-ops-view로 pod 상태를 확인한다.
# AWS LB Controller
helm repo add eks https://aws.github.io/eks-charts
helm repo update
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
# EBS csi driver 설치 확인
eksctl get addon --cluster ${CLUSTER_NAME}
kubectl get pod -n kube-system -l 'app in (ebs-csi-controller,ebs-csi-node)'
kubectl get csinodes
# gp3 스토리지 클래스 생성
kubectl get sc
kubectl apply -f https://raw.githubusercontent.com/gasida/PKOS/main/aews/gp3-sc.yaml
kubectl get sc

+ 여담으로 바로 안 떠서 뭐가 문젠가 했는데, 한 5분 정도 기다렸다 새로고침하니까 잘 되었다.
...가 아니었다. 후술할 $CERT_ARN 이 여기서부터 문제였다. AWS 업데이트로 certificate 없이도 접속이 가능한 옵션을 알려주셔서 그걸로 바꿨더니 된 것이었다.
(Domain 없는 분을 위한) Route53 도메인 구입
- 걱정했는데 정말 하나도! 어렵지 않다! -> 구매는 어렵지 않다...



- TMI로 닉네임 hithere은 hi there(거기 안녕하세요) 와 hit here(여기 눌러보세요) 를 둘다 담고 있어서 골랐었다. 구매하면 바로 사용할 수 있는 게 아니라 조금(며칠) 기다려야 사용이 가능하다고 하는데 나는 30분만에 활성화 되었다.
-cat myeks.yaml | grep managedNodeGroups -A20 | yh 명령어로 확인하면 IRSA(awsLoadBalancerController) 가 False되어 있고 CloudWatch, ebs, externalDNS가 True 되어 있는데 이는 보안상 권장되지는 않는다. 지금은 실습 환경이라 편리성 좋게 사용했지만 실제 적용할 때는 IRSA 적용을 권장한다고 알려주셨다.

1. Logging in EKS
Control Plane Logging
- 아래 실습들을 위해 모든 로그를 활성화 시킨다.
# 모든 로깅 활성화
aws eks update-cluster-config --region $AWS_DEFAULT_REGION --name $CLUSTER_NAME \
--logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'
# 로그 그룹 확인
aws logs describe-log-groups | jq
# EKS Control Plane 로깅(CloudWatch Logs) 비활성화
eksctl utils update-cluster-logging --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION --disable-types all --approve
# 로그 그룹 삭제
aws logs delete-log-group --log-group-name /aws/eks/$CLUSTER_NAME/cluster

- tail, -filter-pattern, -follow 등 다양한 옵션을 사용할 수도 있다.
Pod Logging
- 최종 사용자가 될 nginx 를 배포한다.
이때 실습 편리를 위해 인증서를 명시하지 않고 배포한다.
helm repo add bitnami https://charts.bitnami.com/bitnami
# 파라미터 파일 생성
cat <<EOT > nginx-values.yaml
service:
type: NodePort
networkPolicy:
enabled: false
ingress:
enabled: true
ingressClassName: alb
hostname: nginx.$MyDomain
pathType: Prefix
path: /
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
#alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: $CLUSTER_NAME-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
EOT
cat nginx-values.yaml | yh
# 배포
helm install nginx bitnami/nginx --version 15.14.0 -f nginx-values.yaml
배포가 잘 되었다 + Kube-ops-view 에서도 우측 상단 새 Pod을 확인할 수 있다.


- 배포한 Pod에 대한 로그도 확인할 수 있다.

2. Prometheus-stack
프로메테우스는 메트릭 수집, 저장, 알림 기능을 지원하는 메트릭 오픈소스이다.

- 제공 기능
multi-dimensional data model로 로그를 사용하고, 쿼리 언어로 PromQL을 사용한다.
모니터링 시스템은 크게 Push, pull 방식으로 나눌 수 있는데 Push는 데이터를 가진 곳에서 필요한 곳으로 보내주는 것이고 pull은 데이터가 필요한 곳에서 가 곳의 데이터를 긁어가는 것이다.
Prometheus는 pull 방식을 활용해서 각 서비스의 9100에 접속해서 메트릭 정보를 수집하고 있다.
kubectl get svc,ep -n monitoring kube-prometheus-stack-prometheus-node-exporter

push vs pull 을 간단히 비교하면
- push: 중앙집중형, 수집대상이 가변적(autoscaling) 인 경우 유리
- push: 분산형, 수집 대상(metric을 수집할 feature) 을 유연하게 조정할 경우 유리
- 프로메테우스는 기본적으로 4가지 메트릭 Gauge, Counter, Summary, Histogram 을 제공한다
실습
Prometheus 를 배포해 본다.
이때 로그를 담을 스토리지로 지난주에 학습한 gp3 을 사용함에 유의한다.
# repo 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# 파라미터 파일 생성
cat <<EOT > monitor-values.yaml
prometheus:
prometheusSpec:
podMonitorSelectorNilUsesHelmValues: false
serviceMonitorSelectorNilUsesHelmValues: false
retention: 5d
retentionSize: "10GiB"
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 30Gi
ingress:
enabled: true
ingressClassName: alb
hosts:
- prometheus.$MyDomain
paths:
- /*
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
grafana:
defaultDashboardsTimezone: Asia/Seoul
adminPassword: prom-operator
ingress:
enabled: true
ingressClassName: alb
hosts:
- grafana.$MyDomain
paths:
- /*
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/ssl-redirect: '443'
persistence:
enabled: true
type: sts
storageClassName: "gp3"
accessModes:
- ReadWriteOnce
size: 20Gi
defaultRules:
create: false
kubeControllerManager:
enabled: false
kubeEtcd:
enabled: false
kubeScheduler:
enabled: false
alertmanager:
enabled: false
EOT
cat monitor-values.yaml | yh
# 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 57.1.0 \
--set prometheus.prometheusSpec.scrapeInterval='15s' --set prometheus.prometheusSpec.evaluationInterval='15s' \
-f monitor-values.yaml --namespace monitoring
+DEBUG: 사용 리전의 인증서 ARN이 없어서 prometheus 배포가 아래와 같은 에러메시지를 내면서 실패했는데, 이는 ARN 인증서가 없었기 때문이었다.

아래 코드로 인증서 ARN을 확인했을 때 아무것도 안 나오면 정상 상태가 아니다.
# 사용 리전의 인증서 ARN 확인 : 정상 상태 확인(만료 상태면 에러 발생!)
CERT_ARN=`aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text`
echo $CERT_ARN

처음 도메인을 발급해 보는 분은 도메인 발급 와 쉽다! 에서 끝내지 마시고, 아래 링크에 들어가서 새 도메인에 대한 인증 키를 발급하세요.
https://ap-northeast-2.console.aws.amazon.com/acm/home?region=ap-northeast-2#/welcome ARN 인증서 등록!!
https://ap-northeast-2.console.aws.amazon.com/acm/home?region=ap-northeast-2#/welcome
ap-northeast-2.console.aws.amazon.com
...하면 될 줄 알았는데 배포는 되고, 배포한 주소로 접속에는 실패했다. 검증 이메일을 보내서 Approve 해줘야 한다.
+ 내 경우에는 검증 이메일이 스팸함으로 들어가서... 한참 찾았다. 도대체 왜 이 중요한 걸 스팸으로 분류한 걸까?



- (삽질을 뒤로하고) Prometheus 배포에 성공했다.
# 확인 코드
helm list -n monitoring
kubectl get pod,svc,ingress,pvc -n monitoring
kubectl get-all -n monitoring
kubectl get prometheus,servicemonitors -n monitoring
kubectl get crd | grep monitoring
kubectl df-pv

++DEBUG: Certificate must have a fully-qualified domain name, a supported signature, and a supported key size
내 ingress에 등록된 Prometheus+Grafana에 들어가서 스크린샷을 추가하고 싶었는데 자꾸 DNS가 등록 안되었다는 오류가 발생했다.스택오버플로우에서는 아직 pending 상태이거나 할 때 그런 에러가 발생한다고 하는데 내 경우에는 ARN certificate 을 approve 하고 시간이 꽤 지나자(30분) 자동으로 해결되었다.

- 이제 접속 잘 된다!

- PromQL query를 이용해서 원하는 메트릭을 조회할 수 있다.
일반 SQL하고는 문법이 조금 다르니까 문서를 잘 참고하면서 써야 할 것 같다. 이 블로그에 개략적인 문법이 설명되어 있다.
이 쿼리는 전체 클러스터 노드의 CPU 사용량 합계를 구하는 쿼리이다.
1- avg(rate(node_cpu_seconds_total{mode="idle"}[1m]))

3. Grafana
Grafana는 수집된 메트릭을 가지고 시각화해서 보여주는 대시보드 툴이다. 데이터 자체에 대한 저장은 지원하지 않으며 데이터 자체는 prometheus 에서 가져온다.
https://grafana.com/grafana/dashboards/ 에서 다양한 대시보드의 예시를 확인할 수 있다. 클러스터 모니터링 뿐 아니라 다양한 형태의 모니터링에도 사용할 수 있을 것 같다. 예전에 집 소개하는 프로그램에서 개발자 건축주 분이 집 안 온도랑 미세먼지 등을 그라파나 대시보드로 벽에 걸어놓으셨었는데, 좋은 사용방법 같았다.
Dashboards | Grafana Labs
Thank you! Your message has been received!
grafana.com
- 처음 접속하면 아래와 같이 당연하게도 대시보드가 없다.

- 대시보드 화면에서 New를 클릭해서 새 대시보드를 추가할 수 있다.

- Import Dashboard를 클릭하면 기존 대시보드의 번호를 넣어서 가져올 수 있다. 15757번 대시보드를 가져왔다.

- 기존 대시보드 들은 Grafana Labs 에서 보고 가져올 수 있다. 대시보드 리스트를 클릭해보면 우측 하단에 대시보드 ID가 있으니 그걸 활용해서 가져온다.

- 이때 하단 데이터 소스가 Prometheus 로 설정되어 있는지 확인하고 import 한다.

-이제 대시보드에서 내 클러스터 환경을 모니터링할 수 있다! (시각적으로 너무 예쁘다)

- 17900번 대시보드를 가져와 보았다. 우측 중단에 'API 서버 호출' 플랏에 보면 GET이 계속 발생하고 있는데 이 호출은 Prometheus가 노드별로 9100번 포트에서 메트릭을 읽어오는 호출이다.

잊지 말아요 자원 삭제
- 이번에는 별도로 EC2 삭제 후 console에 들어가서 남아 있는 볼륨도 삭제해줘야 한다!
eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME
지금은 실습 환경이라 짜주신 대로 따라가기 바빴지만, 어떤 메트릭을 수집할지 고민하고 개선해나가는 과정 자체도 굉장히 공부가 많이 될 것 같다.
대시보드가 있으면 확실히 운영할 때 많이 편리할 듯 하다. 현재 K8S 환경은 아니지만 사내 GPU 관리나 모델 테스트에 어떻게 도입할 수 있을지 고민해봐야겠다.
읽어주셔서 감사합니다!
'EKS@CloudNet' 카테고리의 다른 글
[EKS@CloudNet] EKS Security (0) | 2024.04.14 |
---|---|
[EKS@CloudNet] EKS Autoscaling: Karpenter 외 (0) | 2024.04.07 |
[EKS@CloudNet] EKS Storage & Nodegroup (1) | 2024.03.23 |
[EKS@CloudNet] EKS Networking (3) | 2024.03.17 |
[EKS@CloudNet] Amazon EKS 설치 및 기본 사용 (2) | 2024.03.10 |