Istio 기반 마이크로서비스 관측 가능성 모범 사례¶
Istio¶
Service Mesh란?¶
지난 몇 년간 마이크로서비스가 소프트웨어 애플리케이션에서 빠르게 보급되면서 대규모 애플리케이션이 여러 개의 마이크로서비스로 분할되었습니다. 각 마이크로서비스는 컨테이너화를 통해 개별 컨테이너에서 실행될 수 있지만, 서비스 간 통신의 네트워크 토폴로지는 여전히 매우 복잡합니다. 마이크로서비스 간 네트워크 통신이 매우 중요하기 때문에, 여러 서비스 프록시를 구현하여 제어된 서비스 간 통신 채널을 안전하고 견고하게 보장하는 기본 구성 요소가 필요합니다.
서비스 메시(Service Mesh)는 이러한 애플리케이션을 구성하는 마이크로서비스 네트워크와 그들 간의 상호작용을 설명하는 데 사용됩니다. 개별 서비스 호출은 Sidecar로 나타납니다. 많은 수의 서비스가 있는 경우 메시 형태로 나타나며, 아래 그림에서 녹색 사각형은 애플리케이션 마이크로서비스를, 파란색 사각형은 Sidecar를, 선은 서비스 간 호출 관계를 나타내며, Sidecar 간의 연결은 네트워크를 형성합니다.

