Cloud/Monitoring

유용한 PromQL 목록들

Taemy 2021. 9. 13. 08:50

 Prometheus는 PromQL(Prometheus Query Language)라는 쿼리문을 제공한다. Prometheus나 Grafana에서 요청된 쿼리 결과는 사용자가 가공할 수 있는 형태로 전달되고, 이 요청은 http api형태로 전달된다.

 

 종종 Grafana에서 볼 수 있는 수많은 대시보드들은 전부 이 PromQL과 Grafana에서 제공하는 추가 문법들로 이루어진다.

 

 이번 포스팅은 sysdig에서 소개한 Top 10 PromQL example for monitoring Kubernetes라는 포스팅에 나와있는 쿼리들을 소개하고 분석하는 시간을 가지려 한다.

 

1. namespace별 Pod 수

sum by (namespace) (kube_pod_info)

kube_pod_info 쿼리는 쿠버네티스 내 파드 정보를 가져오는 쿼리다. 

해당 쿼리는 sum by (namespace)로 둘러쌓여 있다.

 

sum은 PromQL에서 제공하는 Operation으로, kube_pod_info를 통해 출력된 각 쿼리 결과값을 모두 더하는 함수다.

sum (kube_pod_info) 로 쓰게 되면 모든 쿼리 결과들을 다 더하고, by ( )를 추가로 적게되면 by 안에 있는 라벨이 같은 것들 끼리 더하는 특성을 가지고 있다.

 

 즉 위의 함수는 namespace가 같은 쿼리 결과들을 모두 더하는 함수다.

 kube_pod_info의 각 쿼리 결과값이 전부 1이기 때문에 위 쿼리는 결과적으로 namespace별 파드 수를 출력하는 결과를 가지게 된다. 

 물론 count 함수도 제공하기 때문에 count by (namespace) (kube_pod_info)가 좀더 직관적일거라는 생각은 든다.

 

2. CPU limits가 없는 container의 수

count by (namespace)(sum by (namespace,pod,container)(kube_pod_container_info{container!=""}) unless sum by (namespace,pod,container)(kube_pod_container_resource_limits{resource="cpu"}))

 kube_pod_container_info 는 container의 namespace, pod, node 등의 정보를 포함한 라벨을 및 value를 가져오는 쿼리다.

또한 kube_pod_container_resource_limits의 경우 container에 부여된 limit resource label들을 결과로 가져오는데, resource 라벨에 어떤 리소스에 대한 것인지 정보를 명시한다. 해당 쿼리에서는 cpu로 지정했기 때문에 cpu limit 정보를 가져오는 쿼리가 된다.

 

 이때 unless sum by로 (namespace, pod, container )를 명시한 것을 볼 수 있다. 

 unless의 경우 on 과 달리 by 아래 기재된 label을 가진 결과들을 빼는 결과를 가져온다. 따라서 (kube_pod_container_info{container!=""}) unless sum by (namespace,pod,container)(kube_pod_container_resource_limits{resource="cpu"}) 쿼리는 컨테이너 중 limit cpu를 가진 컨테이너들을 빼고 더하는 결과를 가진다. 이후 namespace 단위로 conut를 했기 때문에 해당 쿼리는 namespace 단위로 limits가 없는 컨테이너 수를 구한다.

 

3. 파드 재시작 수

sum by (namespace)(changes(kube_pod_status_ready{condition="true"}[5m]))

kube_pod_status_ready 쿼리는 Pod 상태가 Ready 인지의 여부를 True, False로 반환한다. condition 라벨이 true인 것을 지정했기 때문에 Ready 상태인 파드만을 결과로 가져온다.

 

이 때 changes를 통해 이 쿼리를 감싸고 5m(5 minutes)를 지정했다.

changes 함수는 [ ] 안에 지정한 시간 내에 변경사항이 있는지를 체크한다. 해당 쿼리의 경우 Ready 결과를 가져오는 쿼리의 changes이기 때문에 5분 내에 Ready 상태가 변경되어 True가 된, 즉 재시작된 파드를 가져오는 쿼리이다.

 

여기에 namespace 기준 sum 함수를 적용했기 때문에 이 쿼리는 아래와 같이 해석할 수 있다.

"namespace 별로 5분 내에 재시작된 파드의 수"

 

4. Ready 상태가 아닌 Pod 수

