lapee79's Tech Blog

lapee79의 기술 지식 창고.

Blackbox exporter를 이용한 HTTP 모니터링

Prometheus에서는 Blackbox exporter 를 이용하여 외부에 있는 서비스의 HTTP/HTTPS, DNS, TCP, ICMP 모니터링을 할 수 있습니다. 이 포스트에서는 이중에 HTTP/HTTPS를 모니터링하는 방식을 간단하게 알아보도록 하겠습니다. Kubernetes 상에서 Prometheus를 사용하는 환경의 사용자를 대상으로 작성하였습니다.

실행환경

여기에서는 다음과 같은 환경에서 Blackbox exporter를 사용한 모니터링 실습을 진행합니다.

  • Kubernetes
  • Prometheus operator

Blackbox exporter 설정 파일 생성

웹 서비스 엔드포인트를 모니터링하기 위한 http 모듈을 구성하기 위해 Blackbox configuration 파일을 ConfigMap으로 작성합니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-blackbox-exporter
  labels:
    app: prometheus-blackbox-exporter
data:
  blackbox.yaml: |
    modules:
      http_2xx:
        http:
          no_follow_redirects: false
          preferred_ip_protocol: ip4
          valid_http_versions:
          - HTTP/1.1
          - HTTP/2
          valid_status_codes: []
        prober: http
        timeout: 5s

위 모듈은 HTTP 프로토콜을 통해 액세스했을 때 서비스에서 2xx HTTP 상태 코드를 반환하는지를 확인하는데 사용되는 http_2xx라는 모듈을 작성한 것입니다. 설정값에 대한 상세한 내용은 다음 문서 에서 확인하실 수 있습니다.

Kubernetes에 Blackbox exporter 배포

Kubernetes에 배포할 수 있도록 Deployment와 Service를 작성합니다.

---
kind: Service
apiVersion: v1
metadata:
  name: prometheus-blackbox-exporter
  labels:
    app: prometheus-blackbox-exporter
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 9115
      protocol: TCP
  selector:
    app: prometheus-blackbox-exporter

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus-blackbox-exporter
  labels:
    app: prometheus-blackbox-exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus-blackbox-exporter
  template:
    metadata:
      labels:
        app: prometheus-blackbox-exporter
    spec:
      restartPolicy: Always
      containers:
        - name: blackbox-exporter
          image: "prom/blackbox-exporter:v0.15.1"
          imagePullPolicy: IfNotPresent
          securityContext:
            readOnlyRootFilesystem: true
            runAsNonRoot: true
            runAsUser: 1000
          args:
            - "--config.file=/config/blackbox.yaml"
          resources:
            {}
          ports:
            - containerPort: 9115
              name: http
          livenessProbe:
            httpGet:
              path: /health
              port: http
          readinessProbe:
            httpGet:
              path: /health
              port: http
          volumeMounts:
            - mountPath: /config
              name: config
        - name: configmap-reload
          image: "jimmidyson/configmap-reload:v0.2.2"
          imagePullPolicy: "IfNotPresent"
          securityContext:
            runAsNonRoot: true
            runAsUser: 65534
          args:
            - --volume-dir=/etc/config
            - --webhook-url=http://localhost:9115/-/reload
          resources:
            {}
          volumeMounts:
            - mountPath: /etc/config
              name: config
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: prometheus-blackbox-exporter

다음 명령어를 실행하여 Blackbox exporter를 Kubernetes에 배포합니다. Prometheus operator가 위치한 monitoring Namespace를 지정하여 배포했습니다.

kubectl --namespace=monitoring apply -f blackbox-exporter.yaml

설치를 검증합니다.

kubectl --namespace=monitoring get all --selector=app=prometheus-blackbox-exporter

Blackbox exporter Test

port-forward 를 통해 Blackbox exporter Web UI에 접속하여 상태를 확인할 수 있습니다.

kubectl --namespace=monitoring port-forward svc/prometheus-blackbox-exporter 9115:9115

웹 브라우져에서 http://localhost:9115 에 접속하면 다음과 같이 Web UI를 확인하실 수 있습니다.

Blackbox Exporter Web UI

웹 브라우져에서 http://localhost:9115/probe?module=http_2xx&target=https://www.google.com 으로 접속하면 target URL에 대한 메트릭 정보를 확인하실 수 있습니다.

URL Test on web browser

예를 들면 probe_success 메트릭이 1이면 성공이고 0이면 실패를 나타냅니다.

Prometheus 구성

위와 같이 검증을 마쳤다면, 이제 모니터링을 위한 설정을 Prometheus에 구성해줍니다.

- job_name: 'kube-api-blackbox'
  scrape_interval: 1w
  metrics_path: /probe
  params:
    module: [http_2xx]
  static_configs:
   - targets:
      - https://www.google.com
      - http://www.example.com
      - https://prometheus.io
  relabel_configs:
   - source_labels: [__address__]
     target_label: __param_target
   - source_labels: [__param_target]
     target_label: instance
   - target_label: __address__
     replacement: prometheus-blackbox-exporter:9115 # The blackbox exporter.

위의 내용을 prometheus-additional.yaml 에 추가하고 다음과 같이 Secret 을 생성합니다.

