개요
안녕하세요. 오늘은 회사에서 PoC를 진행했던 O-Tel을 통한 Observalbility 구성하기 중 .Net Core App을 대상으로 Trace 메트릭을 수집하는 방법에 대해 정리하고자 합니다. 공식 문서를 참고하며 구성하였고, PoC를 진행했던 것보단 최소한으로 핵심적인 것들만 정리해 보려 합니다.
아키텍처
구현 목표
이번 글에서의 흐름은 아래와 같이 진행됩니다.
1. kind를 통해 간단한 kubernetes 클러스터를 생성합니다.
2. Trace Metrics을 확인하기 위한 Grafana를 설치합니다.
3. Trace Metrics의 수집, 저장을 위한 Tempo를 설치합니다.
4. Open Telemetry Collector를 설치하고, Trace Metrics 자동 수집을 위한 CRD를 구성합니다.
5. .Net Application을 배포합니다. 이 때 Trace Metrics을 자동 수집해주기 위한 Annotation을 설정합니다.
6. Grafana에서 Tempo 데이터를 추가하고, 조회 합니다.
쿠버네티스 환경에서 .Net Application의 별도 코드 수정 없이, O-Tel 구성을 통해 Trace Metrics을 자동 수집하는 것을 목표로 합니다.
참고로 .Net Application에 O-Tel SDK를 구성하여 수집할 메트릭을 직접 정의할 수도 있습니다.
구현하기
Step 1. Kind로 간단한 Kubernetes 클러스터 생성하기
아래 사진처럼 kind로 간단한 Kubernetes 클러스터를 생성합니다. kind는 로컬 환경에서 소규모로 kubernetes 클러스터를 간단히 생성할 수 있게 도와주며, 처음 접해보신다면 공식 문서를 참고하여 설정해 보시기 바랍니다.
Step 2. Grafana 설치하기
Trace Metrics을 시각화 하여 볼 수 있도록 공식 문서를 참고하여 Helm을 통해 Grafana를 설치합니다.
먼저 Helm 설치가 안되어 있다면, Helm을 설치합니다.
그 다음 아래 명령을 통해 Grafana repo를 등록합니다.
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
Grafana 컴포넌트를 설치할 네임스페이스를 생성하고, Grafana 설치를 진행합니다.
kubectl create namespace monitoring
helm install my-grafana grafana/grafana --namespace monitoring
설치가 정상적으로 완료되었는지 확인합니다.
관리자 비밀번호를 확인하기 위해 secret 데이터를 조회합니다.
kubectl get secret --namespace monitoring my-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
새로운 터미널을 띄우고 `kubectl port-forward` 명령을 사용하여 Grafana 대시보드에 접근할 수 있도록 합니다. 호스트 포트에 접근하여 Grafana에 접근합니다. 이 때 로그인 ID는 `admin` 이고, 비밀번호는 위에서 확인한 비밀번호를 입력합니다.
kubectl port-forward -n monitoring services/my-grafana 30080:80
Step 3. Tempo 설치하기
Trace 메트릭을 받고, 저장, 관리할 수 있도록 Tempo를 설치합니다. Tempo는 Grafana와 같은 Helm repo를 사용하기 때문에 윗 단계에서 repo add를 진행하였다면 바로 설치할 수 있습니다.
먼저 `vi values.yaml`을 통해 Tempo 설치에 사용될 Helm value 파일을 생성합니다.
traces:
otlp:
http:
enabled: true
receiverConfig: {}
grpc:
enabled: true
receiverConfig: {}
global_overrides:
metrics_generator_processors:
- service-graphs
아래 명령어로 Tempo를 설치하기 위한 네임스페이스를 생성 및 설치를 진행합니다.
kubectl create namespace tempo
helm -n tempo install tempo grafana/tempo-distributed -f values.yaml
설치가 정상적으로 완료되었는지 확인합니다.
Step 4. Opentelemetry Collector 설치 및 CRD(Auto-Instrument) 구성하기
Otel Operator 설치 및 Otel Collector 설치하기
Open Telemetry Collector의 경우 Helm 설치와 Operator를 통한 설치가 가능합니다. Helm을 통한 구성이 무조건 안되는 것인지는 모르겠으나 저의 경우 Helm을 통해 구성시 실패하였고, Operator를 통해 구성 시 성공하였기에 Operator를 통한 구성으로 내용을 정리하겠습니다.
먼저 Otel-Opertaor 설치 시 Cert-manager가 선제적으로 설치되어 있어야 하기에 cert-manager를 설치해 줍니다.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml
다음으로, Otel-Operator를 설치 합니다.
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
설치가 성공적으로 완료되면 Otel CRD도 설치됩니다. 따라서 아래와 같이 `kind: OpenTelemetryCollector`인 리소스도 쿠버네티스 환경에 설치할 수 있게 됩니다. 아래 파일을 생성하고 `kubectl apply -f <filename.yaml>`을 통해 Opentelemetry Collector를 설치합니다. 저는 otel.yaml 이라는 이름으로 생성하였습니다.
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: collector
namespace: otel-trace
spec:
config: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 15
batch:
send_batch_size: 10000
timeout: 10s
exporters:
otlphttp/tempo:
endpoint: http://tempo-distributor.tempo.svc.cluster.local:4318
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/tempo]
위 Otel Collector Config를 해석 해보겠습니다. pipeline쪽을 보시면 traces 메트릭에 대해 recivers가 otlp로 구성되어 있습니다.
상단의 `config.receivers.otlp.protocols` 부분에 4317, 4318 포트로 OTLP를 리슨하는 것을 의미합니다. 아래 단계에서 .Net Application 구성 중 Trace 메트릭을 Otel Collector의 4317 혹은 4318 포트로 전송하면 될 것 입니다.
다음으로 processors가 있습니다. 수집된 데이터를 가공하는 단계 입니다. 마지막으로 exporters가 있습니다. 수집, 가공한 데이터를 tempo로 송신하게 됩니다.
이로써 유추할 수 있는 Trace 데이터의 흐름은 .Net App -> Otel-Collector -> Tempo -> Grafana를 통한 Trace 데이터 시각화 일 것 입니다.
위 YAML 파일을 작성하였다면 Otel Collector 설치를 위한 네임스페이스 생성 및 Collector 설치를 진행합니다.
kubectl create namespace otel-trace
kubectl apply -f otel.yaml
설치가 잘 되었는지 확인합니다.
Auto-Instrument 구성하기
먼저 Auto-Instrument에 대해 간략히 설명하겠습니다. Traces 메트릭은 Application의 상태 혹은 성능과 관련된 메트릭 입니다. 따라서 Trace 메트릭을 수집하기 위해서는 아래의 간단한 예시처럼 소스 코드에 Otel SDK를 적용하여 Trace 메트릭의 생성에 대해 정의해야 합니다.
반면 Auto-Instrument를 사용하면, 기존 Application의 코드 수정 없이 Traces와 관련된 메트릭을 수집할 수 있습니다.(정확히는 metrics, logs, traces 모든 메트릭에 대해 수집 가능합니다.)
기존 코드 수정없이 메트릭을 수집할 수 있기에 관리의 복잡성이 개선됩니다. 하지만 직접 코드에 정의하는 방식 보다 구성에 제약이 있어, 필요 없는 메트릭 까지 수집하게 될 수 있는 단점이 존재합니다.
Datadog에서는 별도의 Agent 설치를 통해 코드 수정 없이 APM 메트릭을 수집합니다. 쿠버네티스 환경에서의 Opentelemetry는 Instrument라는 리소스를 통해 메트릭을 수집하게 됩니다.
윗 단계에서 Opentelemetry Operator를 설치하며 Instrument를 배포할 수 있습니다. 그럼 아래의 YAML파일을 생성하고, Instrument 리소스 배포를 진행합니다.
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: dotnet-instrumentation
spec:
exporter:
endpoint: http://collector-collector.otel-trace.svc.cluster.local:4318
propagators:
- tracecontext
- baggage
sampler:
type: parentbased_traceidratio
argument: '1'
dotnet:
env:
- name: OTEL_DOTNET_AUTO_TRACES_INSTRUMENTATION_ENABLED
value: "true"
- name: OTEL_DOTNET_AUTO_METRICS_INSTRUMENTATION_ENABLED
value: "false"
- name: OTEL_DOTNET_AUTO_LOGS_INSTRUMENTATION_ENABLED
value: "false"
위 config를 살펴 보겠습니다.
- spec.exporter : Instrument에서 수집한 메트릭을 전송할 Otel Collector의 주소입니다. 이전 단계에서 생성한 Otel-Collector의 서비스 주소를 입력하였습니다.
- spec.propagators: Trace ID의 Context를 관리하기 위해 설정합니다. 만약 여러 서비스를 호출하는 MSA 구조인 Application이 존재한다면 API GW -> Backend -> DB 간의 Trace 추적을 해야할 것입니다. 이 옵션을 활성화 함으로써 1개의 요청에 대한 서비스 간 흐름을 1개의 Trace ID로 파악할 수 있습니다.
- spec.sampler: Trace 추적을 필터링 합니다. 현재 argument는 1(100%)로 모든 요청에 대한 Trace를 기록하게 됩니다.
- spec.dotnet.env: 메트릭 수집에 대한 옵션을 제공합니다. 현재는 Trace 메트릭만 수집하게 됩니다.
그럼 Instrument를 배포하고, 리소스가 잘 배포되었는지 확인합니다.
# 위 instrument yaml을 생성
kubectl apply -f instrument.yaml
# 리소스 배포 확인
kubectl get instrumentations.opentelemetry.io
Step 5. .Net Core App 배포하기
이번 글의 핵심(?)인 .Net Core Application을 배포합니다. 샘플 코드는 Opentelemetry의 문서를 참고 하였으며 핵심 로직은 아래 코드를 참고 합니다.
/rolldice를 호출하면 1~6 의 숫자 중 한 개의 숫자를 리턴하는 샘플 코드입니다.
using System.Globalization;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
string HandleRollDice([FromServices]ILogger<Program> logger, string? player)
{
var result = RollDice();
if (string.IsNullOrEmpty(player))
{
logger.LogInformation("Anonymous player is rolling the dice: {result}", result);
}
else
{
logger.LogInformation("{player} is rolling the dice: {result}", player, result);
}
return result.ToString(CultureInfo.InvariantCulture);
}
int RollDice()
{
return Random.Shared.Next(1, 7);
}
app.MapGet("/rolldice/{player?}", HandleRollDice);
app.Run();
위 .Net Core App을 컨테이너 이미지화 하였으며, 아래의 Yaml을 배포하여 deployment 리소스를 배포합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp
name: myapp-deployment
namespace: app
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-dotnet: "default/dotnet-instrumentation"
labels:
app: myapp
spec:
containers:
- image: kimhj4270/rolldice:0.1
name: myapp
ports:
- containerPort: 80
protocol: TCP
배포 후 리소스가 잘 배포되었는지 확인합니다.
kubectl apply -f app.yaml
kubectl get pod -n app
Step 6. Grafana에 Tempo 데이터 연결 및 Trace 데이터 조회하기
Tempo Datasource 추가하기
먼저 Grafana의 Connections > Data sources > Add new Data source에 접근합니다. `Tempo`를 검색하고 클릭합니다.
Connection URL에 `http://tempo-query-frontend-discovery.tempo.svc.cluster.local:3100/`를 입력합니다.
하단의 [Save & Test]를 클릭합니다. 성공적으로 데이터가 연결 됐는지 확인합니다.
Trace 데이터 조회하기
Trace 데이터를 조회하려면, Trace 데이터를 생성해야 합니다. 따라서 아래의 절차에 따라 Application에 요청을 보내 Trace 메트릭을 발생 시킵니다.
먼저 새로운 터미널에서 `kubectl port-forward` 명령으로 로컬호스트에서 App 파드로 요청할 수 있는 환경을 만들어 줍니다.
kubectl port-forward -n app pods/myapp-deployment-d7bd896fd-t6gsk 30081:80
다음으로 `curl localhost/rolldice` 명령으로 App 파드에 http 요청을 보냅니다. 사진과 같이 1~6 사일의 랜덤 숫자를 리턴 받아야 합니다.
Trace 메트릭을 발생 시켰으니 Grafana에서 확인 합니다. Explore 메뉴에 접근하고, Data Source를 Tempo로 지정합니다. Query type을 Search로 변경하면 하위에 Trace ID를 확인할 수 있습니다. Trace ID를 클릭합니다.
Trace 메트릭을 아래 사진처럼 확인할 수 있습니다.
마무리 하며
이번 글에서는 Otel과 Tempo를 사용한 Trace 메트릭 수집 과정을 살펴 보았습니다. 사실 Application의 성능 관측을 위해선 Trace 메트릭 뿐만 아니라, Metrics, Logs 메트릭도 수집하고, 대시보드화 해야 할 것입니다. Trace는 단지 최초 요청으로 부터의 서비스 호출 흐름과 시간, 실패 여부만 파악할 수 있기 때문이죠.
Metrics을 통해 HTTP 요청이 초당 얼마나 들어오는지, 1 req당 응답 시간이 얼마나 걸리는지 확인할 수 있으며, Logs를 통해 오류가 발생한 요청의 TraceID를 검색하여 Error Logs도 손쉽게 확인해 볼 수 있을것입니다. (아래는 PoC를 완료한 샘플 대시보드 입니다. 물론 공개된 대시보드를 불러와, 일부 수정해서 사용했습니다.)
여러분도 이 과정을 참고하여 Metrics과 Logs를 수집하고 대시보드화 하는데 도움이 되었으면 합니다.
감사합니다.
'클라우드' 카테고리의 다른 글
[cks][killershell] Auditing Enable Audit Logging 실습 (0) | 2024.07.31 |
---|---|
[cks][killershell] NodeRestriction 실습 (0) | 2024.07.30 |
[cks][killershell] Apiserver Crash 실습 (0) | 2024.07.29 |
[EKS] IaC (0) | 2024.04.27 |
[k8s] Pod의 전략적 배치 - Node Affinity (0) | 2024.04.17 |