brunch

You can make anything
by writing

C.S.Lewis

by Master Seo May 17. 2023

EKS 8탄-7. EKS 옵저버빌리트1-컨트롤-7/17

EKS 8탄 - 4주차

본 내용은 CloudNet 주말 스터디 내용을 참고로 작성되었습니다.

https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863  

계속 테스트하며  내용과 설명이 업데이트 됩니다.


목표

컨트롤 플래인 로깅 설정과 이해

컨테이너(파드)로깅  설정과 이해

컨테이너 로그 확인법

Container Insights metrics in Amazon CloudWatch  이해

Fluent Bit (Logs) 이해 




옵저버빌리티(Observability) =  관찰 가능성

로그,메트릭,트레이스 3가지 관찰


이론 1시간

실습 1시간

이론부터 1시간 설명후 바로 실습 진행합니다.





<1> 원클릭 배포

<2> 기본 설정과 확인

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

<4> 쿠버네티스 API를 통해서 리소스 및 정보를 확인

<5> 컨트롤 플래인 로깅

<6> 컨트롤 플래인 메트릭 확인

<7> 컨테이너(파드)로깅

<8> 컨테이너 로그가 조회 가능한 이유 ?

<9> Container Insights metrics in Amazon CloudWatch  과  Fluent Bit (Logs)

<10> CloudWatch Container Insight

<11>  nginx 웹서버 로그 확인

<12> 개인 정리




<1> 원클릭 배포


1

콘솔 로그인

https://console.aws.amazon.com/




2

제 PC는 windows라  콘솔에서 Cloudformation 으로 배포합니다.



3

myeks

mykops


준비 ?

Ec2 키페어

access-key / secret-key

node는 t3.xlarge(기본값) 사용  = 프로메테우스 , 그라파나에서 필요 사양. 

xlarge 서버로 비용  나옵니다.

테스트 후 빠르게 삭제하세요~



4

Amazon EKS 윈클릭 배포 내용  ?

NATGW

IRSA  load-balancer-controller 

IRSA  efs-csi-controller-sa 

EFS-FileSystem 

EBS-csi-driver 


수동설치는 ?

load-balancer-controller 수동설치

EFS csi driver 수동설치


// 이번 실습에 EFS는 사용하지 않음



(15분 걸림)



시작시간 확인!!

https://vclock.kr/timer/#countdown=00:10:00&enabled=0&seconds=0&sound=xylophone&loop=1




AWSTemplateFormatVersion: '2010-09-09'


:


# NAT Gateway

  MYVPCEIP:

    Type: AWS::EC2::EIP

    Properties:

      Domain: vpc

  MYVPCNATGW:

    Type: AWS::EC2::NatGateway

    Properties:

      AllocationId: !GetAtt MYVPCEIP.AllocationId

      SubnetId: !Ref PublicSubnet1

      Tags:

        - Key: Name

          Value: !Sub ${ClusterBaseName}--NATGW


:

      UserData:

        Fn::Base64:

          !Sub |

            #!/bin/bash

            hostnamectl --static set-hostname "${ClusterBaseName}-bastion-EC2"



            # Setting EFS Filesystem

            mkdir -p /mnt/myefs

            echo "export EfsFsId=${ElasticFileSystem}" >> /etc/profile


:


            # CLUSTER_NAME

            export CLUSTER_NAME=${ClusterBaseName}

            echo "export CLUSTER_NAME=$CLUSTER_NAME" >> /etc/profile


            # K8S Version

            export KUBERNETES_VERSION=${KubernetesVersion}

            echo "export KUBERNETES_VERSION=$KUBERNETES_VERSION" >> /etc/profile


            

            # Create EKS Cluster & Nodegroup 

            eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=ng1 --node-type=${WorkerNodeInstanceType} --nodes ${WorkerNodeCount} --node-volume-size=${WorkerNodeVolumesize} --vpc-public-subnets "$PubSubnet1","$PubSubnet2","$PubSubnet3" --version ${KubernetesVersion} --max-pods-per-node 50 --ssh-access --ssh-public-key /root/.ssh/id_rsa.pub --with-oidc --external-dns-access --full-ecr-access --dry-run > myeks.yaml

            sed -i 's/certManager: false/certManager: true/g' myeks.yaml

            sed -i 's/ebs: false/ebs: true/g' myeks.yaml

            sed -i 's/cloudWatch: false/cloudWatch: true/g' myeks.yaml

            sed -i 's/xRay: false/xRay: true/g' myeks.yaml

            cat <<EOT >> myeks.yaml

            addons:

            - name: vpc-cni # no version is specified so it deploys the default version

              version: latest # auto discovers the latest available

              attachPolicyARNs:

                - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy

            - name: kube-proxy

              version: latest

            - name: coredns

              version: latest

            - name: aws-ebs-csi-driver

              wellKnownPolicies:      # add IAM and service account

                ebsCSIController: true

            EOT

            cat <<EOT > irsa.yaml

              serviceAccounts:

              - metadata:

                  name: aws-load-balancer-controller

                  namespace: kube-system

                wellKnownPolicies:

                  awsLoadBalancerController: true

              - metadata:

                  name: efs-csi-controller-sa

                  namespace: kube-system

                wellKnownPolicies:

                  efsCSIController: true

            EOT

            sed -i -n -e '/withOIDC/r irsa.yaml' -e '1,$p' myeks.yaml

            cat <<EOT > precmd.yaml

              preBootstrapCommands:

                - "yum install links tree jq tcpdump sysstat -y"

            EOT

            sed -i -n -e '/instanceType/r precmd.yaml' -e '1,$p' myeks.yaml

            nohup eksctl create cluster -f myeks.yaml --verbose 4 --kubeconfig "/root/.kube/config" 1> /root/create-eks.log 2>&1 &


            echo 'cloudinit End!'