sum by (namespace) (kube_pod_status_ready{condition="false"})

 3번 쿼리에서 changes가 빠진 형태다.

 condition 라벨 값이 false인 결과만을 가져오고 이것을 namespace label기준으로 sum 하는 쿼리이기 때문에 결과적으로 Ready 상태가 아닌 Pod 수를 계산하는 쿼리가 된다.

 

5. Overcommit된 CPU 값

sum(kube_pod_container_resource_limits{resource="cpu"}) - sum(kube_node_status_capacity_cpu_cores)

쿼리를 설명하기 전에, Overcommit이란 클러스터가 할당가능한 Core보다 할당된 CPU Limit이 큰 경우를 의미한다.

kube_pod_container_resource_limits 쿼리는 리소스의 Limit을 가져오는 쿼리이고 resource라벨을 cpu로 지정했기 때문에 할당된 cpu limit값을 가져온다.

kube_node_status_capacity_cpu_cores는 클러스터가 할당 가능한 총 core수를 반환한다.

각각의 sum을 - 로 빼기 때문에 결과적으로 Limit과 할당가능한 Core의 차가 반환된다. 만약 할당가능한 값이 더 크다면 음수를 반환할 것이다.

 

6. Overcommit된 Memory 값

sum(kube_pod_container_resource_limits{resource="memory"}) - sum(kube_node_status_capacity_memory_bytes)

Production 단계에서 일어나선 안될 일이지만 Overcommit된 Memory의 값을 출력하는 함수이다.

원리는 5번과 동일하다.

 

7. 클러스터 별 Ready 상태인 노드 수

sum(kube_node_status_condition{condition="Ready", status="true"}==1)

kube_node_status_condition 쿼리는 노드의 상태를 출력하는 쿼리다.

 condition이 Ready, status를 true로 지정하고 비교 연산자로 이 값이 1인지를 확인하기 때문에 결과적으로 정상 상태 노드 개수를 가져오는 쿼리가 된다.

 

8. 클러스터 별 정상화된 노드 수

sum(changes(kube_node_status_condition{status="true",condition="Ready"}[15m])) by (node) > 2

 7번에 더해서 kube_node_status_condition{status="true",condition="Ready"}로 Ready 상태인 노드를 가져오되 changes 함수로 변경 사항이 있었던 노드만을 가져온다. 위의 경우 15m으로 지정했기 때문에 15분 동안 다시 시작된 노드를 가져온다.

 Prometheus의 경우 비교 연산자를 통해 boolean 결과를 가져올 수 있다. 따라서 위의 구문의 경우 15분 동안 되살아난 노드가 2개 이상인지의 결과를 가져오는 쿼리가 된다.

 

9. 유휴 CPU 상태

sum((rate(container_cpu_usage_seconds_total{container!="POD",container!=""}[30m]) - on (namespace,pod,container) group_left avg by (namespace,pod,container)(kube_pod_container_resource_requests{resource="cpu"})) * -1 >0)

 

조금 복잡하지만 내용은 어렵지 않다.

container_cpu_usage_seconds_total는 CPU 사용량을 가져오는 쿼리이고, 컨테이너 명으로 "POD", ""가 아닌 것을 지정했다. 즉 모든 컨테이너라고 볼 수 있다. 

rate 함수는 일정 시간동안 쿼리 결과의 평균값을 계산한다. 여기서는 30m로 지정했기 때문에 30분 동안의 사용량 평균을 계산한다.

 

kube_pod_container_resource_requests은 컨테이너 request 리소스 요청량을 가져오는 쿼리이고 cpu를 지정했기 때문에 cpu request값을 가져온다.

group_left의 경우, 왼쪽의 결과는 같은 namespace, pod, container 라벨을 가진 결과가 여러 개 존재할 수 있다. 반대로 오른쪽의 결과는 컨테이너까지 지정했기 때문에 라벨 조합 별로 하나의 결과만을 가지게 된다. 즉 many-to-one의 결과가 된다. 이 때 group_left를 적용하면 같은 레벨을 가진 모든 쿼리에 대해 동일한 operation 을 사용할 수 있다.

 

10. 유휴 메모리 상태

sum((container_memory_usage_bytes{container!="POD",container!=""} - on (namespace,pod,container) avg by (namespace,pod,container)(kube_pod_container_resource_requests{resource="memory"})) * -1 >0 ) / (1024*1024*1024)

9와 동일하된 cpu가 memory로 변경된 결과를 가진다.