스터디/AEWS

[AEWS] 4주차 kube-prometheus-stack 설치 및 PromQL 쿼리 사용해보기

안녕유지 2025. 3. 2. 05:07
Cloudnet AWES 4주차 스터디를 진행하며 정리한 글입니다.

 

이번 포스팅에서는 쿠버네티스 환경에서 kube-prometheus-stack을 설치하고, 다양한 PromQL 쿼리를 이용하며 수집한 메트릭을 확인해보도록 하겠습니다.

 

kube-prometheus-stack 설치

# repo 추가
❯ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# 파라미터 파일 생성
❯ cat <<EOT > monitor-values.yaml
prometheus:
  prometheusSpec:
    scrapeInterval: "15s"
    evaluationInterval: "15s"
    podMonitorSelectorNilUsesHelmValues: false
    serviceMonitorSelectorNilUsesHelmValues: false
    retention: 5d
    retentionSize: "10GiB"
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: gp3
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 30Gi

  ingress:
    enabled: true
    ingressClassName: alb
    hosts: 
      - prometheus.$MyDomain
    paths: 
      - /*
    annotations:
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-type: ip
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
      alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
      alb.ingress.kubernetes.io/success-codes: 200-399
      alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
      alb.ingress.kubernetes.io/group.name: study
      alb.ingress.kubernetes.io/ssl-redirect: '443'

grafana:
  defaultDashboardsTimezone: Asia/Seoul
  adminPassword: prom-operator

  ingress:
    enabled: true
    ingressClassName: alb
    hosts: 
      - grafana.$MyDomain
    paths: 
      - /*
    annotations:
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-type: ip
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
      alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
      alb.ingress.kubernetes.io/success-codes: 200-399
      alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
      alb.ingress.kubernetes.io/group.name: study
      alb.ingress.kubernetes.io/ssl-redirect: '443'

  persistence:
    enabled: true
    type: sts
    storageClassName: "gp3"
    accessModes:
      - ReadWriteOnce
    size: 20Gi

alertmanager:
  enabled: false
defaultRules:
  create: false
kubeControllerManager:
  enabled: false
kubeEtcd:
  enabled: false
kubeScheduler:
  enabled: false
prometheus-windows-exporter:
  prometheus:
    monitor:
      enabled: false
EOT

❯ helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 69.3.1 \
-f monitor-values.yaml --create-namespace --namespace monitoring

 

grafana와 prometheus가 잘 설치 되었고, ALB를 통해 도메인과 연결되어 라우팅 되는 것도 확인할 수 있었습니다.

 

프로메테우스 대시보드 사용방법

프로메테우스의 모니터링 되는 서비스는 일반적으로 /metrics 엔드포인트 경로에 다양한 메트릭 정보를 노출시킵니다.

이후 프로메테우스는 해당 경로에 http get 방식으로 메트릭 정보를 가져와서 TSDB에 저장합니다.

  • Query : PromQL을 통해 메트릭 정보를 조회
  • Alerts : 사전에 정의한 경고 정책 (Prometheus rule)에 대한 상황
  • Status : 프로메테우스 서버의 현재 상태 및 동작을 모니터링하는데 필요한 정보
    • Monitoring Status (모니터링 상태)
      • target health : 프로메테우스가 스크랩하고 있는 타켓 Exporter등의 상태 확인 (업다운, 스크랩 성공여부, 주기 등)
      • rule health : 레코딩 규칙 및 알람 규칙 상태 확인
      • service discovery : 자동으로 발견한 모니터링 대상 목록
    • Server Status (서버 상태)
      • Run & build information : 프로메테우스 버전, 빌드 시점, 실행 환경 등에 대한 정보
      • TSDB status : TSDB 상태 (저장된 시계열 데이터 수, 활성화된 블록 수, 메모리 사용량 등)
      • command-line flags : 커맨드라인 옵션 목록
      • Configuration : 프로메테우스 설정파일 yaml 확인
      • Alertmanager discovery : Alertmanager 인스턴스 목록

 

Configuration에서 지금 프로메테우스에 적용된 설정파일 정보로 어느 수집 주기를 가지는지, 어떤 걸 수집하는지 확인해보도록 하겠습니다.

global:
  scrape_interval: 15s # 메트릭 수집 주기
  scrape_timeout: 10s # 메트릭 타임 아웃
  scrape_protocols:
  - OpenMetricsText1.0.0
  - OpenMetricsText0.0.1
  - PrometheusText1.0.0
  - PrometheusText0.0.4
  evaluation_interval: 15s
  external_labels:
    prometheus: monitoring/kube-prometheus-stack-prometheus
    prometheus_replica: prometheus-kube-prometheus-stack-prometheus-0
runtime:
  gogc: 75
rule_files:
- /etc/prometheus/rules/prometheus-kube-prometheus-stack-prometheus-rulefiles-0/*.yaml
scrape_configs:
- job_name: serviceMonitor/monitoring/kube-prometheus-stack-apiserver/0 # kube-prometheus-stack-apiserver 에 대한 수집 메트릭 처리
  honor_timestamps: true
  track_timestamps_staleness: false
  scrape_interval: 15s
  scrape_timeout: 10s
  scrape_protocols:
  - OpenMetricsText1.0.0
  - OpenMetricsText0.0.1
  - PrometheusText1.0.0
  - PrometheusText0.0.4
  metrics_path: /metrics
  scheme: https
  enable_compression: true

 

 

아이고,, 헷갈렸던 부분이 target health에서 보이는 것과 service discovery에서 보이는 것이 달라서였는데 차이를 알게 되었습니다.

예를 들어 kube-prometheus-stack-apiserver라는 serviceMonitor는 쿠버네티스 API 서버의 메트릭 정보를 프로메테우스가 수집할 수 있도록 설정한 serviceMonitor입니다.

이 때 실제 target의 헬스체크에서는 프로메테우스가 API 서버의 메트릭을 잘 가져오고 있고, 모니터링 하는 대상은 2개임을 알 수 있습니다.

다만, service discovery에서 2/10으로 나오는데, 이 때 실제 자동적으로 발견한 대상은 일반 어플리케이션 파드에 관련된 메트릭도 있었습니다. 왜 그랬을까요? 

service discovery는 프로메테우스가 감지한 모든 엔드포인트를 보여주는 페이지로, 모든 엔드포인트가 프로메테우스에서 수집되는 것은 아닙니다. 총 10개의 엔드포인트를 발견했지만, 실제로 모니터링 중인 타켓은 2개라는 의미입니다.

target health
service discovery

 

 

Prometheus가 kube-prometheus-stack-apiserver ServiceMonitor를 통해 감지한 Kubernetes API Server (kube-apiserver)의 엔드포인트는 각 클러스터의 kube-apiserver 서비스가 실행되는 노드(컨트롤 플레인 노드)의 IP 주소입니다.

이 때, EKS는 컨트롤 플레인을 AWS에서 관리해서 직접 사용자가 컨트롤 플레인을 볼 수 는 없지만, 컨트롤 플레인이 2개로 보이는 것은 실제로 내부적으로 2개의 API 서버를 운영하거나, 부하 분산을 위해 여러 개의 엔드포인트를 제공하는 것일 가능성이 크다고 합니다.

❯ kubectl get endpoints kubernetes                                              
NAME         ENDPOINTS                             AGE
kubernetes   192.168.2.222:443,192.168.3.105:443   11h

AWS EKS Control Plane의 scheduler, controller-manager 메트릭 수집

현재 target 대상을 확인해보면

apiserver, coredns, kube-proxy, kube-state-metrics, kubelet, kube-prometheus-stack-operator, node-exporter, prometheus에 대해서만 pulling을 하고 있습니다.

 

그렇다면, EKS Control plane에서 scheduler와 controller manager에 대해서는 메트릭 수집을 할 수 없을까요?

(kube-apiserversms kubernetes 서비스로 접근이 가능하지만, scheduler랑 controller-manager는 내부적으로만 실행됩니다.)

 

일반 API 서버의 /metrics 엔드포인트는 특정 메트릭을 살펴볼 때 유용합니다.

Kubernetes 버전 1.28이상인 클러스터의 경우 Amazon EKS는 API 그룹 하위 메트릭(metrics.eks.amazonaws.com)도 노출합니다. 이러한 메트릭에는 kube-scheduler, kube-controller-manager과 같은  같은 컨트롤 플레인 컴포넌트도 포함됩니다.

 

만약 프로메테우스에서 해당 엔드포인트에 대해 스크랩하고 싶다면, scrape_config에 scrape job을 추가하면 될 것으로 보입니다.

https://docs.aws.amazon.com/eks/latest/userguide/view-raw-metrics.html

 

Fetch control plane raw metrics in Prometheus format - Amazon EKS

If you have a webhook configuration that could block the creation of the new APIService resource v1.metrics.eks.amazonaws.com on your cluster, the metrics endpoint feature might not be available. You can verify that in the kube-apiserver audit log by searc

docs.aws.amazon.com

 

❯ kubectl get --raw /metrics
rest_client_response_size_bytes_count{host="localhost:10277",verb="POST"} 3824
rest_client_response_size_bytes_bucket{host="localhost:21362",verb="POST",le="64"} 0
rest_client_response_size_bytes_bucket{host="localhost:21362",verb="POST",le="256"} 0
rest_client_response_size_bytes_bucket{host="localhost:21362",verb="POST",le="512"} 128
...

# kube-scheduler 메트릭
❯ kubectl get --raw "/apis/metrics.eks.amazonaws.com/v1/ksh/container/metrics"
# HELP scheduler_pending_pods [STABLE] Number of pending pods, by the queue type. 'active' means number of pods in activeQ; 'backoff' means number of pods in backoffQ; 'unschedulable' means number of pods in unschedulablePods that the scheduler attempted to schedule and failed; 'gated' is the number of unschedulable pods that the scheduler never attempted to schedule because they are gated.
# TYPE scheduler_pending_pods gauge
scheduler_pending_pods{queue="active"} 0
scheduler_pending_pods{queue="backoff"} 0
scheduler_pending_pods{queue="gated"} 0
scheduler_pending_pods{queue="unschedulable"} 0
# HELP scheduler_pod_scheduling_attempts [STABLE] Number of attempts to successfully schedule a pod.
# TYPE scheduler_pod_scheduling_attempts histogram
scheduler_pod_scheduling_attempts_bucket{le="1"} 0
scheduler_pod_scheduling_attempts_bucket{le="2"} 0
scheduler_pod_scheduling_attempts_bucket{le="4"} 0
scheduler_pod_scheduling_attempts_bucket{le="8"} 0
scheduler_pod_scheduling_attempts_bucket{le="16"} 0
scheduler_pod_scheduling_attempts_bucket{le="+Inf"} 0
scheduler_pod_scheduling_attempts_sum 0
scheduler_pod_scheduling_attempts_count 0
# HELP scheduler_preemption_attempts_total [STABLE] Total preemption attempts in the cluster till now
# TYPE scheduler_preemption_attempts_total counter
scheduler_preemption_attempts_total 0
# HELP scheduler_preemption_victims [STABLE] Number of selected preemption victims
# TYPE scheduler_preemption_victims histogram
scheduler_preemption_victims_bucket{le="1"} 0
scheduler_preemption_victims_bucket{le="2"} 0
scheduler_preemption_victims_bucket{le="4"} 0
scheduler_preemption_victims_bucket{le="8"} 0

# kube-controller-manager 메트릭
❯ kubectl get --raw "/apis/metrics.eks.amazonaws.com/v1/kcm/container/metrics"
# HELP workqueue_adds_total [ALPHA] Total number of adds handled by workqueue
# TYPE workqueue_adds_total counter
workqueue_adds_total{name="DynamicConfigMapCABundle-client-ca"} 1436
workqueue_adds_total{name="DynamicServingCertificateController"} 719
workqueue_adds_total{name="RequestHeaderAuthRequestController"} 1
# HELP workqueue_depth [ALPHA] Current depth of workqueue
# TYPE workqueue_depth gauge
workqueue_depth{name="DynamicConfigMapCABundle-client-ca"} 0
workqueue_depth{name="DynamicServingCertificateController"} 0
workqueue_depth{name="RequestHeaderAuthRequestController"} 0
# HELP workqueue_queue_duration_seconds [ALPHA] How long in seconds an item stays in workqueue before being requested.
# TYPE workqueue_queue_duration_seconds histogram
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="1e-08"} 0
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="1e-07"} 0
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="1e-06"} 0
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="9.999999999999999e-06"} 1346
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="9.999999999999999e-05"} 1432
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="0.001"} 1434
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="0.01"} 1434
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="0.1"} 1436
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="1"} 1436
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="10"} 1436
workqueue_queue_duration_seconds_bucket{name="DynamicConfigMapCABundle-client-ca",le="+Inf"} 1436
workqueue_queue_duration_seconds_sum{name="DynamicConfigMapCABundle-client-ca"} 0.20809325699999992
workqueue_queue_duration_seconds_count{name="DynamicConfigMapCABundle-client-ca"} 1436
workqueue_queue_duration_seconds_bucket{name="DynamicServingCertificateController",le="1e-08"} 0
workqueue_queue_duration_seconds_bucket{name="DynamicServingCertificateController",le="1e-07"} 0
workqueue_queue_duration_seconds_bucket{name="DynamicServingCertificateController",le="1e-06"} 0
workqueue_queue_duration_seconds_bucket{name="DynamicServingCertificateController",le="9.999999999999999e-06"} 11

 

 

AWS EKS CNI Metrics 수집

AWS에서는 CNI로 VPC-CNI를 사용합니다. 이 설정은 aws-node 파드에 들어가있죠. 따라서 AWS EKS CNI에 대한 메트릭을 수집하고 싶다면, aws-node에 대한 PodMonitor를 배포하면 됩니다.

# PodMonitor 배포
❯ cat <<EOF | kubectl create -f -
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: aws-cni-metrics
  namespace: kube-system
spec:
  jobLabel: k8s-app
  namespaceSelector:
    matchNames:
    - kube-system
  podMetricsEndpoints:
  - interval: 30s
    path: /metrics
    port: metrics
  selector:
    matchLabels:
      k8s-app: aws-node
EOF

# PodMonitor 확인
❯ kubectl get podmonitor -n kube-system
❯ kubectl get podmonitor -n kube-system aws-cni-metrics -o yaml | kubectl neat
          
# metrics url 접속 확인
❯ curl -s $N1:61678/metrics | grep '^awscni'
awscni_add_ip_req_count 11
awscni_assigned_ip_addresses 8
awscni_assigned_ip_per_cidr{cidr="192.168.1.123/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.139/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.14/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.21/32"} 0
awscni_assigned_ip_per_cidr{cidr="192.168.1.222/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.227/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.236/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.4/32"} 1
awscni_assigned_ip_per_cidr{cidr="192.168.1.92/32"} 1
awscni_assigned_ip_per_eni{eni="eni-087024b16973016df"} 2
awscni_assigned_ip_per_eni{eni="eni-0a2342b642db635c3"} 1
awscni_assigned_ip_per_eni{eni="eni-0f95bf034923b2f78"} 5
awscni_aws_api_latency_ms_sum{api="AssignPrivateIpAddresses",error="false",status="200"} 386
awscni_aws_api_latency_ms_count{api="AssignPrivateIpAddresses",error="false",status="200"} 1
awscni_aws_api_latency_ms_sum{api="AttachNetworkInterface",error="false",status="200"} 1636
awscni_aws_api_latency_ms_count{api="AttachNetworkInterface",error="false",status="200"} 2
awscni_aws_api_latency_ms_sum{api="CreateNetworkInterface",error="false",status="200"} 917
awscni_aws_api_latency_ms_count{api="CreateNetworkInterface",error="false",status="200"} 2
awscni_aws_api_latency_ms_sum{api="CreateTags",error="false",status="200"} 141
awscni_aws_api_latency_ms_count{api="CreateTags",error="false",status="200"} 1
awscni_aws_api_latency_ms_sum{api="DescribeInstances",error="false",status="200"} 272
awscni_aws_api_latency_ms_count{api="DescribeInstances",error="false",status="200"} 2
awscni_aws_api_latency_ms_sum{api="DescribeNetworkInterfaces",error="false",status="200"} 210
awscni_aws_api_latency_ms_count{api="DescribeNetworkInterfaces",error="false",status="200"} 1
awscni_aws_api_latency_ms_sum{api="DescribeSubnets",error="false",status="200"} 466
awscni_aws_api_latency_ms_count{api="DescribeSubnets",error="false",status="200"} 2
awscni_aws_api_latency_ms_sum{api="GetMetadata",error="false",status="200"} 8710
awscni_aws_api_latency_ms_count{api="GetMetadata",error="false",status="200"} 18579
awscni_aws_api_latency_ms_sum{api="GetMetadata",error="true",status="404"} 956
awscni_aws_api_latency_ms_count{api="GetMetadata",error="true",status="404"} 2138
awscni_aws_api_latency_ms_sum{api="ModifyNetworkInterfaceAttribute",error="false",status="200"} 1247
awscni_aws_api_latency_ms_count{api="ModifyNetworkInterfaceAttribute",error="false",status="200"} 3
awscni_aws_api_latency_ms_sum{api="waitForENIAndIPsAttached",error="false",status="200"} 1699
awscni_aws_api_latency_ms_count{api="waitForENIAndIPsAttached",error="false",status="200"} 2
awscni_build_info{goversion="go1.22.12",version=""} 1
awscni_del_ip_req_count{reason="PodDeleted"} 9
awscni_ec2api_req_count{fn="AssignPrivateIpAddresses"} 1
awscni_ec2api_req_count{fn="AttachNetworkInterface"} 2
awscni_ec2api_req_count{fn="CreateNetworkInterface"} 2
awscni_ec2api_req_count{fn="CreateTags"} 1
awscni_ec2api_req_count{fn="DescribeInstances"} 2
awscni_ec2api_req_count{fn="DescribeNetworkInterfaces"} 13
awscni_ec2api_req_count{fn="DescribeSubnets"} 2
awscni_ec2api_req_count{fn="ModifyNetworkInterfaceAttribute"} 3
awscni_eni_allocated 3
awscni_eni_max 3
awscni_force_removed_enis 0
awscni_force_removed_ips 0
awscni_ip_max 15
awscni_ipamd_action_inprogress{fn="increaseDatastorePool"} 0
awscni_ipamd_action_inprogress{fn="nodeIPPoolReconcile"} 0
awscni_ipamd_action_inprogress{fn="nodeInit"} 0
awscni_no_available_ip_addresses 0
awscni_reconcile_count{fn="eniDataStorePoolReconcileAdd"} 10615
awscni_total_ip_addresses 15

 

추가적으로, 해당 메트릭을 Grafana에서 예쁘게 볼 수 있는 대시보드도 있습니다.

https://grafana.com/grafana/dashboards/16032-aws-cni-metrics/

 

AWS CNI Metrics | Grafana Labs

The AWS VPC CNI, found on EKS, exposes metrics that can be collected in Prometheus. This is not the case by default, AWS favoring CloudWatch, so you’ll have to add a podMonitor matching the aws-node daemonset: apiVersion: monitoring.coreos.com/v1 kind: P

grafana.com

 

 

PromQL 활용하기

이제, 프로메테우스 대시보드에서 메트릭을 Graph로 조회해보며, 메트릭 값과 프로메테우스에서 사용하는 쿼리문에 대한 이해를 해보겠습니다.

node_cpu_seconds_total에 대한 메트릭으로 확인해보겠습니다. 해당 메트릭은 특정 모드별로 CPU가 소비한 총 시간을 초 단위로 측정한 값입니다.

하지만 (node_cpu_seconds_total{mode="idle"}[1m])는 값을 반환하지 못했습니다.

그 이유는 프롬쿼리(PromQL)에서 [1m]는 범위 벡터(range vector) 선택자인데, 범위 벡터를 단순히 조회할 수 없습니다.

따라서, 이러한 경우네는 rate(), avg_over_time()과 같은 함수를 사용해야합니다. 

다음과 같이 1분평균 CPU Idle 비율을 확인하는 쿼리는 정상 수행된 것을 확인할 수 있습니다.

 

++ Time Series Selector

  • Instance Vector : 시점에 대한 메트릭 값만 가지는 타입
  • Range Vector : 시간의 구간을 가지는 타입

 

 

node exporter

리눅스 서버의 하드웨어 및 시스템 리소스 관련 메트릭을 수집하는 익스포터입니다.

Node exporter는 /proc, /sys에서 다양한 정보를 가져오는 collector를 사용합니다.

 

1) CPU Collector

/proc/stat 파일에서 CPU 관련 정보를 가져옵니다.

CPU의 상태별 시간(Idle, user, system, iowait 등)을 측정합니다.

ex)

 

  • node_cpu_seconds_total{mode="idle"} → 1362393초
  • node_cpu_seconds_total{mode="user"} → 4695초

2) Diskstats Collector

/proc/diskstats 파일에서 디스크 I/O상태를 수집합니다.

디스크 사용량, 읽기쓰기 횟수, I/O 대기 시간등을 측정합니다.

ex)

 

  • node_disk_reads_completed_total → 124335 (디스크 읽기 완료 횟수)
  • node_disk_writes_completed_total → 181373 (디스크 쓰기 완료 횟수)
  • node_disk_io_time_seconds_total → 932412 (총 디스크 I/O 시간)

3) Filesystem Collector

/proc/mounts, /sys/fs/cgroup, /proc/diskstats 등을 활용해 파일 시스템 정보를 수집합니다.

마운트된 파일 시스템별 사용량을 보여줍니다.

ex) 

  • node_filesystem_size_bytes{mountpoint="/"} 500000000000
  • node_filesystem_free_bytes{mountpoint="/"} 200000000000

4) Memeory Collector

/proc/meminfo 파일을 읽어 총 메모리, 사용 가능한 메모리, 캐시, 스왑 정보를 제공합니다.

ex)

  • node_memory_MemTotal_bytes 16777216
  • node_memory_MemAvailable_bytes 8388608
  • node_memory_Cached_bytes 4194304

5) Load Average, Update 등등

 

 

kube-state-metrics exporter

쿠버네티스 리소스(pod, deployment, node, namespace)의 상태 정보를 제공합니다.

ex)

  • kube_pod_status_phase : 각 Pod의 태 (Pending, Running, Succeeded, Failed)
  • kube_pod_container_status_restarts_total : 컨테이너 재시작 횟수
  • kube_node_status_ready : 노드가 Ready 상태인지 확인 (1 = Ready)
  • kube_deployment_status_replicas_available : Deployment에서 사용 가능한 Replica 수
  • kube_service_spec_type : Service의 Type (ClusterIP, NodePort, LoadBalancer)
  • kube_namespace_status_phase : 네임스페이스의 상태 (Active, Terminating)

 

kube-proxy exporter

쿠버네티스에서 service와 Pod간의 네트워크 라우팅을 담당할 때, iptables, ipvs 등 네트워크 라우팅을 관리하고 모니터링하는 메트릭을 제공합니다.

ex)

  • kubeproxy_network_programming_duration_seconds : 네트워크 규칙(iptables/IPVS) 적용에 걸린 시간
  • kubeproxy_sync_proxy_rules_duration_seconds : kube-proxy가 iptables 규칙을 동기화하는 데 걸린 시간
  • kubeproxy_sync_proxy_rules_count : kube-proxy의 프로세스가 iptables/ipvs 규칙을 몇 번 업데이트했는지
  • kubeproxy_total_sync_proxy_rules_duration_seconds : kube-proxy가 iptables/ipvs 규칙을 완전히 동기화하는 데 걸린 총 시간

 

 

이러한 EKS 기본 Exporter 말고, 내가 배포하고자 하는 서비스에 대해서 Exporter를 추가하여 프로메테우스로 모니터링 할 수 있습니다.

 

어플리케이션 ServiceMonitor, Exporter

https://docs-archive.sc.otc.t-systems.com/usermanual/cce/cce_10_0201.html

 

nginx 웹서버에 metrics 수집 설정을 추가합니다.

기존에는 nginx를 수집할 수 있는 target이 없었습니다.

 

# 모니터링
❯ watch -d "kubectl get pod; echo; kubectl get servicemonitors -n monitoring"

# nginx 파드내에 컨테이너 갯수 확인 
❯ kubectl describe pod -l app.kubernetes.io/instance=nginx
1개 있음 (nginx)

# 서비스 모니터 방식으로 nginx 모니터링 대상을 등록하고, export 는 9113 포트 사용
cat <<EOT > nginx-values.yaml
metrics:
  enabled: true

  service:
    port: 9113

  serviceMonitor:
    enabled: true
    namespace: monitoring
    interval: 10s
EOT

# 배포
helm upgrade nginx bitnami/nginx --reuse-values -f nginx-values.yaml

# 확인
kubectl get pod,svc,ep | grep nginx
❯ kubectl get pod,svc,ep | grep nginx                                                   
pod/nginx-85df7754bf-dr6pm           2/2     Running   0          51s
service/nginx         NodePort    10.100.80.120    <none>        80:31818/TCP,443:31903/TCP,9113:32378/TCP   3h55m
endpoints/nginx         192.168.1.21:9113,192.168.1.21:8443,192.168.1.21:8080      3h55m



# [운영서버 EC2] 메트릭 확인 >> 프로메테우스에서 Target 확인
**## nginx sub_status url 접속해보기**
NGINXIP=$(kubectl get pod -l app.kubernetes.io/instance=nginx -o jsonpath="{.items[0].status.podIP}")
curl -s http://$NGINXIP:9113/metrics # nginx_connections_active Y 값 확인해보기
curl -s http://$NGINXIP:9113/metrics | grep nginx
# HELP nginx_connections_accepted Accepted client connections
# TYPE nginx_connections_accepted counter
nginx_connections_accepted 80
# HELP nginx_connections_active Active client connections
# TYPE nginx_connections_active gauge
nginx_connections_active 1
# HELP nginx_connections_handled Handled client connections
# TYPE nginx_connections_handled counter
nginx_connections_handled 80
# HELP nginx_connections_reading Connections where NGINX is reading the request header
# TYPE nginx_connections_reading gauge
nginx_connections_reading 0
# HELP nginx_connections_waiting Idle client connections
# TYPE nginx_connections_waiting gauge
nginx_connections_waiting 0
# HELP nginx_connections_writing Connections where NGINX is writing the response back to the client
# TYPE nginx_connections_writing gauge
nginx_connections_writing 1
# HELP nginx_exporter_build_info A metric with a constant '1' value labeled by version, revision, branch, goversion from which nginx_exporter was built, and the goos and goarch for the build.
# TYPE nginx_exporter_build_info gauge
nginx_exporter_build_info{branch="HEAD",goarch="amd64",goos="linux",goversion="go1.22.12",revision="8da901c87176210a4951f427742c05bfa96c838f",tags="unknown",version="1.4.1"} 1
# HELP nginx_http_requests_total Total http requests
# TYPE nginx_http_requests_total counter
nginx_http_requests_total 102
# HELP nginx_up Status of the last metric scrape
# TYPE nginx_up gauge
nginx_up 1

curl -s http://$NGINXIP:9113/metrics | grep ^nginx_connections_active

# nginx 파드내에 컨테이너 갯수 확인 : metrics 컨테이너 확인
kubectl get pod -l app.kubernetes.io/instance=nginx
2개 있음 (metrics, nginx)


# 접속 주소 확인 및 접속
echo -e "Nginx WebServer URL = https://nginx.$MyDomain"
curl -s https://nginx.$MyDomain
kubectl stern deploy/nginx

# 반복 접속
while true; do curl -s https://nginx.$MyDomain -I | head -n 1; date; sleep 1; done

 

하지만, 배포 후 serviceMonitor가 9113 포트, container도 metrics 컨테이너에 대해 노출된 것을 볼 수 있습니다.

(위에 배포한 serviceMonitor는, monitoring 네임스페이스에 배포된다는 것일뿐, 실제 메트릭 수집대상과는 관련이 없어서 다른 네임스페이스에 있는 서비스를 수집할 수도 있습니다.)