이번 포스트에서는 EKS의 모니터링과 로깅에 대해서 살펴보겠습니다.

 

먼저 모니터링과 옵저버빌리티에 대한 차이와 이에 사용되는 지표인 메트릭, 로그, 트레이싱에 대한 용어를 살펴보겠습니다. 이후 Kubernetes 환경의 모니터링 관점을 설명하고, EKS에서 어떤 방식으로 클러스터 모니터링을 제공하는지를 살펴보겠습니다. 그리고 마지막으로 AKS(Azure Kubernetes Service)의 모니터링을 비교해 보겠습니다.

 

본 포스트는 CSP 사에서 제공하는 메트릭과 이벤트, 로그 수준의 모니터링 관점으로 주로 설명을 드리겠습니다.

 

목차

  1. Monitoring과 Observability
  2. Kuberntes 환경의 모니터링
  3. 실습 환경 생성
  4. EKS의 모니터링과 로깅
  5. AKS의 모니터링과 로깅
  6. 리소스 정리

 

1. Monitoring과 Observability

과거부터 흔히 사용한 모니터링(Monitoring)이라는 단어가 익숙한데 비해 최근에 옵저버빌리티(Observability)라고 표현하는 관측 가능성이라는 용어는 조금 낯설기도 합니다. 이번 절에서는 모니터링과 옵저버빌리티를 구분을 해보고자 합니다.

 

그리고 모니터링과 옵저버빌리티에서 사용되는 Metric, Log, Tracing과 같은 용어도 알아 보겠습니다.

 

Monitoring과 Observability

모니터링은 전체적인 시스템 상태를 이해하고 감시하기 위한 활동입니다. 이를 위해 정의된 기준을 기반으로 성능 지표를 수집하여 예상치 못한 문제를 조기에 감지하는 과정을 말합니다.

과거부터 모니터링은 IT 시스템을 측정하고 장애를 예방하기 위한 목적으로 널리 사용되었지만, 시스템이 점차 다양해지고 분산 환경으로 변화됨에 따라, 개별 구성 요소들의 모니터링 지표로는 전체 서비스를 이해하기는 어려운 한계를 가지고 있습니다.

다만 시스템의 복잡성이 높아진다고 해서 모니터링 자체가 불필요 해지는 것은 아니며, 문제를 Drill down 하기 위해서는 개별 시스템의 모니터링 지표와 로그에서 유용한 정보를 찾을 필요도 있습니다.

 

옵저버빌리티 혹은 관측 가능성은 클라우드 네이티브 처럼 분산된 환경의 애플리케이션에서 발생할 수 있는 문제에 대해서 각 이벤트에 대한 통찰력을 제공하기 위해서, 각 마이크로 서비스 간의 태그, 로그를 결합해 컨텍스트(Context)를 제공하는 것이 목표입니다.

마이크로 서비스 환경에서 발생한 문제는 개별 시스템 차원의 분석으로는 설명하기는 어려울 수 있고, 각 마이크로 서비스 간의 연결 과정에서 파악해야 할 수 있습니다. 이를 파악하기 위해 지표나 이벤트를 통한 접근도 중요하지만 한편으로 이를 디버깅하는 과정에 옵저버빌리티의 역할이 커지고 있는 것 같습니다.

 

Metric, Log, Tracing

메트릭(Metrics): 특정 대상에 대한 정량화 되는 값을 의미합니다. 이는 시스템의 성능과 상태를 수치로 표현한 데이터로, 예를 들어, CPU 사용량, 메모리 사용량, 요청 지연 시간, 오류율 등이 있습니다.

시스템의 전반적인 상태를 한눈에 볼 수 있고, 이상 징후를 감지하도록 도움을 줍니다. 보통은 시간에 따른 추이를 보고, 임계치를 벗어나거나 혹은 패턴을 벗어나는 이상치를 감지할 수 있습니다.

 

로그(Logs): 시스템에서 발생한 이벤트를 기록한 텍스트나 구조화된 데이터 입니다. 로그는 보통 타임스탭프, 상태 코드, 상세 로그와 같은 형태로 기록되어, 이상 상황이나 오류가 발생한 시점을 기준으로 상세한 이유를 알 수 있어, 디버깅에 유용합니다. 예를 들어, 애플리케이션 로그, 시스템 이벤트 로그와 같은 형태입니다.

 

추적(Tracing): 분산 시스템에서 요청이 어떤 구성 요소들을 통해서 이동하는지 파악하는 것을 의미합니다. 요청의 흐름을 시각화 하고, 성능 이슈나 병목 혹은 이슈가 여러 서비스에 걸쳐 발생하는 경우 이를 진단하는데 도움을 줍니다. 예를 들어, 사용자가 어떤 화면을 접근했을 때, 그 요청이 어떤 내부 서비스를 거치는지 알 수 있습니다.

 

 

2. Kuberntes 환경의 모니터링

옵저버빌리티는 모니터링과는 다른 접근이나 솔루션이 필요하기 때문에 이후 설명은 쿠버네티스 관점에서 모니터링 관점으로 글을 이어 나가겠습니다.

