Home
home

3장 실습 - Amazon EKS - LGTM Observability Full Stack 구성하기

1. 기본 환경 배포

이번 실습은 IAM 사용자 계정을 통해 관리 콘솔에 접근하고 액세스 키를 활용해 awscli 도구를 사용합니다.
해당 작업을 수행하지 않았다면 아래 토글을 확장해 작업을 선행하고 본격적인 실습에 들어갑니다.
IAM 사용자 생성 및 액세스 키 생성

1.1. Terraform을 통한 기본 인프라 배포

Terraform을 통한 기본 인프라 배포에 앞서 SSH 키 페어, IAM User Access Key ID, IAM User Secret Access Key를 미리 확인하고 메모해 둡니다.
Terraform으로 기본 인프라 배포
cd cnaee_class_tf/ch3
Bash
복사
# 실습 디렉터리 경로 진입
export TF_VAR_KeyName=[각자 ssh keypair] export TF_VAR_MyIamUserAccessKeyID=[각자 iam 사용자의 access key id] export TF_VAR_MyIamUserSecretAccessKey=[각자 iam 사용자의 secret access key] export TF_VAR_SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32
Bash
복사
# Terraform 환경 변수 저장
terraform init terraform plan
Bash
복사
# Terraform 배포
nohup sh -c "terraform apply -auto-approve" > create.log 2>&1 &
Bash
복사
Note:  nohup으로 백그라운드로 실행하도록 변경했습니다. Terraform 배포가 완료되면 정상적으로 자원 생성이 되었는지 확인을 합니다.(cat create.log)
Terraform을 통한 기본 인프라 배포가 완료되면 관리 콘솔에서 생성된 인프라들을 확인합니다.
Note: 
AWS 관리 콘솔에 로그인 할 땐 IAM 사용자 계정으로 진행합니다.

1.2. 기본 정보 확인 및 설정

