4W - 오픈텔레메트리 기반 트레이싱 예거 시각화, 키알리 시각화
개요
이번에는 서비스 메시에서 정말 중요한 모니터링 대상 중 하나인 트레이스를 알아본다.
25년 현재 트레이싱 도구, 표준의 De Facto는 오픈텔레메트리인데, 이걸 활용해 볼 것이다.
마지막으로 간단하게 여태까지 편하게 서비스 메시 환경을 볼 수 있게 도와준 서비스 메시 전문 시각화 툴, 키알리도 간단하게 짚는다.
사전 지식
트레이스(Trace)란?
트래픽, 혹은 프로세스 등의 어떤 실제나 논리적 작업의 흐름을 말한다.
분산 아키텍쳐에서는 하나의 프로세스가 모든 로직을 담당하지 않는 경우가 왕왕 있다.
가령 어떤 유저가 자신의 글을 확인하는 api를 요청했다고 해보자.
어떤 아키텍처에서는 먼저 게이트웨이에 이 요청이 온 후에 인증 서버, 인가 서버를 거쳐 유저의 요청을 허용할지 말지를 정한다.
이후에는 디비와 통신하는 서버로 요청이 들어가고, 샤딩된 디비에서는 어떤 디비에서 데이터를 가져올지 정한다.
이런 식의 일련의 트래픽이 발생할 때, 정확하게 어떤 프로세스가 어떤 요청을 받았는지 추적하고 이를 측정하는 것이 바로 trace이다.
트레이스는 복수의 주체가 있을 때 이들 간의 통신에 대한 정보를 보이는 것을 목표로 하기 때문에, 해당 통신이 이어지고 있다는 단서가 필요하다.
이 단서란 것을 조금 더 개념화시키면 흔히 문맥(context)이라고 표현하는데, 아무튼,
이렇게 작업의 흐름이 이어지는 것을 나타내는 단서를 span이라고 한다.
가령 http요청에 대해 헤더에 어떤 고유한 span 값을 붙이고 다음 서버로 전달하는 것이다.
그러면 스팬 데이터를 공유하는 모든 요청은 궁극적으로 하나의 요청이니 이를 추적하는 것이 가능해진다.
이렇게 현재 작업의 상태를 넘겨서 추적할 수 있게 만드는 과정을 문맥을 전파한다하여 context propagation이라고 부른다.
스팬(span)
트레이스, 즉 추적을 하기 위해서는 추적이 될 수 있도록 하는 단서가 필요하다.
이때 사용되는 것이 바로 span이다.
스팬은 서비스나 구성 요소 내에서 한 작업 단위를 나타내는 데이터 모음, 로그를 말한다.
이 값은 마치 연결 리스트마냥 이전 요청에서 들어온 id를 가진다던가 하는 방식으로 꼬리를 물고 추적할 수 있도록 돼있다.
{
"name": "hello",
"context": {
"trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",
"span_id": "051581bf3cb55c13"
},
"parent_id": null,
"start_time": "2022-04-29T18:52:58.114201Z",
"end_time": "2022-04-29T18:52:58.114687Z",
"events": [
{
"name": "Guten Tag!",
}
]
}
이런 어떤 데이터가 있다 해보자.
context 부분에 trace_id와 span_id가 들어갔고, 그 아래에 parent_id는 없다.
이것을 부모가 없다하여 루트 스팬이라 부른다.
{
"name": "hello-greetings",
"context": {
"trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",
"span_id": "5fb397be34d26b51"
},
"parent_id": "051581bf3cb55c13",
"start_time": "2022-04-29T18:52:58.114304Z",
"end_time": "2022-04-29T22:52:58.114561Z",
"events": [
{
"name": "hey there!",
"timestamp": "2022-04-29T18:52:58.114561Z",
},
{
"name": "bye now!",
"timestamp": "2022-04-29T18:52:58.114585Z",
}
]
}
그렇다면 이 데이터는 어떤가?
위의 루트 스팬의 id를 parent_id로 가지고 있다.
이 데이터는 루트 스팬의 자식 스팬이 되는 것이다.
이렇게 스팬을 통해 각 데이터간의 위계를 명확하게 파악할 수 있다.
그러면서 전체는 하나의 trace_id를 가지므로, 궁극적으로는 하나로 봐야한다는 것을 확인할 수 있게 되는 것이다!
스팬의 형식
내가 아는 범주에서만 해도, HTTP 헤더로 붙는 스팬 규격 종류는 다양하다(다른 것들도 있긴 할 것이다).
- W3C - W3C에서 지정한 표준 형식으로, 오픈텔레메트리에서도 채택한 형식[1]
- traceparent - {버전}-{트레이스 id}-{부모 스팬 id}-
- 벤더 중립적인 트레이스의 필수 정보
- 전부 16진법으로 인코딩된다.
- tracestate
- 벤더 별, 운영 조직 별 커스텀할 수 있는 정보
- 맘대로 키값쌍 때려박으면 된다.
- traceparent - {버전}-{트레이스 id}-{부모 스팬 id}-
- B3 - Zipkin에서 지정한 형식[2]
- 이전에 쓰던 방식은 각각 헤더가 있었다.
- X-B3-Traceid, X-B3-Spanid, X-B3-Parentspanid, X-B3-Sampled, X-B3-Flags
- 그나마 최신 방식은 하나의 헤더를 사용한다.
- b3 : {트레이스 id}-{스팬 id}-{샘플링 비율}-
- 이전에 쓰던 방식은 각각 헤더가 있었다.
- Jaeger
- uber-trace-id : {트레이스 id}:{스팬 id}:{부모 스팬 id}:
오픈텔레메트리가 굉장히 유명해지면서 기여도 활발하게 일어났고, 이에 따라 빠르게 발전했다.
워낙에 형식을 잘 정의하기도 해서 그런지, 점차 다른 툴들도 오텔의 형식을 지원하거나, 아예 오텔의 형식을 베이스로 하는 케이스가 늘어나고 있다.
OpenTelemetry란?
오픈텔레메트리는 관측 가능성을 위한 오픈소스 api, sdk, 툴의 집합체이다.
관측 가능성을 위한 하나의 프로토콜 표준이자, 개발 도구이면서 시스템 도구라는 것이다.
그만큼 광범위한 내용을 담고 있고 다양한 생태계를 확보하고 있으며, 용어 하나에 많은 의미를 담고 있다.
- 모든 요소들에 대한 명세서
- 텔레메트리 데이터 형식을 지정하는 표준 프로토콜
- 데이터 형식과 이름 양식을 지정하는 컨벤션
- 위의 각 요소를 활용해 개발하기 위한 언어 개발 환경(SDK)
- 라이브러리와 프레임워크로 이루어진 에코시스템
- 제로 코드로 데이터를 생성하는 자동 도구
- 데이터를 수집하고 처리하는 컬렉터
굳이? 싶을 정도로 한 용어에 알차게 많은 개념을 담았다.
결국 관측 가능성을 위한 프로토콜을 정의하면서 관련한 코드를 개발할 수도 있는 한편, 코드 없이 운영적 관점에서 데이터를 생성해낼 수도 있고 전반 시스템을 구축할 수도 있고..
관측 가능성의 필요성이 대두된 이후, 다양한 시도와 생태계가 난립하는 관측 가능성 춘추 전국시대에 구국을 위해 등장한 오픈텔레메트리.
원래는 OpenTracing, OpenCensus라는 별개의 두 가지 프로젝트가 있었는데 CNCF에 프로젝트가 병합되어 기증되며 오텔이 생겨나게 됐다.
두 프로젝트는 데이터를 보내고 수집하는 등의 표준을 지정하고자 했고, 이들의 결합으로 비로소 다양한 케이스를 커버할 수 있고, 나아가 확장이 용이한 시스템이자 프로토콜, 툴로서의 오픈텔레메트리가 만들어지게 됐다.
오픈텔레메트리의 특징
오픈텔레메트리는 다음의 특징을 가진다.
- 벤더 중립적
- 개발자든, 운영자든 이를 위한 구축과 개발을 진행할 수 있다.
- 개발자는 자신의 로직에 관련 세팅을 추가한다.
- 운영자는 전반 아키텍쳐를 구축하고, 코드를 건드리지 않으면서 최대한 데이터를 수집할 수 있도록 에이전트를 배포한다.
- 그래서 zero code, code based, libraries라 계측 도구를 자유롭게 정의할 수 있다.
- 언어, 인프라, 런타임 환경 등 어떤 것에서든 데이터를 가져올 수 있도록 정의한다.
- 관측 가능성의 모든 시그널 유형을 아우른다.
- Trace, Log, Metric 등 모든 데이터의 양식을 지정하고 방향성을 제시한다.
- 현재 가장 성숙하게 발전된 것은 Trace이고, 점차 Log도 안정화단계로 접어들 것으로 생각된다.
계측(instrumentation) 방법
오픈텔레메트리에서는 여러 방법으로 데이터를 계측할 수 있도록 지원하고 있다.
코드 베이스
개발자가 어플리케이션을 개발하며 내부에서 오텔 api를 사용해 데이터를 만들고 전달한다.
오텔 sdk를 이용해 관련 설정들을 코드 내부에 구현하여 사용하는 방식이다.
그럼 직접 api를 정의하고, sdk고 데이터를 만들고 외부로 전파하는 것까지 전부 직접 구현하면 된다!
그렇다면 다른 오텔 호환 툴들에서 시그널들을 활용할 수 있게 될 것이다.
제로 코드
(대체로) 개발자가 이미 만들어진 라이브러리를 런타임에 포함해 알아서 데이터를 전달하는 방식이다.
운영자 입장에서 편리하게 세팅할 수 있다는 장점이 있다.
다만 상세한 커스텀은 힘들 것이다.
제로코드는 이렇게 이미 잘 만들어진 번들을 어플리케이션 런타임에 주입하는 것이다.
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
opentelemetry-instrument \
python myapp.py
파이썬으로 치면 이런 식으로 실행한다.
이러면 내부 코드 중에 requests, flask 등의 코드가 들어가는 지점마다 자동으로 오텔 관련 코드가 주입된다.
Go 언어의 경우도 이렇게 하는 게 가능한데, 이렇게 컴파일된 채 실행되는 프로그램의 경우, eBPF를 활용해서 네트워크 스택 호출, 프로세스 작업 전환 등의 케이스에 대해 필요한 작업들을 수행한다.
(이래서 go instrument의 경우 루트 권한으로 실행돼야 한다.)
이번 실습에서는 제로 코드 방식을 이용해 트레이싱 데이터를 만들어낼 것이다!
오픈텔레메트리 오퍼레이터
OpenTelemetry를 위한 오퍼레이터.
구체적으로는 오텔 컬렉터, 오토 인스트루멘탈을 관리해준다.
깊게 다루지는 않겠다.
Jaeger란?
예거는 관측 가능성 중 트레이싱 지표를 시각화해주는 도구이다.
Uber Technologies에서 개발됐으며 2016년에 CNCF에 기증되어 지금은 졸업했다.
트레이싱 시각화 맛집이다.
그러나 사실 단순한 시각화 툴이 아니라, 트레이스를 위한 컬렉터와 데이저 저장까지 아우르는 아키텍쳐를 가지고 있다.
즉 예거라는 툴을 하나로 보았을 때 예거는 다음의 기능을 지원한다.
- 트레이스 시그널 컬렉터
- OpenTelemetry의 컨텍스트인 W3C TraceContext, Zipkin의 B3 헤더 전부 인식할 수 있다.
- 수집한 데이터를 가공해 바로 데이터베이스로 보내거나, 카프라를 거쳐서 저장한다.
- 트레이싱 시각화
기본적으로는 OTel의 전신이 OpenTracing의 설정을 따르는 방식에 대해 트레이싱을 지원했으나, 이제는 OTLP(오픈텔레메트리 프로토콜)도 지원한다.
24년 말 V2로 올라오면서 기본 베이스 설정도 오텔 기반으로 바뀌었다.[3]
아키텍처에 대한 더 자세한 내용은 Jaeger 참고.
실습 진행
오텔 오퍼레이터, 예거 세팅
최신에 나온 예거 v2를 세팅해보자.
이번에는 오텔을 활용할 것이므로 아예 오픈텔레메트리 오퍼레이터를 활용한다.
# 서트 매니저와 오픈텔레메트리 오퍼레이터 설치
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
위 예시 파일에서는 서트 매니저를 같이 설치해야 하는데, 어드미션 웹훅에서 api 서버와 통신에 사용할 인증서를 세팅하기 위함이다.
한꺼번에 세팅하면 서트매니저가 세팅되는 시간 때문에 에러가 보일 수도 있으니, 살짝 텀을 두고 적용하는 것을 추천한다.
이렇게 세팅되면 성공.
kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: jaeger-inmemory-instance
spec:
image: jaegertracing/jaeger:latest
ports:
- name: jaeger
port: 16686
config:
service:
extensions: [jaeger_storage, jaeger_query]
pipelines:
traces:
receivers: [otlp]
exporters: [jaeger_storage_exporter]
extensions:
jaeger_query:
storage:
traces: memstore
jaeger_storage:
backends:
memstore:
memory:
max_traces: 100000
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
jaeger_storage_exporter:
trace_storage: memstore
EOF
그 다음에는 예거를 세팅한다.
예거 자체를 오픈텔레메트리 컬렉터로서 활용하는데, 올인원 형태로 세팅하여 시각화까지 가능하게 하는 세팅이다.
원래는 데이터베이스를 배치할 수도 있으나, 실습에서는 간단하게 인메모리 형태로 설치한다.
예거는 이제 오텔의 따까리가 돼버렸다..
kubectl patch svc jaeger-inmemory-instance-collector -p '{"spec": {"type": "NodePort", "ports": [{"port": 16686, "targetPort": 16686, "nodePort": 30004}]}}'
이렇게 세팅된다면 일차적으로 성공이다.
오퍼레이터의 커스텀 리소스로 예거가 배치된 것을 확인할 수 있다.
실제로는 해당 리소스의 설정을 기반으로 예거 워크로드가 배치될 뿐이다.
현재 세팅 상에서는 한 예거 프로세스가 ui, 컬렉팅, 저장 모든 기능을 하고 있어 이 예거의 주소를 프로바이더로 이스티오에 전달하면 된다.
트레이싱 이스티오 연동
enableTracing: true
defaultProviders:
tracing: []
extensionProviders:
- name: jaeger
opentelemetry:
port: 4317
service: jaeger-inmemory-instance-collector.istioinaction.svc.cluster.local
트레이싱을 위해서는 일단 트레이싱 프로바이더를 이스티오 오퍼레이터에 등록하는 과정이 필요하다.
간단하게 예거를 등록해주면 되는데, 실질적으로 예거의 탈을 쓴 오텔을 쓸 것이므로 필드에는 opentelemetry
라고 적어준다.
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
namespace: istio-system
name: tracing
spec:
tracing:
- providers:
- name: jaeger
randomSamplingPercentage: 20.0
customTags:
my_tag:
literal:
value: "zerotay"
그 다음 트레이싱을 적용하는 텔레메트리 리소스를 만들어주면 끝이다.
그냥 실험해보고 싶어서 커스텀 태그도 달았다.
httpbin을 활용한 트레이싱 확인
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
- "httpbin.istioinaction.io"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: thin-httbin-virtualservice
spec:
hosts:
- "httpbin.istioinaction.io"
gateways:
- coolstore-gateway
http:
- route:
- destination:
host: httpbin.org
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-httpbin-org
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
location: MESH_EXTERNAL
resolution: DNS
이제 제대로 세팅이 됐는지 확인하기 위해, 간단하게 트래픽을 외부로 보내어 헤더가 어떻게 돌아오는지 확인해볼 것이다.
책의 예제는 외부의 httpbin 서버로 트래픽을 보내는데, 좋은 방법인 것 같아서 그대로 사용했다.
SIMPLEWEB="httpbin.istioinaction.io"
curl -s http://$SIMPLEWEB:30000 --resolve "$SIMPLEWEB:30000:127.0.0.1"
사용하려 했는데.. 해당 사이트에 현재 문제가 있는 건지 응답이 엄청 느리게 온다..
아무래도 사람들이 많이 사용해서 부하가 걸리고 있는 게 아닐까 싶다.
간단하게 웹 상으로 확인해보려고 하는데에만 1분 가량 걸렸다.
apiVersion: v1
kind: Service
metadata:
name: httpbin
spec:
selector:
app: httpbin
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: httpbin
labels:
app: httpbin
spec:
containers:
- name: httpbin
image: kennethreitz/httpbin
ports:
- containerPort: 80
protocol: TCP
restartPolicy: Always
그래서 해당 서버에 민폐 그만 주고 그냥 클러스터에 배포하기로 마음 먹었다.
서비스엔트리 리소스는 없애고 버츄얼 서비스에는 mesh 설정과 호스트 값 정도만 세팅해준다.
이렇게 나오면 성공이다.
오픈텔레메트리의 기본 헤더인 Traceparent
와 Tracestate
값이 확인된다.
이 값은 매번 달리는데 샘플링으로 인해 예거에 저장되는 건 5개 중 하나일 것이다.
몇 번 요청을 보내니 예거에 해당 트레이스가 전송되어 이제 추적이 가능해졌다.
매우 간단한 트레이스다.
내가 마음대로 넣은 my_tag: zerotay
도 확인된다!
httpbin 쪽의 스팬ID 중에서는 아까 발생시킨 요청의 헤더에 달렸던 값이 있을 것이다.
운 좋게 가장 마지막으로 날렸던 요청에 대해 샘플링이 된 모양이다.
Traceparent
부분의 3번째 자리에 해당 ID가 확인된다.
심플 메시 서버를 이용한 트레이싱 실습
4W - 번외 - 트레이싱용 심플 메시 서버 개발을 통해 나만의 작은 서버를 만들었다.
이 서버는 url을 기반으로 트래픽을 연속적으로 발생시켜 트레이싱 실습을 하기에 적합하도록 개발됐다.
해당 내용은 너무 딴 이야기라서 따로 뺐지만, 아래 내용을 위해서는 간단하게 읽어두는 것이 좋다.
컨테이너 이미지에 제로코드 인스트루멘트 세팅
오텔에서는 제로코드 인스트루멘트 도구를 제공해준다고 했으니, 이를 활용해볼 것이다.
이미 서버 로직도 다 짠 마당에 그냥 코드 안에 삽입도 못할 건 없긴 하지만, 그래도 제로코드가 돌아가는 동작 원리를 자세히 구경해보고 싶기도 했다.
uv add opentelemetry-distro opentelemetry-exporter-otlp
uv run opentelemetry-bootstrap -a requirements | uv add -r -
uv run opentelemetry-instrument python myapp.py
위 명령어들을 순차적으로 수행한다.
기본 문서에서는 uv pip를 사용하나, 나는 이미 프로젝트 단위 의존성관리를 하고 있던 관계로 add를 활용했다.
처음에는 그냥 세팅을 위한 기본적인 의존성만이 설치된다.
그러나 부트스트랩 명령어를 거치면 현재 의존성으로 엮인 라이브러리들을 읽은 후에 이를 위한 추가 의존성을 세팅해준다.
uv tree
많은 의존성들이 세팅된 것을 확인할 수 있다.
# Use a Python image with uv pre-installed
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
# Install the project into `/app`
WORKDIR /app
# Enable bytecode compilation
ENV UV_COMPILE_BYTECODE=1
# Copy from the cache instead of linking since it's a mounted volume
ENV UV_LINK_MODE=copy
# Install the project's dependencies using the lockfile and settings
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project --no-dev
# Then, add the rest of the project source code and install it
# Installing separately from its dependencies allows optimal layer caching
ADD . /app
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"
CMD ["uv", "run", "opentelemetry-instrument", "python", "main.py"]
그 다음에는 오텔 공식 문서에 나온 내용을 그대로 옮겨 넣어 이미지를 만들었다.
의존성 설정은 bootstrap을 거치며 이미 완료됐기 때문에 이를 sync 명령어를 통해 컨테이너 환경에서 다시 세팅만 하면, 위와 같이 opentelemetry-instrument 명령을 통해 오텔 데이터를 만들어낼 수 있다.
docker build -t zerotay/simple-mesh:1.0.0 .
docker push zerotay/simple-mesh:1.0.0
기본이 distroless 이미지라서 그런지 크기가 굉장히 경량이었다.
apiVersion: v1
kind: Service
metadata:
name: a
spec:
selector:
app: a
ports:
- protocol: TCP
port: 80
targetPort: 9090
---
apiVersion: v1
kind: Pod
metadata:
name: a
labels:
app: a
spec:
containers:
- name: a
image: zerotay/simple-mesh:1.0.5
env:
- name: HOST
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: ADDRESS
value: "0.0.0.0"
- name: PORT
value: "9090"
- name: DELAY
value: "0.5"
- name: OTEL_SERVICE_NAME
value: a
- name: OTEL_TRACES_EXPORTER
value: console,otlp
- name: OTEL_METRICS_EXPORTER
value: console
- name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
value: jaeger-inmemory-instance-collector.istioinaction.svc:4317
남은 일은 이제 클러스터에 이 서버를 배포하는 일이다!
여기에 환경 변수 세팅을 조금 해주었는데, 오텔 관련 부분들은 오토 인스트루멘트를 위한 세팅으로 트레이스를 만들고 이를 예거로 보내도록 하는 설정이다.
메트릭은 콘솔로 출력될 수 있게 설정한 건데 이건 적용이 잘 되지 않았다.
아무튼 이 서버들을 여러 개 배치해서 본격적으로 테스트를 해본다.
이 이미지를 그대로 이용하고자 한다면 기왕이면 파드 이름을 간단하게 두는 것을 추천한다.
그래야 url로 적는 길이가 줄어들어서 실습이 편해지기 때문이다.
아울러, 초기 이미지 버전을 사용하면 이렇게 제대로 컨텍스트 전파가 안 되지 않을 수 있다.
문서를 보니 코드 수정에 따라 자동으로 reload를 하도록 세팅돼있는 경우 동작이 제대로 이뤄지지 않는다고 해서 버전 업데이트를 하며 이걸 수정해줬다.
제대로 동작하긴 한다.
굉장히 모양 빠지긴 하지만..!
각 서버에 지연 시간을 조금 더 부여했다.
그런데 보통 저 검은 선이 실제 해당 서버로 인해 트래픽이 지연된 시간을 나타낼 때 사용되는데, 이런 부분의 시각화가 제대로 이뤄지진 않았다.
조금 더 데이터를 보았을 때도 스팬 id에 문제가 있다고 출력되고 있다.
오텔 오퍼레이터 Instrument 리소스 활용
내 이미지 1.0.x버전은 제로코드 인스트루멘트를 이미지 단에서 삽입하는 방식으로 진행했다.
이번에는 오텔 오퍼레이터 측에서 제공하는 인스트루멘트 자동 주입 기능을 활용해본다.
이를 위해 이미지 1.1.0버전부터는 이미지 단에 인스트루멘트 설정을 넣지 않는다.
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: python-instrument
spec:
exporter:
endpoint: jaeger-inmemory-instance-collector.istioinaction.svc:4317
propagators:
- tracecontext
- baggage
대신 오텔 오퍼레이터에서 제공하는 Instrumentation 리소스를 사용할 것이다.
필수적인 필드만 넣어서 만들었지만, 여기에 각 언어 별로 필드를 추가해 커스텀 설정을 하는 것이 가능하다.[4]
가령 python
필드를 넣어서 어떤 이미지를 쓸 것인지, 초기화 컨테이너의 자원 사용량은 어떻게 할 것인지등을 커스텀할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: a
annotations:
instrumentation.opentelemetry.io/inject-python: "true"
labels:
app: a
위 리소스를 만들었으면 주입을 바라는 파드에 어노테이션을 이렇게 달아주면 된다.
허허.. 이스티오 iptable 초기화 컨테이너, 사이드카 컨테이너에 오텔 세팅 컨테이너까지 해서 이제는 초기화 컨테이너만 세 개다..
양식을 조금 뜯어봤는데, 기존 컨테이너의 환경 변수에 몇 가지 값을 주입하는 것이 보인다.
초기화 컨테이너 양식은 이것 뿐이다.
눈으로만 봤을 때는 그저 오토 인스트루멘트 관련 파일을 옮기는 작업밖에 없는 것 같다..?
이게 앱 컨테이너가 실행되기 전에 일어난다고 해서 어떻게 인스트루멘트가 된다는 건지
모르겠지만 된다?
도저히 말이 안 된다고 생각해서 조금 더 봤는데, 알고보니 앱 컨테이너 쪽에 환경변수로 파이썬 실행 경로를 바꾸는 것을 볼 수 있었다.
이전에는 제대로 세팅되지 않았던 메트릭에 대한 값도 표준 출력으로 찍힌다.
Instrumentation 리소스에는 어떤 시그널만 설정하겠다 하는 옵션이 없었는데, 아무래도 그로 인해 메트릭까지 설정이 돼버린 모양이다.
키알리 오퍼레이터 세팅
마지막으로는 간단하게 키알리를 세팅하는 것만 하고 마치려고 한다.
helm repo add kiali https://kiali.org/helm-charts
helm install \
--namespace kiali-operator \
--create-namespace \
kiali-operator \
kiali/kiali-operator
키알리도 오퍼레이터가 있으며, 문서에서도 이걸 활용하기를 권장하고 있으니 이걸로 세팅해본다.
키알리 리소스가 이스티오 루트 네임스페이스에 들어가도록 세팅했다.
키알리 리소스를 describe 해보면 progress 값이 계속 바뀐다.
대충 확인해봤는데 5 단계 정도까지 있는 것 같다.
기왕 리소스 만들었으면 get으로도 편하게 볼 수 있게 좀 해줬으면
여태 K9s 써봤자 효용이 크지 않다는 입장이었는데, 이런 커스텀 리소스를 접하게 되니 어떤 요청이든 오토 리로드를 해주는 k9s의 저력이 절실하게 느껴지기 시작했다.
a에서 b와 c로 갔다가 다시 a로 또 요청을 보내는 괴상한 구조라, 그래프도 괴상하게 나온다.
아래 빨간 부분은 예거 연동이 아직 제대로 안 돼서 나온 에러.
예거와 키알리를 연동하는 과정에서 계속 문제가 발생했다.
오텔로 예거를 배포하는 것에 문제가 있는 건지, 예거 v2가 키알리와의 연동에서 문제가 있는 건지, 아니면 그냥 내가 세팅을 잘못 한 건지 명확하게는 파악하지 못했다.
아무튼 문제를 해결하고자 gRPC가 아닌 http를 통해 통신을 하도록 설정했고, 그러자 문제가 해소됐다.
결론
본문에는 담지 못했는데, 이스티오 환경에서 설정만 하면 엔보이가 알아서 트레이스 헤더를 붙여서 트래픽을 전달한다.
다만 제대로 하나의 문맥으로 인식되기 위해서는 어플리케이션 단에서도 엔보이로부터 들어온 헤더가 그대로 붙어서 나갈 수 있도록 세팅을 해야 한다.
이번 실습에서는 오텔의 제로코드 인스트루멘트를 통해 이 조건을 충족시킨 것이다.
트레이싱은 트래픽의 지연 지점, 병목 현상이 발생하는 포인트를 명확하게 파악할 수 있도록 도와주기 때문에 상당히 유용한 데이터이다.
트레이싱 자체는 각 트래픽에 간단한 헤더를 붙이는 방식으로 세팅이 이뤄지나, 관련한 통계 정보를 중앙 수집 장치에 전달하는 주체(서버 미들웨어, 엔보이 등)의 숫자가 많고 넣는 데이터 양도 상당하기 때문에, 대체로 트레이싱을 샘플링을 통해 만들어지는 데이터의 양을 줄이는 식으로 운용된다.
이스티오에서 트레이싱 관련해서 할 수 있는 세팅은 커스텀 태그를 다는 것과 샘플링 비율을 설정하는 것인데, 실제로 트레이싱 데이터를 더 유용하게 활용하려면 결국 코드 단에서도 컨텍스트를 구분시키고 전파하는 세팅을 해야 한다고 생각한다.
이전 글, 다음 글
다른 글 보기
이름 | index | noteType | created |
---|---|---|---|
1W - 서비스 메시와 이스티오 | 1 | published | 2025-04-10 |
1W - 간단한 장애 상황 구현 후 대응 실습 | 2 | published | 2025-04-10 |
1W - Gateway API를 활용한 설정 | 3 | published | 2025-04-10 |
1W - 네이티브 사이드카 컨테이너 이용 | 4 | published | 2025-04-10 |
2W - 엔보이 | 5 | published | 2025-04-19 |
2W - 인그레스 게이트웨이 실습 | 6 | published | 2025-04-17 |
3W - 버츄얼 서비스를 활용한 기본 트래픽 관리 | 7 | published | 2025-04-22 |
3W - 트래픽 가중치 - flagger와 argo rollout을 이용한 점진적 배포 | 8 | published | 2025-04-22 |
3W - 트래픽 미러링 패킷 캡쳐 | 9 | published | 2025-04-22 |
3W - 서비스 엔트리와 이그레스 게이트웨이 | 10 | published | 2025-04-22 |
3W - 데스티네이션 룰을 활용한 네트워크 복원력 | 11 | published | 2025-04-26 |
3W - 타임아웃, 재시도를 활용한 네트워크 복원력 | 12 | published | 2025-04-26 |
4W - 이스티오 메트릭 확인 | 13 | published | 2025-05-03 |
4W - 이스티오 메트릭 커스텀, 프로메테우스와 그라파나 | 14 | published | 2025-05-03 |
4W - 오픈텔레메트리 기반 트레이싱 예거 시각화, 키알리 시각화 | 15 | published | 2025-05-03 |
4W - 번외 - 트레이싱용 심플 메시 서버 개발 | 16 | published | 2025-05-03 |
5W - 이스티오 mTLS와 SPIFFE | 17 | published | 2025-05-11 |
5W - 이스티오 JWT 인증 | 18 | published | 2025-05-11 |
5W - 이스티오 인가 정책 설정 | 19 | published | 2025-05-11 |
6W - 이스티오 설정 트러블슈팅 | 20 | published | 2025-05-18 |
6W - 이스티오 컨트롤 플레인 성능 최적화 | 21 | published | 2025-05-18 |
8W - 가상머신 통합하기 | 22 | published | 2025-06-01 |
8W - 엔보이와 iptables 뜯어먹기 | 23 | published | 2025-06-01 |
9W - 앰비언트 모드 구조, 원리 | 24 | published | 2025-06-07 |
9W - 앰비언트 헬름 설치, 각종 리소스 실습 | 25 | published | 2025-06-07 |
7W - 이스티오 메시 스케일링 | 26 | published | 2025-06-09 |
7W - 엔보이 필터를 통한 기능 확장 | 27 | published | 2025-06-09 |
관련 문서
이름 | noteType | created |
---|---|---|
Jaeger | knowledge | 2025-04-29 |