물론 쿠버네티스를 자체를 모니터링 한다기 보다는 쿠버네티스 환경에서 실행되는 애플리케이션의 안전성을 위해 각 레이어별 모니터링을 설명하고자 합니다.

 

이를 설명을 하기 위해서 Azure에서 제공하는 아래 그림을 기반으로 설명을 이어 가겠습니다.

출처: https://learn.microsoft.com/ko-kr/azure/aks/monitor-aks

 

먼저 Level 1 클러스터가 위치한 네트워크 수준의 모니터링이고, Level 2로 클러스터 레벨 컴포넌트인 노드(가상머신 세트)를 모니터링 해야합니다.

그리고 Level 3은 쿠버네티스 컴포넌트에 대한 모니터링으로, 컨트롤 프레인 컴포넌트인 API 서버, Cloud Controller, Kubelet과 같은 요소들을 모니터링 해야합니다.

Level 4는 쿠버네티스 관점의 오브젝트와 워크로드에 대한 모니터링이며, 예를 들어, 컨테이너에 대한 메트릭과 파드의 재시작과 같은 이벤트도 포함해야 합니다. 한편으로 쿠버네티스에서 발생한 Event도 중요합니다.

Level 5는 애플리케이션 수준의 모니터링입니다. Level 4와 다소 겹칠 수 있지만, 애플리케이션 지표를 포함해 애플리케이션의 로그를 모니터링 할 수 있습니다.

 

그리고 이를 위한 모니터링 도구와 시각화 도구가 필요함을 설명하고 있습니다.

 

여기서 클라우드의 Managed Kubernetes Service 관점으로 생각해 볼 때, 리소스에 대한 CRUD 또한 모니터링 해야할 수도 있습니다. 예를 들어, 누가 새로운 리소스를 만들고, 구성을 변경하거나 잘못된 삭제를 한 것과 같은 이벤트입니다.

 

각 CSP(Cloud Service Provider)에서는 보통 각 상품을 위한 일반적인 모니터링을 기능을 제공하고 있습니다. AWS의 CloudWatch나 Azure의 Azure Monitor가 될 수 있습니다.

그리고 로깅 서비스를 통해 로그 데이터를 적재하고 쿼리를 통해 데이터를 조회하기 위한 기능을 제공합니다. AWS의 CloudWatch Logs와 Azure Log Analytics Workspace가 이에 해당합니다.

 

이후에는 EKS에서 모니터링을 어떤 방식으로 제공하는지를 모니터링과 로깅 관점으로 살펴보겠습니다.

 

 

3. 실습 환경 생성

EKS에서 제공하는 모니터링과 로깅을 살펴보기 위해서 아래와 같은 실습환경을 구성하도록 하겠습니다.

 

Note: 본 실습 환경은 AEWS(AWS EKS Workshop Study) 3기를 진행하 과정에서 제공받았습니다.

 

아래와 같이 CloudFormation을 통해 실습 환경을 배포합니다.

# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/myeks-4week.yaml

# 변수 지정
CLUSTER_NAME=myeks
SSHKEYNAME=ekskey
MYACCESSKEY=<IAM Uesr 액세스 키>
MYSECRETKEY=<IAM Uesr 시크릿 키>
WorkerNodeInstanceType=t3.xlarge # 워커노드 인스턴스 타입 변경 가능

# CloudFormation 스택 배포
aws cloudformation deploy --template-file myeks-4week.yaml --stack-name $CLUSTER_NAME --parameter-overrides KeyName=$SSHKEYNAME SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32  MyIamUserAccessKeyID=$MYACCESSKEY MyIamUserSecretAccessKey=$MYSECRETKEY ClusterBaseName=$CLUSTER_NAME WorkerNodeInstanceType=$WorkerNodeInstanceType --region ap-northeast-2

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

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

 

해당 CloudFormation 스택에 배포된 운영서버를 통해서 EKS 배포까지 포함되어 있습니다.

 

EKS 배포가 완료되기 위해 20분 정도를 기다리고, 이후 설치된 EKS를 확인해 보겠습니다.

# 변수 지정
CLUSTER_NAME=myeks
SSHKEYNAME=ekskey

# 클러스터 설치 확인
eksctl get cluster
NAME    REGION          EKSCTL CREATED
myeks   ap-northeast-2  True

eksctl get nodegroup --cluster $CLUSTER_NAME
CLUSTER NODEGROUP       STATUS  CREATED                 MIN SIZE        MAX SIZE        DESIRED CAPACITY        INSTANCE TYPE   IMAGE ID                ASG NAME                                   TYPE
myeks   ng1             ACTIVE  2025-02-28T15:05:57Z    3               3               3                       t3.xlarge       AL2023_x86_64_STANDARD  eks-ng1-b4caa68b-dac3-4a9c-a489-7d63a0d70934       managed

