교육, 커뮤니티 후기/AEWS 스터디

AEWS 스터디 4주차 - EKS Observability

Somaz 2023. 5. 17. 22:50
728x90
반응형

출처 : 스터디원 이현수님

Overview

CloudNet@ AEWS 스터디 4주차는 EKS Observability 이다.
 
이번에는 t3.xlarge로 노드를 바꾸었다. 기존에 사용하던 노드타입(t3.medium)보다 3배는 비싸다.

 

출처: 스터디원 이지오님


 
 


0. 실습 환경 배포


Amazon EKS 윈클릭 배포 (natgw, ebs addon, ec2 iam role add, irsa lb/efs, preCmd 추가) & 기본 설정

 
노드 t3.xlarge(기본값) 사용

  • 인스턴스 t3a.xlarge(AMD CPU)유형은 서울 리전 2b 가용영역에 미지원으로 사용하지 않는다.
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/eks-oneclick3.yaml

# CloudFormation 스택 배포
예시) aws cloudformation deploy --template-file eks-oneclick3.yaml --stack-name myeks --parameter-overrides KeyName=somaz-key SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32  MyIamUserAccessKeyID=AKIA5... MyIamUserSecretAccessKey='CVNa2...' ClusterBaseName=myeks --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text
43.201.35.227

# 작업용 EC2 SSH 접속
ssh -i ~/.ssh/somaz-key.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)

(somaz@myeks:N/A) [root@myeks-bastion-EC2 ~]#

미리 배포되는 스택이 엄청 많아졌다!

 

기본 설정 및 EFS 확인

# default 네임스페이스 적용
kubectl ns default

# (옵션) context 이름 변경
NICK=<각자 자신의 닉네임>
NICK=somaz

kubectl ctx
somaz@myeks.ap-northeast-2.eksctl.io

kubectl config rename-context admin@myeks.ap-northeast-2.eksctl.io $NICK@myeks

# EFS 확인 : AWS 관리콘솔 EFS 확인해보자
echo $EfsFsId
fs-062cc113e40373398

mount -t efs -o tls $EfsFsId:/ /mnt/myefs
df -hT --type nfs4
Filesystem     Type  Size  Used Avail Use% Mounted on
127.0.0.1:/    nfs4  8.0E     0  8.0E   0% /mnt/myefs

EFS ID 확인

# 노드 정보 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
NAME                                               STATUS   ROLES    AGE   VERSION
      INSTANCE-TYPE   CAPACITYTYPE   ZONE
ip-192-168-1-175.ap-northeast-2.compute.internal   Ready    <none>   10m   v1.24.11-eks-a59e1f0   t3.xlarge       ON_DEMAND      ap-northeast-2a
ip-192-168-2-84.ap-northeast-2.compute.internal    Ready    <none>   10m   v1.24.11-eks-a59e1f0   t3.xlarge       ON_DEMAND      ap-northeast-2b
ip-192-168-3-212.ap-northeast-2.compute.internal   Ready    <none>   11m   v1.24.11-eks-a59e1f0   t3.xlarge       ON_DEMAND      ap-northeast-2c

eksctl get iamidentitymapping --cluster myeks
ARN                                                                                        USERNAME                         GROUPS                                  ACCOUNT
arn:aws:iam::611841095956:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1RPCMD65Z16ZR   system:node:{{EC2PrivateDNSName}}        system:bootstrappers,system:nodes

# 노드 IP 확인 및 PrivateIP 변수 지정
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
192.168.1.175, 192.168.2.84, 192.168.3.212

# 노드 보안그룹 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
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-070ba239fbf977858",
            "GroupId": "sg-081101b573bd5c361",
            "GroupOwnerId": "61184xxxxxxx",
            "IsEgress": false,
            "IpProtocol": "-1",
            "FromPort": -1,
            "ToPort": -1,
            "CidrIpv4": "192.168.1.100/32"
        }
    ]
}

# 워커 노드 SSH 접속
for node in $N1 $N2 $N3; do ssh ec2-user@$node hostname; done

 

AWS LB/ExternalDNS/EBS/EFS, kube-ops-view 설치

# ExternalDNS
MyDomain=<자신의 도메인>
echo "export MyDomain=<자신의 도메인>" >> /etc/profile

MyDomain=somaz.link
echo "export MyDomain=somaz.link" >> /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"
Kube Ops View URL = http://kubeopsview.somaz.link:8080/#scale=1.5

# 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)'
NAME                                  READY   STATUS    RESTARTS   AGE
ebs-csi-controller-67658f895c-pqxbw   6/6     Running   0          16m
ebs-csi-controller-67658f895c-ts2qp   6/6     Running   0          16m
ebs-csi-node-67mvs                    3/3     Running   0          16m
ebs-csi-node-fsrcj                    3/3     Running   0          16m
ebs-csi-node-hmxtf                    3/3     Running   0          16m

kubectl get csinodes
NAME                                               DRIVERS   AGE
ip-192-168-1-175.ap-northeast-2.compute.internal   1         19m
ip-192-168-2-84.ap-northeast-2.compute.internal    1         19m
ip-192-168-3-212.ap-northeast-2.compute.internal   1         19m

# gp3 스토리지 클래스 생성
kubectl get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  31m

cat <<EOT > gp3-sc.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gp3
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  allowAutoIOPSPerGBIncrease: 'true'
  encrypted: 'true'
EOT
kubectl apply -f gp3-sc.yaml
kubectl get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  31m
gp3             ebs.csi.aws.com         Delete          WaitForFirstConsumer   true
          1s

# EFS csi driver 설치
helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/
helm repo update
helm upgrade -i aws-efs-csi-driver aws-efs-csi-driver/aws-efs-csi-driver \
    --namespace kube-system \
    --set image.repository=602401143452.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/eks/aws-efs-csi-driver \
    --set controller.serviceAccount.create=false \
    --set controller.serviceAccount.name=efs-csi-controller-sa

# EFS 스토리지클래스 생성 및 확인
curl -s -O https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml
sed -i "s/fs-92107410/$EfsFsId/g" storageclass.yaml
kubectl apply -f storageclass.yaml
kubectl get sc efs-sc
NAME     PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
efs-sc   efs.csi.aws.com   Delete          Immediate           false                  2s

 
설치 정보 확인

# 이미지 정보 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c

# eksctl 설치/업데이트 addon 확인
eksctl get addon --cluster $CLUSTER_NAME

# IRSA 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
NAMESPACE       NAME                            ROLE ARN
kube-system     aws-load-balancer-controller    arn:aws:iam::61184xxxxxxx:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-1OS9A860DJ93R
kube-system     efs-csi-controller-sa           arn:aws:iam::61184xxxxxxx:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-HF4C3TN5CNJQ

 


1. EKS Console

쿠버네티스 API를 통해서 리소스 및 정보를 확인 할 수 있다.

  • Docs permissions