Outputs:

  eksctlhost:

    Value: !GetAtt EKSEC2.PublicIp



5

(선택)

cli로 EKS 원클릭 배포


# 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=kp-gasida 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



6

브라우저 -> 새탭에서 보기


# EC2 인스턴스 모니터링

while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --output text | sort; echo "------------------------------" ;date; sleep 2; done



(노드 서버 생성 2분후 노드로  kubectl 명령어로 조회가 가능하다.)

while true ; do kubectl get nodes ;echo "-----------";date; sleep 2 ;done



# 작업용 EC2 SSH 접속

ssh -i ~/.ssh/kp-gasida.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)



7

노드 확인

k get nodes

NAME                                               STATUS   ROLES    AGE    VERSION

ip-192-168-1-150.ap-northeast-2.compute.internal   Ready    <none>   2m  v1.24.11-eks-ass

ip-192-168-2-166.ap-northeast-2.compute.internal   Ready    <none>   2m  v1.24.11-eks-ada

ip-192-168-3-112.ap-northeast-2.compute.internal   Ready    <none>   11   v1.24.11-eks-asd






<2> 기본 설정과 확인


 

1

EKS콘솔에서 다양한 정보를 볼수 있다.

EKS > 클러스터 



2

CLI 사용


# default 네임스페이스 적용

kubectl ns default



3

# (옵션) context 이름 변경

NICK=<각자 자신의 닉네임>


NICK=masterseo1.link

kubectl ctx

kubectl config rename-context  access-05-03@myeks.ap-northeast-2.eksctl.io $NICK@myeks

// access-05-03 이름은 access-key 이름이다.



4

# EFS 확인 : AWS 관리콘솔 EFS 확인해보자

mount -t efs -o tls $EfsFsId:/ /mnt/myefs


df -hT --type nfs4


(masterseo1:default) [root@myeks-bastion-EC2 ~]# 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


(masterseo1:default) [root@myeks-bastion-EC2 ~]# df -h

Filesystem      Size  Used Avail Use% Mounted on

devtmpfs        1.9G     0  1.9G   0% /dev

tmpfs           1.9G     0  1.9G   0% /dev/shm

tmpfs           1.9G  484K  1.9G   1% /run

tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup

/dev/nvme0n1p1   30G  2.7G   28G   9% /

tmpfs           388M     0  388M   0% /run/user/1000

127.0.0.1:/     8.0E     0  8.0E   0% /mnt/myefs





5

# 노드 정보 확인

인스턴스 타입 = t3.xlarge  확인

cap 타입 = ON_DEMAND

Zone  확인


kubectl get node --label-columns=node.kubernetes.io/instance-type


kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType



인스턴스 타입 = t3.xlarge  확인 , cap 타입 = ON_DEMAND  , Zone  확인  명령어 ?


kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone



192.168.1.x , 192.168.2.x  , 192.168.3.x   = node 3개

t3.xlarge 생성됨.

Zone 2a,2b,2c에 생성됨.



5

eksctl get iamidentitymapping --cluster myeks




6

# 노드 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.150, 192.168.2.166, 192.168.3.112




6

# 노드 보안그룹 ID 확인

NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values='*ng1*' --query "SecurityGroups[*].[GroupId]" --output text)


# 명령 ec2 100번 IP에서는 접근에 되도록 허용 적용

aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.100/32



7

# 워커 노드 SSH 접속

