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
콘솔 로그인
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
브라우저 -> 새탭에서 보기
(노드 서버 생성 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
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
1
다른 터미널에서 모니터링
watch -d kubectl get svc,deploy,rs,pods -A
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 확인하자.
# 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
로드 밸런서 컨트롤로 설치하기 = # 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번~~~~~~
1
View Kubernetes resources
https://docs.aws.amazon.com/eks/latest/userguide/view-kubernetes-resources.html
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가지 관찰
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
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
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
# 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
# 파라미터 파일 생성
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
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
// 심볼릭 링크가 걸려 있다!!!
// 컨테이너 이미지를 만들때 이미 링크가 걸려 있다.
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
1
파드에 CloudWatch Agent 파드와 Fluent Bit 파드가 데몬셋으로 배치되어 Metrics 과 Logs 수집.
CW Agent
https://docs.docker.com/config/containers/logging/
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
구성도
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`), 쿠버네티스 데이터플레인 로그
컨테이너형 애플리케이션 및 마이크로 서비스에 대한 모니터링, 트러블 슈팅 및 알람을 위한
완전 관리형 관측 서비스입니다
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
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 선택
다음 공부
https://brunch.co.kr/@topasvga/3240
전체 보기
https://brunch.co.kr/@topasvga/3217
감사합니다.