본문 바로가기

DevOps

[AWS EKS] (11) EKS 스터디 4주차 ( pod 로깅 )

CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.

 

pod 로깅 

 

pod로깅은 data plane 노드 로그와 노드에서 실행 중인 pod로그를 말합니다. pod로깅은 EKS설정을 지원하지 않습니다. 

사용자가 도구를 선택해서 pod로그 수집과 저장 해야 합니다.

 

본 포스팅에서는 Fluentbit또는 FlunetD 사용하여 pod 수집하고 cloudwatch 전송하는 예제를 다룸

 

1. 로그수집은 누가? 

who collects logs? Fluentd 

2. 로그 전송은 누가?

who transfer logs? Fluentd

3. 로그 저장과 검색은 누가? 

who stores and search logs? ElasticSearch Kibana

 

 

 

CW Agent & Fluent Bit

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

CloudWatch Agent vs. Fluent Bit (로그 전송)

CloudWatch Agent VS Fluent Bit

사용 목적 CloudWatch Logs 및 Metrics 전송 Lightweight 로그 수집 및 전송
지원 로그 시스템 로그, 애플리케이션 로그, Prometheus 메트릭 컨테이너 로그 (stdout, stderr), 애플리케이션 로그
통합 대상 CloudWatch Logs, CloudWatch Metrics, Prometheus Elasticsearch, CloudWatch, S3, Kafka 등

즉, CloudWatch Agent는

  • CloudWatch Logs와 CloudWatch Metrics로 로그 및 메트릭을 전송하는 역할
  • Prometheus 메트릭을 수집하여 CloudWatch에서 모니터링할 수 있도록 지원
  • Fluent Bit과 함께 사용하여 로그를 더 효과적으로 CloudWatch로 보낼 수도 있음

→ Fluent Bit을 사용하는 환경에서도, CloudWatch Logs로 보내려면 CloudWatch Agent를 함께 구성하는 경우가 많음!

  • [수집] 플루언트비트 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 의 대시보드로 시각화한다
목표:

Fluent Bit is a lightweight log processor and forwarder that allows you to collect data and logs from different sources, enrich them with filters and send them to multiple destinations like CloudWatch, Kinesis Data Firehose, Kinesis Data Streams and Amazon OpenSearch Service.

CloudWatch Container Insight ( CCI )는 컨테이너형 애플리케이션마이크로 서비스에 대한 모니터링, 트러블 슈팅 및 알람을 위한 완전 관리형 관측 서비스입니다.

  • 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 클러스터에서 사용 가능합니다.

1. 로그 종류 확인

 