eksctl get addon --cluster $CLUSTER_NAME
2025-03-01 00:26:31 [ℹ]  Kubernetes version "1.31" in use by cluster "myeks"
2025-03-01 00:26:31 [ℹ]  getting all addons
2025-03-01 00:26:33 [ℹ]  to see issues for an addon run `eksctl get addon --name <addon-name> --cluster <cluster-name>`
NAME                    VERSION                 STATUS  ISSUES  IAMROLE                                                                                 UPDATE AVAILABLE   CONFIGURATION VALUES            POD IDENTITY ASSOCIATION ROLES
aws-ebs-csi-driver      v1.40.0-eksbuild.1      ACTIVE  0       arn:aws:iam::430118812536:role/eksctl-myeks-addon-aws-ebs-csi-driver-Role1-Ks7b8mzq4vmu
coredns                 v1.11.4-eksbuild.2      ACTIVE  0
kube-proxy              v1.31.3-eksbuild.2      ACTIVE  0
metrics-server          v0.7.2-eksbuild.2       ACTIVE  0
vpc-cni                 v1.19.3-eksbuild.1      ACTIVE  0       arn:aws:iam::430118812536:role/eksctl-myeks-addon-vpc-cni-Role1-He4lLHyBeE62              enableNetworkPolicy: "true"

eksctl get iamserviceaccount --cluster $CLUSTER_NAME

NAMESPACE       NAME                            ROLE ARN
kube-system     aws-load-balancer-controller    arn:aws:iam::430118812536:role/eksctl-myeks-addon-iamserviceaccount-kube-sys-Role1-1GFoeNZ7Z43o

# kubeconfig 생성
aws sts get-caller-identity --query Arn
aws eks update-kubeconfig --name myeks --user-alias <위 출력된 자격증명 사용자>

# 기본 구성 정보 확인
kubectl cluster-info
Kubernetes control plane is running at https://7984C504F1BE86380015EB205905A2C5.gr7.ap-northeast-2.eks.amazonaws.com
CoreDNS is running at https://7984C504F1BE86380015EB205905A2C5.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

kubectl get node
NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-1-115.ap-northeast-2.compute.internal   Ready    <none>   21m   v1.31.5-eks-5d632ec
ip-192-168-2-178.ap-northeast-2.compute.internal   Ready    <none>   21m   v1.31.5-eks-5d632ec
ip-192-168-3-168.ap-northeast-2.compute.internal   Ready    <none>   21m   v1.31.5-eks-5d632ec


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-115.ap-northeast-2.compute.internal   Ready    <none>   21m   v1.31.5-eks-5d632ec   t3.xlarge       ON_DEMAND      ap-northeast-2a
ip-192-168-2-178.ap-northeast-2.compute.internal   Ready    <none>   21m   v1.31.5-eks-5d632ec   t3.xlarge       ON_DEMAND      ap-northeast-2b
ip-192-168-3-168.ap-northeast-2.compute.internal   Ready    <none>   21m   v1.31.5-eks-5d632ec   t3.xlarge       ON_DEMAND      ap-northeast-2c


kubectl get pod -A
NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
kube-system   aws-node-4jsvr                        2/2     Running   0          21m
kube-system   aws-node-bkp8n                        2/2     Running   0          21m
kube-system   aws-node-v5rhv                        2/2     Running   0          21m
kube-system   coredns-86f5954566-4j74x              1/1     Running   0          27m
kube-system   coredns-86f5954566-mcw5d              1/1     Running   0          27m
kube-system   ebs-csi-controller-549bf6879f-26wqx   6/6     Running   0          17m
kube-system   ebs-csi-controller-549bf6879f-qgqtz   6/6     Running   0          17m
kube-system   ebs-csi-node-8zr72                    3/3     Running   0          17m
kube-system   ebs-csi-node-sc6tt                    3/3     Running   0          17m
kube-system   ebs-csi-node-v48kr                    3/3     Running   0          17m
kube-system   kube-proxy-6wkjg                      1/1     Running   0          21m
kube-system   kube-proxy-v8228                      1/1     Running   0          21m
kube-system   kube-proxy-xw8hc                      1/1     Running   0          21m
kube-system   metrics-server-6bf5998d9c-2gngg       1/1     Running   0          27m
kube-system   metrics-server-6bf5998d9c-wv68w       1/1     Running   0          27m

 

이후 실습에 사용될 일부 구성 요소를 배포하겠습니다.

 

[Note]
참고로 본 실습 전에 Route 53에서 도메인을 생성했습니다. 만약 도메인 없는 경우 Loadbalancer 등으로 서비스를 변경해야 해서 실습에 제한이 있을 수 있습니다.
- Route53을 통한 도메인 구매: https://www.youtube.com/watch?v=4HBFozkJUeU

또한 해당 도메인에 대해서 AWS Certificate Manager를 통해 인증서를 발급 받아야 합니다.
- 인증서 발급: https://www.youtube.com/watch?v=mMpPlaUj-vI

 

이어서 진행하겠습니다.

# 환경 변수
MyDomain=aperson.link # 각자 자신의 도메인 이름 입력
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "$MyDomain." --query "HostedZones[0].Id" --output text)
CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text) #사용 리전의 인증서 ARN 확인

# 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 service.main.type=ClusterIP  --set env.TZ="Asia/Seoul" --namespace kube-system

# gp3 스토리지 클래스 생성
cat <<EOF | kubectl apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gp3
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  allowAutoIOPSPerGBIncrease: 'true'
  encrypted: 'true'
  fsType: xfs # 기본값이 ext4