kubectl get ClusterRole | grep eks
eks:addon-manager                                                      2023-05-14T10:39:03Z
eks:az-poller                                                          2023-05-14T10:39:00Z
eks:certificate-controller-approver                                    2023-05-14T10:39:00Z
eks:certificate-controller-signer                                      2023-05-14T10:39:00Z
eks:cloud-controller-manager                                           2023-05-14T10:39:00Z
eks:cloud-provider-extraction-migration                                2023-05-14T10:39:01Z
eks:cluster-event-watcher                                              2023-05-14T10:39:00Z
eks:fargate-manager                                                    2023-05-14T10:39:04Z
eks:fargate-scheduler                                                  2023-05-14T10:39:00Z
eks:k8s-metrics                                                        2023-05-14T10:39:00Z
eks:node-bootstrapper                                                  2023-05-14T10:39:04Z
eks:node-manager                                                       2023-05-14T10:39:03Z
eks:nodewatcher                                                        2023-05-14T10:39:00Z
eks:pod-identity-mutating-webhook                                      2023-05-14T10:39:00Z
eks:podsecuritypolicy:privileged                                       2023-05-14T10:39:04Z
eks:tagging-controller                                                 2023-05-14T10:39:01Z
  • 클러스터 ARN : arn:aws:eks:ap-northeast-2:6118xxxxxxx:cluster/myeks

EKS 클러스터 IAM 역할 ARN 정보(연결 정책) 확인


2. Logging in EKS

출처 : 최성욱(악분일상)님 블로그
https://malwareanalysis.tistory.com/600

 

EKS 스터디 - 4주차 1편 - 컨트롤 플레인 로깅

안녕하세요. 이 글은 EKS 컨트롤 플레인 로그수집 방법을 설명합니다. EKS 컨트롤 플레인 로그란? 컨트롤 플레인 발생한 이벤트를 EKS 옵션을 설정하여 로그로 남길 수 있습니다. 디폴트 설정은 로

malwareanalysis.tistory.com

 

Logging

EKS logging에는 Control Plane logging, Node logging 그리고 application logging이 있다.

  • Docs

Control Plane logging

컨트롤 플레인에서 발생한 이벤트를 EKS 옵션을 설정하여 로그로 남길 수 있다.
 
디폴트 설정은 로깅이 비활성화 되어 있고, 수집된 컨트롤 플레인 로그는 CloudWatch에서 볼 수 있다.

모든 로깅 기능이 OFF 되어 있다.

 
로그 이름( /aws/eks/<cluster-name>/cluster )

  1. Kubernetes API server component logs *api) – kube-apiserver-<nnn...>
  2. Audit (audit) – kube-apiserver-audit-<nnn...>
  3. Authenticator (**authenticator) – authenticator-<nnn...>
  4. Controller manager (controllerManager) – kube-controller-manager-<nnn...>
  5. Scheduler (scheduler) – kube-scheduler-<nnn...>
# 모든 로깅 활성화
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
{
  "logGroups": [
    {
      "logGroupName": "/aws/eks/myeks/cluster",
      "creationTime": 1684062806655,
      "metricFilterCount": 0,
      "arn": "arn:aws:logs:ap-northeast-2:6118xxxxxxx:log-group:/aws/eks/myeks/cluster:*",
      "storedBytes": 0
    }
  ]
}

# 로그 tail 확인 : aws logs tail help
aws logs tail /aws/eks/$CLUSTER_NAME/cluster | more

# 신규 로그를 바로 출력
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --follow

# 필터 패턴
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --filter-pattern <필터 패턴>

# 로그 스트림이름
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix <로그 스트림 prefix> --follow
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix kube-controller-manager --follow
kubectl scale deployment -n kube-system coredns --replicas=1
kubectl scale deployment -n kube-system coredns --replicas=2

# 시간 지정: 1초(s) 1분(m) 1시간(h) 하루(d) 한주(w)
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --since 1h30m

# 짧게 출력
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --since 1h30m --format short

로그 그룹 확인

 
 

CloudWatch Log Insights

  • 링크
# EC2 Instance가 NodeNotReady 상태인 로그 검색
fields @timestamp, @message
| filter @message like /NodeNotReady/
| sort @timestamp desc

# kube-apiserver-audit 로그에서 userAgent 정렬해서 아래 4개 필드 정보 검색
fields userAgent, requestURI, @timestamp, @message
| filter @logStream ~= "kube-apiserver-audit"
| stats count(userAgent) as count by userAgent
| sort count desc

#
fields @timestamp, @message
| filter @logStream ~= "kube-scheduler"
| sort @timestamp desc

#
fields @timestamp, @message
| filter @logStream ~= "authenticator"
| sort @timestamp desc

#
fields @timestamp, @message
| filter @logStream ~= "kube-controller-manager"
| sort @timestamp desc

 
 
로깅 끄기

# 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

로그 그룹 삭제 확인


Control Plane metrics with Prometheus & CW Logs Insights 쿼리

  • 링크
# How to monitor etcd database size? >> 아래 10.0.X.Y IP는 어디일까요? >> 아래 주소로 프로메테우스 메트릭 수집 endpoint 주소로 사용 가능한지???
kubectl get --raw /metrics | grep "etcd_db_total_size_in_bytes"
etcd_db_total_size_in_bytes{endpoint="http://10.0.160.16:2379"} 4.665344e+06
etcd_db_total_size_in_bytes{endpoint="http://10.0.32.16:2379"} 4.636672e+06
etcd_db_total_size_in_bytes{endpoint="http://10.0.96.16:2379"} 4.640768e+06

kubectl get --raw=/metrics | grep apiserver_storage_objects |awk '$2>100' |sort -g -k 2

# CW Logs Insights 쿼리
fields @timestamp, @message, @logStream
| filter @logStream like /kube-apiserver-audit/
| filter @message like /mvcc: database space exceeded/
| limit 10

# How do I identify what is consuming etcd database space?
kubectl get --raw=/metrics | grep apiserver_storage_objects |awk '$2>100' |sort -g -k 2
kubectl get --raw=/metrics | grep apiserver_storage_objects |awk '$2>50' |sort -g -k 2
apiserver_storage_objects{resource="clusterrolebindings.rbac.authorization.k8s.io"} 78
apiserver_storage_objects{resource="clusterroles.rbac.authorization.k8s.io"} 92

# CW Logs Insights 쿼리 : Request volume - Requests by User Agent:
fields userAgent, requestURI, @timestamp, @message
| filter @logStream like /kube-apiserver-audit/
| stats count(*) as count by userAgent
| sort count desc

# CW Logs Insights 쿼리 : Request volume - Requests by Universal Resource Identifier (URI)/Verb:
filter @logStream like /kube-apiserver-audit/
| stats count(*) as count by requestURI, verb, user.username
| sort count desc

# Object revision updates
fields requestURI
| filter @logStream like /kube-apiserver-audit/
| filter requestURI like /pods/
| filter verb like /patch/
| filter count > 8
| stats count(*) as count by requestURI, responseStatus.code
| filter responseStatus.code not like /500/
| sort count desc

#
fields @timestamp, userAgent, responseStatus.code, requestURI
| filter @logStream like /kube-apiserver-audit/
| filter requestURI like /pods/
| filter verb like /patch/
| filter requestURI like /name_of_the_pod_that_is_updating_fast/
| sort @timestamp

 


 

