관찰성 모범 사례
관찰성 모범 사례 (Observability Best Practices)
Istio를 사용해 애플리케이션을 관찰하기 위한 모범 사례를 다뤄요. Prometheus를 프로덕션 규모로 이용한 모니터링, 계층적 페더레이션, recording rules를 통한 메트릭 수집 최적화를 배워요.
출처: Istio 문서
본문
프로덕션 규모 모니터링에 Prometheus 사용하기
Prometheus로 Istio 메시를 프로덕션 규모로 모니터링하기 위한 권장 접근 방식은 계층적 페더레이션(hierarchical federation)을 recording rules 모음과 함께 사용하는 것이에요.
Istio를 설치해도 Prometheus가 기본으로 배포되지는 않지만, Getting Started 지침은 Prometheus 통합 가이드에 설명된 Option 1: Quick Start 배포를 설치해요. 이 Prometheus 배포는 의도적으로 매우 짧은 보존 기간(6시간)으로 구성돼 있어요. Also quick-start Prometheus 배포는 메시에서 실행되는 각 Envoy 프록시의 메트릭을 수집하고, 각 메트릭에 기원에 대한 라벨 집합(instance, pod, namespace)을 추가하도록 구성돼 있어요.
recording rules를 통한 워크로드 수준 집계
인스턴스와 파드에 걸쳐 메트릭을 집계하려면 기본 Prometheus 구성을 다음 recording rules로 업데이트하세요.
groups:
- name: "istio.recording-rules"
interval: 5s
rules:
- record: "workload:istio_requests_total"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_requests_total)
- record: "workload:istio_request_duration_milliseconds_count"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_duration_milliseconds_count)
- record: "workload:istio_request_duration_milliseconds_sum"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_duration_milliseconds_sum)
- record: "workload:istio_request_duration_milliseconds_bucket"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_duration_milliseconds_bucket)
- record: "workload:istio_request_bytes_count"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_bytes_count)
- record: "workload:istio_request_bytes_sum"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_bytes_sum)
- record: "workload:istio_request_bytes_bucket"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_bytes_bucket)
- record: "workload:istio_response_bytes_count"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_response_bytes_count)
- record: "workload:istio_response_bytes_sum"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_response_bytes_sum)
- record: "workload:istio_response_bytes_bucket"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_response_bytes_bucket)
- record: "workload:istio_tcp_sent_bytes_total"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_sent_bytes_total)
- record: "workload:istio_tcp_received_bytes_total"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_received_bytes_total)
- record: "workload:istio_tcp_connections_opened_total"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_connections_opened_total)
- record: "workload:istio_tcp_connections_closed_total"
expr: |
sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_connections_closed_total)
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: istio-metrics-aggregation
labels:
app.kubernetes.io/name: istio-prometheus
spec:
groups:
- name: "istio.metricsAggregation-rules"
interval: 5s
rules:
- record: "workload:istio_requests_total"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_requests_total)"
- record: "workload:istio_request_duration_milliseconds_count"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_duration_milliseconds_count)"
- record: "workload:istio_request_duration_milliseconds_sum"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_duration_milliseconds_sum)"
- record: "workload:istio_request_duration_milliseconds_bucket"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_duration_milliseconds_bucket)"
- record: "workload:istio_request_bytes_count"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_bytes_count)"
- record: "workload:istio_request_bytes_sum"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_bytes_sum)"
- record: "workload:istio_request_bytes_bucket"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_request_bytes_bucket)"
- record: "workload:istio_response_bytes_count"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_response_bytes_count)"
- record: "workload:istio_response_bytes_sum"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_response_bytes_sum)"
- record: "workload:istio_response_bytes_bucket"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_response_bytes_bucket)"
- record: "workload:istio_tcp_sent_bytes_total"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_sent_bytes_total)"
- record: "workload:istio_tcp_received_bytes_total"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_received_bytes_total)"
- record: "workload:istio_tcp_connections_opened_total"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_connections_opened_total)"
- record: "workload:istio_tcp_connections_closed_total"
expr: "sum without(instance, kubernetes_namespace, kubernetes_pod_name) (istio_tcp_connections_closed_total)"
위 recording rules는 파드와 인스턴스에 걸쳐서만 집계해요. 모든 Istio 차원을 포함한 Istio Standard Metrics의 전체 집합은 여전히 보존해요. 이것이 페더레이션을 통한 메트릭 카디널리티 제어에 도움이 되지만, 기존 대시보드, 알림, 임시 쿼리에 맞게 recording rules를 더 최적화하고 싶을 수 있어요.
recording rules를 맞춤화하는 방법에 대한 자세한 내용은 recording rules로 메트릭 수집 최적화 섹션을 참고하세요.
워크로드 수준 집계 메트릭을 사용한 페더레이션
Prometheus 페더레이션을 구축하려면 프로덕션급 Prometheus 배포의 구성을 수정해 Istio Prometheus의 페더레이션 엔드포인트를 스크래이프하세요.
구성에 다음 작업을 추가하세요.
- job_name: 'istio-prometheus'
honor_labels: true
metrics_path: '/federate'
kubernetes_sd_configs:
- role: pod
namespaces:
names: ['istio-system']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'workload:(.*)'
target_label: __name__
action: replace
params:
'match[]':
- '{__name__=~"workload:(.*)"}'
- '{__name__=~"pilot(.*)"}'
Prometheus Operator를 사용한다면 대신 다음 구성을 사용하세요.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: istio-federation
labels:
app.kubernetes.io/name: istio-prometheus
spec:
namespaceSelector:
matchNames:
- istio-system
selector:
matchLabels:
app: prometheus
endpoints:
- interval: 30s
scrapeTimeout: 30s
params:
'match[]':
- '{__name__=~"workload:(.*)"}'
- '{__name__=~"pilot(.*)"}'
path: /federate
targetPort: 9090
honorLabels: true
metricRelabelings:
- sourceLabels: ["__name__"]
regex: 'workload:(.*)'
targetLabel: "__name__"
action: replace
페더레이션 구성의 핵심은 Istio가 배포한 Prometheus에서 Istio Standard Metrics를 수집하는 작업과 매칭하고, 워크로드 수준 recording rules에 사용된 접두사(workload:)를 제거해서 수집된 메트릭의 이름을 바꾸는 것이에요. 이렇게 하면 기존 대시보드와 쿼리가 프로덕션 Prometheus 인스턴스를 가리킬 때(Istio 인스턴스에서 벗어나서) 매끄럽게 계속 작동하게 돼요.
페더레이션을 설정할 때 추가 메트릭(예: envoy, go 등)도 포함할 수 있어요.
컨트롤 플레인 메트릭도 수집되어 프로덕션 Prometheus로 페더레이션돼요.
recording rules로 메트릭 수집 최적화
파드와 인스턴스에 걸쳐 집계하는 방법으로 recording rules를 사용하는 것 이상으로, 기존 대시보드와 알림에 특별히 맞춘 집계 메트릭을 생성하기 위해 recording rules를 사용하고 싶을 수 있어요. 이런 방식으로 수집을 최적화하면 프로덕션 Prometheus 인스턴스에서 리소스 소비를 크게 절약하고 쿼리 성능도 더 빨라져요.
예를 들어 다음 Prometheus 쿼리를 사용한 커스텀 모니터링 대시보드를 상상해 보세요.
- 지난 1분 동안 목적지 서비스 이름과 네임스페이스별로 평균 낸 요청 총 비율
sum(irate(istio_requests_total{reporter="source"}[1m]))
by (
destination_canonical_service,
destination_workload_namespace
)
- 지난 1분 동안 소스 및 목적지 서비스 이름과 네임스페이스별로 평균 낸 P95 클라이언트 지연 시간
histogram_quantile(0.95,
sum(irate(istio_request_duration_milliseconds_bucket{reporter="source"}[1m]))
by (
destination_canonical_service,
destination_workload_namespace,
source_canonical_service,
source_workload_namespace,
le
)
)
다음 recording rules 집합을 Istio Prometheus 구성에 추가할 수 있는데, istio 접두사를 사용해 페더레이션용 메트릭 식별을 쉽게 해요.
groups:
- name: "istio.recording-rules"
interval: 5s
rules:
- record: "istio:istio_requests:by_destination_service:rate1m"
expr: |
sum(irate(istio_requests_total{reporter="destination"}[1m]))
by (
destination_canonical_service,
destination_workload_namespace
)
- record: "istio:istio_request_duration_milliseconds_bucket:p95:rate1m"
expr: |
histogram_quantile(0.95,
sum(irate(istio_request_duration_milliseconds_bucket{reporter="source"}[1m]))
by (
destination_canonical_service,
destination_workload_namespace,
source_canonical_service,
source_workload_namespace,
le
)
)
그러면 프로덕션 Prometheus 인스턴스는 다음으로 Istio 인스턴스에서 페더레이션하도록 업데이트돼요.
{__name__=~"istio:(.*)"}매치 절regex: "istio:(.*)"가 있는 메트릭 재라벨링 구성
원래 쿼리는 다음으로 대체돼요.
istio_requests:by_destination_service:rate1mavg(istio_request_duration_milliseconds_bucket:p95:rate1m)