EOF
kubectl get sc

# ExternalDNS
curl -s https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml | MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst | kubectl apply -f -

# AWS LoadBalancerController
helm repo add eks https://aws.github.io/eks-charts
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

# kubeopsview 용 Ingress 설정 : group 설정으로 1대의 ALB를 여러개의 ingress 에서 공용 사용
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
    alb.ingress.kubernetes.io/group.name: study
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/load-balancer-name: $CLUSTER_NAME-ingress-alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/success-codes: 200-399
    alb.ingress.kubernetes.io/target-type: ip
  labels:
    app.kubernetes.io/name: kubeopsview
  name: kubeopsview
  namespace: kube-system
spec:
  ingressClassName: alb
  rules:
  - host: kubeopsview.$MyDomain
    http:
      paths:
      - backend:
          service:
            name: kube-ops-view
            port:
              number: 8080
        path: /
        pathType: Prefix
EOF

 

또한 더불어 실습에 필요한 모니터링 데이터를 누적하기 위해서 샘플 애플리케이션도 같이 배포하겠습니다.

# Bookinfo 애플리케이션 배포
kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml

# 확인
kubectl get all,sa

# product 웹 접속 확인
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

# 로그
kubectl log -l app=productpage -f


# Ingress 배포
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
    alb.ingress.kubernetes.io/group.name: study
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/load-balancer-name: $CLUSTER_NAME-ingress-alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/success-codes: 200-399
    alb.ingress.kubernetes.io/target-type: ip
  labels:
    app.kubernetes.io/name: bookinfo
  name: bookinfo
spec:
  ingressClassName: alb
  rules:
  - host: bookinfo.$MyDomain
    http:
      paths:
      - backend:
          service:
            name: productpage
            port:
              number: 9080
        path: /
        pathType: Prefix
EOF
kubectl get ingress

# bookinfo 접속 정보 확인 
echo -e "bookinfo URL = https://bookinfo.$MyDomain/productpage"
open "https://bookinfo.$MyDomain/productpage" # macOS

 

배포된 리소스를 확인해봅니다. external dns 를 통해 DNS가 등록되지만 전파에 시간이 걸릴 수 있습니다.

kubectl get ingress -n kube-system
NAME          CLASS   HOSTS                      ADDRESS                                                        PORTS   AGE
kubeopsview   alb     kubeopsview.aperson.link   myeks-ingress-alb-665851389.ap-northeast-2.elb.amazonaws.com   80      5m

kubectl get ingress
NAME       CLASS   HOSTS                   ADDRESS                                                        PORTS   AGE
bookinfo   alb     bookinfo.aperson.link   myeks-ingress-alb-665851389.ap-northeast-2.elb.amazonaws.com   80      7s

 

접속을 확인해봅니다.

 

샘플 애플리케이션도 정상적으로 실행 되었습니다.

 

 

로그 발생을 위해서 아래와 같이 반복 접속을 해볼 수 있습니다.

curl -s -k https://bookinfo.$MyDomain/productpage | grep -o "<title>.*</title>"
while true; do curl -s -k https://bookinfo.$MyDomain/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 1; done
for i in {1..100};  do curl -s -k https://bookinfo.$MyDomain/productpage | grep -o "<title>.*</title>" ; done

 

 

4. EKS의 모니터링과 로깅

먼저 EKS의 모니터링과 로깅에 대한 설명을 아래 두가지 문서에서 살펴볼 수 있습니다.

https://docs.aws.amazon.com/prescriptive-guidance/latest/implementing-logging-monitoring-cloudwatch/amazon-eks-logging-monitoring.html

 

EKS에서는 CloudWatch Logs를 통합하여 컨트롤 플레인 로그를 확인할 수 있습니다. 또한 CloudWatch agent를 EKS 노드에 배포하여 노드와 컨테이너 로그를 수집하는 방법도 제공합니다. 이때 Fluent Bit과 Fluentd가 컨테이너 로그를 수집하여 CloudWatch Logs로 전송하도록 지원합니다.

 

CloudWatch Container Insight는 EKS 클러스터, 노드, 파드, 서비스와 같은 수준의 모니터링을 제공하는 도구입니다. 또한 Prometheus를 통해 다양한 메트릭을 수집하는 방식도 제공합니다.

EKS의 모니터링 솔루션을 아래와 같은 그림으로 확인하실 수 있습니다.

출처: https://www.youtube.com/watch?v=349ywnrrROg

 

본 포스트에서는 CloudWatch Logs와 CloudWatch Container Insight 활용해 EKS 모니터링과 로깅을 확인해보겠습니다.

 

EKS 로깅

컨트롤 프레인 로깅

먼저 컨트롤 플레인 로깅을 먼저 살펴 보겠습니다.

컨트롤 플레인 로깅에서는 API Server, Audit, Authenticator, Controller manager, Scheduler와 같은 로그 유형을 제공하고 있습니다. 이에 대한 설명은 아래 문서를 참고 하실 수 있습니다.

https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html

 