Terraform 배포가 완료 후 출력되는 Output 정보에서 bastion_host_ip의 퍼블릭 IP를 확인합니다.
해당 IP로 EKS 관리용 인스턴스(myeks-bastion-EC2)에 SSH로 접속하고 아래 명령어를 통해 정보를 확인합니다.
Note:
myeks-bastion-EC2의 OS 변경으로 SSH 접근에 대한 계정을 ubuntu로 지정합니다.
(ssh -i ~/.ssh/XXXX.pem ubuntu@X.X.X.X)
기본 설정 및 확인
aws eks update-kubeconfig \ --region $AWS_DEFAULT_REGION \ --name $CLUSTER_NAME
Shell
복사
# EKS 클러스터 인증 정보 업데이트
kubens default
Bash
복사
# kubens default 설정
echo $AWS_DEFAULT_REGION echo $CLUSTER_NAME echo $VPCID echo $PublicSubnet1,$PublicSubnet2,$PublicSubnet3 echo $PrivateSubnet1,$PrivateSubnet2,$PrivateSubnet3
Bash
복사
# 변수 호출 종합
eksctl get cluster
Bash
복사
# eksctl을 통한 eks cluster 정보 확인
eksctl get nodegroup \ --cluster $CLUSTER_NAME \ --name ${CLUSTER_NAME}-node-group
Bash
복사
# eksctl을 통한 노드 그룹 정보 확인
kubectl get node -owide
Bash
복사
# kubectl을 통한 노드 정보 확인
PublicN1=$(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}) PublicN2=$(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}) PublicN3=$(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 PublicN1=$PublicN1" >> /etc/profile echo "export PublicN2=$PublicN2" >> /etc/profile echo "export PublicN3=$PublicN3" >> /etc/profile echo $PublicN1, $PublicN2, $PublicN3
Bash
복사
# 노드 IP 변수 선언
for node in $PublicN1 $PublicN2 $PublicN3; \ do \ ssh -i ~/.ssh/kp_node.pem -o StrictHostKeyChecking=no ec2-user@$node hostname; \ done
Bash
복사
# 노드에 ssh 접근 확인

2. Observability Backends 설치

LGTM Observability Full Stack 환경 구성을 위한 Backend System을 설치합니다.
[Metrics] - Grafana Mimir
[Logs] - Grafana Loki
[Traces] - Grafana Tempo
사전 준비
export CERT_ARN=`aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text` echo "export CERT_ARN=$CERT_ARN" >> /etc/profile; echo $CERT_ARN export NICKNAME=[각자의 닉네임] echo "export NICKNAME=$NICKNAME" >> /etc/profile; echo $NICKNAME export OIDC_ARN=$(aws iam list-open-id-connect-providers --query 'OpenIDConnectProviderList[*].Arn' --output text) echo "export OIDC_ARN=$OIDC_ARN" >> /etc/profile; echo $OIDC_ARN export OIDC_URL=${OIDC_ARN#*oidc-provider/} echo "export OIDC_URL=$OIDC_URL" >> /etc/profile; echo $OIDC_URL
Bash
복사
# 변수 선언
만약 인증서가 없을 경우..
cat <<EOT | kubectl apply -f - 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
Bash
복사
# gp3 storage class 생성
helm repo add grafana https://grafana.github.io/helm-charts helm repo update
Bash
복사
# helm repo - grafana 추가
kubectl create ns monitoring kubectl create ns logging kubectl create ns tracing kubectl create ns grafana
Bash
복사
# namespace 생성
Values 파일 다운로드
wget https://github.com/cloudneta/cnaeelab/raw/master/_data/values.zip unzip values.zip; rm values.zip cd values tree
Bash
복사
# values 파일 다운로드 및 경로 진입 후 tree 명령

2.1. Grafana Mimir 설치 및 확인

Grafana Mimir 모니터링
watch kubectl get pod,pv,pvc,cm -n monitoring
Bash
복사
# [모니터링1] monitoring 네임스페이스 - pod, pv, pvc, configmap 모니터링
while true; do aws ec2 describe-volumes \ --filters Name=tag:ebs.csi.aws.com/cluster,Values=true \ --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" \ --output text; date; sleep 1; done
Bash
복사
# [모니터링2] 동적 프로비저닝으로 생성되는 EBS 볼륨 확인
Mimir용 S3 Bucket 생성
mkdir ~/irsa; cd ~/irsa
Bash
복사
# irsa 설정 파일 경로 생성 및 진입
aws s3api create-bucket \ --bucket mimir-${NICKNAME} \ --region $AWS_DEFAULT_REGION \ --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION aws s3 ls
Bash
복사
# mimir용 s3 bucket 생성 및 확인
export MIMIR_BUCKET_NAME="mimir-${NICKNAME}" echo "export MIMIR_BUCKET_NAME=$MIMIR_BUCKET_NAME" >> /etc/profile; echo $MIMIR_BUCKET_NAME
Bash
복사
# s3 bucket 이름 변수 저장
Mimir - S3 IAM Policy 생성
cat >grafana-mimir-s3-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "MimirStorage", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::${MIMIR_BUCKET_NAME}", "arn:aws:s3:::${MIMIR_BUCKET_NAME}/*" ] } ] } EOF cat grafana-mimir-s3-policy.json
Bash
복사
# grafana-mimir-s3-poilcy.json 파일 생성
aws iam create-policy \ --policy-name aws-mimir-s3 \ --policy-document file://grafana-mimir-s3-policy.json
Bash
복사
# aws-mimir-s3 IAM Policy 생성
Mimir - S3 IAM Role 생성
cat >trust-rs-mimir.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "${OIDC_ARN}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDC_URL}:sub": "system:serviceaccount:monitoring:mimir", "${OIDC_URL}:aud": "sts.amazonaws.com" } } } ] } EOF cat trust-rs-mimir.json
Bash
복사
# Mimir IAM Role Trust rs 생성
aws iam create-role \ --role-name AWS-Mimir-Role \ --assume-role-policy-document file://trust-rs-mimir.json
Bash
복사
# AWS-Mimir-Role 생성
aws iam attach-role-policy \ --role-name AWS-Mimir-Role \ --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-mimir-s3
Bash
복사
# IAM Policy와 IAM Role 연결
export MIMIR_ROLE_ARN=arn:aws:iam::${ACCOUNT_ID}:role/AWS-Mimir-Role echo "export MIMIR_ROLE_ARN=$MIMIR_ROLE_ARN" >> /etc/profile; echo $MIMIR_ROLE_ARN
Bash
복사
# Mimir IAM Role ARN 변수 선언
Mimir 설치
export | grep MIMIR
Bash
복사
# MIMIR 변수 출력
cd ~/values; envsubst < mimir-temp-values.yaml > mimir-values.yaml cat mimir-values.yaml | yh
Bash
복사
# mimir-values.yaml 확인
helm install mimir grafana/mimir-distributed \ -n monitoring \ -f mimir-values.yaml \ --version 5.4.0
Bash
복사
# mimir-values 파일을 활용해서 Mimir를 helm chart로 설치

2.2. Grafana Loki 설치 및 확인

Grafana Loki 모니터링
watch kubectl get pod,pv,pvc -n logging
Bash
복사
# [모니터링1] logging 네임스페이스 - pod, pv, pvc 모니터링
Loki용 S3 Bucket 생성
cd ~/irsa
Bash
복사
# irsa 경로 이동
aws s3api create-bucket \ --bucket loki-${NICKNAME} \ --region $AWS_DEFAULT_REGION \ --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION aws s3 ls
Bash
복사
# loki용 s3 bucket 생성
export LOKI_BUCKET_NAME="loki-${NICKNAME}" echo "export LOKI_BUCKET_NAME=$LOKI_BUCKET_NAME" >> /etc/profile; echo $LOKI_BUCKET_NAME
Bash
복사
# s3 bucket 이름 변수 저장
Loki - S3 IAM Policy 생성
cat >grafana-loki-s3-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "LokiStorage", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::${LOKI_BUCKET_NAME}", "arn:aws:s3:::${LOKI_BUCKET_NAME}/*" ] } ] } EOF cat grafana-loki-s3-policy.json
Bash
복사
# grafana-loki-s3-poilcy.json 파일 생성
aws iam create-policy \ --policy-name aws-loki-s3 \ --policy-document file://grafana-loki-s3-policy.json
Bash
복사
# aws-loki-s3 IAM Policy 생성
Loki - S3 IAM Role 생성
# Loki IAM Role Trust rs 생성 cat >trust-rs-loki.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "${OIDC_ARN}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDC_URL}:sub": "system:serviceaccount:logging:loki", "${OIDC_URL}:aud": "sts.amazonaws.com" } } }, { "Effect": "Allow", "Principal": { "Federated": "${OIDC_ARN}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDC_URL}:sub": "system:serviceaccount:logging:loki-compactor", "${OIDC_URL}:aud": "sts.amazonaws.com" } } } ] } EOF cat trust-rs-loki.json
Bash
복사
aws iam create-role \ --role-name AWS-Loki-Role \ --assume-role-policy-document file://trust-rs-loki.json
Bash
복사
# AWS-Loki-Role 생성
aws iam attach-role-policy \ --role-name AWS-Loki-Role \ --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-loki-s3
Bash
복사
# IAM Policy와 IAM Role 연결
export LOKI_ROLE_ARN=arn:aws:iam::${ACCOUNT_ID}:role/AWS-Loki-Role echo "export LOKI_ROLE_ARN=$LOKI_ROLE_ARN" >> /etc/profile; echo $LOKI_ROLE_ARN
Bash
복사
# Loki IAM Role ARN 변수 선언
Loki 설치
export | grep LOKI
Bash
복사
# LOKI 변수 출력
cd ~/values; envsubst < loki-temp-values.yaml > loki-values.yaml cat loki-values.yaml | yh
Bash
복사
# loki-values.yaml 파일 확인
helm install loki grafana/loki-distributed \ -n logging \ -f loki-values.yaml \ --version 0.79.1
Bash
복사
# loki-values 파일을 활용해서 loki를 helm chart로 설치

2.3. Grafana Tempo 설치 및 확인

Grafana Tempo 모니터링
watch kubectl get pod,pv,pvc -n tracing
Bash
복사
# [모니터링1] tracing 네임스페이스 - pod, pv, pvc 모니터링
Tempo용 S3 Bucket 생성
cd ~/irsa
Bash
복사
# irsa 경로 이동
aws s3api create-bucket \ --bucket tempo-${NICKNAME} \ --region $AWS_DEFAULT_REGION \ --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION aws s3 ls
Bash
복사
# tempo용 s3 bucket 생성
export TEMPO_BUCKET_NAME="tempo-${NICKNAME}" echo "export TEMPO_BUCKET_NAME=$TEMPO_BUCKET_NAME" >> /etc/profile; echo $TEMPO_BUCKET_NAME
Bash
복사
# s3 bucket 이름 변수 저장
Tempo - S3 IAM Policy 생성
cat >grafana-tempo-s3-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "TempoStorage", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::${TEMPO_BUCKET_NAME}", "arn:aws:s3:::${TEMPO_BUCKET_NAME}/*" ] } ] } EOF cat grafana-tempo-s3-policy.json
Bash
복사
# grafana-tempo-s3-poilcy.json 파일 생성
aws iam create-policy \ --policy-name aws-tempo-s3 \ --policy-document file://grafana-tempo-s3-policy.json
Bash
복사
# aws-tempo-s3 IAM Policy 생성
Tempo - S3 IAM Role 생성
cat >trust-rs-tempo.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "${OIDC_ARN}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${OIDC_URL}:sub": "system:serviceaccount:tracing:tempo", "${OIDC_URL}:aud": "sts.amazonaws.com" } } } ] } EOF cat trust-rs-tempo.json
Bash
복사
# Tempo IAM Role Trust rs 생성
aws iam create-role \ --role-name AWS-Tempo-Role \ --assume-role-policy-document file://trust-rs-tempo.json
Bash
복사
# AWS-Tempo-Role 생성
aws iam attach-role-policy \ --role-name AWS-Tempo-Role \ --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-tempo-s3
Bash
복사
# IAM Policy와 IAM Role 연결
export TEMPO_ROLE_ARN=arn:aws:iam::${ACCOUNT_ID}:role/AWS-Tempo-Role echo "export TEMPO_ROLE_ARN=$TEMPO_ROLE_ARN" >> /etc/profile; echo $TEMPO_ROLE_ARN
Bash
복사
# Tempo IAM Role ARN 변수 선언
IAM Policy와 Role 확인
aws iam list-policies \ --query 'Policies[?contains(PolicyName, `mimir`) || contains(PolicyName, `loki`) || contains(PolicyName, `tempo`)].PolicyName' \ --output text
Bash
복사
# Mimir, Loki, Tempo - S3 IAM Policy 확인
aws iam list-roles \ --query 'Roles[?contains(RoleName, `Mimir`) || contains(RoleName, `Loki`) || contains(RoleName, `Tempo`)].RoleName' \ --output text
Bash
복사
# Mimir, Loki, Tempo - S3 IAM Role 확인
Tempo 설치
export | grep TEMPO
Bash
복사
# TEMPO 변수 출력
cd ~/values; envsubst < tempo-temp-values.yaml > tempo-values.yaml cat tempo-values.yaml | yh
Bash
복사
# tempo-values.yaml 파일 확인
helm install tempo grafana/tempo-distributed \ -n tracing \ -f tempo-values.yaml \ --version 1.15.2
Bash
복사
# tempo-values 파일을 활용해서 tempo를 helm chart로 설치
Observability Backend 설치 확인
for ns in monitoring logging tracing; do helm list -n $ns; done
Bash
복사
# helm chart로 설치한 Obervability Backend 시스템 확인

3. OpenTelemetry Operator & Collector 설치

OpenTelemetry Operator를 통해 OpenTelemetry CRD를 생성해서 OTel Collector, OTel Auto-Instrumentation을 설치할 수 있습니다.

3.1. OpenTelemetry Operator 설치

cert-manager 설치 및 확인
helm repo add jetstack https://charts.jetstack.io --force-update helm repo update
Bash
복사
# helm repo 추가
helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version 1.15.1 \ --set crds.enabled=true
Bash
복사
# cert-manager 설치
kubectl get pod -n cert-manager
Bash
복사
# cert-manager 생성 확인
kubectl get crd | grep cert-manager
Bash
복사
# cert-manager crd 확인
OpenTelemetry Operator 설치 및 확인
watch kubectl get all -n otel
Bash
복사
# [모니터링1] otel 네임스페이스
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts helm repo update
Bash
복사
# helm repo 추가
helm install opentelemetry-operator open-telemetry/opentelemetry-operator \ --version 0.82.0 \ --namespace otel \ --create-namespace \ --set "manager.collectorImage.repository=otel/opentelemetry-collector-k8s"
Bash
복사
# otel-operator 설치
kubectl get crd | grep open
Bash
복사
# otel-operator crd 설치 확인

3.2. OpenTelemetry Collector 생성

OpenTelemetry Collector 생성
cd ~/values; cat otelcol-values.yaml | yh
Bash
복사
# otelcol-values.yaml 확인
helm install opentelemetry open-telemetry/opentelemetry-collector \ -n otel \ -f otelcol-values.yaml \ --version 0.81.0
Bash
복사
# Otel Collector 설치

4. Observability Visualization 설치

Observability Visualization 도구로 Grafana를 설치하고 결과를 확인합니다.

4.1. Grafana 설치

Grafana 모니터링
watch kubectl get pod,svc,ep,ingress,pv,pvc -n grafana
Bash
복사
# [모니터링1] grafana 네임스페이스 - pod, svc, ep, ingress, pv, pvc 모니터링
while true; do aws ec2 describe-volumes \ --filters Name=tag:ebs.csi.aws.com/cluster,Values=true \ --query "Volumes[].{VolumeId: VolumeId, VolumeType: VolumeType, InstanceId: Attachments[0].InstanceId, State: Attachments[0].State}" \ --output text; date; sleep 1; done
Bash
복사
# [모니터링2] 동적 프로비저닝으로 생성되는 EBS 볼륨 확인
Grafana 설치
export MyDomain=[각자 도메인 네임] echo "export MyDomain=$MyDomain" >> /etc/profile; echo $MyDomain
Bash
복사
# MyDomain 변수 선언
cd ~/values; envsubst < grafana-temp-values.yaml > grafana-values.yaml cat grafana-values.yaml | yh
Bash
복사
# grafana-values.yaml 확인
helm install grafana grafana/grafana \ -n grafana \ -f grafana-values.yaml \ --version 8.3.6
Bash
복사
# grafana-values 파일을 활용해서 grafana를 helm chart로 설치
while true; do \ aws elbv2 describe-load-balancers \ --query 'LoadBalancers[*].[LoadBalancerName,State.Code]' \ --output table; \ done
Bash
복사
# elb 생성 확인 (Ctrl + Z로 중지)
Note:
https://grafana.${MyDomain}/grafana로 접속합니다. (id: admin, pw: qwer1234)

5. LGTM Observability 검증

5.1. [Metrics] Grafana Mimir 확인

Grafana Data Source 설정
Data Source 지정 [Connections → Data Sources → Add data source → Prometheus]
Name: Mimir
Connection - Prometheus server URL
http://mimir-nginx.monitoring/prometheus
Bash
복사
Save & Test
이미지 빌드
Test Pod 생성
cd; cat >test-pod.yaml <<EOF apiVersion: v1 kind: Pod metadata: name: python-metric-test labels: app: python-metric annotations: prometheus.io/scrape: 'true' prometheus.io/port: '5000' spec: containers: - name: python-app image: ongja/my-flask-app:latest ports: - containerPort: 5000 EOF
Bash
복사
# test-pod.yaml 생성
kubectl apply -f test-pod.yaml
Bash
복사
# test pod 배포
kubectl exec -it python-metric-test \ -- /bin/sh -c "apt-get update && apt-get install -y stress && stress --cpu 4 --timeout 300"
Bash
복사
# test pod에 cpu 부하
Grafana에서 Mimir 정보 확인
Grafana 웹 페이지에서 Explorer 메뉴로 진입합니다.
Outline: Mimir
BuilderCode
Last 15 minutes
Run Query
container_cpu_usage_seconds_total{pod="python-metric-test"}
Bash
복사
# [Query] 대상 파드의 누적 CPU 사용
(sum(rate(container_cpu_usage_seconds_total{namespace="default", pod="python-metric-test"}[5m])) / sum(rate(container_cpu_usage_seconds_total[5m]))) * 100
Bash
복사
# [Query] 대상 파드의 CPU 사용량이 전체 CPU에 차지하는 비율

5.2. [Logs] Grafana Loki 확인

Grafana Data Source 설정
Data Source 지정 [Connections → Data Sources → Add data source → Loki]
Name: Loki
Connection - Loki server URL
http://loki-loki-distributed-gateway.logging
Bash
복사
Save & Test
Grafana에서 Loki 정보 확인
Grafana 웹 페이지에서 Explorer 메뉴로 진입합니다.
Outline: Loki
BuilderCode
Last 5 minutes
Run Query
{k8s_pod_name="python-metric-test"}
Bash
복사
# [Query] 대상 파드의 모든 로그 정보 확인
파드 로그 정보 확인
cat ~/values/otelcol-values.yaml | grep -A 1 "filelog:"
Bash
복사
# otel collector 설정 정보 필터링
for node in $PublicN1 $PublicN2 $PublicN3; do ssh -i ~/.ssh/kp_node.pem ec2-user@$node "sudo sh -c 'ls /var/log/pods/default*/python-app/'" done
Bash
복사
# 노드에 구성된 파드의 로그 파일 확인
for node in $PublicN1 $PublicN2 $PublicN3; do ssh -i ~/.ssh/kp_node.pem ec2-user@$node "sudo sh -c 'cat /var/log/pods/default*/python-app/0.log'" done
Bash
복사
# 노드에 구성된 파드의 로그 파일 내용 확인

5.3. [Traces] Grafana Tempo 확인

Grafana Data Source 설정
Data Source 지정 [Connections → Data Sources → Add data source → Tempo]
Name: Tempo
Connection - Tempo server URL
http://tempo-query-frontend-discovery.tracing:3100
Bash
복사
Save & Test
1.
수동 계측
이미지 빌드
Trace 수동 계측
cat << EOF > 1_deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: python-app spec: replicas: 1 selector: matchLabels: app: python-app template: metadata: labels: app: python-app spec: containers: - name: python-app image: ongja/inst-1:latest ports: - containerPort: 5000 --- apiVersion: v1 kind: Service metadata: name: python-app-service spec: selector: app: python-app ports: - protocol: TCP port: 80 targetPort: 5000 EOF
Bash
복사
# 1_deploy.yaml 생성
kubectl apply -f 1_deploy.yaml kubectl get pod,svc
Bash
복사
# 배포 및 확인
kubectl run curl \ --image=appropriate/curl \ --restart=Never \ --rm -it -- sh
Bash
복사
# 테스트 파드에 접근해서 확인
curl http://python-app-service.default.svc.cluster.local
Bash
복사
2.
프로그래밍 계측
이미지 빌드
Trace 프로그래밍 계측
cat << EOF > app-1.yaml apiVersion: v1 kind: Service metadata: name: app-1 spec: selector: app: app-1 ports: - protocol: TCP port: 80 targetPort: 5000 name: http --- apiVersion: apps/v1 kind: Deployment metadata: name: app-1 spec: replicas: 1 selector: matchLabels: app: app-1 template: metadata: labels: app: app-1 spec: containers: - name: app-1 image: ongja/tempo-app-1:latest command: ["/bin/sh"] args: - "-c" - | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://tempo-distributor-discovery.tracing:4318/v1/traces opentelemetry-instrument python app-1.py ports: - containerPort: 5000 name: http env: - name: SERVICE_B_HOST value: "app-2" - name: SERVICE_B_PORT value: "80" - name: PORT value: "5000" - name: OTEL_SERVICE_NAME value: "app-1" - name: OTEL_TRACES_EXPORTER value: "console,otlp" - name: OTEL_EXPORTER_OTLP_TRACES_HEADERS value: "api-key=key,other-config-value=value" - name: OTEL_TRACES_SAMPLER_ARG value: "1" - name: OTEL_EXPORTER_OTLP_PROTOCOL value: "http/protobuf" - name: OTEL_METRICS_EXPORTER value: "none" EOF
Bash
복사
# app-1.yaml 생성
cat << EOF > app-2.yaml apiVersion: v1 kind: Service metadata: name: app-2 spec: selector: app: app-2 ports: - protocol: TCP port: 80 targetPort: 5001 name: http --- apiVersion: apps/v1 kind: Deployment metadata: name: app-2 spec: replicas: 1 selector: matchLabels: app: app-2 template: metadata: labels: app: app-2 spec: containers: - name: app-2 image: ongja/tempo-app-2:latest command: ["/bin/sh"] args: - "-c" - | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://tempo-distributor-discovery.tracing:4318/v1/traces opentelemetry-instrument python app-2.py ports: - containerPort: 5001 name: http env: - name: PORT value: "5001" - name: SERVICE_C_HOST value: "app-3" - name: SERVICE_C_PORT value: "80" - name: OTEL_SERVICE_NAME value: "app-2" - name: OTEL_TRACES_SAMPLER_ARG value: "100" - name: OTEL_TRACES_EXPORTER value: "console,otlp" - name: OTEL_EXPORTER_OTLP_PROTOCOL value: "http/protobuf" - name: OTEL_METRICS_EXPORTER value: "none" EOF
Bash
복사
# app-2.yaml 생성
cat << EOF > app-3.yaml apiVersion: v1 kind: Service metadata: name: app-3 spec: selector: app: app-3 ports: - protocol: TCP port: 80 targetPort: 5002 name: http --- apiVersion: apps/v1 kind: Deployment metadata: name: app-3 spec: replicas: 1 selector: matchLabels: app: app-3 template: metadata: labels: app: app-3 spec: containers: - name: app-3 image: ongja/tempo-app-3:latest command: ["/bin/sh"] args: - "-c" - | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://tempo-distributor-discovery.tracing:4318/v1/traces opentelemetry-instrument python app-3.py ports: - containerPort: 5002 name: http env: - name: PORT value: "5002" - name: OTEL_SERVICE_NAME value: "app-3" - name: OTEL_EXPORTER_OTLP_TRACES_HEADERS value: "api-key=key,other-config-value=value" - name: OTEL_TRACES_SAMPLER_ARG value: "100" - name: OTEL_EXPORTER_OTLP_PROTOCOL value: "http/protobuf" - name: OTEL_METRICS_EXPORTER value: "none" - name: OTEL_TRACES_EXPORTER value: "console,otlp" EOF
Bash
복사
# app-3.yaml 생성
kubectl create ns tempo-test kubectl apply -f app-1.yaml -n tempo-test kubectl apply -f app-2.yaml -n tempo-test kubectl apply -f app-3.yaml -n tempo-test kubectl get pod,svc -n tempo-test
Bash
복사
# 배포 및 확인
kubectl run -n tempo-test curl \ --image=appropriate/curl \ --restart=Never \ --rm -it -- sh
Bash
복사
# 테스트 파드에 접근해서 확인
curl http://app-1
Bash
복사
curl http://app-1/error
Bash
복사
curl http://app-2
Bash
복사
curl http://app-2/error
Bash
복사
curl http://app-3
Bash
복사
curl http://app-3/error
Bash
복사
3.
자동 계측
Trace 자동 계측 - auto-instrumentation 생성
cat >auto-instrumentation.yaml <<EOF apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: otel-instrumentation spec: exporter: endpoint: http://opentelemetry-opentelemetry-collector.otel.svc.cluster.local:4317 propagators: - tracecontext - baggage sampler: type: parentbased_traceidratio argument: "1" nodejs: env: - name: OTEL_EXPORTER_OTLP_TRACES_PROTOCOL value: "grpc" - name: OTEL_EXPORTER_OTLP_METRICS_PROTOCOL value: "grpc" - name: OTEL_NODE_DISABLED_INSTRUMENTATIONS value: "fs" EOF
Bash
복사
# auto-instrumentation.yaml 생성
kubectl apply -f auto-instrumentation.yaml kubectl get instrumentations.opentelemetry.io
Bash
복사
# auto-instrumentation 배포 및 확인
Trace 자동 계측 - java 환경 테스트
cat >spring-java.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: java-app spec: selector: matchLabels: app: java-app replicas: 1 template: metadata: labels: app: java-app annotations: sidecar.opentelemetry.io/inject: "true" instrumentation.opentelemetry.io/inject-java: "true" spec: containers: - name: app image: springio/gs-spring-boot-docker --- apiVersion: v1 kind: Service metadata: name: java-app-service spec: type: NodePort selector: app: java-app ports: - protocol: TCP port: 8080 targetPort: 8080 EOF
Bash
복사
# spring-java.yaml 생성
kubectl apply -f spring-java.yaml
Bash
복사
# spring-java.yaml 배포
kubectl run curl \ --image=appropriate/curl \ --restart=Never \ --rm -it -- sh
Bash
복사
# 테스트 파드에 접근해서 확인
curl http://java-app-service:8080
Bash
복사
Trace 자동 계측 - nodejs 환경 테스트
cat >nodejs-test.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: nodejs-express spec: replicas: 1 selector: matchLabels: app: nodejs-express template: metadata: labels: app: nodejs-express annotations: instrumentation.opentelemetry.io/inject-nodejs: "true" spec: containers: - name: nodejs-express image: bitnami/node:14 command: ["sh", "-c"] args: ["npm install express && node -e \"const express = require('express'); const app = express(); app.get('/', (req, res) => res.send('Hello World!')); app.listen(8080);\""] ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: nodejs-express-service spec: type: NodePort selector: app: nodejs-express ports: - protocol: TCP port: 80 targetPort: 8080 EOF
Bash
복사
# nodejs-test.yaml 생성
kubectl apply -f nodejs-test.yaml
Bash
복사
# nodejs-test.yaml 배포
kubectl run curl \ --image=appropriate/curl \ --restart=Never \ --rm -it -- sh
Bash
복사
# 테스트 파드에 접근해서 확인
curl http://nodejs-express-service
Bash
복사

6. 실습 환경 삭제

실습 환경 삭제와 Terraform 삭제 작업을 진행합니다.

6.1. 실습 자원 삭제

실습 애플리케이션 삭제
cd ~ kubectl delete -f nodejs-test.yaml kubectl delete -f spring-java.yaml kubectl delete -f 1_deploy.yaml kubectl delete -f test-pod.yaml kubectl delete -f app-1.yaml -n tempo-test kubectl delete -f app-2.yaml -n tempo-test kubectl delete -f app-3.yaml -n tempo-test
Bash
복사
# 실습 애플리케이션 삭제
helm과 pvc 삭제
helm uninstall grafana -n grafana helm uninstall opentelemetry -n otel helm uninstall opentelemetry-operator -n otel helm uninstall cert-manager -n cert-manager
Bash
복사
# helm과 pvc 삭제
helm uninstall tempo -n tracing kubectl delete pvc --all -n tracing
Bash
복사
helm uninstall loki -n logging kubectl delete pvc --all -n logging
Bash
복사
helm uninstall mimir -n monitoring kubectl delete pvc --all -n monitoring
Bash
복사
Observability Backend - S3 IAM Policy와 Role 삭제
aws iam detach-role-policy --role-name AWS-Loki-Role --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-loki-s3 aws iam detach-role-policy --role-name AWS-Mimir-Role --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-mimir-s3 aws iam detach-role-policy --role-name AWS-Tempo-Role --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-tempo-s3 aws iam delete-policy --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-loki-s3 aws iam delete-policy --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-mimir-s3 aws iam delete-policy --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/aws-tempo-s3 aws iam delete-role --role-name AWS-Loki-Role aws iam delete-role --role-name AWS-Mimir-Role aws iam delete-role --role-name AWS-Tempo-Role
Bash
복사
# IAM Policy와 Role 삭제
S3 Bucket 삭제
aws s3 rm s3://$MIMIR_BUCKET_NAME --recursive aws s3 rm s3://$LOKI_BUCKET_NAME --recursive aws s3 rm s3://$TEMPO_BUCKET_NAME --recursive aws s3api delete-bucket --bucket $MIMIR_BUCKET_NAME --region $AWS_DEFAULT_REGION aws s3api delete-bucket --bucket $LOKI_BUCKET_NAME --region $AWS_DEFAULT_REGION aws s3api delete-bucket --bucket $TEMPO_BUCKET_NAME --region $AWS_DEFAULT_REGION aws s3 ls
Bash
복사
# s3 bucket 삭제 및 확인

6.2. Terraform 삭제

Terraform 자원 삭제
nohup sh -c "terraform destroy -auto-approve" > delete.log 2>&1 &
Bash
복사
# terraform 자원 삭제
Warning:
nohup으로 백그라운드로 실행하도록 변경했습니다. Terraform 삭제가 완료되면 정상적으로 자원 삭제 되었는지 확인을 합니다.(cat delete.log)
여기까지 3장의 첫 번째 실습인 “LGTM Observability Full Stack 구성하기” 실습을 마칩니다.
수고하셨습니다 :)