zabbix HTTP 헬스 체크
zabbix 모니터링에서는 기본적으로 "Template App HTTP Service" 템플릿을 제공하여 HTTP 서비스의 작동 유무를 체크합니다. 하지만 해당 템플릿에서 제공하는 아이템으로는 포트 수신 여부까지만 체크가 가능하고, 포트가 올라와있으나 서비스가 비정상적인 경우 등을 체크하기 어렵기 때문에 HTTP 에이전트를 통한 아이템 및 트리거를 생성하여 웹서비스의 상태를 체크할 수 있는 방법을 공유드리고자합니다.
1. 기존 "Template App HTTP Service" 템플릿에서 제공하는 아이템, 트리거의 한계
"Template App HTTP Service" 템플릿은 아래와 같이 "net.tcp.service[http]" 키 값을 사용하는 "HTTP service is running" 아이템(갱신시간 1분)과 해당 아이템의 최근 3회의 값이 0인 경우 발생하는 "HTTP service is down on {HOST.NAME }" 트리거를 가지고 있습니다.
"HTTP service is running" 아이템의 종류는 간단 검사로, 간단 검사는 에이전트 설치가 필요하지 않으며 자빅스 서버에서 모니터링 대상으로 ping, 포트 체크 등이 이뤄집니다.
간단 검사 관련 자빅스 공식 문서
https://www.zabbix.com/documentation/current/manual/config/items/itemtypes/simple_checks
이 때, "HTTP service is running" 아이템에 사용되는 "net.tcp.service[http]" 키의 경우 자빅스 서버에서 모니터링 대상으로 80번 포트에 대한 TCP 연결 수락 여부만을 체크합니다.
때문에 만약 80번 포트에 HTTP 서비스가 아닌 다른 서비스가 올라와 있어도 정상적인 상태로 인식하며, HTTP 서비스가 올라와 있더라도 500 에러 등으로 웹페이지가 정상적으로 뜨지 않더라도 정상적인 상태로 인식합니다.
<sshd의 포트를 80번으로 변경한 경우>
<HTTP 서비스는 올라와 있으나 500 에러가 발생하는 경우HTTP 서비스는 올라와 있으나 500 에러가 발생하는 경우>
위의 두 경우 모두 자빅스 서버에서는 정상적인 상태로 인식합니다.
2. HTTP 에이전트를 통한 헬스 체크 설정
위와 같이 기본 "HTTP service is running" 아이템만으로는 실제로 HTTP 서비스의 정상 상태를 확인하기 어렵기 때문에 AWS ALB에서와 같이 특정 URL에 대한 주기적인 HTTP 요청을 통해 웹서비스의 상태를 체크하는 방식의 아이템과 트리거를 만들어보도록 하겠습니다.
1) 아이템 설정
먼저 특정 URL의 상태를 체크하는 아이템을 만들기 위해서는 기존 간단 검사가 아닌 "HTTP 에이전트"라는 유형으로 설정합니다.
HTTP 에이전트 관련 자빅스 공식 문서
https://www.zabbix.com/documentation/current/manual/config/items/itemtypes/http
저는 "Template App HTTP Service" 하위에 아이템을 추가하였습니다. 이 경우 기존 "Template App HTTP Service" 템플릿이 연결된 모든 호스트에 해당 아이템이 생성됩니다.
설정한 아이템의 항목 중 중요 내용으로 생각되는 항목을 아래와 같이 정리하였습니다.
1. 이름 : HTTP health check -> 임의로 지정
2. 종류 : HTTP 에이전트
3. 키 : http.healthcheck -> 임의로 지정
4. URL : http://{HOST.IP}/check -> 상태 체크할 URL
-> URL 관련 지원되는 매크로
Supported macros: {HOST.IP}, {HOST.CONN}, {HOST.DNS}, {HOST.HOST}, {HOST.NAME}, {ITEM.ID}, {ITEM.KEY}, {ITEM.KEY.ORIG}, user macros, low-level discovery macros.
-> URL에 쿼리스트링이 포함되어 있는 경우 URL 입력 후 "Parse" 버튼 누르면 자동으로 나눠줌
-> 해당 URL로 커넥션이 불가한 경우 "취득 불가" 상태로 표시되며 아래와 같이 사유 표시
Cannot perform request: Failed connect to 52.78.78.123:80; Connection refused
5. 리퀘스트 타입 : GET -> 필요에 따라 POST 등도 가능
6. 타임아웃 : 5s -> 상태 체크할 URL에 대한 응답 대기 시간
7. 요구 스테이터스 코드 -> 정상 응답으로 판단하는 HTTP 코드
-> 응답 코드가 일치하지 않을 경우 "취득 불가" 상태로 표시되며 아래와 같이 사유 표시
Response code "403" did not match any of the required status codes "200"
Response code "500" did not match any of the required status codes "200"
8. 데이터형 : 수치(unsigned) -> 응답으로 받은 값의 데이터형을 설정
-> HTTP 상태 코드가 일치하더라도 응답 값의 데이터 형이 일치하지 않을 경우 "취득 불가" 상태로 표시되며 아래와 같이 사유 표시
Value "test" of type "string" is not suitable for value type "Numeric (unsigned)"
데이터형(Type of information) 관련 참고
https://www.zabbix.com/documentation/current/manual/config/items/item
9. 갱신 간격 : 60s -> 해당 아이템의 갱신 간격
동일하게 아이템이 "취득 불가" 상태라고 해도, 사유에 따라 갱신 간격이 다름
-> 해당 URL로 커넥션이 불가하여 아이템 수집에 실패하는 경우 매 10분마다 다시 시도
-> 응답 코드가 일치하지 않아 아이템 수집에 실패하는 경우 매 10분마다 다시 시도
-> 데이터형이 일치하지 않은 경우 기본 갱신 간격대로 갱신 시도
(참고) zabbix 취득불가 아이템의 갱신간격
관리 > 일반 > 우측 표시설정 > 기타
취득불가 아이템의 갱신간격 : 10m(기본 값) -> 원하는대로 조정 가능
아이템이 설정 완료되었다면, 실제 서버에서는 HTTP 체크를 위한 방화벽 허용(80포트) 및 URL(http://{HOST.IP}/check)에 대한 파일을 생성해줍니다. 헬스 체크를 위한 URL이 "http://{HOST.IP}/check" 이기 때문에 check라는 파일을 생성하며, 파일의 내용은 "1"로 하였습니다.
이 때, 위의 8번에서 설정한 데이터형이 "수치"이기 때문에 파일이 비어있거나, 숫자가 아닌 값이 파일에 들어가면 아이템을 수집하지 못합니다. "1"이 아니어도 관계는 없지만 수집되는 데이터를 그래프로 볼 때, 시인성이 좋기 때문에 "1"로 하였습니다.
모니터링 대상 서버에서는 아래와 같이 웹로그가 찍히는 것을 확인할 수 있습니다.
<실제 수집된 데이터에 대한 그래프>
만약 서버에 대한 웹 접속이 불가하거나, 데이터형이 일치하지 않거나, 응답이 설정한 요구 스테이터스 코드인 200이 아닌 경우 아이템은 "수집 불가"로 표시되며, 수집 불가된 상세 사유를 확인 가능합니다. 아래는 응답 코드가 일치하지 않은 경우 발생하는 메시지입니다.
2) 트리거 설정
이제 웹 페이지에 대한 아이템 수집 설정은 완료되었으니 장애가 발생했을 경우 장애로 표시되도록 하기 위해 트리거를 설정합니다.
트리거 설정 항목 중 가장 중요한 부분은 조건식에 대한 부분으로 아래와 같이 정리하였습니다.
1. 이름 : HTTP health check is down on {HOST.NAME} -> 임의로 지정
2. 심각도 : 적절히 선택
3. 조건식 : 아래와 같이 체크할 환경에 따라 따라 단일 조건 혹은 여러 조건을 조합(AND, OR)하여 설정
응답 코드만 일치 조건
{Template App HTTP Service:http.healthcheck.nodata(3m)}=1
-> 최근 1분동안 해당 아이템의 데이터가 수집되지 않는 경우
-> nodata(시간)의 경우 1=값 없음, 0=값 있음
응답 코드, 응답 값까지 일치 조건
{Template App HTTP Service:http.healthcheck.nodata(#3)}<>1
-> 최근 3회 응답의 값이 1이 아닐 경우 트리거 발동
-> 아이템이 "취득 불가" 상태인 경우 트리거가 "알 수 없음" 상태로 표시되어 트리거 발동하지 않음
Cannot evaluate expression: "Cannot evaluate function "Template App HTTP Service:http.healthcheck.nodata(#3)": item is not supported.".
조건식 만들려면 조건식 빌더 활용
조건에 대한 테스트는 테스트 버튼 클릭하여 실행
(참고) 조건식 빌더 상의 "최근 (T)" 값의 "회"와 "시각"의 차이
조건식 빌더의 "최근 (T)" 값 뒤에 "회"가 붙는 경우 횟수는 "#N" 으로 표현되어 아이템의 갱신 간격을 따라 일정 횟수를 기준으로 트리거 발동
조건식 빌더의 "최근 (T)" 값 뒤에 "시각"이 붙는 경우 시간은 "Nm" 으로 표현되어 해당 아이템의 갱신 간격과 별개로 시간 지정
캡쳐한 위의 이미지와 같이 200 응답으로 수치 데이터가 정상적으로 수신되는지 여부만 체크할 수도 있고, 위의 코드 블럭 내용 중 "응답 코드, 응답 값까지 일치 조건"과 같이 응답 값(0인지, 1인지 등)에 대한 체크도 가능합니다. 또 여러 조건을 AND, OR로 조합하여 설정도 가능합니다.
3. 장애가 발생하는 경우를 가정하여 테스트
아이템과 트리거 설정까지 완료되었기 때문에 이제 장애 상황을 가정하여 테스트를 진행합니다.
먼저 기존 "HTTP service is running" 아이템으로는 체크가 되지 않았던 500 에러가 발생한 경우입니다.
위와 같이 3분 간 설정한 응답 코드와 다른 응답 코드가 발생하는 경우 트리거가 발동합니다.
서비스를 정상화 시킨 뒤, 이번에는 HTTP 서비스가 아닌 다른 서비스를 80번 포트에 올려봅니다.
이렇게 80번 포트에 다른 서비스가 올라가 있는 경우 정상적으로 HTTP 응답을 받을 수 없기 때문에 트리거가 발동합니다. 테스트를 하는 동안에도 기본 템플릿에서 제공하는 "HTTP service is down on {HOST.NAME }" 트리거는 포트 수신 여부만을 체크하기 때문에 트리거가 발동하지 않는 것을 확인할 수 있습니다.
4. 마치며
자빅스에서 기본 제공하는 "Template App HTTP Service" 템플릿의 아이템이 포트를 체크하는 것일까 아니면 실제 웹서비스의 정상 여부를 체크하는 것일까 하는 궁금증에서 시작해서 HTTP 에이전트를 통한 헬스 체크까지 설정해보았습니다. 설정 내용은 간단한데 여러 케이스를 테스트해보느라 내용이 불필요하게 좀 길어진 것 같습니다.