컨트롤 플레인 로깅이 필요한 경우를 예를 들어보면, 특정 시점 생성된 오브젝트를 추적하기 위해 Audit 로그를 보거나, 클러스터가 비정상 동작하는 경우에 대한 API 서버 로그를 확인 하는 것, AWS 수준의 리소스와 연관된 경우 Controller manager 로그를 점검하는 것과 같은 상황이 있을 수 있습니다.

 

컨트롤 플레인 로깅은 웹 콘솔에서 Observability 탭으로 이동하여 아래로 이동하면 Control plane logs가 확인됩니다. eksctl 로 설치한 클러스터에는 기본적으로 모든 옵션이 off 인 것을 알 수 있습니다.

 

컨트롤 플레인 로깅을 활성화 하고 로그를 살펴보겠습니다.

# 모든 로깅 활성화
aws eks update-cluster-config --region ap-northeast-2 --name $CLUSTER_NAME \
    --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'

 

웹 콘솔에서 확인해보면 로그가 활성화되었습니다.

 

그리고 CloudWatch를 접근해보면 새로운 Log group이 생성된 것이 확인됩니다.

 

해당 로그 그룹으로 진입하면, 아래와 같이 각 로그에 해당하는 Log stream이 생성된 것을 확인할 수 있습니다.

 

로그 스트림 중 하나를 선택하면 실제 로그를 확인하실 수 있습니다.

 

또한 CloudWatch Log Insights를 통해서 쿼리를 통해 로그를 확인할 수 있습니다.

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

# kube-apiserver-audit 로그에서 userAgent 정렬해서 결과 확인
fields userAgent, requestURI, @timestamp, @message
| filter @logStream ~= "kube-apiserver-audit"
| stats count(userAgent) as count by userAgent
| sort count desc

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

# authenticator 로그 확인
fields @timestamp, @message
| filter @logStream ~= "authenticator"
| sort @timestamp desc

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

 

이 중 kube-audit 로그를 통해 접근한 userAgent의 갯수를 확인한 예시 입니다.

 

또한 aws logs 명령으로 로그를 확인할 수도 있습니다.

# 로그 그룹 확인
aws logs describe-log-groups | jq

# 로그 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-apiserver --follow
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix kube-apiserver-audit --follow
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix kube-scheduler --follow
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix authenticator --follow
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix kube-controller-manager --follow
aws logs tail /aws/eks/$CLUSTER_NAME/cluster --log-stream-name-prefix cloud-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 Logs에서 aws logs tail 과 같은 방식으로 손 쉽게 로그를 확인할 수 있는 방식을 제공하는 점이 큰 장점으로 보였습니다.

 

실습을 종료하고, 컨트롤 플레인 로그를 비활성화 화도록 하겠습니다.

# EKS Control Plane 로깅(CloudWatch Logs) 비활성화
eksctl utils update-cluster-logging --cluster $CLUSTER_NAME --region ap-northeast-2 --disable-types all --approve

# 로그 그룹 삭제
aws logs delete-log-group --log-group-name /aws/eks/$CLUSTER_NAME/cluster

 

 

노드와 애플리케이션 로깅

EKS의 노드와 컨테이너 모니터링을 위해서 CloudWatch agent와 Fluent Bit을 사용합니다. 두 파드는 데몬 셋으로 구성되어 아래와 같은 형태로 구성됩니다.

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

 

이들은 CloudWatch Observability라는 Addon으로 제공되므로, 아래와 같이 설치를 진행합니다.

# IRSA 설정
eksctl create iamserviceaccount \
  --name cloudwatch-agent \
  --namespace amazon-cloudwatch --cluster $CLUSTER_NAME \
  --role-name $CLUSTER_NAME-cloudwatch-agent-role \
  --attach-policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy \
  --role-only \
  --approve

# addon 배포 (사전에 환경 변수가 정의된 EC2 인스턴스에서 실행)
aws eks create-addon --addon-name amazon-cloudwatch-observability --cluster-name $CLUSTER_NAME --service-account-role-arn arn:aws:iam::$ACCOUNT_ID:role/$CLUSTER_NAME-cloudwatch-agent-role

# addon 확인
aws eks list-addons --cluster-name myeks --output table
---------------------------------------
|             ListAddons              |
+-------------------------------------+
||              addons               ||
|+-----------------------------------+|
||  amazon-cloudwatch-observability  ||
||  aws-ebs-csi-driver               ||
||  coredns                          ||
||  kube-proxy                       ||
||  metrics-server                   ||
||  vpc-cni                          ||
|+-----------------------------------+|

# 설치 확인
kubectl get crd | grep -i cloudwatch

amazoncloudwatchagents.cloudwatch.aws.amazon.com   2025-02-28T16:27:24Z
dcgmexporters.cloudwatch.aws.amazon.com            2025-02-28T16:27:24Z
instrumentations.cloudwatch.aws.amazon.com         2025-02-28T16:27:25Z
neuronmonitors.cloudwatch.aws.amazon.com           2025-02-28T16:27:25Z

kubectl get all -n amazon-cloudwatch

