더 많은 어플리케이션을 마이크로서비스로 구축할수록 비즈니스 목표 달성을 위해 협업하는 분산 구성 요소의 네트워크를 만들어가는 것이다. 요청 경로에서 문제가 발생하기 시작하면 무슨일이 일어나고 있는지 이해하는 것은 매우 중요하다. 그래야 빠르게 진단하고 고칠 수 있기 때문이다.
모놀리스에서는 무언가 오동작하기 시작하면 친숙한 도구를 사용해 디버깅할 수 있다. 디버거, 런타임 프로파일러, 메모리 분석 도구를 사용해 코드의 어느 부분이 지연이나 오작동을 유발하는지 찾을 수 있다. 하지만 분산 구조로 이루어진 어플리케이션에서는 같은 일을 하려면 새로운 도구들이 필요하다.
분산 트레이싱을 사용하면 요청을 처리하는 데 관여한 분산 시스템의 구성 요소에 대한 통찰력을 얻을 수 있다. 분산 트레이싱은 구글 대퍼 논문에서 도입한 개념이며 요청에 주석을 붙이는 작업이 포함된다. 이때 붙이는 주석은 서비스 간 호출을 나타내는 상관관계 ID와 이 서비스 간 호출 그래프를 거치는 특정 요청을 나타내는 트레이스 ID이다. 이스티오의 데이터 플레인은 요청이 데이터 플레인을 통과할 때 이런 메타데이터를 요청에 추가할 수 있다. 그리고 인식할 수 없거나 외부 개체에서 온 메타데이터는 제거한다는 점이 중요하다.
오픈텔레메트리는 커뮤니티 주도 프레임워크로 오픈 트레이싱을 포함한다. 여기서 오픈 트레이싱이란 분산 틀이싱과 관련된 개념 및 API를 정의하는 사양을 말한다. 분산 트레이싱은 어느 정도 개발자에게 의존하는데 코드를 계측하는 작업이나 어플리케이션에서 요청을 처리하고 다른 시스템으로 새로운 요청을 보낼 때 요청에 주석을 붙이는 작업이 필요하기 때문이다. 트레이싱 엔진은 요청 흐름의 전체 상황을 파악하는 데 도움이 되며 이와 같은 특성은 아키텍쳐에서 오동작하는 영역을 식별하는 데 유용하다.
이스티오를 사용하면 개발자가 직접 구현해야 하는 부담을 크게 덜어줄 수 있으며 분산 트레이싱을 서비스 메시의 일부로 제공할 수 있다.
1️⃣ 분산 트레이싱의 작동 방식
가장 단순한 형태의 오픈 트레이시을 활용한 분산 트레이싱은 어플리케이션이 스팬을 생성하고 이를 오픈 트레이싱 엔진과 공유하며 뒤이어 호출하는 서비스로 트레이스 콘텍스트를 전파하는 것으로 이루어진다.
SPAN이란 서비스나 구성 요소 내에서 작업 단위를 나타내는 데이터 모음을 말한다. 이 데이터에는 작업 시작 시각, 종료 시각, 작업 이름, 태그 및 로그 집합 등이 포함된다.
업스트림 서비스도 동일한 작업을 수행한다. 요청 중 자신이 처리하는 부분을 나타내는 스팬을 만들고 이를 오픈 트레이싱 엔진에 보내고 트레이스 콘텍스트를 다른 서비스로 전파한다. 분산 트레이싱 엔진은 이런 스팬과 트레이스 콘텍스트를 사용해 트레이스ㅡㄹ 구축할 수 있다.
트레이스란 서비스 간의 인과 관계를 말하며 방향, 타이밍과 기타 디버깅 정보를 보여준다. 스팬에는 스팬 ID와 트레이스 ID가 있다. 이러한 ID들은 서비스 간의 작업 상관관계를 파악하는 데 사용되며 서비스 간 전파되어야 한다.
오픈 트레이싱 구현체에는 다음과 같은 시스템들이 있다.
- 예거 - 라이트스텝
- 집킨 - 인스타나
이스티오는 스팬을 분산 트레이싱 엔진으로 보낼 수 있으므로 이 작업을 위해 언어 전용 라이브러리나 어플리케이션 전용 설정이 필요 없다. 요청이 이스티오 서비스 프록시를 통과할 때 이미 진행 중인 트레이스가 없으면 트레이스를 새로 시작하고 요청의 시작 및 종료 시간을 스팬의 일부로 기록한다. 이스티오는 후속 스팬을 전체 트레이스에 연관 짓는데 사용할 수 있도록 보통 집킨 트레이싱 헤더라고 하는 HTTP 헤더를 요청에 덧붙인다. 요청이 서비스로 들어왔을 때 이스티오 프록시가 분산 트레이싱 헤더를 인식하면 프록시는 트레이스가 진행 중인 것으로 취급해 트레이스를 새로 만들지 않는다. 이스티오와 분산 트레이싱 기능에서 사용하는 집킨 트레이싱 헤더는 다음과 같다.
- x-request-id
- x-b3-traceid
- x-b3-spanid
- x-b3-parentspanid
- x-b3-sampled
- x-b3-flags
- x-ot-span-context
이스티오가 제공하는 분산 트레이싱 기능이 요청 호출 그래프 전체에 걸쳐 작동하려면 각 어플리케이션이 이 헤더들을 자신이 하는 모든 호출에 전파해야 한다.
1. 요청이 들어옴
2. 트레이싱 헤더가 없는 것을 보고 새로운 요청임을 파악. 요청이 서비스 사이를 오가는 과정을 추적할 수 있도록 트레이스 헤더를 생성
3. 트레이스 헤더가 요청 헤더에 추가됨 -> x-request-id: c9421
4. 어플리케이션은 다른 서비스를 호출할 때 트레이스 헤더를 전파해야 함
5. 트레이스 헤더를 전파 -> x-request-id: c9421
6. 이스티오 프록시는 기존 트레이스 헤더를 어플리케이션으로 전파
7. 만약 어플리케이션이 요청 헤더를 전파하지 않을 경우
8. 앱이 전파되지 않았기 때문에 요청에 트레이스 헤더가 누락
이스티오는 어떤 호출이 어떤 수신 요청의 결과물인지 모르기 때문에 업스트림 호출과 서비스로 들어온 호출을 올바르게 연결하려면 어플리케이션이 반드시 이런 헤더를 전파하는 역할을 맡아야 한다. 대부분의 경우 기본 RPC 프레임워크는 오픈 트레이싱과 통합되거나 오픈트레이싱을 직접 지원해 이런 헤더를 자동으로 전파해준다. 어느 방식이든 어플리케이션은 이런 헤더가 전파됨을 보장해야 한다.
2️⃣ 분산 트레이싱 시스템 설치
예거는 좀 더 복잡하여 데이터베이스가 필요하기 때문에 예거 일체형 배포 샘플을 그대로 사용할 것이다. 아래 샘플은 zipkin 쿠버네티스 서비스도 만드는데 이스티오가 기대하는 기본 설정에 맞춰 만들어지는 덕분에 바로 연결할 수 있다.
PS C:\CODE> docker exec -it myk8s-control-plane bash
# 설치 파일 확인
root@myk8s-control-plane:/# pwd
/
root@myk8s-control-plane:/# ls istio-$ISTIOV/samples/addons
README.md extras grafana.yaml jaeger.yaml kiali.yaml prometheus.yaml
root@myk8s-control-plane:/# cat istio-$ISTIOV/samples/addons/jaeger.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
namespace: istio-system
labels:
app: jaeger
spec:
selector:
matchLabels:
app: jaeger
template:
metadata:
labels:
app: jaeger
sidecar.istio.io/inject: "false"
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "14269"
spec:
containers:
- name: jaeger
image: "docker.io/jaegertracing/all-in-one:1.35"
env:
- name: BADGER_EPHEMERAL
value: "false"
- name: SPAN_STORAGE_TYPE
value: "badger"
- name: BADGER_DIRECTORY_VALUE
value: "/badger/data"
- name: BADGER_DIRECTORY_KEY
value: "/badger/key"
- name: COLLECTOR_ZIPKIN_HOST_PORT
value: ":9411"
- name: MEMORY_MAX_TRACES
value: "50000"
- name: QUERY_BASE_PATH
value: /jaeger
livenessProbe:
httpGet:
path: /
port: 14269
readinessProbe:
httpGet:
path: /
port: 14269
volumeMounts:
- name: data
mountPath: /badger
resources:
requests:
cpu: 10m
volumes:
- name: data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: tracing
namespace: istio-system
labels:
app: jaeger
spec:
type: ClusterIP
ports:
- name: http-query
port: 80
protocol: TCP
targetPort: 16686
# Note: Change port name if you add '--query.grpc.tls.enabled=true'
- name: grpc-query
port: 16685
protocol: TCP
targetPort: 16685
selector:
app: jaeger
---
# Jaeger implements the Zipkin API. To support swapping out the tracing backend, we use a Service named Zipkin.
apiVersion: v1
kind: Service
metadata:
labels:
name: zipkin
name: zipkin
namespace: istio-system
spec:
ports:
- port: 9411
targetPort: 9411
name: http-query
selector:
app: jaeger
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-collector
namespace: istio-system
labels:
app: jaeger
spec:
type: ClusterIP
ports:
- name: jaeger-collector-http
port: 14268
targetPort: 14268
protocol: TCP
- name: jaeger-collector-grpc
port: 14250
targetPort: 14250
protocol: TCP
- port: 9411
targetPort: 9411
name: http-zipkin
selector:
app: jaeger
# 설치
root@myk8s-control-plane:/# kubectl apply -f istio-$ISTIOV/samples/addons/jaeger.yaml
deployment.apps/jaeger created
service/tracing created
service/zipkin created
service/jaeger-collector created
root@myk8s-control-plane:/# exit
exit
# 배포 확인
PS C:\CODE> kubectl get deploy,pod,svc,ep -n istio-system
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/istio-egressgateway 1/1 1 1 8h
deployment.apps/istio-ingressgateway 1/1 1 1 46h
deployment.apps/istiod 1/1 1 1 46h
deployment.apps/jaeger 1/1 1 1 70s
NAME READY STATUS RESTARTS AGE
pod/istio-egressgateway-85df6b84b7-tjx54 1/1 Running 0 8h
pod/istio-ingressgateway-6bb8fb6549-x5gpt 1/1 Running 0 8h
pod/istiod-8d74787f-8mkt5 1/1 Running 0 8h
pod/jaeger-5556cd8fcf-74lms 1/1 Running 0 70s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/istio-egressgateway ClusterIP 10.200.1.204 <none> 80/TCP,443/TCP 8h
service/istio-ingressgateway LoadBalancer 10.200.1.49 <pending> 15021:30292/TCP,80:30000/TCP,443:30005/TCP,31400:31495/TCP,15443:30108/TCP 46h
service/istiod ClusterIP 10.200.1.85 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 46h
service/jaeger-collector ClusterIP 10.200.1.148 <none> 14268/TCP,14250/TCP,9411/TCP 70s
service/tracing ClusterIP 10.200.1.186 <none> 80/TCP,16685/TCP 70s
service/zipkin ClusterIP 10.200.1.185 <none> 9411/TCP 70s
NAME ENDPOINTS AGE
endpoints/istio-egressgateway 10.10.0.18:8080,10.10.0.18:8443 8h
endpoints/istio-ingressgateway 10.10.0.17:15443,10.10.0.17:15021,10.10.0.17:31400 + 2 more... 46h
endpoints/istiod 10.10.0.16:15012,10.10.0.16:15010,10.10.0.16:15017 + 1 more... 46h
endpoints/jaeger-collector 10.10.0.21:9411,10.10.0.21:14250,10.10.0.21:14268 70s
endpoints/tracing 10.10.0.21:16685,10.10.0.21:16686 70s
endpoints/zipkin 10.10.0.21:9411 70s
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'
3️⃣ 분산 트레이싱을 수행하도록 이스티오 설정하기
✔️ 설치 시 트레이싱 설치
이스티오를 설치 할 때 IstioOperator 리소스를 이스티오를 사용하는 샘플 설정으로 다양한 분산 트레이싱 백엔드를 설정
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
spec:
meshConfig:
defaultConfig:
tracing:
lightstep: {}
zipkin: {}
datadog: {}
stackdriver: {}
예를 들어 집킨 호환형인 예거를 사용하려면 아래와 같이 설정
# cat ch8/install-istio-tracing-zipkin.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
spec:
meshConfig:
defaultConfig:
tracing:
sampling: 100
zipkin:
address: zipkin.istio-system:9411
# 배포
PS C:\CODE> docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# cat << EOF > install-istio-tracing-zipkin.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
spec:
meshConfig:
defaultConfig:
tracing:
sampling: 100
zipkin:
address: zipkin.istio-system:9411
EOF
root@myk8s-control-plane:/# istioctl install -y -f install-istio-tracing-zipkin.yaml
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
- Pruning removed resources Removed Deployment:istio-system:istio-egressgateway.
Removed Service:istio-system:istio-egressgateway.
Removed ServiceAccount:istio-system:istio-egressgateway-service-account.
Removed RoleBinding:istio-system:istio-egressgateway-sds.
Removed Role:istio-system:istio-egressgateway-sds.
Removed PodDisruptionBudget:istio-system:istio-egressgateway.
✔ Installation complete Making this installation the default for injection and validation.
root@myk8s-control-plane:/# exit
exit
# 확인
PS C:\CODE> kubectl describe cm -n istio-system istio
Name: istio
Namespace: istio-system
...
mesh:
----
defaultConfig:
discoveryAddress: istiod.istio-system.svc:15012
proxyMetadata: {}
tracing:
sampling: 100
zipkin:
address: zipkin.istio-system:9411
enablePrometheusMerge: true
rootNamespace: istio-system
trustDomain: cluster.local
...
✔️ MeshConfig를 이용한 트레이싱 설정
kubectl edit cm -n istio-system istio
istio configmap 설정으로 MeshConfig를 이용한 트레이싱 설정하는 것이다. 이는 메시 범위의 기본 설정은 어떤 것이라도 defaultConfig.tracing 부분에서 업데이트 할 수 있다.
✔️ 워크로드 별로 트레이싱 설정
apiVersion: apps/v1
kind: Deployment
...
spec:
template:
metadata:
annotations:
proxy.istio.io/config: |
tracing:
zipkin:
address: zipkin.istio-system:9411
...
파드 spec에 직접 어노테이션을 추가한다.
✔️ 기본 트레이싱 헤더 살펴보기
이스티오가 생성한 트레이싱용 집킨 헤더가 예상한 대로 작동하는지 확인하는 단계이다. 이스티오가 오픈트레이싱 헤더와 상관관계 ID를 자동으로 주입한다는 것을 보여주고자 이스티오 인그레스 게이트웨이를 사용해 외부 httpbin 서비스를 호출하고 요청 헤더를 표시하는 엔드포인트를 호출할 것이다.
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> cat ch8/tracing/thin-httpbin-virtualservice.yaml
---
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
# 배포
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> kubectl apply -n istioinaction -f ch8/tracing/thin-httpbin-virtualservice.yaml
gateway.networking.istio.io/coolstore-gateway configured
virtualservice.networking.istio.io/thin-httbin-virtualservice created
serviceentry.networking.istio.io/external-httpbin-org created
# 확인
PS C:\CODE> kubectl get gw,vs,serviceentry -n istioinaction
NAME AGE
gateway.networking.istio.io/coolstore-gateway 47h
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/thin-httbin-virtualservice ["coolstore-gateway"] ["httpbin.istioinaction.io"] 23s
virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 47h
NAME HOSTS LOCATION RESOLUTION AGE
serviceentry.networking.istio.io/external-httpbin-org ["httpbin.org"] MESH_EXTERNAL DNS 23s
호스트에서 호출 시, 어떻게 외부 서비스로 전달되는지 살펴보자. 원래 요청에서 사용된 헤더를 반환해야 한다.
fish@jellyfish:~$ curl -H "Host: httpbin.istioinaction.io" http://localhost:30000/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.istioinaction.io",
"User-Agent": "curl/7.81.0",
"X-Amzn-Trace-Id": "Root=1-68164975-0af368b5135d76bd077629ff",
"X-B3-Sampled": "1",
"X-B3-Spanid": "262200514bd9c879",
"X-B3-Traceid": "f2d414eed4937b3c262200514bd9c879",
"X-Envoy-Attempt-Count": "1",
"X-Envoy-Decorator-Operation": "httpbin.org:80/*",
"X-Envoy-Internal": "true",
"X-Envoy-Peer-Metadata": "ChQKDkFQUF9DT05UQUlORVJTEgIaAAoaCgpDTFVTVEVSX0lEEgwaCkt1YmVybmV0ZXMKHAoMSU5TVEFOQ0VfSVBTEgwaCjEwLjEwLjAuMjMKGQoNSVNUSU9fVkVSU0lPThIIGgYxLjE3LjgKnAMKBkxBQkVMUxKRAyqOAwodCgNhcHASFhoUaXN0aW8taW5ncmVzc2dhdGV3YXkKEwoFY2hhcnQSChoIZ2F0ZXdheXMKFAoIaGVyaXRhZ2USCBoGVGlsbGVyCjYKKWluc3RhbGwub3BlcmF0b3IuaXN0aW8uaW8vb3duaW5nLXJlc291cmNlEgkaB3Vua25vd24KGQoFaXN0aW8SEBoOaW5ncmVzc2dhdGV3YXkKGQoMaXN0aW8uaW8vcmV2EgkaB2RlZmF1bHQKMAobb3BlcmF0b3IuaXN0aW8uaW8vY29tcG9uZW50EhEaD0luZ3Jlc3NHYXRld2F5cwoSCgdyZWxlYXNlEgcaBWlzdGlvCjkKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSFhoUaXN0aW8taW5ncmVzc2dhdGV3YXkKLwojc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtcmV2aXNpb24SCBoGbGF0ZXN0CiIKF3NpZGVjYXIuaXN0aW8uaW8vaW5qZWN0EgcaBWZhbHNlChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAouCgROQU1FEiYaJGlzdGlvLWluZ3Jlc3NnYXRld2F5LTk5NmJjNmJiNi1ja2c2agobCglOQU1FU1BBQ0USDhoMaXN0aW8tc3lzdGVtCl0KBU9XTkVSElQaUmt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9pc3Rpby1zeXN0ZW0vZGVwbG95bWVudHMvaXN0aW8taW5ncmVzc2dhdGV3YXkKFwoRUExBVEZPUk1fTUVUQURBVEESAioACicKDVdPUktMT0FEX05BTUUSFhoUaXN0aW8taW5ncmVzc2dhdGV3YXk=",
"X-Envoy-Peer-Metadata-Id": "router~10.10.0.23~istio-ingressgateway-996bc6bb6-ckg6j.istio-system~istio-system.svc.cluster.local"
}
}
4️⃣ 분산 트레이싱 데이터 보기
스팬이 예거(혹은 기타 오픈트레이싱 엔진)로 보내질 때, 트레이스 및 관련 스팬을 쿼리하고 볼 수 있는 방법이 필요하다.
트레이스 콘텍스트 및 헤더 전파하기 Propagating trace context and headers : 올바른 동작을 위해 아래와 같은 헤더 전파 필요
- x-request-id
- x-b3-traceid
- x-b3-spanid
- x-b3-parentspanid
- x-b3-sampled
- x-b3-flags
- x-ot-span-context
즉, 애플리케이션 코드가 요청을 받아 처리를 시작할 때 이 헤더와 그 값을 저장했다가 애플리케이션이 수행해야 하는 모든 발신 요청에 삽입해야 한다는 것이다. 이 작업은 프록시에서 자동으로 수행할 수 없다.
5️⃣ 트레이스 샘플링, 강제 트레이스, 커스텀 태그
분산 트레이싱 및 스캔 수집은 시스템에 상당한 성능 저하를 초래할 수 있으므로 서비스가 올바르게 실행 중일 때 분산 트레이싱 수집 빈도를 제한하도록 선택할 수 있다. 앞에서 설치한 데모 프로필은 분산 트레이싱의 샘플링을 100%로 설정했다. 시스템에서 수집할 트레이스 비율을 설정함으로써 트레이스 샘플링을 제어할 수 있다.
✔️ 메시의 트레이스 샘플링 비율 조절
백엔드 분산 트레이싱을 설치할 때, 런타임에 혹은 워크로드별로 설정했던 것처럼 샘플링 비율도 마찬가지로 설정할 수 있다. 트레이싱 설정이 다음과 같아지도록 istio-system 네임스페이스에 있는 istio configmap 의 MeshConfig 를 수정해보자.
PS C:\CODE> kubectl edit -n istio-system cm istio
configmap/istio edited
...
sampling: 10 # <-- from 100
...
# 샘플링 적용
PS C:\CODE> kubectl rollout restart deploy -n istio-system istio-ingressgateway
deployment.apps/istio-ingressgateway restarted
이로써 서비스 메시 내 모든 워크로드에서 샘플링 비율이 전역적으로 10%로 바뀐다. 전역 설정 대신 애노테이션으로 워크로드별로도 설정할 수 있다. 여기서는 트레이싱 설정을 포함하도록 디플로이먼트 파드 템플릿의 애노테이션을 편집한다.
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> cat ch8/webapp-deployment-zipkin.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webapp
name: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
annotations:
proxy.istio.io/config: |
tracing:
sampling: 10
zipkin:
address: zipkin.istio-system:9411
labels:
app: webapp
spec:
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CATALOG_SERVICE_HOST
value: catalog.istioinaction
- name: CATALOG_SERVICE_PORT
value: "80"
- name: FORUM_SERVICE_HOST
value: forum.istioinaction
- name: FORUM_SERVICE_PORT
value: "80"
image: istioinaction/webapp:latest
imagePullPolicy: IfNotPresent
name: webapp
ports:
- containerPort: 8080
name: http
protocol: TCP
securityContext:
privileged: false
# 배포
kubectl apply -f ch8/webapp-deployment-zipkin.yaml -n istioinaction
# 호출 테스트
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
수집이 10번 중에 1번 꼴로 되어 수집 주기가 넓어지는 것을 확인할 수 있다.
✔️ 클라이언트에서 강제하기
운영 환경에서는 트레이스의 샘플링 비율을 최소한으로 설정한 후 문제가 있을 때만 특정 워크로드에 대해 활성화하는 것이 이치에 맞다. 가끔은 특정 요청(건)에 트레이싱을 활성화해야 하는 경우가 있다. 이스티오에서는 특정 요청에만 트레이싱을 강제하도록 설정 가능하다.
예를 들어 어플리케이션 요청에 x-envoy-force-trace 헤더를 추가해 요청이 만드는 호출 그래프의 스팬과 트레이스를 이스티오가 포착하도록 만들 수 있다.
# 반복 테스트
curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
특정 요청에 대해 더 많은 정보를 얻고 싶을 때 이 헤더를 주입할 수 있는 API 게이트웨이와 진단 서비스 같은 도구를 이스티오 위에 구축할 수 있다.
✔️ 트레이스의 태그 커스터마이징하기
스팬에 태그를 추가하는 것은 애플리케이션이 트레이스에 추가 메타데이터를 부여하는 방법이다. 태그는 단순한 키-값 쌍을 말하는 것으로, 애플리케이션 혹은 조직별 커스텀 정보를 담고 있으며 백엔드 분산 트레이싱 엔진으로 보내는 스팬에 추가된다. 태그는 3가지 유형으로 설정할 수 있다.
- 명시적으로 값 지정하기
- 환경 변수에서 값 가져오기
- 요청 헤더에서 값 가져오기
예를 들어 webapp 서비스의 스팬에 커스텀 태그를 추가하려면, 해당 워크로드의 Deployment 리소스에 다음과 같이 어노테이션을 추가할 수 있다.
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> cat ch8/webapp-deployment-zipkin-tag.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webapp
name: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
annotations:
proxy.istio.io/config: |
tracing:
sampling: 100
customTags:
custom_tag:
literal:
value: "Test Tag" ##
zipkin:
address: zipkin.istio-system:9411
labels:
app: webapp
spec:
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CATALOG_SERVICE_HOST
value: catalog.istioinaction
- name: CATALOG_SERVICE_PORT
value: "80"
- name: FORUM_SERVICE_HOST
value: forum.istioinaction
- name: FORUM_SERVICE_PORT
value: "80"
image: istioinaction/webapp:latest
imagePullPolicy: IfNotPresent
name: webapp
ports:
- containerPort: 8080
name: http
protocol: TCP
securityContext:
privileged: false
# 배포
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> kubectl apply -n istioinaction -f ch8/webapp-deployment-zipkin-tag.yaml
deployment.apps/webapp configured
# 호출
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
커스텀 태그는 보고, 필터링, 트레이싱 데이터 탐색에 사용할 수 있다.
Distributed Tracing
This task shows you how to configure Istio-enabled applications to collect trace spans.
istio.io
✔️ 백엔드 분산 트레이싱 엔진 커스터마이징하기
이스티오는 1.12 버전에서 트레이싱을 포함하는 새로운 텔레메트리용 알파 API를 릴리스했으므로, 트레이싱 설정 면에서 사용자 경험이 개선될 것이라고 기대할 수 있다. 단, 지금 다루는 내용은 다소 심화된 내용이므로 독자의 사용 사례에는 적용되지 않을 수 있다.
지금까지의 예제에서는 백엔드 트레이싱 엔진의 호스트네임과 포트로 이스티오를 설정했다. 그런데 더 많은 설정을 조정해야 하는 경우에는 어떻게 할까? 예를 들어, 예거의 집긴 호환성을 사용하려면 예거 수집기의 특정 엔드포인트로 추적을 전송해야 한다. 기본적으로는 이스티오 프록시에서 정적 설정으로 설정한다. 집킨 기반 트레이싱 엔진의 기본 트레이싱 설정을 살펴보자.
PS C:\CODE> docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# istioctl pc bootstrap -n istioinaction deploy/webapp -o json | jq .bootstrap.tracing
{
"http": {
"name": "envoy.tracers.zipkin",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
"collectorCluster": "zipkin",
"collectorEndpoint": "/api/v2/spans",
"traceId128bit": true,
"sharedSpanContext": false,
"collectorEndpointVersion": "HTTP_JSON"
}
}
}
root@myk8s-control-plane:/# exit
exit
현재 기본 설정은 다음과 같다. tracing enging은 Zipkin-based이며 Span은 /api/v2/spans로 전달된다. 그리고 JSON 엔드포인트로 처리되고 있다. 이 기본 설정은 커스텀 부트스트랩 설정으로 변경할 수 있다. 이를 위해 configmap 에서 튜닝하고자 하는 설정 스니펫을 지정한다.
# 해당 configmap 은 collectorEndpoint 를 변경한 설정 스니펫
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> cat ch8/istio-custom-bootstrap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: istio-custom-zipkin
data:
custom_bootstrap.json: |
{
"tracing": {
"http": {
"name": "envoy.tracers.zipkin",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
"collectorCluster": "zipkin",
"collectorEndpoint": "/zipkin/api/v1/spans",
"traceId128bit": "true",
"collectorEndpointVersion": "HTTP_JSON"
}
}
}
}
# 이 부트스트랩 설정을 덮어 쓰려는 워크로드가 있는 네임스페이스에 configmap 을 적용할 수 있다.
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> kubectl apply -n istioinaction -f ch8/istio-custom-bootstrap.yaml
configmap/istio-custom-zipkin created
# 확인
PS C:\CODE> kubectl get cm -n istioinaction
NAME DATA AGE
istio-ca-root-cert 1 2d1h
istio-custom-zipkin 1 10s
kube-root-ca.crt 1 2d1h
# 해당 configmap 을 참조하는 Deployment 리소스의 파드 템플릿에 애노테이션을 추가
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> cat ch8/webapp-deployment-custom-boot.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: webapp
name: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
annotations:
sidecar.istio.io/bootstrapOverride: "istio-custom-zipkin"
proxy.istio.io/config: |
tracing:
sampling: 10
zipkin:
address: zipkin.istio-system:9411
labels:
app: webapp
spec:
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CATALOG_SERVICE_HOST
value: catalog.istioinaction
- name: CATALOG_SERVICE_PORT
value: "80"
- name: FORUM_SERVICE_HOST
value: forum.istioinaction
- name: FORUM_SERVICE_PORT
value: "80"
image: istioinaction/webapp:latest
imagePullPolicy: IfNotPresent
name: webapp
ports:
- containerPort: 8080
name: http
protocol: TCP
securityContext:
privileged: false
# 변경된 설정으로 webapp 재배포
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> kubectl apply -n istioinaction -f ch8/webapp-deployment-custom-boot.yaml
deployment.apps/webapp configured
# 확인
PS C:\CODE> docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# istioctl pc bootstrap -n istioinaction deploy/webapp -o json | jq .bootstrap.tracing
{
"http": {
"name": "envoy.tracers.zipkin",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
"collectorCluster": "zipkin",
"collectorEndpoint": "/zipkin/api/v1/spans", ##
"traceId128bit": true,
"collectorEndpointVersion": "HTTP_JSON"
}
}
}
변경된 사항을 배포하니 엔드포인트가 변경된 것을 확인할 수 있다. 참고로 이는 잘못된 경로이다.
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
그렇기 때문에 예거에서 호출되지 않는 것을 확인할 수 있다.
설정 원상복구는 아래 명령어를 수행하면 된다.
PS C:\CODE\kubernetes\istio\istio-in-action\book-source-code-master> kubectl apply -n istioinaction -f services/webapp/kubernetes/webapp.yaml
serviceaccount/webapp unchanged
service/webapp unchanged
deployment.apps/webapp configured
'Istio' 카테고리의 다른 글
자동 상호 TLS (1) | 2025.05.10 |
---|---|
어플리케이션 네트워크 보안 (0) | 2025.05.08 |
모니터링 (2) 그라파나와 키알리 (0) | 2025.05.03 |
모니터링 (1) 이스티오 표준 메트릭 커스터마이징 (1) | 2025.05.03 |
프로메테우스를 이용한 이스티오 메트릭 분석 (1) | 2025.05.03 |