/var/log/pods/

  • 어플리케이션 로그 
  • 로그 소스(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
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

 

/var/log/dmesg 

/var/log/secure

/var/log/mesages

  • 호스트 로그
  • 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

 

/var/log/journal

  • 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

 

2. CloudWatch Container observability 설치

  • Fluentbit 설정 시 호스트 패스 공유를 하는데 보안상 안전한가?
 
host에서 사용하는 docker.sock가 Pod에 mount 되어있는 상태에서 악의적인 사용자가 해당 Pod에 docker만 설치할 수 있다면, mount된 dock.sock을 이용하여 host의 docker에 명령을 보낼 수 있게 된다(docker가 client-server 구조이기 때문에 가능).이는 container escape라고도 할 수 있다.
# 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 배포
aws eks create-addon --addon-name amazon-cloudwatch-observability --cluster-name $CLUSTER_NAME --service-account-role-arn arn:aws:iam::015609516422:role/$CLUSTER_NAME-cloudwatch-agent-role

# addon 확인
aws eks list-addons --cluster-name myeks --output table


# 설치 확인
kubectl get crd | grep -i cloudwatch
kubectl get-all -n amazon-cloudwatch
kubectl get ds,pod,cm,sa,amazoncloudwatchagent -n amazon-cloudwatch
kubectl describe clusterrole cloudwatch-agent-role amazon-cloudwatch-observability-manager-role    # 클러스터롤 확인
kubectl describe clusterrolebindings cloudwatch-agent-role-binding amazon-cloudwatch-observability-manager-rolebinding  # 클러스터롤 바인딩 확인
kubectl -n amazon-cloudwatch logs -l app.kubernetes.io/component=amazon-cloudwatch-agent -f # 파드 로그 확인
kubectl -n amazon-cloudwatch logs -l k8s-app=fluent-bit -f    # 파드 로그 확인

# 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를 살펴보자! >> / 호스트 패스 공유??? 보안상 안전한가? 좀 더 범위를 좁힐수는 없을까요? 
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
...

# Fluent Bit 파드가 수집하는 방법 : Volumes에 HostPath를 살펴보자!
kubectl describe -n amazon-cloudwatch ds fluent-bit
...
ssh ec2-user@$N1 sudo tree /var/log
ssh ec2-user@$N2 sudo tree /var/log
ssh ec2-user@$N3 sudo tree /var/log
  • 사전확인 한대로 로그 그룹에는 application, dataplane, host의 로그등을 Cloudwatch로 전송하고 있음을 알수 있습니다.

  • 메트릭 확인은 Container insight에서 확인할수 있습니다.

 

  • nginx pod 헬름 설치
# 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

# 도메인 확인
echo $MyDomain

# 파라미터 파일 생성 : 인증서 ARN 지정하지 않아도 가능! 혹시 https 리스너 설정 안 될 경우 인증서 설정 추가(주석 제거)해서 배포 할 것
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

# 확인
kubectl get ingress,deploy,svc,ep nginx
kubectl get targetgroupbindings # ALB TG 확인

# 접속 주소 확인 및 접속
echo -e "Nginx WebServer URL = https://nginx.$MyDomain"
curl -s https://nginx.$MyDomain
kubectl logs deploy/nginx -f

## 외부에서는 접속이 잘되나, myeks EC2에서 url 접속이 잘 되지 않을 경우 : 이전 aws DNS cache 영향(추정)
dig +short nginx.$MyDomain
dig +short nginx.$MyDomain @192.168.0.2
dig +short nginx.$MyDomain @1.1.1.1
dig +short nginx.$MyDomain @8.8.8.8
cat /etc/resolv.conf
sed -i "s/^nameserver 192.168.0.2/nameserver 1.1.1.1/g" /etc/resolv.conf
cat /etc/resolv.conf
dig +short nginx.$MyDomain
dig +short nginx.$MyDomain @8.8.8.8
dig +short nginx.$MyDomain @192.168.0.2
curl -s https://nginx.$MyDomain
----

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

# (참고) 삭제 시
helm uninstall nginx
  • 컨테이너 로그 환경의 로그는 표준 출력 stdout과 표준 에러 stderr로 보내는 것을 권고 
    • 왜 ? 컨테이너 환경에서 로그를 표준 출력(stdout)과 표준 에러(stderr)로 보내는 것이 권장되는 이유는 다음과 같습니다.

1. 로깅 드라이버와의 통합이 용이

  • Docker 및 Kubernetes와 같은 컨테이너 오케스트레이션 시스템에서는 기본적으로 표준 출력(stdout)과 표준 에러(stderr)를 통해 로그를 수집합니다.
  • Docker의 docker logs 또는 Kubernetes의 kubectl logs 명령어를 사용하면 별도의 설정 없이 로그를 쉽게 확인할 수 있습니다.
  • 다양한 로깅 드라이버(GCP Stackdriver, AWS CloudWatch, Elasticsearch 등)와 연계하여 중앙 집중식 로그 관리가 가능해집니다.

2. 로그 수집 및 관리의 일관성 유지

  • 컨테이너 내부에서 직접 파일로 로그를 남길 경우, 컨테이너가 재시작되면 로그가 손실될 수 있습니다.
  • 반면, stdout과 stderr로 로그를 출력하면, 컨테이너의 수명과 관계없이 로그 수집기가 이를 처리할 수 있어 데이터 보존이 용이합니다.
  • Kubernetes에서는 fluentd, logstash와 같은 로그 수집 에이전트가 표준 출력 기반으로 동작하며, 이를 통해 클러스터 전반의 로그를 중앙화할 수 있습니다.

3. 컨테이너 불변성(Immutable Infrastructure) 유지

  • 컨테이너 환경에서는 컨테이너 이미지를 변경하지 않고 배포 및 롤백하는 것이 일반적입니다.
  • 로그를 파일로 저장하면 컨테이너 내부에서 상태를 유지하게 되어 불변성이 깨질 수 있습니다.
  • 표준 출력으로 로그를 보내면 애플리케이션의 로그 관리 방식이 컨테이너의 수명과 무관하게 유지될 수 있습니다.

4. 리소스 효율성과 스토리지 관리

  • 컨테이너 내부에 로그 파일을 저장하면 디스크 공간을 차지하며, 장기 실행되는 컨테이너의 경우 디스크가 가득 차는 문제가 발생할 수 있습니다.
  • 로그를 stdout/stderr로 출력하면 로그 수집 시스템이 이를 자동으로 외부 저장소로 보내므로 컨테이너 내부의 디스크 공간이 불필요하게 사용되지 않습니다.

5. Kubernetes와의 최적화된 연동

  • Kubernetes의 로그 수집 방식은 kubectl logs 명령어를 통해 stdout/stderr를 기반으로 작동합니다.
  • sidecar 패턴을 사용하여 추가적인 로그 수집기를 배포할 수도 있으며, fluentd, logstash 등과의 연계를 통해 로그를 중앙화하고 분석할 수 있습니다.
  • Kubernetes에서는 컨테이너가 재시작되더라도 로그를 보존하기 위해 log rotation 및 persistent storage를 활용하는 것이 일반적입니다.

6. 다양한 로깅 백엔드와의 손쉬운 연계

  • stdout과 stderr를 활용하면 Docker logging driver, ELK stack (Elasticsearch, Logstash, Kibana), Promtail + Loki, AWS CloudWatch, Google Stackdriver 등 다양한 로그 관리 솔루션과 쉽게 연계할 수 있습니다.
  • 만약 로그를 파일로 저장하는 경우, 추가적인 에이전트가 필요하며 설정이 복잡해질 수 있습니다.

7. 가독성과 디버깅의 편리함

  • docker logs <container_id> 또는 kubectl logs <pod_name> 명령어만으로 컨테이너의 실시간 로그를 확인할 수 있어 디버깅이 편리합니다.
  • 로그 파일을 따로 찾아보지 않아도 되므로 운영 및 트러블슈팅 과정에서 시간을 절약할 수 있습니다.

결론

컨테이너 환경에서는 로그를 표준 출력(stdout)과 표준 에러(stderr)로 출력하는 것이 가장 효율적인 방식입니다. 이를 통해 로깅 시스템과 쉽게 연계할 수 있으며, 컨테이너의 불변성을 유지하고, 디스크 공간을 절약하며, 디버깅을 용이하게 할 수 있습니다.

실제 운영 환경에서는 이러한 원칙을 기반으로 로깅 드라이버를 설정하고, 중앙 집중식 로그 수집 시스템과 연계하여 로그를 효과적으로 관리하는 것이 중요합니다.

# 로그 모니터링
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