NAME                                                                  READY   STATUS    RESTARTS   AGE
pod/amazon-cloudwatch-observability-controller-manager-6f76854w9rvx   1/1     Running   0          69s
pod/cloudwatch-agent-dcfqq                                            1/1     Running   0          64s
pod/cloudwatch-agent-jcvk5                                            1/1     Running   0          65s
pod/cloudwatch-agent-r8tcw                                            1/1     Running   0          64s
pod/fluent-bit-6zbmk                                                  1/1     Running   0          69s
pod/fluent-bit-j9hl8                                                  1/1     Running   0          69s
pod/fluent-bit-zrw4v                                                  1/1     Running   0          69s

..


# cloudwatch-agent 설정 확인
kubectl describe cm cloudwatch-agent -n amazon-cloudwatch
kubectl get cm cloudwatch-agent -n amazon-cloudwatch -o jsonpath="{.data.cwagentconfig\.json}" | jq
{
  "agent": {
    "region": "ap-northeast-2"
  },
  "logs": {
    "metrics_collected": {
      "application_signals": {
        "hosted_in": "myeks"
      },
      "kubernetes": {
        "cluster_name": "myeks",
        "enhanced_container_insights": true
      }
    }
  },
  "traces": {
    "traces_collected": {
      "application_signals": {}
    }
  }
}

#Fluent bit 파드 수집하는 방법 : Volumes에 HostPath를 통해서 Node Log, Container Log에 접근함
kubectl describe -n amazon-cloudwatch ds cloudwatch-agent
...
  Volumes:
   ...
   rootfs:
    Type:          HostPath (bare host directory volume)
    Path:          /
    HostPathType:  


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

 

Addon을 통해 생성되는 로그 그룹과 대응하는 로그는 아래와 같습니다.

출처: https://docs.aws.amazon.com/prescriptive-guidance/latest/implementing-logging-monitoring-cloudwatch/kubernetes-eks-logging.html#eks-node-application-logging

 

CloudWatch Logs에 보면 아래와 같은 로그 그룹이 생성된 것을 알 수 있습니다.

 

다만 의아한 부분은 분명 configmap에 log_group_name에 /host가 있는데 이것은 생성되지 않았고, /performance라는 로그 그룹이 추가 되어 있습니다.

kubectl describe cm fluent-bit-config -n amazon-cloudwatch |grep log_group_name
  log_group_name      /aws/containerinsights/${CLUSTER_NAME}/application
  log_group_name      /aws/containerinsights/${CLUSTER_NAME}/dataplane
  log_group_name      /aws/containerinsights/${CLUSTER_NAME}/host

 

fluent-bit 에서도 log group 생성이 실패한 것으로 보입니다.

kubectl logs -f -n amazon-cloudwatch fluent-bit-zrw4v
AWS for Fluent Bit Container Image Version 2.32.5
Fluent Bit v1.9.10
* Copyright (C) 2015-2022 The Fluent Bit Authors
* Fluent Bit is a CNCF sub-project under the umbrella of Fluentd
* https://fluentbit.io

[2025/02/28 16:27:34] [error] [filter:kubernetes:kubernetes.1] [kubernetes] no upstream connections available to cloudwatch-agent.amazon-cloudwatch:4311
[2025/02/28 16:27:39] [error] [output:cloudwatch_logs:cloudwatch_logs.0] CreateLogGroup API responded with error='OperationAbortedException', message='A conflicting operation is currently in progress against this resource. Please try again.'
[2025/02/28 16:27:39] [error] [output:cloudwatch_logs:cloudwatch_logs.0] Failed to create log group
[2025/02/28 16:27:39] [error] [output:cloudwatch_logs:cloudwatch_logs.0] Failed to send events

 

버그인거 같지만 Addon에서 관리되는 영역이라 확인이 어려운 것 같습니다.

https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html

  • OperationAbortedException
  • Multiple concurrent requests to update the same resource were in conflict.HTTP Status Code: 400

 

/performance 로그 그룹은 container Insight를 위한 성능 데이터를 CloudWatch Agent가 쌓고 있는 것으로 보입니다.

kubectl logs -f -n amazon-cloudwatch   cloudwatch-agent-dcfqq |grep log_group_name
        log_group_name: /aws/application-signals/data
        log_group_name: /aws/containerinsights/{ClusterName}/performance

 

 

EKS 메트릭 기반 모니터링

앞서 설치한 CloudWatch Observability 애드온에 으해서 Container Insight에 해당하는 메트릭도 수집됩니다.

웹 콘솔에서 내용을 살펴 보겠습니다.

CloudWatch → Insights → Container Insights 으로 접근할 수 있습니다.

 

우측 상단의 View performance dashboard를 눌러면 여러가지 뷰로 다양한 메트릭과 그래프를 확인 가능합니다.

 

생성된 특정 리소스(네임스페이스와 Workload로 선택)를 선택한 경우 해당 각종 메트릭을 확인할 수 있습니다.

 

전반적으로 Container Insight를 통해 확인하는 정보들이 체계적으로 분류되어 있고, 각 항목에서 시각화가 잘되어 있는 점이 인상 깊습니다. 그리고 각 View에 대한 response time도 빨랐습니다.

 

실습을 마무리하고 애드온과 생성된 로그 그룹을 삭제하도록 하겠습니다.

aws eks delete-addon --cluster-name $CLUSTER_NAME --addon-name amazon-cloudwatch-observability

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

 

 

