KubeDay 2022 - Distributed Tracing Integration with OpenTelemetry and Knative
James Falkner
- Technical Product management and marketing for hybrid platform product (Openshift, Jboss)
- Redhat
Daniel Oh
- Developer Advocate / CNCF Ambassador.
- Focused on k8s, serverless, serviceMesh / cloud-native runtime
- Redhat
Production level 수준으로 knative에서 openTelemetry 적용하는 방법을 설명하는 영상인 줄 알았는데, OpenTelemetry 소개하고 knative에 연결하는 정도로만 영상이 마무리돼서 조금 실망한 강연. 그냥 PoC 정도잖아..
OpenTelemetry 소개
Observability : You can See & Understand what you're seeing.
- 우리가 개발한 시스템을 더 준수하게 만들기 위해 필요함.
- 중요한 Challenge 중 하나: What you are going to possibly ask in the future before the time comes to ask the question
- Defining the types of data you can collect / observe.
User 입장에서 Observability로 정답을 얻고 싶은 질문은 대개 위와 같다.
- Application 상태는 현재 어떠한지
- Error / Defect의 발생지점은 어디이고, 발생원인은 무엇인지
- 사용자 경험에 영향을 미치는 서비스 병목지점은 어디인지
모두가 납득할 만큼 명쾌한 설명은 아니지만, Observability를 처음 이해하는 사람에게는 보통 위의 세 가지 분류방식을 소개하곤 한다.
- Metrics: Numbers describing a particular process of activity, measured over interval of time.
- i.e) 어떤 시간대에 메모리 사용량은 어느 정도였는가.
- Logs: Immutable record of discrete events that happen over time.
- Traces (Distributed Traces): Data that shows which lines of coding is falling to gain better visibility at the individual user level for events that have occured.
- distributed tracing의 경우, 간단하게 이해하자면 '하나의 request가 어떤 서비스들을 거쳤는지 path'.
Log / Traces은 Request가 증가하면 선형적으로 (Linearly) 상승하는 반면
Metric은 무엇을 어떻게 정의했느냐에 따라 다름.
Monolitic / Mainframe 시절에는
- 대상이 되는 데이터: log files / stacktraces. 좀더 옛날에는 core dumps from kernel
- SRE는 위 데이터가 의미하는 특정 시점의 snapshot을 해석.
예전에는 각 영역 (instrument, Data collection & processing, Visualization)마다 서비스를 개발하는 Vendor사가 있었고, 프로덕트 호환이 좋지 못했다. 하나의 프로덕트를 선택하면 다른 프로덕트로 교체하는 게 어려웠음.
- 오픈소스 프로덕트가 쓸만해지고
- 좀더 부가가치가 높은 개발 (AIops라거나...)에 집중하기 위해
지금은 오픈소스를 대부분 사용하려는 편.
문제는 오픈소스도 선택지가 무지하게 많았다는 점. 이 중 어떤 건 상호보완적이고, 어떤 건 상호경쟁적 (대체재) 성격의 프로덕트다.
- Tracing 쪽에 집중한 OpenTracing.
- Define What Tracing is. -> Directed acyclic graph of spans of work with different metadata associated with each of those spans
- Define API for tracing.
- Tracing에만 집중하는 게 아니라, SDK라거나 Metric같은 Beyond Tracing 추구하던 진영 OpenCensus (일종의 full-stack support)
- collecting / storing / processing
- providing hooks for other vendors
- tracing 기능도 당연히 포함
크게 두 진영으로 각자 진행되고 있었는데, 2019년경 Merge 선언 = OpenTelemetry.
- 두 진영의 장점만을 합친다 + Full Stack Observability를 제공한다.
- Collect / Store / Analyze -> Vendor 솔루션 (DataDog같은)와 High-Level에서 경쟁할 수 있는 수준의 프로덕트.
- 여러 프레임워크 / 언어 / 라이브러리를 지원하겠다.
- 수많은 개발자들이 오픈소스에서 활동하고 있음.
- 각자 진영에서 진행하던 프로젝트는 서서히 EOL / Deprecated.
어쨌든 OpenTelemtry는 Tracing, Logging, Metric Monitoring 셋 다 지원한다.
OpenTelemetry에서 제공하는 컴포넌트 목록
- Log / Metrics / Tracing 세 가지를 전부 제공, SDK / API / Data 지원.
How to Enable Serverless Java OpenTelemetry - with Knative
Serverless App의 경우 incoming Network traffic에 따라 앱이 scale up / down된다. 즉 항상 serving중인 일반적인 앱과는 tracing / logging 방식이 달라야 함.
Quarkus : Supersonic / Subatomic Java.
- serverless 애플리케이션으로 Java는 그다지 환영받지 못했음.
- kubernetes + Container-based, Scale out이 보편화된 방식에서 JVM 기반의 자바 동작방식은 그다지 효율적이지 않음.
- Container-based 환경에서 Java를 활용하기 위해 만들어진 게 Quarkus라고 보면 됨
- Performance Tuning
- Architecture 구조 변경
아래 내용은 강연의 실습을 정리한 것. 소스코드는 https://github.com/danieloh30/otel-knative-java 참고
OpenTelemetry Setting
# docker-compose.yaml
version: "2"
services:
# Jaeger
jaeger-all-in-one:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
- "14268"
- "14250"
# Collector
otel-collector:
image: otel/opentelemetry-collector:latest
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "13133:13133" # Health_check extension
- "4317:4317" # OTLP gRPC receiver. -> Gethering Message & Send back to jaeger Server.
- "55680:55680" # OTLP gRPC receiver alternative port
depends_on:
- jaeger-all-in-one
quarkus 앱을 jaeger와 연결하기 위한 세팅. src/main/resources/application.properties
# %dev.quarkus.application.name=myservice
# %dev.quarkus.opentelemetry.enabled=true
# %dev.quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317
# %prod.quarkus.container-image.group=otel-knative-java
# %prod.quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000
# %prod.quarkus.kubernetes.deploy=true
# %prod.quarkus.kubernetes.deployment-target=knative
# %prod.openshift.expose=true
# %prod.quarkus.kubernetes-client.trust-certs=true
username=Dan
# default 설정으로도 충분하긴 한데, 예시를 위해 명시한 거라고 함.
%dev.quarkus.application.name=myservice ## jaeger가 인식하는 service name
%dev.quarkus.opentelemetry.enabled=true ## opentelemetry setting
%dev.quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317 ## collector 서버로 전송.
%prod.quarkus.kubernetes.deploy=true
%prod.quarkus.kubernetes.deployment-target=knative
%prod.quarkus.container-image.group=otel-knative-java
%prod.quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000
%prod.quarkus.openshift.route.expose=true
%prod.quarkus.kubernetes-client.trust-certs=true
- 예시 프로젝트의 pom.xml에서는 quarkus-openshift dependency를 사용함. https://github.com/danieloh30/otel-knative-java/blob/ee07a5980f24c40ccb38cd0042ac2c1c9a7c0531/pom.xml#L43
quarkus build
명령어로 packaging -> containerizing -> deploying to openshift k8s cluster 까지 한 번에 진행.
배포를 진행하면, knative serving yaml의 옵션에 tracing 옵션이 추가된 것을 볼 수 있다.
OpenTelemetry CR의 옵션을 보면 receiver로 jaeger 설정이 포함된 것을 확인할 수 있다.
다시말해
- knative 애플리케이션에 tracing 옵션으로 opentelemetry collector를 연결하고
- opentelemetry collector는 knative app으로부터 데이터를 받아 jaeger로 전송함.
- serverless 여부를 고민하지 않아도 된다. 연결되면 알아서 tracing / logging 해줌
Q&A 세션 내용
Q. health check과 같은 API Call은 tracing할 필요가 없는 경우가 있음. 그럴 땐 어떻게 함?
- OpenTelemetry Collector Configuration에서 설정할 수 있음. filter out 가능.
- 또는 service mesh에서 특정 엔드포인트는 trace 대상에서 제외한다거나.
- 적용할 수 있는 layer가 굉장히 많을 것.