[모니터링] Alert rule에 labeling 하기

옵주비·2023년 2월 16일
1
post-thumbnail

인턴 시작 후 많은 시행착오 끝에 프로젝트 중간 평가가 임박한 시점부터 모니터링을 전담하기로 했는데, 참고할 수 있는 자료가 너무 적었다. 이전 글에서도 언급했지만 공식 홈페이지에 나와있는 설명은 너무나도 부족했고, 깃허브로 들어가도 그래서 어떻게 해야한다는 것인지에 대한 설명이 없었다. 국내, 해외 블로그도 모두 찾아봤지만 대부분 실속이 없었다. 공홈에 있는 내용을 그대로 번역해놓거나, 결과 스크린샷만 성의없이 나열해놓은 것들이 많았다.

촉박한 프로젝트 일정 상, 그리고 최초에는 혼자 이 모니터링을 담당해야 했던 사정으로 인해 최대한 효율적인 방법을 급히 강구해야 했다. 테크 직군으로의 경력이 전무한 상황에서, 아무래도 빠른 학습을 위해서는 강의가 최선이라고 생각했다. 그래서 직접 사비로 프로메테우스와 그라파나에 대한 강의를 며칠간 꼼꼼이 비교해보고, 그 중 패스트캠퍼스와 Udemy에서 몇몇 강의를 구입해서 수강했다. 이 강의들을 통해 모니터링 시스템 전반에 대한 이해를 빠르게 높이고 적용해보는 것은 어느정도 도움이 되었지만, 아쉽게도 입문자를 위한 강의이다보니 디테일은 부족했다.

그래서 정말 맨땅에 헤딩해가며 여러 시행착오를 겪어가며 구현했으며, 그 중 일부에 대해서 기술일지를 틈틈이 작성하려고 한다. 제대로 된 레퍼런스가 없었던 답답함을 해소하기 위해 직접 쓴다🤣 이전에 HTTP Service Discovery에 대한 글을 남겼는데, 오늘은 그 HTTP Service Discovery에서 붙여온 라벨을 기준으로 alert_rule에 적용하는 방법에 대해 간단히 정리해보겠다.

Alert rule에 labeling 하기

앞서 HTTP service discovery 글에서 어떤 label을 붙였는지 확인하기 위해, 백엔드 코드 일부를 다시 가져와보았다.

def http_service_discovery():
    
    # TODO: DB 조회를 통해 targets를 유동적으로 변경 가능하도록 구성
    
    mysql_primary = {
        "targets": ["0.0.0.0:9100", "0.0.0.0:9100"],
        "labels": {
	        "dbms": "MySQL",
            "service_name": "My서비스",
            "db_name" : "프라이머리"
        }
    }
		
    mysql_secondary_A = {
        "targets": ["0.0.0.1:9100", "0.0.0.1:9104"],
        "labels": {
            "dbms": "MySQL",
            "service_name": "My서비스",
            "db_name" : "세컨더리A"
        }
    }
    
    mysql_secondary_B = {
        "targets": ["0.0.0.2:9100", "0.0.0.2:9104"],
        "labels": {
            "dbms": "MySQL",
            "service_name": "My서비스",
            "db_name" : "세컨더리B"
        }
    }

여기서 내가 각 수집대상에 붙여놓은 label인 dbms, service_name, db_name을 알람 발송에 활용하기 위해서는 alert rule에도 동일한 라벨을 붙여주어야 한다. 대괄호 2개를 겹치고, 그 안에 $로 가져와주어야 하는데 이러한 정보가 잘 나와있지 않아서 고민을 많이 했다.

	  - alert: MysqlDown
        expr: 'mysql_up == 0'
        for: 0m
        labels:
          severity: critical
          instance: "{{ $labels.instance }}"
          dbms: "{{ $labels.dbms }}"
          service_name: "{{ $labels.service_name }}"
          db_name: "{{ $labels.db_name }}"
        annotations:
          summary: MySQL instance down 
          description: "MySQL instance is down on {{ $labels.instance }}"

하지만 보다시피, 알고보면 정말 간단하다. 여기서 severity는 알람의 심각성 정도를 나타내는 지표로, 각 alert rule에 적절하다고 판단되는 정도를 붙여주면 된다. 나의 경우엔 info-warning-critical 3가지로 분류했다. 그리고 instance에는 우리가 수집대상으로 가져오는 target이 라벨에 자동으로 담기게 된다. 가령 mysql_primary에 대해 알람이 발생했으면 0.0.0.1:9100 혹은 0.0.0.1:9104가 담기게 될 것이다. dbms, service_name, db_name은 우리가 HTTP Service Discovery에서 라벨링해준 것들을 그대로 옮겨가기 위함이다.

TIP) labels.라벨명 이 어떻게 나오는 구조인지 궁금하다면, description에 그냥 {{ $labels }} 만 기재해서 webhook url로 한 번 찍어보는 것을 추천한다. map 형태로 어떤 key-value가 담겨오는지 좀 더 직관적으로 확인할 수 있다.

라벨을 설정했는데 None으로 담기는 경우

위와 같이 설정했는데, 간혹 특정 Alert의 경우에는 webhook으로 alertmanager가 보내오는 POST의 body 내용을 보면 일부 label이 None으로 담겨오는 경우가 있을 수 있다. 이런 경우는 해당 Alert의 PromQL expr에 따른 것일 가능성이 높다. 만약 특정 라벨을 기준으로 그룹화된 것에 대한 expression이라면, 특정 라벨 외의 다른 라벨들은 모두 소멸된다.

가령 어떤 Alert rule의 PromQL이 sum 어떤메트릭 by (service_name) 이라면, service_name 외엔 다른 label들은 해당 알람에 대해 더 이상 유효하지 않다. 따라서 이러한 Alert rule에서도 dbms, db_name 등의 정보가 필요하다면 백엔드 단에서 메타DB를 조회한다든지 등의 처리를 통해 확보해야 한다.

이처럼 alert rule에 대한 labeling은 매우 유용하긴 하지만 모든 케이스에 활용 가능하진 않으므로, 이런 점을 잘 고려해서 설계해야 오류를 최소화할 수 있을 것이다

0개의 댓글