EKS 리소스 이벤트 확인

EKS는 AWS CloudTrail과 통합되어 있습니다. CloudTrail는 리소스에 일어난 활동을 기록하는 서비스입니다. CloudTrail은 EKS에 일어난 모든 API 요청을 이벤트로 기록하고 있습니다. 여기에는 웹 콘솔이나 코드를 통한 Amazon EKS API operation을 모두 포함하고 있습니다.

 

Trails를 생성했다면 이러한 로그를 Amazon S3 bucket을 통해 장기 보관할 수 있으며, 특별한 설정을 하지 않아도 CloudTrail의 Event histry를 통해서 리소스에 발생한 활동을 확인할 수 있습니다.

 

보통 이런 이벤트를 확인하는 경우는 특정 리소스의 변경이나 이벤트가 EKS에 의한 것인지 아니면 사용자에 의한 것인지 확인이 필요한 경우 등이 있습니다.

 

아래와 같이 확인이 가능합니다.

 

 

해당 항목을 누르면 UserIdentity, sourceIPAddress, userAgent와 같은 상세한 내용을 확인할 수 있습니다.

AWS CloudTrail은 리소스의 변경 사항 뿐 아니라, Read를 발생시킨 요청에 대해서도 기록하고 있는 점이 인상 깊습니다.

 

EKS의 CloudTail에 대해서 아래 문서를 확인하실 수 있습니다.

https://docs.aws.amazon.com/eks/latest/userguide/logging-using-cloudtrail.html

 

여기서 EKS의 모니터링과 로깅을 마무리 하겠습니다. EKS에서도 다양한 메트릭을 제공과 시각화를 위해서 Amazon Managed Prometheus 와 Amazon Managed Grafana 서비스를 제공하고 있습니다.

 

 

5. AKS의 모니터링과 로깅

Azure의 모니터링과 로깅 솔루션으로 Azure Monitor와 Log Analytics Workspace가 있습니다.

각 AWS의 CloudWatch와 CloudWatch Logs와 대응합니다. Azure Monitor에서는 사전에 제공하는 뷰나 신규 블레이드를 생성하여 데이터를 확인할 수 있으며, Log Analytics Workspace는 테이블 형태로 데이터를 수집하므로 KQL(Kusto Query Language)를 통해서 쿼리를 수행할 수 있습니다.

 

또한 AKS 환경에 전문화된 메트릭/로깅을 제공하기 위해 Container Insight를 제공하고 있습니다.

전반적인 AKS 모니터링 옵션을 아래 문서에서 설명하고 있습니다.

 

https://learn.microsoft.com/en-us/azure/aks/monitor-aks?tabs=cilium

 

이 중 EKS에서 살펴본 순서대로 로깅과 메트릭 부분을 살펴보겠습니다.

 

AKS 로깅

먼저 컨트롤 플레인 로그는 위 테이블의 Resource logs 에서 설명하고 있습니다. Azure에서는 각 상품별로 진단 설정(Diagnostics setting)을 할 수 있는데, AKS에서는 진단 설정을 통해서 컨트롤 플레인 로그를 선택적으로 수집할 수 있습니다.

 

진단 설정에서 제공되는 항목은 아래와 같습니다. EKS와 다르게 CA나 CSI controller에 해당하는 파드들이 컨트롤 플레인에 구성되므로 해당 컴포넌트에 대한 로그도 진단 설정에서 선택할 수 있습니다.

 

다음으로 노드와 애플리케이션 모니터링을 위해서 Container Insight를 설정할 수 있습니다. Container Insight의 로그는 Log Analytics Workspace에 저장되어, 비용 측면에 아래와 같이 사전에 정의된 세트를 지정할 수 있습니다.

 

이후 수집 설정을 수정을 눌러보면 어떤 로그/메트릭 유형이 수집되는지 확인할 수 있습니다.

 

수집을 원하는 항목을 선택할 수 있으며, 성능관련 지표나, 컨테이너 로그, 그리고 각 오브젝트의 상태나 쿠버네티스 Event와 같은 정보를 수집할 수 있는 것을 알 수 있습니다.

이러한 항목은 Log Analytics Workspace에 개별 테이블로 저장되며, 클러스터의 Monitoring>Logs를 통해서 접근하거나 혹은 Log Analytics Workspace로 직접 접근해 쿼리를 사용할 수 있습니다.

 

아래 샘플 쿼리를 참고 부탁드립니다.

https://docs.azure.cn/en-us/azure-monitor/reference/queries/containerlog

 

Container Insight의 모니터링에도 Performance, Metrics를 볼 수 있지만 최근에는 Prometheus Metric으로 전환되는 방향성을 가진 것 같기도 합니다.

 

 

AKS 메트릭 기반 모니터링

다음으로 메트릭을 살펴보겠습니다.

 

Azure는 플랫폼 메트릭으로 리소스 별로 기본 제공되는 메트릭을 무료로 제공합니다. 보통 고급 모니터링 기능을 활성화 하지 않은 상태에서도 AKS>Monitoring>Metrics에서 일부 값들을 확인하실 수 있습니다.

 