PROMETHEUS_ADD_CONFIG=$(cat prometheus-additional.yaml | base64)
cat << EOF | kubectl --namespace=monitoring apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: additional-scrape-configs
type: Opaque
data:
  prometheus-additional.yaml: $PROMETHEUS_ADD_CONFIG
EOF

생성된 Secret 을 Prometheus operator에 적용해줍니다.

kubectl --namespace=monitoring edit prometheuses k8s
...
spec:
  additionalScrapeConfigs:
    key: prometheus-additional.yaml
    name: additional-scrape-configs

Prometheus Web UI에 접속하여 메트릭 수집과 타겟 등록이 정상적으로 등록되었는지 확인합니다.

kubectl --namespace=monitoring port-forward svc/prometheus-k8s 9090:9090

Prometheus Metrics

Prometheus Targets

정상적으로 Prometheus에 등록되어 메트릭이 수집되는 것을 확인할 수 있을 것입니다.

Alert rule 추가

이제 알람 정책을 추가하여 장애발생 시에 알람을 받을 수 있도록 구성합니다.

kubectl --namespace=monitoring edit prometheusrules prometheus-k8s-rules
...
  - name: blackbox-exporter
    rules:
    - alert: ProbeFailed
      expr: probe_success == 0
      for: 5m
      labels:
        severity: error
      annotations:
        summary: "Probe failed (instance {{ $labels.instance }})"
        description: "Probe failed\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    - alert: SlowProbe
      expr: avg_over_time(probe_duration_seconds[1m]) > 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Slow probe (instance {{ $labels.instance }})"
        description: "Blackbox probe took more than 1s to complete\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    - alert: HttpStatusCode
      expr: probe_http_status_code <= 199 OR probe_http_status_code >= 400
      for: 5m
      labels:
        severity: error
      annotations:
        summary: "HTTP Status Code (instance {{ $labels.instance }})"
        description: "HTTP status code is not 200-399\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    - alert: SslCertificateWillExpireSoon
      expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 30
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "SSL certificate will expire soon (instance {{ $labels.instance }})"
        description: "SSL certificate expires in 30 days\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    - alert: SslCertificateHasExpired
      expr: probe_ssl_earliest_cert_expiry - time()  <= 0
      for: 5m
      labels:
        severity: error
      annotations:
        summary: "SSL certificate has expired (instance {{ $labels.instance }})"
        description: "SSL certificate has expired already\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    - alert: HttpSlowRequests
      expr: avg_over_time(probe_http_duration_seconds[1m]) > 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "HTTP slow requests (instance {{ $labels.instance }})"
        description: "HTTP request took more than 1s\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    - alert: SlowPing
      expr: avg_over_time(probe_icmp_duration_seconds[1m]) > 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Slow ping (instance {{ $labels.instance }})"
        description: "Blackbox ping took more than 1s\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"

Prometheus Web UI에서 Status => Rules 에서 alert rule이 등록되었는지 확인합니다.

Prometheus Alert rules

Kubernetes API Server SSL 인증서 만료 알람

추가적으로 Kubernetes API Server의 SSL 인증서를 모니터링하여 만료되기 3달 전에 1주일에 1번씩 알람을 발송하는 설정을 추가해보도록 하겠습니다.

Kubernetes API Server Authentication을 위한 Blackbox exporter module 설정 추가

kubectl --namespace=monitoring edit configmap prometheus-blackbox-exporter
...
      kube-api:
        http:
          method: GET
          no_follow_redirects: false
          preferred_ip_protocol: ip4
          tls_config:
            insecure_skip_verify: false
            ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
          valid_http_versions:
          - HTTP/1.1
          - HTTP/2
          valid_status_codes: []
        prober: http
        timeout: 5s

Prometheus configuration 추가

- job_name: 'kube-api-blackbox'
  metrics_path: /probe
  params:
    module: [kube-api]
  static_configs:
   - targets:
      - https://kubernetes.default.svc/api
  relabel_configs:
   - source_labels: [__address__]
     target_label: __param_target
   - source_labels: [__param_target]
     target_label: instance
   - target_label: __address__
     replacement: prometheus-blackbox-exporter:9115 # The blackbox exporter.

Prometheus Secret에 적용

PROMETHEUS_ADD_CONFIG=$(cat prometheus-additional.yaml | base64)
cat << EOF | kubectl --namespace=monitoring apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: additional-scrape-configs
type: Opaque
data:
  prometheus-additional.yaml: $PROMETHEUS_ADD_CONFIG
EOF

Alert rule 추가

kubectl --namespace=monitoring edit prometheusrules prometheus-k8s-rules
...
  - name: k8s-api-server-cert-expiry
    rules:
    - alert: K8sAPIServerSSLCertExpiringAfterThreeMonths
      expr: probe_ssl_earliest_cert_expiry{job="kube-api-blackbox"} - time() < 86400 * 90 
      for: 1w
      labels:
        severity: warning
      annotations:
        summary: "Kubernetes API Server SSL certificate will expire after three months (instance {{ $labels.instance }})"
        description: "Kubernetes API Server SSL certificate expires in 90 days\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
comments powered by Disqus