Container Logging


 

NGINX 웹서버 배포

  • Helm
# NGINX 웹서버 배포
helm repo add bitnami https://charts.bitnami.com/bitnami

# 사용 리전의 인증서 ARN 확인
CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text)
echo $CERT_ARN
arn:aws:acm:ap-northeast-2:6118xxxxxxxx:certificate/75e6fb4f-5xxx-4xxx-8xxx-ab94xxxxxxxx

# 도메인 확인
echo $MyDomain
somaz.link

# 파라미터 파일 생성
cat <<EOT > nginx-values.yaml
service:
    type: NodePort

ingress:
  enabled: true
  ingressClassName: alb
  hostname: nginx.$MyDomain
  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 14.1.0 -f nginx-values.yaml

# 확인
kubectl get ingress,deploy,svc,ep nginx
NAME                              CLASS   HOSTS              ADDRESS
                                PORTS   AGE
ingress.networking.k8s.io/nginx   alb     nginx.somaz.link   myeks-ingress-alb-687395566.ap-northeast-2.elb.amazonaws.com   80      2m8s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           2m8s

NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/nginx   NodePort   10.100.179.230   <none>        80:32635/TCP   2m8s

NAME              ENDPOINTS            AGE
endpoints/nginx   192.168.1.213:8080   2m8s

kubectl get targetgroupbindings # ALB TG 확인
NAME                           SERVICE-NAME   SERVICE-PORT   TARGET-TYPE   AGE
k8s-default-nginx-9b94557b6c   nginx          http           ip            2m21s

# 접속 주소 확인 및 접속
echo -e "Nginx WebServer URL = https://nginx.$MyDomain"
Nginx WebServer URL = https://nginx.somaz.link

curl -s https://nginx.$MyDomain
kubectl logs deploy/nginx -f
...
192.168.2.250 - - [14/May/2023:11:30:44 +0000] "GET / HTTP/1.1" 200  409 "-" "ELB-HealthChecker/2.0" "-"
192.168.1.124 - - [14/May/2023:11:30:56 +0000] "GET / HTTP/1.1" 200  409 "-" "ELB-HealthChecker/2.0" "-"
192.168.3.211 - - [14/May/2023:11:30:56 +0000] "GET / HTTP/1.1" 200  409 "-" "ELB-HealthChecker/2.0" "-"

# 반복 접속
while true; do curl -s https://nginx.$MyDomain -I | head -n 1; date; sleep 1; done

# (참고) 삭제 시
helm uninstall nginx

nginx 접속 확인

 


 

컨테이너 로그 환경의 로그는 표준 출력 stdout과 표준 에러 stderr로 보내는 것을 권고

  • 링크

권고에 따라 작성된 컨테이너 애플리케이션의 로그는 해당 파드 안으로 접속하지 않아도 사용자는 외부에서 kubectl logs 명령어로 애플리케이션 종류에 상관없이, 애플리케이션마다 로그 파일 위치에 상관없이, 단일 명령어로 조회 가능하다.

# 로그 모니터링
kubectl logs deploy/nginx -f

# nginx 웹 접속 시도

# 컨테이너 로그 파일 위치 확인
kubectl exec -it deploy/nginx -- ls -l /opt/bitnami/nginx/logs/
total 0
lrwxrwxrwx 1 root root 11 Feb 18 13:35 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 Feb 18 13:35 error.log -> /dev/stderr

 


Pod Logging

출처 : 최성욱(악분일상)님 블로그
https://malwareanalysis.tistory.com/601

 

EKS 스터디 - 4주차 2편 - pod로깅

pod로깅이란? pod로깅은 data plane 노드 로그와 노드에서 실행 중인 pod로그를 말합니다. pod로깅은 EKS설정을 지원하지 않습니다. 사용자가 도구를 선택해서 pod로그 수집과 저장을 해야 합니다. AWS공

malwareanalysis.tistory.com

CloudWatch Container Insights + Fluent Bit로 파드 로그 수집 가능 ⇒ 메트릭과 함께 다룬다.
pod로깅은 data plane 노드 로그와 노드에서 실행 중인 pod로그를 말한다. pod로깅은 EKS설정을 지원하지 않는다. 사용자가 도구를 선택해서 pod로그 수집과 저장해야 한다.


3. Container Insights metrics in Amazon CloudWatch & Fluent Bit (Logs)

 

CloudWatch Container Insight(CCI)

노드에 CW Agent 파드와 Fluent Bit 파드가 데몬셋으로 배치되어 Metrics 와 Logs 수집한다.

  • CloudWatch Container Insight는 컨테이너형 애플리케이션 및 마이크로 서비스에 대한 모니터링트러블 슈팅 및 알람을 위한 완전 관리형 관측 서비스이다.
  • CloudWatch 콘솔에서 자동화된 대시보드를 통해 container metrics, Prometeus metrics, application logs 및 performance log events를 탐색, 분석 및 시각화할 수 있다.
  • CloudWatch Container Insight는 CPU, 메모리, 디스크 및 네트워크와 같은 인프라 메트릭을 자동으로 수집한다.
  • EKS 클러스터의 crashloop backoffs와 같은 진단 정보를 제공하여 문제를 격리하고 신속하게 해결할 수 있도록 지원한다.
  • 이러한 대시보드는 Amazon ECS, Amazon EKS, AWS ECS Fargate 그리고 EC2 위에 구동되는 k8s 클러스터에서 사용 가능하다.

출처 : CloudNet@ 스터디

 

Fluent Bit란?

Fluent Bit는 오픈 소스, 다중 플랫폼 로그 프로세서 및 전달자이다. 서로 다른 소스에서 데이터/로그를 수집하고 통합하여 여러 대상으로 보내는 데 사용된다. Fluentd 산하의 CNCF(Cloud Native Computing Foundation) 하위 프로젝트이다.
 
Fluent Bit는 가볍고 메모리 사용량이 적도록 설계되어 Kubernetes, Docker 등과 같은 컨테이너화된 환경에서 애플리케이션을 포함하거나 함께 배포하는 데 이상적이다.

출처 : https://fluentbit.io/how-it-works/


Fluent Bit (as a DaemonSet to send logs to CloudWatch Logs) Integration in CloudWatch Container Insights for EKS 

  • Docs Blog Fluentd TS

https://aws.amazon.com/ko/blogs/containers/fluent-bit-integration-in-cloudwatch-container-insights-for-eks/

  • [수집] 플루언트비트 Fluent Bit 컨테이너를 데몬셋으로 동작시키고, 아래 3가지 종류의 로그CloudWatch Logs 에 전송
    1. /aws/containerinsights/Cluster_Name/application : 로그 소스(All log files in /var/log/containers), 각 컨테이너/파드 로그
    2. /aws/containerinsights/Cluster_Name/host : 로그 소스(Logs from /var/log/dmesg, /var/log/secure, and /var/log/messages), 노드(호스트) 로그
    3. /aws/containerinsights/Cluster_Name/dataplane : 로그 소스(/var/log/journal for kubelet.service, kubeproxy.service, and docker.service), 쿠버네티스 데이터플레인 로그
  • [저장] : CloudWatch Logs 에 로그를 저장, 로그 그룹 별 로그 보존 기간 설정 가능
  • [시각화] : CloudWatch 의 Logs Insights 를 사용하여 대상 로그를 분석하고, CloudWatch 의 대시보드로 시각화한다