예를 들어, 노드 상태, 파드 상태나 노드 리소스 메트릭 등이 선택가능하며, AKS도 최근 컨트롤 플레인 메트릭을 Preview로 제공하고 있습니다.

 

플랫폼 메트릭에 대한 전체 메트릭 설명은 아래를 참고하실 수 있습니다.

https://learn.microsoft.com/en-us/azure/aks/monitor-aks-reference#metrics

 

최근 Container Insight에서 Prometheus 메트릭과 로깅을 활성화 한 경우 AKS Monitor Experience이 크게 개선되었으며 현재 Preview 상태입니다.

https://techcommunity.microsoft.com/blog/azureobservabilityblog/public-preview-the-new-aks-monitoring-experience/4297181

 

AKS 리소스 이벤트 확인

마지막으로 Activity Log에서 해당 리로스에 대한 이벤트를 확인할 수 있습니다.

 

EKS와 마찬가지로 AKS에서도 Managed Prometheus와 Managed Grafana를 통해서 모니터링을 통합할 수 있는 기능이 제공됩니다.

 

참고로 기본 AKS>Monitoring>Insight로 접근하던 Container Insight가 AKS의 Monitor로 변경이 되었습니다. 아래 화면은 Monitor Settings으로, Container Logs 설정 외에도 Managed PrometheusManaged Grafana를 선택 할 수 있습니다.

 

다만 EKS와 비교해 보면 CloudWatch Container Insight가 조금 더 완성도 있는 구성과 시각화를 보여주는 것 같습니다.

 

 

6. 리소스 정리

실습에 사용된 환경을 아래와 같이 정리하도록 하겠습니다.

nohup sh -c "eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME" > /root/delete.log 2>&1 &

 

CloudWatch Logs가 비용이 많이 드는 것으로 알려져 있어 모든 로그 그룹이 삭제되었는지 꼭 확인하시기 바랍니다.

# 로그 그룹 삭제 : 컨트롤 플레인
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

 

마지막으로 EC2에서 혹시나 남아 있는 볼륨(Prometheus용 PV 등)들이 있다면 확인 후 모두 삭제해야 하시기 바랍니다.

 

 

마무리

해당 포스트를 통해서 Kubernetes 환경의 모니터링에 대해서 살펴보고, 이러한 모니터링을 EKS에서 어떻게 활성화 하고 지표를 살펴볼 수 있는지 확인했습니다. 또한 AKS의 모니터링 제공 수준과 살펴보고 서로 비교해봤습니다.

 

이 과정은 대체적으로 CSP에서 제공하는 옵션을 위주로 설명을 하였습니다. 반면 일부 사용자는 Prometheus나 Grafana와 같은 오픈소스로 직접 모니터링을 구성하기도 합니다. 그리고 모니터링을 전문으로 하는 SaaS 서비스를 사용할 수도 있습니다. CSP의 모니터링 솔루션을 사용할 것인지 혹은 오픈소스나 다른 형태의 모니터링을 사용할지는 사용자에게 달려있습니다.

 

살펴보기로는 CSP에서는 옵저버빌리티 수준으로 모니터링을 고도화 해가는 방향성을 가지고 있는 것을 확인할 수 있습니다. 다만 CSP 모니터링 솔루션이 비용 효율적인지에 대한 의문과, 또한 블레이드나 혹은 알림과 같은 기능에 커스터마이즈에 한계가 있기도 합니다. 그리고 멀티 클라우드 환경이라면 각 사별로 서로 다른 모니터링 스택을 관리해야하는 문제도 있습니다.

 

그러한 측면에서 오픈소스 모니터링 솔루션을 사용할 수 있습니다. 다만 각 클러스터별로 Prometheus Stack을 위한 컴포넌트가 배포되는 중복성이나 비용이 발생하는 측면과, 또한 모니터링 솔루션을 자체를 관리해야 하는 부가적인 업무도 부담이 되기는 합니다. 다만 시각화나 모니터링 항목의 커스터마이즈가 가능한 점, 다양한 환경에 동일한 모니터링 스택을 배포하며 통일된 환경을 구성할 수 있는 장점이 있습니다.

 

모니터링을 전문으로 하는 SaaS 서비스를 사용하는 옵션도 있습니다. 대체적으로 이러한 솔루션은 우수하지만 데이터를 전송하는 비용 및 보안적인 우려가 있을 수도 있고, 솔루션 자체의 비용도 부담이 될 수 있습니다.

 

어떤 모니터링을 솔루션을 사용하는 것에는 장/단점이 있기 때문에 이는 사용자의 선택이나 기술적 판단이 필요할 수 있습니다.

 

해당 포스트는 여기서 마무리 하도록 하겠습니다.

'EKS' 카테고리의 다른 글

[5-2] EKS의 오토스케일링 Part2  (0) 2025.03.07
[5-1] EKS의 오토스케일링 Part1  (0) 2025.03.07
[3-2] EKS 노드 그룹  (0) 2025.02.23
[3-1] EKS 스토리지 옵션  (0) 2025.02.23
[2-2] EKS Networking Part2 - LoadBalancer와 Ingress  (0) 2025.02.16

+ Recent posts