for node in $N1 $N2 $N3; do ssh ec2-user@$node hostname; done


ssh ec2-user@$N1

ssh ec2-user@$N2

ssh ec2-user@$N3






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



1

다른 터미널에서 모니터링

watch -d kubectl get svc,deploy,rs,pods -A



<필수1>


2

# ExternalDNS 사용시 필요한 도메인 


MyDomain=<자신의 도메인>   

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


MyDomain=taeho11.co.kr

echo "export MyDomain=taeho11.co.kr" >> /etc/profile


MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text)




도메인과 호스트존이 있어야 한다.  

호스트 존이 정상 동작해야 External DNS가 제대로 된다.

External DNS는 별도로 설치되며, LB에 대해 외부에서 접속 가능하도록 도메인으로 등록해준다.


echo $MyDomain, $MyDnzHostedZoneId

-----------------------------------------

masterseo0.link, /hostedzone/Z065511738EYRCJRN3389



curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml





MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -


(masterseo1:default) [root@myeks-bastion-EC2 ~]# MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -

serviceaccount/external-dns 

clusterrole.rbac.authorization.k8s.io/external-dns 

clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer

deployment.apps/external-dns 



3

k get pods -A


external-dns  Pod 확인하자.





<필수2>


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


( 2분 걸림)



k ns kube-system


http://ac38a5187702848a2815569ff521101d-751328758.ap-northeast-2.elb.amazonaws.com:8080/




https://vclock.kr/timer/#countdown=00:02:00&enabled=0&seconds=0&sound=xylophone&loop=1



:8080로 접속 해야 한다.



 http://kubeopsview.taeho11.co.kr:8080/#scale=1.5


http://kubeopsview.masterseo1.link:8080/#scale=1.5







<필수3>


로드 밸런서 컨트롤로 설치하기 =  # 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



kube-system 네임스페이스에 lb pod 2개 생김





5

# EBS csi driver 설치 확인  ?


eksctl로 설치된 addon 된것들에 대한 확인 ?

eksctl get addon --cluster ${CLUSTER_NAME}


4가지 추가

ebs-csi-driver , iamrole 추가됨.

coredns

kube-proxy

vpc-cni , iamrole






kubectl get pod -n kube-system -l 'app in (ebs-csi-controller,ebs-csi-node)'

-------------------------------------------------------------------------

NAME                                  READY   STATUS    RESTARTS   AGE

ebs-csi-controller-67658f895c-9275d   6/6     Running   0          26m

ebs-csi-controller-67658f895c-p9xw2   6/6     Running   0          26m

ebs-csi-node-g672x                    3/3     Running   0          26m

ebs-csi-node-l7mpw                    3/3     Running   0          26m

ebs-csi-node-nsgdd                    3/3     Running   0          26m

-


kubectl get csinodes

NAME                                               DRIVERS   AGE

ip-192-168-1-150.ap-northeast-2.compute.internal   1         27m

ip-192-168-2-82.ap-northeast-2.compute.internal    1         27m

ip-192-168-3-229.ap-northeast-2.compute.internal   1         27m




6

gp3로 바꿔보자.

# gp3 스토리지 클래스 생성


현재 스토리지 클레스는 gp2이다.


kubectl get sc

(masterseo1:kube-system) [root@myeks-bastion-EC2 ~]# kubectl get sc

NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE

gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                



gp3로 바꿔보자.


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





7

# 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



kubectl get deploy,pods 




8

# 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


(masterseo1:kube-system) [root@myeks-bastion-EC2 ~]# kubectl get sc efs-sc

NAME     PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE

efs-sc   efs.csi.aws.com   Delete          Immediate           false                  1s




9

확인

# 이미지 정보 확인

kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c



10

# eksctl 설치/업데이트 addon 확인

4개


eksctl get addon --cluster $CLUSTER_NAME


ebs-csi-driver




11

# IRSA 확인 ?

IRSA는  Cloudformation으로 적용 됨.

role 2개 확인 됨.

로드 밸런서와 efs의  IRSA 확인



eksctl get iamserviceaccount --cluster $CLUSTER_NAME







여기까지 설치 부분~~~~~~

이해 되시죠?

되시면 채팅창에 1번~~~~~~





<4> 쿠버네티스 API를 통해서 리소스 및 정보를 확인



1

View Kubernetes resources

https://docs.aws.amazon.com/eks/latest/userguide/view-kubernetes-resources.html


https://docs.aws.amazon.com/eks/latest/userguide/view-kubernetes-resources.html#view-kubernetes-resources-permissions



2

#  EKS이름이 있는 롤이 포함되어 있다.

