ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Monitoring] Prometheus + google chat 으로 알림받기
    Infra/devOps 2024. 11. 6. 05:42

     

    Prometheus는 SoundCloud사에서 만든 오픈소스 시스템 모니터링 및 경고 툴킷이다.

    지금은 독립형 오픈소스 프로젝트이며 많은 회사들이 사용 하고 있고, 또한 kubernetes에서도 Prometheus를 사용하여 매트릭 수집 및 대시보드 구축하는 방식을 장려하고 있다.

     

     

     

    저기 보이는 exporter 들은 값을 수집하는 프로세스라고 보면 된다.

     

    이 exporter가 매트릭을 수집하고 HTTP 통신을 통해 매트릭 데이터를 가져갈 수 있게 /metrics 라는 HTTP 엔드포인트를 제공한다.

    그러면 프로메테우스가 Get 요청으로 받아온다고 한다.

     

    필자는 도커로 프로메테우스를 설정하였다.

     

    먼저 prometheus.yml 설정을 확인해보자.

    global:
      scrape_interval: 15s 
      evaluation_interval: 15s
    
    alerting:
      alertmanagers:
        - static_configs:
            - targets: ["alertmanager:9093"]
    
    rule_files:
      - "alert.rules.yml"
    
    scrape_configs:
      - job_name: "mysql_exporters"
        static_configs:
          - targets:
              - "mysql_exporter-prod:9104" 
              - "mysql_exporter-qa:9104"
              - "mysql_exporter-dev:9104" 
    
      - job_name: "node_exporters"
        static_configs:
          - targets:
              - "1.2.3.4:9100"
              - "1.2.3.5:9100"
              - "1.2.3.6:9100"

     

    내가 사용한 코드는 다음과 같다.

     

    scrape_interval: Prometheus가 정의된 모든 scrape_configs에서 메트릭 데이터를 수집하는 주기이다.
    evaluation_interval: Prometheus가 정의된 규칙을 평가하는 주기라고 하는데 Alerting이나 Recording 규칙이라고 한다.

     

     

    AlertManager 설정

    alerting 이 있는 부분은

    경고를 발생시킬 때 경고를 전송할 alertmanager를 정의한 것이다.

     

    필자는 google chat 으로 요청을 받고 싶은데 그냥 웹훅을 설정하면

     

    Invalid JSON payload received. Unknown name

     

    라는 에러로 Json 형식의 에러가 난다.

    alertmanager 에서는 이런 설정을 해줄 수 없다.

     

    그래서 내가 설정한 방법은 파이썬 컨테이너를 동작시켜 그 서버에서 처리를 하여 

    내 alertmanager 에게 요청을 전달하는 것이다.

     

    from flask import Flask, request, jsonify
    import requests
    
    app = Flask(__name__)
    
    GOOGLE_CHAT_WEBHOOK_URL = "https://chat.googleapis.com/v1/spaces/{SPACE}/messages?key={KEY}&token={TOKEN}"
    
    @app.route('/alert', methods=['POST'])
    def alert():
        data = request.json
    
        google_chat_message = {
            "text": f"Alerts from Alertmanager:\n\n{data.get('alerts', [])}"
        }
    
        response = requests.post(GOOGLE_CHAT_WEBHOOK_URL, json=google_chat_message)
        return jsonify({"status": response.status_code})
    
    if __name__ == '__main__':
        app.run(host="0.0.0.0", port=5000)

     

    이 스크립트를 도커라이제이션할 수 있도록 Dockerfile 을 작성한다.

     

    FROM python:3.10-slim
    
    WORKDIR /app
    
    COPY . .
    
    RUN pip install --no-cache-dir flask requests
    
    CMD ["python", "scipt.py"]

     

     

    이를 이제 image 로 build 하고 run 하면 된다.

     

    docker build -t {imageName} .
    
    docker run -d --name {containerName} -p 5000:5000 {imageName}

     

     

    이제 컨테이너가 동작한다.

    잘 돌아가는지 확인하기 위해서는

     

    curl -X POST http://localhost:5000/alert -H "Content-Type: application/json" -d '{"alerts": [{"status": "firing", "labels": {"alertname": "HighMemoryUsage", "severity": "critical"}, "annotations": {"description": "Memory usage is above 90%!"}}]}'

     

    를 통해 쏘면

     

     

    이와 같이 동작하는 것을 볼 수 있다.

     

    alert manager 의 설정은 다음과 같다.

     

    global:
      resolve_timeout: 5m
    
    route:
      receiver: "google_chat"
      group_wait: 30s
      group_interval: 5m
      repeat_interval: 3h
    
    receivers:
      - name: "google_chat"
        webhook_configs:
          - url: "http://relay:5000/alert"
            send_resolved: true

     

    도커 실행 명령어

    docker run -d   --name alertmanager   -p 9093:9093   -v /path/to/alertmanager.yml:/etc/alertmanager/alertmanager.yml   prom/alertmanager

     

     

    이후 실제 동작 메세지

     

    Rules 

    groups:
      - name: node_exporter_alerts
        rules:
          - alert: LowStorageSpace
            expr: node_filesystem_avail_bytes < 500 * 1024 * 1024
            for: 1m
            labels:
              severity: warning
            annotations:
              summary: "Low storage space on {{ $labels.instance }}"
              description: "Storage space is below 500MB on instance {{ $labels.instance }}."
    
          - alert: HighMemoryUsage
            expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes > 0.9
            for: 1m
            labels:
              severity: warning
            annotations:
              summary: "High memory usage on {{ $labels.instance }}"
              description: "Memory usage is above 90% on instance {{ $labels.instance }}."
    
          - alert: InstanceDown
            expr: up == 0
            for: 1m
            labels:
              severity: critical
            annotations:
              summary: "Instance {{ $labels.instance }} is down"
              description: "The instance {{ $labels.instance }} is not reachable."

     

    이렇게 언제 알림을 보낼지에 대한 규칙을 추가해준다.

     

    exporter

    mysql_exporter

    docker run -d   --name {containerName}   -p {port}:9104   prom/mysqld-exporter  --mysqld.address={host}:{port}  --mysqld.username={id}:{pw}

     

    -e DATA_SOURCE_NAME 이런 방식으로 전달하려 했는데

    에러가 발생했다. 

    나는 mysqld 를 활용해서 전달하였더니 잘 가져왔다.

     

    node_exporter

    docker run -d   --name {containerName}   -p {port}:9100   prom/node-exporter

     

    필자는 node_exporter 는 대상 인스턴스에,

    나머지는 외부 인스턴스에 두어서 설치하였다.

     

    최종 컨테이너 상태는 다음과 같다.

     

    그라파나로 대시보드 구성하였는데 

    이는 다음에 더 정리해보려 한다.

     

Designed by Tistory.