(사전 확인) 노드의 로그 확인

 
1. application 로그 소스(All log files in /var/log/containers → 심볼릭 링크 /var/log/pods/<컨테이너>, 각 컨테이너/파드 로그

# 로그 위치 확인
#ssh ec2-user@$N1 sudo tree /var/log/containers
#ssh ec2-user@$N1 sudo ls -al /var/log/containers
for node in $N1 $N2 $N3; do echo ">>>>> $node <<<<<"; ssh ec2-user@$node sudo tree /var/log/containers; echo; done
...
/var/log/containers
├── aws-load-balancer-controller-6fb4f86d9d-dq922_kube-system_aws-load-balancer-controller-2b96ca5eaaac0fedc98c5d84af7368c711f54f3f01935b5656e3efd15e69eb99.log -> /var/log/pods/kube-system_aws-load-balancer-controller-6fb4f86d9d-dq922_43633283-a0d2-4aaa-b880-723a2473653f/aws-load-balancer-controller/0.log
...

for node in $N1 $N2 $N3; do echo ">>>>> $node <<<<<"; ssh ec2-user@$node sudo ls -al /var/log/containers; echo; done


# 개별 파드 로그 확인 : 아래 각자 디렉터리 경로는 다름
ssh ec2-user@$N1 sudo tail -f /var/log/pods/default_nginx-685c67bc9-pkvzd_69b28caf-7fe2-422b-aad8-f1f70a206d9e/nginx/0.log

 
2. host 로그 소스(Logs from /var/log/dmesg, /var/log/secure, and /var/log/messages), 노드(호스트) 로그

# 로그 위치 확인
#ssh ec2-user@$N1 sudo tree /var/log/ -L 1
#ssh ec2-user@$N1 sudo ls -la /var/log/
for node in $N1 $N2 $N3; do echo ">>>>> $node <<<<<"; ssh ec2-user@$node sudo tree /var/log/ -L 1; echo; done
for node in $N1 $N2 $N3; do echo ">>>>> $node <<<<<"; ssh ec2-user@$node sudo ls -la /var/log/; echo; done

# 호스트 로그 확인
#ssh ec2-user@$N1 sudo tail /var/log/dmesg
#ssh ec2-user@$N1 sudo tail /var/log/secure
#ssh ec2-user@$N1 sudo tail /var/log/messages
for log in dmesg secure messages; do echo ">>>>> Node1: /var/log/$log <<<<<"; ssh ec2-user@$N1 sudo tail /var/log/$log; echo; done
for log in dmesg secure messages; do echo ">>>>> Node2: /var/log/$log <<<<<"; ssh ec2-user@$N2 sudo tail /var/log/$log; echo; done
for log in dmesg secure messages; do echo ">>>>> Node3: /var/log/$log <<<<<"; ssh ec2-user@$N3 sudo tail /var/log/$log; echo; done

 
3. dataplane 로그 소스(/var/log/journal for kubelet.service, kubeproxy.service, and docker.service), 쿠버네티스 데이터플레인 로그

# 로그 위치 확인
#ssh ec2-user@$N1 sudo tree /var/log/journal -L 1
#ssh ec2-user@$N1 sudo ls -la /var/log/journal
for node in $N1 $N2 $N3; do echo ">>>>> $node <<<<<"; ssh ec2-user@$node sudo tree /var/log/journal -L 1; echo; done

# 저널 로그 확인 - 링크
ssh ec2-user@$N3 sudo journalctl -x -n 200
ssh ec2-user@$N3 sudo journalctl -f

 


CloudWatch Container Insight 설치

  • cloudwatch-agent & fluent-bit - 링크 & Setting up Fluent Bit - Docs
# 설치
FluentBitHttpServer='On'
FluentBitHttpPort='2020'
FluentBitReadFromHead='Off'
FluentBitReadFromTail='On'
curl -s https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluent-bit-quickstart.yaml | sed 's/{{cluster_name}}/'${CLUSTER_NAME}'/;s/{{region_name}}/'${AWS_DEFAULT_REGION}'/;s/{{http_server_toggle}}/"'${FluentBitHttpServer}'"/;s/{{http_server_port}}/"'${FluentBitHttpPort}'"/;s/{{read_from_head}}/"'${FluentBitReadFromHead}'"/;s/{{read_from_tail}}/"'${FluentBitReadFromTail}'"/' | kubectl apply -f -

# 설치 확인
kubectl get-all -n amazon-cloudwatch
NAME                                                NAMESPACE          AGE
configmap/cwagent-clusterleader                     amazon-cloudwatch  2s
configmap/cwagentconfig                             amazon-cloudwatch  12s
configmap/fluent-bit-cluster-info                   amazon-cloudwatch  12s
configmap/kube-root-ca.crt                          amazon-cloudwatch  12s
pod/cloudwatch-agent-6699r                          amazon-cloudwatch  12s
pod/cloudwatch-agent-jpdts                          amazon-cloudwatch  12s
pod/cloudwatch-agent-wtcfm                          amazon-cloudwatch  12s
pod/fluent-bit-2jhxx                                amazon-cloudwatch  11s
pod/fluent-bit-5qzbx                                amazon-cloudwatch  11s
pod/fluent-bit-6wl44                                amazon-cloudwatch  11s
serviceaccount/cloudwatch-agent                     amazon-cloudwatch  12s
serviceaccount/default                              amazon-cloudwatch  12s
serviceaccount/fluent-bit                           amazon-cloudwatch  12s
controllerrevision.apps/cloudwatch-agent-bfcddf455  amazon-cloudwatch  12s
controllerrevision.apps/fluent-bit-98d767484        amazon-cloudwatch  11s
daemonset.apps/cloudwatch-agent                     amazon-cloudwatch  12s
daemonset.apps/fluent-bit                           amazon-cloudwatch  11s


kubectl get ds,pod,cm,sa -n amazon-cloudwatch
kubectl describe clusterrole cloudwatch-agent-role fluent-bit-role                          # 클러스터롤 확인
kubectl describe clusterrolebindings cloudwatch-agent-role-binding fluent-bit-role-binding  # 클러스터롤 바인딩 확인
kubectl -n amazon-cloudwatch logs -l name=cloudwatch-agent -f # 파드 로그 확인
kubectl -n amazon-cloudwatch logs -l k8s-app=fluent-bit -f    # 파드 로그 확인
for node in $N1 $N2 $N3; do echo ">>>>> $node <<<<<"; ssh ec2-user@$node sudo ss -tnlp | grep fluent-bit; echo; done

# cloudwatch-agent 설정 확인
kubectl describe cm cwagentconfig -n amazon-cloudwatch
{
  "agent": {
    "region": "ap-northeast-2"
  },
  "logs": {
    "metrics_collected": {
      "kubernetes": {
        "cluster_name": "myeks",
        "metrics_collection_interval": 60
      }
    },
    "force_flush_interval": 5
  }
}

# CW 파드가 수집하는 방법 : Volumes에 HostPath를 살펴보자! >> / 호스트 패스 공유??? 보안상 안전한가? 좀 더 범위를 좁힐수는 없을까요?
kubectl describe -n amazon-cloudwatch ds cloudwatch-agent
...
ssh ec2-user@$N1 sudo tree /dev/disk
...

# Fluent Bit Cluster Info 확인
kubectl get cm -n amazon-cloudwatch fluent-bit-cluster-info -o yaml | yh
apiVersion: v1
data:
  cluster.name: myeks
  http.port: "2020"
  http.server: "On"
  logs.region: ap-northeast-2
  read.head: "Off"
  read.tail: "On"
kind: ConfigMap
...

# Fluent Bit 로그 INPUT/FILTER/OUTPUT 설정 확인 - 링크
## 설정 부분 구성 : application-log.conf , dataplane-log.conf , fluent-bit.conf , host-log.conf , parsers.conf
kubectl describe cm fluent-bit-config -n amazon-cloudwatch
...
application-log.conf:
----
[INPUT]
    Name                tail
    Tag                 application.*
    Exclude_Path        /var/log/containers/cloudwatch-agent*, /var/log/containers/fluent-bit*, /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
    Path                /var/log/containers/*.log
    multiline.parser    docker, cri
    DB                  /var/fluent-bit/state/flb_container.db
    Mem_Buf_Limit       50MB
    Skip_Long_Lines     On
    Refresh_Interval    10
    Rotate_Wait         30
    storage.type        filesystem
    Read_from_Head      ${READ_FROM_HEAD}

[FILTER]
    Name                kubernetes
    Match               application.*
    Kube_URL            https://kubernetes.default.svc:443
    Kube_Tag_Prefix     application.var.log.containers.
    Merge_Log           On
    Merge_Log_Key       log_processed
    K8S-Logging.Parser  On
    K8S-Logging.Exclude Off
    Labels              Off
    Annotations         Off
    Use_Kubelet         On
    Kubelet_Port        10250
    Buffer_Size         0

[OUTPUT]
    Name                cloudwatch_logs
    Match               application.*
    region              ${AWS_REGION}
    log_group_name      /aws/containerinsights/${CLUSTER_NAME}/application
    log_stream_prefix   ${HOST_NAME}-
    auto_create_group   true
    extra_user_agent    container-insights
...

# Fluent Bit 파드가 수집하는 방법 : Volumes에 HostPath를 살펴보자!
kubectl describe -n amazon-cloudwatch ds fluent-bit
...
ssh ec2-user@$N1 sudo tree /var/log
...

# (참고) 삭제
curl -s https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluent-bit-quickstart.yaml | sed 's/{{cluster_name}}/'${CLUSTER_NAME}'/;s/{{region_name}}/'${AWS_DEFAULT_REGION}'/;s/{{http_server_toggle}}/"'${FluentBitHttpServer}'"/;s/{{http_server_port}}/"'${FluentBitHttpPort}'"/;s/{{read_from_head}}/"'${FluentBitReadFromHead}'"/;s/{{read_from_tail}}/"'${FluentBitReadFromTail}'"/' | kubectl delete -f -

 
 

로깅 확인 : CW 로그 그룹

 

메트릭 확인 : CW 인사이트 & Container Insights

 


 

로그 확인 : nginx 웹서버

  • Docs
# 부하 발생
curl -s https://nginx.$MyDomain
yum install -y httpd
ab -c 500 -n 30000 https://nginx.$MyDomain/

# 파드 직접 로그 모니터링
kubectl logs deploy/nginx -f

로그 그룹 & application & 로그 스트림 : nginx 필터링 & 클릭 후 확인 & ApacheBench 필터링 확인

 


 

Logs Insights

# Application log errors by container name : 컨테이너 이름별 애플리케이션 로그 오류
# 로그 그룹 선택 : /aws/containerinsights/<CLUSTER_NAME>/application
stats count() as error_count by kubernetes.container_name 
| filter stream="stderr" 
| sort error_count desc

# All Kubelet errors/warning logs for for a given EKS worker node
# 로그 그룹 선택 : /aws/containerinsights/<CLUSTER_NAME>/dataplane
fields @timestamp, @message, ec2_instance_id
| filter  message =~ /.*(E|W)[0-9]{4}.*/ and ec2_instance_id="<YOUR INSTANCE ID>"
| sort @timestamp desc

# Kubelet errors/warning count per EKS worker node in the cluster
# 로그 그룹 선택 : /aws/containerinsights/<CLUSTER_NAME>/dataplane
fields @timestamp, @message, ec2_instance_id
| filter   message =~ /.*(E|W)[0-9]{4}.*/
| stats count(*) as error_count by ec2_instance_id

# performance 로그 그룹
# 로그 그룹 선택 : /aws/containerinsights/<CLUSTER_NAME>/performance
# 노드별 평균 CPU 사용률
STATS avg(node_cpu_utilization) as avg_node_cpu_utilization by NodeName
| SORT avg_node_cpu_utilization DESC

# 파드별 재시작(restart) 카운트
STATS avg(number_of_container_restarts) as avg_number_of_container_restarts by PodName
| SORT avg_number_of_container_restarts DESC

# 요청된 Pod와 실행 중인 Pod 간 비교
fields @timestamp, @message 
| sort @timestamp desc 
| filter Type="Pod" 
| stats min(pod_number_of_containers) as requested, min(pod_number_of_running_containers) as running, ceil(avg(pod_number_of_containers-pod_number_of_running_containers)) as pods_missing by kubernetes.pod_name 
| sort pods_missing desc

# 클러스터 노드 실패 횟수
stats avg(cluster_failed_node_count) as CountOfNodeFailures 
| filter Type="Cluster" 
| sort @timestamp desc

# 파드별 CPU 사용량
stats pct(container_cpu_usage_total, 50) as CPUPercMedian by kubernetes.container_name 
| filter Type="Container"
| sort CPUPercMedian desc

 


4. Metrics-server & kwatch & botkube

 

Metrics-server 확인

kubelet으로부터 수집한 리소스 메트릭을 수집 및 집계하는 클러스터 애드온 구성 요소이다.

  • EKS Github Docs CMD

 
cAdvisor : kubelet에 포함된 컨테이너 메트릭을 수집, 집계, 노출하는 데몬

https://kubernetes.io/ko/docs/tasks/debug/debug-cluster/resource-metrics-pipeline/

 

# 배포
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 메트릭 서버 확인 : 메트릭은 15초 간격으로 cAdvisor를 통하여 가져옴
kubectl get pod -n kube-system -l k8s-app=metrics-server
NAME                              READY   STATUS    RESTARTS   AGE
metrics-server-6bf466fbf5-9jk7m   1/1     Running   0          3m45s

kubectl api-resources | grep metrics
nodes                                          metrics.k8s.io/v1beta1                 false        NodeMetrics
pods                                           metrics.k8s.io/v1beta1                 true         PodMetrics

kubectl get apiservices |egrep '(AVAILABLE|metrics)'

# 노드 메트릭 확인
kubectl top node
NAME                                               CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
ip-192-168-1-175.ap-northeast-2.compute.internal   57m          1%     743Mi           5%

ip-192-168-2-84.ap-northeast-2.compute.internal    78m          1%     711Mi           4%

ip-192-168-3-212.ap-northeast-2.compute.internal   61m          1%     805Mi           5%

# 파드 메트릭 확인
kubectl top pod -A
...
NAMESPACE     NAME                                            CPU(cores)   MEMORY(bytes)
default       nginx-685c67bc9-pvr46                           1m           4Mi
kube-system   aws-load-balancer-controller-6fb4f86d9d-dq922   1m           20Mi
kube-system   aws-load-balancer-controller-6fb4f86d9d-pwtgf   3m           27Mi
kube-system   aws-node-g6ttb                                  3m           38Mi
kube-system   aws-node-xvmzj                                  3m           38Mi

kubectl top pod -n kube-system --sort-by='cpu'
...
NAME                                            CPU(cores)   MEMORY(bytes)
kube-ops-view-558d87b798-blzhn                  16m          35Mi
metrics-server-6bf466fbf5-9jk7m                 5m           16Mi
ebs-csi-controller-67658f895c-ts2qp             5m           54Mi
aws-node-xvmzj                                  3m           38Mi
aws-node-zvgr6                                  3m           37Mi

kubectl top pod -n kube-system --sort-by='memory'
...
NAME                                            CPU(cores)   MEMORY(bytes)
ebs-csi-controller-67658f895c-ts2qp             4m           54Mi
ebs-csi-controller-67658f895c-pqxbw             2m           50Mi
efs-csi-controller-6f64dcc5dc-g62bj             3m           43Mi
efs-csi-controller-6f64dcc5dc-hngkx             3m           41Mi
aws-node-xvmzj                                  4m           38Mi

 


 

kwatch 소개 및 설치/사용

kwatch는 Kubernetes(K8s) 클러스터의 모든 변경 사항을 모니터링하고, 실행 중인 앱의 충돌을 실시간으로 감지하고, 채널에 알림(슬랙, 디스코드 등)을 즉시 게시할 수 있도록 도와준다.

kwatch helps you monitor all changes in your Kubernetes(K8s) cluster, detects crashes in your running apps in realtime, and publishes notifications to your channels (Slack, Discord, etc.) instantly
  • 링크 Helm Blog

슬랙 웹훅 URL을 각자 상황에 맞게 사용하면 된다!

# configmap 생성
cat <<EOT > ~/kwatch-config.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: kwatch
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: kwatch
  namespace: kwatch
data:
  config.yaml: |
    alert:
      slack:
        webhook: 'https://hooks.slack.com/services/<slack web hook url>'
        title: $NICK-EKS
        #text:
    pvcMonitor:
      enabled: true
      interval: 5
      threshold: 70
EOT
kubectl apply -f kwatch-config.yaml

# 배포
kubectl apply -f https://raw.githubusercontent.com/abahmed/kwatch/v0.8.3/deploy/deploy.yaml

 
잘못된 이미지 파드 배포 및 확인

# 터미널1
watch kubectl get pod

# 잘못된 이미지 정보의 파드 배포
kubectl apply -f https://raw.githubusercontent.com/junghoon2/kube-books/main/ch05/nginx-error-pod.yml
kubectl get events -w
...
kubectl get events -w
LAST SEEN   TYPE      REASON                   OBJECT
     MESSAGE
48m         Normal    SuccessfullyReconciled   targetgroupbinding/k8s-default-nginx-7559586e53   Successfully reconciled
51s         Normal    Scheduled                pod/nginx-19
     Successfully assigned default/nginx-19 to ip-192-168-1-175.ap-northeast-2.compute.internal
5s          Normal    Pulling                  pod/nginx-19
     Pulling image "nginx:1.19.19"
3s          Warning   Failed                   pod/nginx-19
     Failed to pull image "nginx:1.19.19": rpc error: code = NotFound desc = failed to pull and unpack image "docker.io/library/nginx:1.19.19": failed to resolve reference "docker.io/library/nginx:1.19.19": docker.io/library/nginx:1.19.19: not found

# 이미지 업데이트 방안2 : set 사용 - iamge 등 일부 리소스 값을 변경 가능!
kubectl set 
kubectl set image pod nginx-19 nginx-pod=nginx:1.19

# 삭제
kubectl delete pod nginx-19

# kwatch 삭제  
kubectl delete -f https://raw.githubusercontent.com/abahmed/kwatch/v0.8.3/deploy/deploy.yaml

오호 잘된다!


Botkube 란?

BotKube는 Kubernetes(K8s) 클러스터의 모니터링 및 디버깅을 허용하는 오픈 소스 프로젝트이다. Slack, Mattermost 또는 Microsoft Teams와 같은 플랫폼과 통합된 메시징 봇으로 사용하도록 설계되었다.  Kubernetes 환경 내에서 발생하는 특정 이벤트에 대한 알림을 메시징 플랫폼에 보낼 수 있다.
 

  • 공홈 Blog

https://botkube.io/

# 연결 상태, notifications 상태 확인
@Botkube ping
@Botkube status notifications

# 파드 정보 조회
@Botkube k get pod
@Botkube kc get pod --namespace kube-system
@Botkube kubectl get pod --namespace kube-system -o wide

# Actionable notifications
@Botkube kubectl

 
 


5. 프로메테우스-스택

 
Prometheus는 원래 SoundCloud에 구축된 오픈 소스 시스템 모니터링 및 알림 툴킷이다.

  • Prometheus is an open-source systems monitoring and alerting toolkit originally built at SoundCloud

 
Prometheus의 제공기능은 아래와 같다.

  • 메트릭 이름과 키/값 쌍으로 식별되는 시계열 데이터(=TSDB, 시계데이스베터)를 포함하는 다차원 데이터 모델
  • PromQL, a flexible query language to leverage this dimensionality
  • 분산 스토리지에 의존하지 않고, 단일 서버 노드가 자동으로 실행됨
  • time series collection happens via a pull model over HTTP ⇒ 질문 Push 와 Pull 수집 방식 장단점? - 링크

 

https://prometheus.io/docs/introduction/overview/


 

프로메테우스 오퍼레이터

Prometheus Operator는 Prometheus 및 관련 모니터링 구성 요소의 Kubernetes 기본 배포 및 관리를 제공하는 오픈 소스 도구이다. 

Prometheus Operator의 목적은 Kubernetes에서 Prometheus 인스턴스의 구성 및 관리를 단순화하고 자동화하는 것이다.

 
Promethus Operator의 작동 방식은 아래와 같다.
 
맞춤형 리소스 정의(CRD): Prometheus Operator는 Kubernetes에 Prometheus, ServiceMonitor 및 AlertManager와 같은 새로운 맞춤형 리소스 정의(CRD)를 도입했다. 이를 통해 Prometheus 및 AlertManager 인스턴스의 선언적 구성 및 관리가 가능하다.
 
ServiceMonitor를 통한 대상 서비스: 대규모 환경에서 오류가 발생하기 쉽고 확장이 불가능할 수 있는 모니터링할 서비스를 수동으로 지정하는 대신 Prometheus Operator는 모니터링할 서비스를 기반으로 자동으로 검색하는 'ServiceMonitor' 리소스를 사용한다. 
 
AlertManager 구성: Prometheus Operator는 Prometheus와 같은 클라이언트 애플리케이션에서 보낸 경고를 처리하는 AlertManager의 인스턴스도 관리한다. 
 
자동 구성 업데이트: Prometheus 또는 AlertManager 인스턴스의 구성이 변경될 때마다 Operator는 구성이 업데이트되고 새 구성을 선택하기 위해 인스턴스가 다시 시작되는지 필요한 경우에 확인한다.
 
 


Thanos 타노드

Thanos는 프로메테우스 확장성과 고가용성을 개선하기 위한 시스템이다.
Prometheus의 일부 제한 사항, 특히 내구성과 확장 가능한 스토리지 부족을 해결하기 위해 제작되었다.

간단히 말해 Thanos는 "highly available Prometheus setup with long-term storage capabilities" 이다.

Thanos를 사용하여 메모리 문제를 해결하는 첫 번째 단계는 사이드카 구성 요소이다.
S3, Swift, Azure 등에서 객체 스토리지로 메트릭을 원할하게 업로드할 수 있다. StoreAPI 를 API 게이트웨이로 사용 하고 적은 양의 디스크 공간만 사용하여 원격 블록을 추적하고 동기화 상태를 유지한다.
그리고 저장소와 유사하게 Thanos Query는 Prometheus HTTP API를 사용한다. 따라서 PromQL을 통해 Thanos 클러스터 내에서 데이터를 쿼리할 수 있다.
 

출처: https://www.giffgaff.io/tech/monitoring-at-giffgaff/

 
 


프로메테우스-스택 설치

프로메테우스-스택을 설치를 해본다!
 
Kube-prometheus-stack은 문서 및 스크립트와 결합된 Kubernetes 매니페스트, Grafana 대시보드 및 Prometeus 규칙을 수집하여 Prometeus Operator를 사용하여 Prometeus를 사용하여 쉽게 운영할 수 있는 엔드 투 엔드 Kubernetes 클러스터 모니터링을 제공한다.
 
모니터링에 필요한 여러 요소를 단일 차트(스택)으로 제공 ← 시각화(그라파나), 이벤트 메시지 정책(경고 임계값) 등

  • Helm
프로메테우스-스택 설치 시, 주요 애플리케이션(파드)들은 EBS 스토리지클래스를 사용할 수 있게 helm 파라미터를 변경하는 실습을 해본다.

 

# 모니터링
kubectl create ns monitoring
watch kubectl get pod,pvc,svc,ingress -n monitoring

# 사용 리전의 인증서 ARN 확인
CERT_ARN=`aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text`
echo $CERT_ARN

# 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"

  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'

defaultRules:
  create: false
kubeControllerManager:
  enabled: false
kubeEtcd:
  enabled: false
kubeScheduler:
  enabled: false
alertmanager:
  enabled: false

# alertmanager:
#   ingress:
#     enabled: true
#     ingressClassName: alb
#     hosts: 
#       - alertmanager.$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'
EOT
cat ~/monitor-values.yaml | yh

# 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 45.27.2 \
--set prometheus.prometheusSpec.scrapeInterval='15s' --set prometheus.prometheusSpec.evaluationInterval='15s' \
-f monitor-values.yaml --namespace monitoring

# 확인
## alertmanager-0 : 사전에 정의한 정책 기반(예: 노드 다운, 파드 Pending 등)으로 시스템 경고 메시지를 생성 후 경보 채널(슬랙 등)로 전송
## grafana : 프로메테우스는 메트릭 정보를 저장하는 용도로 사용하며, 그라파나로 시각화 처리
## prometheus-0 : 모니터링 대상이 되는 파드는 ‘exporter’라는 별도의 사이드카 형식의 파드에서 모니터링 메트릭을 노출, pull 방식으로 가져와 내부의 시계열 데이터베이스에 저장
## node-exporter : 노드익스포터는 물리 노드에 대한 자원 사용량(네트워크, 스토리지 등 전체) 정보를 메트릭 형태로 변경하여 노출
## operator : 시스템 경고 메시지 정책(prometheus rule), 애플리케이션 모니터링 대상 추가 등의 작업을 편리하게 할수 있게 CRD 지원
## kube-state-metrics : 쿠버네티스의 클러스터의 상태(kube-state)를 메트릭으로 변환하는 파드
helm list -n monitoring
kubectl get pod,svc,ingress -n monitoring
kubectl get-all -n monitoring
...
kubectl get-all -n monitoring
NAME                                                                                 NAMESPACE   AGE
configmap/kube-prometheus-stack-alertmanager-overview                                monitoring  23s
configmap/kube-prometheus-stack-apiserver                                            monitoring  23s
configmap/kube-prometheus-stack-cluster-total                                        monitoring  23s
configmap/kube-prometheus-stack-grafana                                              monitoring  23s

kubectl get prometheus,servicemonitors -n monitoring
kubectl get prometheusrule,alertmanager -n monitoring
kubectl get crd | grep monitoring

 
AWS ELB(ALB) 갯수 확인 → Rule 확인(어떻게 여러 도메인 처리를 하는 걸까?) ⇒ HTTP(80) 인입 시 어떻게 처리하나요?

 
프로메테우스 웹 → Status → Targets 확인

Prometheus 확인

 
(참고) 삭제 시

# helm 삭제
helm uninstall -n monitoring kube-prometheus-stack

# crd 삭제
kubectl delete crd alertmanagerconfigs.monitoring.coreos.com
kubectl delete crd alertmanagers.monitoring.coreos.com
kubectl delete crd podmonitors.monitoring.coreos.com
kubectl delete crd probes.monitoring.coreos.com
kubectl delete crd prometheuses.monitoring.coreos.com
kubectl delete crd prometheusrules.monitoring.coreos.com
kubectl delete crd servicemonitors.monitoring.coreos.com
kubectl delete crd thanosrulers.monitoring.coreos.com

6. 그라파나 Grafana

Grafana는 모니터링 및 관찰 가능성을 위한 오픈 소스 플랫폼이다.

Grafana를 사용하면 메트릭이 저장된 위치에 관계없이 쿼리, 시각화, 경고 및 이해할 수 있다.

확장성이 뛰어나고 Graphite, Elasticsearch, OpenTSDB, Prometheus 및 InfluxDB를 포함하되 이에 국한되지 않는 다양한 데이터 소스를 지원한다.

 
 


그라파나의 주요기능

 

데이터 시각화(Data Visualization): 시계열 데이터를 시각화하기 위한 강력하고 유연한 도구를 제공한다. 패널이 있는 대시보드를 생성할 수 있으며 각 패널은 설정된 기간 동안 특정 메트릭을 나타낸다. Grafana는 다양한 유형의 그래프, 테이블 및 기타 시각화를 지원한다.
 
알림(Alerting): Grafana는 기능이 풍부한 알림 엔진을 제공한다. 가장 중요한 메트릭에 대한 경고 규칙을 생성할 수 있으며 Grafana는 이를 지속적으로 평가한다. 알림은 이메일, Slack, PagerDuty 등을 포함한 다양한 알리미를 통해 보낼 수 있다.
 
주석 및 마커(Annotations & Markers): 다양한 데이터 소스의 풍부한 이벤트로 그래프에 주석을 추가한다. 이벤트 위로 마우스를 가져가면 전체 이벤트 메타데이터 및 태그가 표시된다.
 
Ad-hoc 필터(Ad-hoc Filters): Ad-hoc 필터를 사용하면 해당 데이터 소스를 사용하는 모든 쿼리에 자동으로 적용되는 새로운 키/값 필터를 즉시 생성할 수 있다.
 
혼합 데이터 소스(Mixed Data Sources): 동일한 그래프에 서로 다른 데이터 소스를 혼합하세요! 쿼리별로 데이터 소스를 지정할 수 있다. 이는 사용자 정의 데이터 소스에서도 작동한다.
 
플러그인(Plugins): Grafana는 플러그형 아키텍처를 특징으로 하며 개발자가 패널, 데이터 소스 및 앱용 플러그인으로 기존 기능을 확장할 수 있다.
 
 
 


7. 그라파나 얼럿 Alert

  • 그라파나 9.4 버전이 2월 28일 출시 - 링크 ⇒ Alerting 기능이 강화되었고, 이미지 알람 기능도 제공 - 링크 
  • 그라파나 9.5 버전이 Alerting 기능 업데이트 - 링크

 

그라파나 얼럿

  • Docs 링크 Workshop Blog1 Blog2

https://grafana.com/docs/grafana/latest/alerting/


 

 

8. kubecost

OpenCost 링크를 기반으로 구축되었으며 AWS에서 적극 지원, 쿠버네티스 리소스별 비용 분류 가시화 제공한다.

  • Pricing - 링크 : Free(메트릭 15일 보존, Business(메트릭 30일 보존, …), Enterprise(.)
  • Amazon EKS cost monitoring with Kubecost architecture - 링크

출처 : 가시다님 CloudNet@ 스터디

 


 

설치 및 웹 접속

  • 링크 Chart Gallery
# 
cat <<EOT > cost-values.yaml
global:
  grafana:
    enabled: true
    proxy: false

priority:
  enabled: false
networkPolicy:
  enabled: false
podSecurityPolicy:
  enabled: false

persistentVolume:
    storageClass: "gp3"

prometheus:
  kube-state-metrics:
    disabled: false
  nodeExporter:
    enabled: true

reporting:
  productAnalytics: true
EOT

# kubecost chart 에 프로메테우스가 포함되어 있으니, 기존 프로메테우스-스택은 삭제하자 : node-export 포트 충돌 발생
helm uninstall -n monitoring kube-prometheus-stack

# 배포
kubectl create ns kubecost
helm install kubecost oci://public.ecr.aws/kubecost/cost-analyzer --version 1.103.2 --namespace kubecost -f cost-values.yaml

# 배포 확인
kubectl get-all -n kubecost
NAME                                                                    NAMESPACE  AGE
configmap/attached-disk-metrics-dashboard                               kubecost   11s
configmap/cluster-metrics-dashboard                                     kubecost   11s
configmap/cluster-utilization-dashboard                                 kubecost   11s
configmap/deployment-utilization-dashboard                              kubecost   11s
...

# kubecost-cost-analyzer 파드 IP변수 지정 및 접속 확인
CAIP=$(kubectl get pod -n kubecost -l app=cost-analyzer -o jsonpath={.items[0].status.podIP})
curl -s $CAIP:9090
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
...
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="portal-root"></div>

  </body>
</html>

# 외부에서 bastion EC2 접속하여 특정 파드 접속 방법 : socat(SOcket CAT) 활용
yum -y install socat
socat TCP-LISTEN:80,fork TCP:$CAIP:9090
웹 브라우저에서 bastion EC2 IP로 접속

# 삭제
helm uninstall -n kubecost kubecost
  • socat(SOcket CAT) 활용 - 링크

접속 완료!


9. AWS 관리형 서비스 AMP & AMG

AMP(Amazon Managed Prometheus)는 서버리스 프로메테우스이다. AWS가 프로메테우스를 직접 관리하고 사용자는 프로메테우스 설정만 하면 된다. AMP는 AWS리소스(SNS 등)를 연계하여 알림 기능도 구현할 수 있다.
 
AMP는 AWS 다중 가용영역(Availability Zone)을 활영하여 HA(High Availability)를 지원한다. AMP에 저장된 데이터는 150일동안 저장한다.
 
Amazon Managed Service for Prometheus는 대규모의 컨테이너식 애플리케이션 및 인프라를 모니터링하고 그에 대한 알림을 제공하는 새로운 Prometheus 호환 서비스이다. 이 서비스는 Amazon Elastic Kubernetes Service(EKS), Amazon Elastic Container Service(ECS), AWS Distro for Open Telemetry와도 통합된다.

https://aws.amazon.com/ko/prometheus/

 
 
출처 : 최성욱(악분일상)님 블로그
https://malwareanalysis.tistory.com/602

 

EKS 스터디 - 4주차 3편 - AMP에 EKS메트릭 저장

안녕하세요. 이 글은 EKS메트릭을 AMP(AWS Managed Prometheus)에 저장하고 AMG(AWS Managed Grafana)에서 시각화하는 방법을 설명합니다. AMP란? AMP(Amazon Managed Prometheus)는 서버리스 프로메테우스입니다. AWS가 프

malwareanalysis.tistory.com

 


10. OpenTelemetry(OTel)

OpenTelemetry는 도구, API 및 SDK 모음이다. 소프트웨어의 성능과 동작을 분석하는 데 도움이 되도록 원격 측정 데이터(메트릭, 로그 및 추적)를 계측, 생성, 수집 및 내보내는 데 사용된다.
 
OpenTelemetry는 일반적 으로 여러 언어 로 제공되며 사용하기에 적합하다.

  • Otel 공홈

https://opentelemetry.io/

 
 
 


(실습 완료 후) 자원 삭제

 

Helm Chart 삭제

helm uninstall -n kube-system kube-ops-view
helm uninstall nginx
helm uninstall botkube --namespace botkube
helm uninstall -n monitoring kube-prometheus-stack

 

(옵션) 로깅 삭제 : 위에서 삭제 안 했을 경우 삭제

# 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

---
# 로그 그룹 삭제 : 데이터 플레인
aws logs delete-log-group --log-group-name /aws/containerinsights/$CLUSTER_NAME/application
aws logs delete-log-group --log-group-name /aws/containerinsights/$CLUSTER_NAME/dataplane
aws logs delete-log-group --log-group-name /aws/containerinsights/$CLUSTER_NAME/host
aws logs delete-log-group --log-group-name /aws/containerinsights/$CLUSTER_NAME/performance

 

삭제

eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME

삭제 완료!

 


 

728x90
반응형