기존 쿠버네티스는 eks 달려있는 롤은 없다.


kubectl get ClusterRole | grep eks

---------------------------------------

eks:addon-manager                                                      2023-05-08T04:22:45Z

eks:az-poller                                                          2023-05-08T04:22:42Z

eks:certificate-controller-approver                                    2023-05-08T04:22:42Z

:




3

콘솔로 리소스 확인이 가능하다.

pod 확인 하자.

service 확인하자.


EKS 워크셥 참고 

https://www.eksworkshop.com/docs/observability/resource-view/






옵저버빌리티(Observability) =  관찰 가능성

로그,메트릭,트레이스 3가지 관찰



<5>  EKS 로깅


1

참고 정리 자료

https://malwareanalysis.tistory.com/600


2

로깅 ?

컨트롤 플래인 logging

node logging

application logging



3

컨트롤 플래인 로깅 활성화  ?

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


콘솔에서 확인

디폴트로는 로깅 기능이 켜져 있지 않다.

활성화는 콘솔로 가능하다.

AWS에서 관리하는 영역이다.


EKS > Cluster > Cluster name click > Logging >  Control plane logging 

디폴트 off 상태이다.  5개 타입.


# 모든 로깅 활성화 = 클러스터 로깅 활성화



4

활성화는  명령어로도 가능하다. 


aws eks update-cluster-config --region $AWS_DEFAULT_REGION --name $CLUSTER_NAME     --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'



콘솔에서 확인





5

로깅 활성화 하고 로그 확인은 ?


cloudwatch >  logs > 로그그룹에서 확인하자.

/aws/eks/myeks/cluster




# off로 변경 

비용이 많이 나오는 경우 로그를 남기지 않도록 하자.


aws eks update-cluster-config --region $AWS_DEFAULT_REGION --name $CLUSTER_NAME     --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":false}]}'




# 로그 그룹 확인

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-controller-manager --follow


# code dns 1개로 조정, 2개로 조정하여 로그 보자

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





3

쌓인 로그를 조회해서 확인 하고 싶을때 , CloudWatch Log Insights 에서  확인 ?


Cloudwatch >  Logs insights  > 로그 그룹 선택 > 쿼리 입력하여 확인하자.



https://www.eksworkshop.com/docs/observability/logging/cluster-logging/log-insights/




4

로그 그룹  /aws/eks/myeks/cluste  선택


쿼리 입력


# 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




4

로깅 오프


# 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






<6> 컨트롤 플래인 메트릭 확인


1

https://docs.aws.amazon.com/eks/latest/userguide/prometheus.html



2

# 메트릭 패턴 정보 : metric_name{"tag"="value"[,...]} value

kubectl get --raw /metrics | more



3

# How to monitor etcd database size? >> 아래 10.0.X.Y IP는 어디일까요?
etcd ip ?   aws에서 관리해준다.


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



4

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



5

# 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






<7> 컨테이너(파드) 로깅


1

어플리케이션 로깅.

nginx 로 테스트 해보자.


선행 조건

도메인하나 등록해야 한다.

AWS ACM으로 인증서 하나 등록 해야 한다.

Certificate Manager

masterseo0.link



2

모니터링

watch -d kubectl get deploy,rs,pods,svc,ingress



3

nginx 배포 

https://artifacthub.io/packages/helm/bitnami/nginx




<필수4>


4

# 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

echo $CLUSTER_NAME



MyDomain=masterseo0.link

echo "export MyDomain=masterseo0.link" >> /etc/profile




<필수5>


5

# 파라미터 파일 생성



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


1. Get the NGINX URL and associate its hostname to your cluster external IP:

export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters

export CLUSTER_IP=43.201.94.189

echo "NGINX URL: http://nginx.masterseo0.link"

echo "$CLUSTER_IP  nginx.masterseo0.link" | sudo tee -a /etc/hosts



# 확인

kubectl get ingress  nginx

-----------------------------------------------------

NAME    CLASS   HOSTS                   ADDRESS                                                        PORTS   AGE

nginx   alb     nginx.masterseo1.link   myeks-ingress-alb-878546489.ap-northeast-2.elb.amazonaws.com   80      12s




kubectl get targetgroupbindings 

# ALB TG 확인

// 콜솔 확인



설명 :

    alb.ingress.kubernetes.io/ssl-redirect: '443'

위 설정으로 자동으로 80도 들어간다.

콘솔에서 확인하자.

편리해짐.


ADDRESS에 ALB 앞에 도메인 이름이 들어갈 예정이다.




5

# 접속 주소 확인 및 접속