Istio 개요¶
Istio는 기존 분산형 애플리케이션 위에 투명하게 계층화되는 오픈소스 서비스 메시입니다. 전체 서비스 메시에 대한 동작 인사이트와 운영 제어 기능, 그리고 마이크로서비스 애플리케이션의 다양한 요구 사항을 충족하는 완전한 솔루션을 제공합니다.
Istio 핵심 컴포넌트¶
Istio 서비스 메시는 데이터 플레인과 컨트롤 플레인으로 구성됩니다.
- 데이터 플레인은 지능형 프록시(Envoy) 세트로 구성되며, Envoy는 사이드카로 배포됩니다. 마이크로서비스 간 Sidecar 통신은 정책 제어 및 텔레메트리 수집(Mixer)을 통해 구현됩니다.
- 컨트롤 플레인은 프록시를 관리 및 구성하여 트래픽을 라우팅합니다. Citadel은 기본 제공 ID 및 자격 증명 관리를 통해 강력한 서비스 간 및 최종 사용자 인증을 제공합니다. Pilot은 Envoy 사이드카에 서비스 디스커버리, 지능형 라우팅(예: A/B 테스트, 카나리아 배포 등), 트래픽 관리 및 오류 처리(타임아웃, 재시도 및 서킷 브레이커) 기능을 제공합니다. Galley는 Istio 구성 검증, 획득, 처리 및 배포 컴포넌트입니다.
Istio 분산 추적¶
Envoy는 Jaeger를 기본 지원하며, 트레이스에 필요한 x-b3로 시작하는 헤더(x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, x-b3-flags)와 x-request-id는 비즈니스 로직에 의해 서비스 간에 전달되고 Envoy가 Jaeger에 보고하여 최종적으로 Jaeger가 완전한 트레이스 정보를 생성합니다.
Istio에서 Envoy와 Jaeger의 관계는 다음과 같습니다.
그림에서 Front Envoy는 요청을 처음 수신하는 Envoy Sidecar를 의미하며, 루트 스팬을 생성하여 요청 헤더에 추가합니다. 요청이 다른 서비스에 도달하면 Envoy Sidecar가 트레이스 정보를 보고합니다.
Envoy는 분산 추적에서 Jaeger를 기본 지원하며, 외부 추적 서비스(Zipkin, Zipkin 호환 백엔드(Jaeger)) 통합을 지원합니다. Istio 분산 추적은 전역 설정 zipkinAddress를 제공하며, Envoy의 보고 주소는 proxy_init의 --zipkinAddress 파라미터를 통해 전달됩니다.
Istio 관측 가능성¶
Istio의 강력한 트레이스, 모니터링 및 로깅 기능을 통해 서비스 메시 배포를 심층적으로 이해할 수 있습니다. Istio의 모니터링 기능을 통해 서비스 성능이 업스트림 및 다운스트림에 어떤 영향을 미치는지 실제로 파악할 수 있으며, 맞춤형 대시보드는 모든 서비스 성능에 대한 시각화 기능을 제공하여 다른 프로세스에 미치는 영향을 확인할 수 있습니다. 이러한 모든 기능을 통해 서비스 SLO를 보다 효과적으로 설정, 모니터링 및 강화할 수 있습니다.
BookInfo 개요¶
이 예시는 여러 Istio 기능을 보여주기 위한 애플리케이션을 배포하며, 이 애플리케이션은 4개의 개별 마이크로서비스로 구성됩니다. 이 애플리케이션은 온라인 서점의 카테고리를 모방하여 책 한 권의 정보를 표시합니다. 페이지에는 책 설명, 책 세부 정보(ISBN, 페이지 수 등) 및 책에 대한 리뷰가 표시됩니다.
Bookinfo 애플리케이션은 4개의 개별 마이크로서비스로 구성됩니다.
- productpage: productpage(Python) 마이크로서비스는 details 및 reviews 마이크로서비스를 호출하여 페이지를 채웁니다.
- details: details(Ruby) 마이크로서비스는 책의 상세 정보를 포함합니다.
- reviews: reviews(Java) 마이크로서비스는 책 리뷰를 포함하며, ratings 마이크로서비스도 호출합니다.
- ratings: ratings(Node.js) 마이크로서비스는 책의 순위 정보를 포함합니다.
reviews 마이크로서비스는 3가지 버전을 제공합니다.
- 버전 v1은 ratings 서비스를 호출하지 않습니다.
- 버전 v2는 ratings 서비스를 호출하고 각 등급을 1~5개의 검은색 별로 표시합니다.
- 버전 v3는 ratings 서비스를 호출하고 각 등급을 1~5개의 빨간색 별표로 표시합니다.
Bookinfo의 트레이스 데이터는 istio의 configmap에서 zipkin.address를 DataKit 주소로 수정하기만 하면 되며, DataKit은 Zipkin 수집기를 활성화해야 트레이스 데이터를 DataKit에 푸시할 수 있습니다.
환경 배포¶
전제 조건¶
Kubernetes¶
이 예시는 CentOS 7.9에서 minikube로 생성한 버전 1.21.2의 Kubernetes 클러스터를 사용합니다.
DataKit 배포¶
<DaemonSet으로 DataKit 배포>를 참조하세요.
수집기 활성화¶
DaemonSet으로 DataKit 배포의 datakit.yaml 파일을 사용하여 Kubernetes 클러스터의 마스터 노드 /usr/local/df-demo/datakit.yaml에 업로드하고, datakit.yaml 파일을 수정하여 ConfigMap을 추가하고 파일을 마운트하여 Zipkin 및 Prom 수집기를 활성화합니다. 최종 결과는 배포가 완료된 DataKit입니다.
/usr/local/datakit/conf.d/zipkin/zipkin.conf파일을 추가하여 Zipkin 메트릭 수집기를 활성화합니다./usr/local/datakit/conf.d/prom/prom_istiod.conf파일을 추가하여 Istiod Pod의 메트릭 수집기를 활성화합니다./usr/local/datakit/conf.d/prom/prom-ingressgateway.conf파일을 추가하여 Ingressgateway의 메트릭 수집기를 활성화합니다./usr/local/datakit/conf.d/prom/prom-egressgateway.conf파일을 추가하여 Egressgateway의 메트릭 수집기를 활성화합니다.
ingressgateway 및 egressgateway를 수집하려면 Service를 사용하여 15020 포트에 액세스하므로, ingressgateway 및 egressgateway의 Service를 새로 생성해야 합니다.
istio-ingressgateway-service-ext.yaml
istio-egressgateway-service-ext.yaml
Service 생성
kubectl apply -f istio-ingressgateway-service-ext.yaml
kubectl apply -f istio-egressgateway-service-ext.yaml
다음은 datakit.yaml 파일의 수정 부분입니다.
ConfigMap 추가
apiVersion: v1
kind: ConfigMap
metadata:
name: datakit-conf
namespace: datakit
data:
zipkin.conf: |-
[[inputs.zipkin]]
pathV1 = "/api/v1/spans"
pathV2 = "/api/v2/spans"
prom_istiod.conf: |-
[[inputs.prom]]
url = "http://istiod.istio-system.svc.cluster.local:15014/metrics"
source = "prom-istiod"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name ="cpu"
[inputs.prom.tags]
app_id="istiod"
prom-ingressgateway.conf: |-
[[inputs.prom]]
url = "http://istio-ingressgateway-ext.istio-system.svc.cluster.local:15020/stats/prometheus"
source = "prom-ingressgateway"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name ="cpu"
prom-egressgateway.conf: |-
[[inputs.prom]]
url = "http://istio-egressgateway-ext.istio-system.svc.cluster.local:15020/stats/prometheus"
source = "prom-egressgateway"
metric_types = ["counter", "gauge"]
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
interval = "60s"
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name ="cpu"
zipkin.conf 및 prom_istiod.conf 마운트
apiVersion: apps/v1
kind: DaemonSet
...
spec:
template
spec:
containers:
- env:
volumeMounts: # 아래는 추가된 부분입니다
- mountPath: /usr/local/datakit/conf.d/zipkin/zipkin.conf
name: datakit-conf
subPath: zipkin.conf
- mountPath: /usr/local/datakit/conf.d/prom/prom_istiod.conf
name: datakit-conf
subPath: prom_istiod.conf
- mountPath: /usr/local/datakit/conf.d/prom/prom-ingressgateway.conf
name: datakit-conf
subPath: prom-ingressgateway.conf
- mountPath: /usr/local/datakit/conf.d/prom/prom-egressgateway.conf
name: datakit-conf
subPath: prom-egressgateway.conf
토큰 교체¶
Guance에 로그인하여 '통합' - 'DataKit'에서 토큰을 복사하고 datakit.yaml의 <your-token>를 교체합니다.
DataKit 재배포¶
Istio 배포¶
Istio 다운로드¶
다운로드 소스 코드 및 istio-1.11.2-linux-amd64.tar.gz
Istio 설치¶
istio-1.11.2-linux-amd64.tar.gz를 /usr/local/df-demo/ 디렉터리에 업로드합니다. Kubernetes 서버의 내부 네트워크 주소가 172.16.0.15인지 확인하고 172.16.0.15를 사용자 IP로 교체하세요.
su minikube
cd /usr/local/df-demo/
tar zxvf istio-1.11.2-linux-amd64.tar.gz
cd /usr/local/df-demo/istio-1.11.2
export PATH=$PWD/bin:$PATH$
cp -ar /usr/local/df-demo/istio-1.11.2/bin/istioctl /usr/bin/
istioctl install --set profile=demo
설치 검증¶
배포가 성공하면 ingressgateway, egressgateway, istiod가 Running 상태가 됩니다.
BookInfo 배포¶
파일 복사¶
소스 코드를 압축 해제하고 /usr/local/df-demo/istio-1.11.2/samples/bookinfo/src/productpage 디렉터리를 /usr/local/df-demo/bookinfo 디렉터리로 복사합니다. bookInfo 배포에 필요한 yaml을 복사합니다.
cp /usr/local/df-demo/istio-1.11.2/samples/bookinfo/networking/bookinfo-gateway.yaml /usr/local/df-demo/bookinfo/bookinfo-gateway.yaml
cp /usr/local/df-demo/istio-1.11.2/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml /usr/local/df-demo/bookinfo/virtual-service-ratings-test-delay.yaml
cp /usr/local/df-demo/istio-1.11.2/samples/bookinfo/platform/kube/bookinfo.yaml /usr/local/df-demo/bookinfo/bookinfo.yaml
자동 주입 활성화¶
prod 네임스페이스를 생성하고, 해당 네임스페이스에서 Pod 생성 시 사이드카가 자동으로 주입되어 Pod의 인바운드/아웃바운드 트래픽이 모두 사이드카를 통해 처리되도록 활성화합니다.
RUM 활성화¶
- 1 Guance에 로그인하여 '실제 사용자 모니터링(RUM)' - '애플리케이션 생성'에서 bookinfo를 입력하고,
JS를/usr/local/df-demo/bookinfo/productpage/templates/productpage.html에 복사한 후를 http://<your-外网 ip>:9529로 수정합니다.
- 2
/usr/local/df-demo/bookinfo/productpage/Dockerfile수정
- 3 이미지 빌드
cd /usr/local/df-demo/bookinfo/productpage
eval $(minikube docker-env)
docker build -t product-page:v1 .
- 4 이미지 교체
/usr/local/df-demo/bookinfo/bookinfo.yaml의 image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2를 image: product-page:v1로 교체합니다.
APM과 DataKit 연결¶
위 그림에서 트레이스 데이터가 기본적으로 zipkin.istio-system:9411 주소로 푸시되는 것을 확인할 수 있습니다. DataKit 서비스의 네임스페이스는 datakit이고 포트는 9529이므로, 여기서 변환이 필요합니다.
자세한 내용은 <Kubernetes 클러스터에서 ExternalName을 사용하여 DataKit 서비스 매핑>을 참조하세요.
네임스페이스 추가¶
bookinfo yaml을 수정하여 모든 리소스의 metadata에 namespace: prod를 추가합니다.
vi /usr/local/df-demo/bookinfo/bookinfo.yaml
vi /usr/local/df-demo/bookinfo/bookinfo-gateway.yaml
vi /usr/local/df-demo/bookinfo/virtual-service-ratings-test-delay.yaml
Pod 사용자 정의 수집 활성화¶
bookinfo.yaml 수정
모든 Deployment 컨트롤러의 Pod 템플릿에 annotations을 추가합니다.
파라미터 설명
- url: Exporter 주소
- source: 수집기 이름
- metric_types: 메트릭 유형 필터
- measurement_name: 수집 후 메저먼트 이름
- interval: 메트릭 수집 주기(초)
- $IP: Pod의 내부 네트워크 IP 와일드카드
- $NAMESPACE: Pod가 속한 네임스페이스
- tags_ignore: 무시할 태그
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-product"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
pod_name = "$PODNAME"
- 전체
bookinfo.yaml는 다음과 같습니다.
bookinfo.yaml
apiVersion: v1
kind: Service
metadata:
name: details
namespace: prod
labels:
app: details
service: details
spec:
ports:
- port: 9080
name: http
selector:
app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-details
namespace: prod
labels:
account: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: details-v1
namespace: prod
labels:
app: details
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: details
version: v1
template:
metadata:
labels:
app: details
version: v1
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-details"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
spec:
serviceAccountName: bookinfo-details
containers:
- name: details
image: docker.io/istio/examples-bookinfo-details-v1:1.16.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
securityContext:
runAsUser: 1000
---
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: ratings
namespace: prod
labels:
app: ratings
service: ratings
spec:
ports:
- port: 9080
name: http
selector:
app: ratings
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-ratings
namespace: prod
labels:
account: ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ratings-v1
namespace: prod
labels:
app: ratings
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: ratings
version: v1
template:
metadata:
labels:
app: ratings
version: v1
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-ratings"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
spec:
serviceAccountName: bookinfo-ratings
containers:
- name: ratings
image: docker.io/istio/examples-bookinfo-ratings-v1:1.16.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
securityContext:
runAsUser: 1000
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: reviews
namespace: prod
labels:
app: reviews
service: reviews
spec:
ports:
- port: 9080
name: http
selector:
app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-reviews
namespace: prod
labels:
account: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-v1
namespace: prod
labels:
app: reviews
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: reviews
version: v1
template:
metadata:
labels:
app: reviews
version: v1
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-review1"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
#measurement_prefix = ""
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v1:1.16.2
imagePullPolicy: IfNotPresent
env:
- name: LOG_DIR
value: "/tmp/logs"
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
- name: wlp-output
mountPath: /opt/ibm/wlp/output
securityContext:
runAsUser: 1000
volumes:
- name: wlp-output
emptyDir: {}
- name: tmp
emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-v2
namespace: prod
labels:
app: reviews
version: v2
spec:
replicas: 1
selector:
matchLabels:
app: reviews
version: v2
template:
metadata:
labels:
app: reviews
version: v2
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-review2"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
#measurement_prefix = ""
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v2:1.16.2
imagePullPolicy: IfNotPresent
env:
- name: LOG_DIR
value: "/tmp/logs"
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
- name: wlp-output
mountPath: /opt/ibm/wlp/output
securityContext:
runAsUser: 1000
volumes:
- name: wlp-output
emptyDir: {}
- name: tmp
emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-v3
namespace: prod
labels:
app: reviews
version: v3
spec:
replicas: 1
selector:
matchLabels:
app: reviews
version: v3
template:
metadata:
labels:
app: reviews
version: v3
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-review3"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v3:1.16.2
imagePullPolicy: IfNotPresent
env:
- name: LOG_DIR
value: "/tmp/logs"
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
- name: wlp-output
mountPath: /opt/ibm/wlp/output
securityContext:
runAsUser: 1000
volumes:
- name: wlp-output
emptyDir: {}
- name: tmp
emptyDir: {}
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: productpage
namespace: prod
labels:
app: productpage
service: productpage
spec:
ports:
- port: 9080
name: http
selector:
app: productpage
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-productpage
namespace: prod
labels:
account: productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: productpage-v1
namespace: prod
labels:
app: productpage
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: productpage
version: v1
template:
metadata:
labels:
app: productpage
version: v1
annotations:
datakit/prom.instances: |
[[inputs.prom]]
url = "http://$IP:15020/stats/prometheus"
source = "minik8s-istio-product"
metric_types = ["counter", "gauge"]
interval = "60s"
tags_ignore = ["cache","cluster_type","component","destination_app","destination_canonical_revision","destination_canonical_service","destination_cluster","destination_principal","group","grpc_code","grpc_method","grpc_service","grpc_type","reason","request_protocol","request_type","resource","responce_code_class","response_flags","source_app","source_canonical_revision","source_canonical-service","source_cluster","source_principal","source_version","wasm_filter"]
metric_name_filter = ["istio_requests_total","pilot_k8s_cfg_events","istio_build","process_virtual_memory_bytes","process_resident_memory_bytes","process_cpu_seconds_total","envoy_cluster_assignment_stale","go_goroutines","pilot_xds_pushes","pilot_proxy_convergence_time_bucket","citadel_server_root_cert_expiry_timestamp","pilot_conflict_inbound_listener","pilot_conflict_outbound_listener_http_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_tcp","pilot_conflict_outbound_listener_tcp_over_current_http","pilot_virt_services","galley_validation_failed","pilot_services","envoy_cluster_upstream_cx_total","envoy_cluster_upstream_cx_connect_fail","envoy_cluster_upstream_cx_active","envoy_cluster_upstream_cx_rx_bytes_total","envoy_cluster_upstream_cx_tx_bytes_total","istio_request_duration_milliseconds_bucket","istio_request_duration_seconds_bucket","istio_request_bytes_bucket","istio_response_bytes_bucket"]
#measurement_prefix = ""
measurement_name = "istio_prom"
#[[inputs.prom.measurements]]
# prefix = "cpu_"
# name = "cpu"
[inputs.prom.tags]
namespace = "$NAMESPACE"
spec:
serviceAccountName: bookinfo-productpage
containers:
- name: productpage
#image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2
image: image: product-page:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
securityContext:
runAsUser: 1000
volumes:
- name: tmp
emptyDir: {}
---
- 전체
bookinfo-gateway.yaml
bookinfo-gateway.yaml
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: prod
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
namespace: prod
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
서비스 배포¶
cd /usr/local/df-demo/bookinfo
kubectl apply -f bookinfo.yaml
kubectl apply -f bookinfo-gateway.yaml
nginx로 productpage 서비스 프록시¶
이 예시에서는 minikube를 사용하므로 nginx를 통해 클러스터 내 서비스를 프록시하도록 nginx를 구성해야 합니다.
- minikube http2 URL 확인:
- root 계정으로 서버에 로그인하여
proxy_pass를 http2 서비스 주소로 수정
- nginx 재시작
productpage 액세스¶
http://121.43.225.226/productpage
관측 가능성 실습¶
메트릭¶
BookInfo 배포 시 Pod 사용자 정의 수집을 활성화할 때 measurement_name = "istio_prom"를 구성했습니다.
「Guance」 - 「메트릭」에 로그인하여 istio_prom 메저먼트를 확인합니다.
트레이스¶
RUM¶
실제 사용자 모니터링(RUM) 모듈을 통해 UV, PV, 세션 수, 액세스한 페이지 등의 정보를 확인합니다.
APM¶
애플리케이션 성능 모니터링(APM)을 통해 트레이스 데이터를 확인합니다.
로그¶
stdout¶
DataKit은 기본적으로 /dev/stdout에 출력되는 로그를 수집합니다. 더 고급 기능이 필요한 경우 <컨테이너 로그 수집>을 참조하세요.
로그 파일¶
이 예시에서는 로그 파일 수집을 다루지 않습니다. 필요한 경우 <Kubernetes 애플리케이션의 RUM-APM-LOG 연동 분석>을 참조하세요.
트레이스 타임아웃 분석¶
virtual-service-ratings-test-delay.yaml실행
- jason으로 로그인(비밀번호 없음)하고 productpage 인터페이스에 액세스
- 타임아웃된 트레이스를 클릭하고 플레임 그래프를 관찰하여 타임아웃 호출을 찾습니다.



