echo -e "Nginx WebServer URL = https://nginx.$MyDomain"

---------------------------------------

Nginx WebServer URL = https://nginx.masterseo0.link


curl -s https://nginx.$MyDomain

// 응답이 나와야 한다.




6

별도 터미널에서 로드 모니터링 ?


kubectl logs deploy/nginx -f




7

# 반복 접속


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



8

# (참고) 삭제 시

helm uninstall nginx







<8>  컨테이너 로그가 조회 가능한 이유 ?


1

사용자는 외부에서 kubectl logs 명령어로 애플리케이션 종류에 상관없이, 애플리케이션마다 로그 파일 위치에 상관없이, 단일 명령어로 조회 가능 ?


컨테이너 이미지 생성시 , 로그 출력이 가능하도록 설정을 했다.

원래는 파드에 들어가서 봐야 한다.

중요 로그를 심볼릭 링크로 걸어서 확인 하는 것이다.



2

표준으로 보내는 것을 권고

https://docs.docker.com/config/containers/logging/



3

# 로그 모니터링

kubectl logs deploy/nginx -f



4

# 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

// 심볼릭 링크가 걸려 있다!!!



// 컨테이너 이미지를 만들때 이미 링크가 걸려 있다.

https://github.com/nginxinc/docker-nginx/blob/8921999083def7ba43a06fabd5f80e4406651353/mainline/jessie/Dockerfile#L21-L23



pod를 들어가지 않고도  로그를 볼수 있다.

컨테이너 이미지를 빌드할때  링크를 걸어 만들도록 하자!



5

단점?

명령어로 봐야 한다.

로그 용량 제한이 있다.  10Mi를 초과 불가.



6

Pod로그가 중앙 로그 수집이 필요하다.


nginx docker log collector 예시

https://github.com/bitnami/containers/blob/main/bitnami/nginx/1.23/debian-11/Dockerfile#L42-L43







<9>  Container Insights metrics in Amazon CloudWatch  과  Fluent Bit (Logs)



1

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


CW Agent

https://docs.docker.com/config/containers/logging/

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


Fluent Bit

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs.html

https://hyperconnect.github.io/2023/05/02/troubleshooting-fluent-bit-segmentation-fault.html



2

구성도

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




4

[수집] ?

플루언트비트 Fluent Bit 컨테이너를 데몬셋으로 동작시키고, 

아래 3가지 종류의 로그를 수집해서 CloudWatch Logs 에 전송 한다.


1) 워커노드의 application 로그, 파드 로그 

/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`), 쿠버네티스 데이터플레인 로그





<10> CloudWatch Container Insight



컨테이너형 애플리케이션 및 마이크로 서비스에 대한 모니터링, 트러블 슈팅 및 알람을 위한 

완전 관리형 관측 서비스입니다



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


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






4

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 -



5

# 설치 확인

kubectl get-all -n amazon-cloudwatch

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



6

# 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

  }

}



7

# CW 파드가 수집하는 방법 : Volumes에 HostPath를 살펴보자! >> / 호스트 패스 공유??? 보안상 안전한가?


kubectl describe -n amazon-cloudwatch ds cloudwatch-agent

...

# disk 

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

...



8

# 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

...


9

# Fluent Bit 파드가 수집하는 방법 : Volumes에 HostPath를 살펴보자!

kubectl describe -n amazon-cloudwatch ds fluent-bit

...

ssh ec2-user@$N1 sudo tree /var/log

...



10

콘솔에서 로그 확인하자.

cloudwath > logs > logs group





11

메트릭 확인?

Cloudwatch > 인사이트 > Container insights

Resources 

Container map

Performance monitoring 




12

# (참고) 삭제

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 -




13

로그 확인 ?

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-EKS-logs.html





<11>  nginx 웹서버 로그 확인


1

# 부하 발생

curl -s https://nginx.$MyDomain

yum install -y httpd

ab -c 500 -n 30000 https://nginx.$MyDomain/



2

# 파드 직접 로그 모니터링

kubectl logs deploy/nginx -f



3

콘솔 확인?

Cloudwatch > '로그 그룹 → application → 로그 스트림 : 

nginx 필터링 ⇒ 클릭 후 확인 ⇒ ApacheBench 필터링 확인



4

로그 인사이트 사용하기 ?


# 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



5

메트릭 확인 : CloudWatch → Insights → Container Insights : 

우측 상단(Local Time Zone, 30분) ⇒ 리소스 : myeks 선택







<12> 개인 정리





다음 공부

https://brunch.co.kr/@topasvga/3240



전체 보기

https://brunch.co.kr/@topasvga/3217



감사합니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari