이번 글에서는 프로메테우스의 kubernetes_sd_configs 설정을 사용해 쿠버네티스 클러스터 내 파드들의 메트릭을 수집하는 방법을 정리해보려고 합니다. 다룰 환경은 프로메테우스가 쿠버네티스 클러스터 내부에 있지 않고, 외부에서 클러스터에 접근해 메트릭을 수집하는 구조를 가정합니다.
- kubernetes_sd_configs
먼저 쿠버네티스 클러스터 내의 리소스를 자동으로 발견할 수 있는 설정인 kubernetes_sd_configs 는 프로메테우스 공식 문서에 나와있습니다. 다만 프로메테우스 문서만 보고 설정을 제대로 하기엔 좀 쉽지 않았습니다(개인적으론 문서가 그리 친절하진 않은 듯 합니다..)
요점은 프로메테우스 설정 파일인 prometheus.yml 의 scrape_configs 항목에 kubernetes_sd_configs 를 설정함으로써, 외부에 위치한 프로메테우스가 쿠버네티스 API 서버를 통해 클러스터 내 리소스(특히 파드)에 접근하여 메트릭을 수집할 수 있게 됩니다.
- Kubernetes secret 설정
우선 외부 프로메테우스가 쿠버네티스 API 서버에 접근해서 파드 목록을 조회할 수 있도록, 최소한의 권한을 가진 ServiceAccount 의 토큰(Secret) 을 만들도록 하겠습니다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus-scraper
namespace: kube-system
가장 먼저 ServiceAccount 를 위와 같은 yaml 로 만들어줍니다. 적용은 위와 같은 파일을 xxx.yaml 와 같이 생성하고 kubectl apply -f xxx.yaml 을 하면되는데, 이후 내용에선 이런 부분은 생략하도록 하겠습니다.
하려는건 prometheus-scraper 라는 이름의 SA 를 만들고 이 SA 에 권한을 부여한 후, 이 SA 를 통해 토큰을 발급하려고 합니다.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: list-pods
rules:
- apiGroups: [""]
resources:
- pods
verbs: ["get", "watch", "list"]
그 다음은 ClusterRole 을 만드는 것입니다. 이 list-pods 라는 ClusterRole 은 쿠버네티스의 pods 리소스에 대해 get, watch, list 권한을 갖게 됩니다(읽기 권한만 부여한 것입니다)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: list-pods-global
roleRef:
kind: ClusterRole
name: list-pods
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: prometheus-scraper
namespace: kube-system
ClusterRoleBinding 을 생성해줍니다. 이건 위에서 만든 list-pods 권한을 prometheus-scraper(SA) 에 연결한 것입니다.
이로써 prometheus-scraper 는 클러스터 내 모든 파드 정보를 조회할 수 있는 권한을 갖게 되었습니다.
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: prometheus-scraper
namespace: kube-system
annotations:
kubernetes.io/service-account.name: prometheus-scraper
마지막으로 생성할 것은 Secret 입니다. 그냥 용어 자체를 Secret = 토큰 이라고 봐도 될 것 같은데요.
위 과정들을 통해, list-pods 권한을 가진 SA 를 통해 API 인증에 사용할 prometheus-scraper 라는 이름의 토큰을 만들어 준 것입니다.
이 토큰을 프로메테우스가 사용하면 쿠버네티스 API 서버에 인증된 주체로 접근할 수 있게 되고, 해당 주체는 list-pods 라는 권한을 갖고 있기 때문에(파드에 대한 get, watch, list) 클러스터 내 파드를 조회할 수 있게 됩니다.
여기까지 쿠버네티스 내에서 리소스를 생성했다면, k9s 또는 Lens 등의 도구를 통해서 (혹은 kubectl 을 통해) 생성한 Secret 을 조회할 수 있게 됩니다.
저는 쿠버네티스 클라이언트로 Lens 를 사용하는데요. Lens 에서 생성한 Secret 을 눌러 나오는 패널에서 Data 부분을 보면 ca.crt / namespace / token 이 표시되는걸 볼 수 있습니다. 우리는 여기서 ca.crt 와 token 의 값을 사용합니다.
- Prometheus.yml
위 과정을 통해 생성한 토큰을 이제 프로메테우스 설정에서 사용해 보겠습니다.
생성된 Secret 에서 ca.crt 와 token 값을 사용해야 하는데, 이를 더 우아하게 처리할 방법을 찾지 못해, 결국 두 값을 추출해 별도 파일로 저장한 뒤 사용하는 방식으로 진행했습니다.
- prometheus.yml
- ca.crt
- token
...
먼저 prometheus.yml 위치에 ca.crt 와 token 이라는 두 파일을 만들어줍니다.
편의상 같은 이름을 사용했지만, 설정하는 사람 마음대로 해도 됩니다.
그리고 Lens 에서 ca.crt 와 token 에 대해 이 아이콘을 누른 후, 보이는 값을 복사해 prometheus.yml 파일이 있는 위치에 ca.crt / token 이라는 파일을 생성하고 그대로 붙여넣습니다.
...
scheme: http
kubernetes_sd_configs:
- api_server: <EKS API server endpoint>
role: pod
tls_config:
ca_file: /home/ec2-user/etc/prometheus/ca.crt
insecure_skip_verify: true
bearer_token_file: /home/ec2-user/etc/prometheus/token
namespaces:
names:
- 'xxx'
...
그리고 prometheus.yml 에 위와 같은 kubernetes_sd_configs 를 추가해줍니다.
저는 프로메테우스를 팀에서 사용중인 aws 내의 ec2 에 띄워서 사용하고 있었으므로, 생성했던 ca.crt 와 token 파일의 경로가 /home/ec2-user/etc/prometheus 입니다. 이는 각자의 환경에 맞춰 넣으면 될 것 같습니다.
마찬가지로 api_server 의 API endpoint 도 각자의 쿠버네티스 클러스터에 맞춰 적으면되고, namespace 도 마찬가지입니다.
저는 설정에서 "scheme: http" 와 "insecure_skip_verify: true" 를 사용했는데요. 이는 쿠버네티스 API 서버와 원래는 HTTPS 통신을 해야하지만, 프로메테우스 설정에서 이를 그냥 건너뛰기 위해 추가했습니다. 원래는 ca.crt 를 사용해 HTTPS 통신도 문제가 없어야할 것 같은데, 이부분은 왜인지 설정으로 잘 안풀리더라구요.
여기까지 진행하고 프로메테우스 재시작 또는 무중단 반영등을 통해 설정을 적용하면, 프로메테우스의 Targets 에서 namespace 에 해당하는 파드들이 조회되는 것을 확인할 수 있습니다 (이 포스팅에서 각 파드들이 메트릭을 export 하고있는 부분은 생략했습니다)
- Trouble Shooting
이런 세팅 과정에서 저한테 발생했던 몇가지 문제를 조금 복기해보겠습니다.
- discovery.kubernetes: unable to list pods: forbidden: User "system:serviceaccount:..." cannot list resource "pods"...
진행 과정에서 프로메테우스 로그에 이런게 찍히고, Targets 에는 아무것도 나오지 않는다면, 쿠버네티스 클러스터에 Secret 리소스를 생성하는 과정에서부터 잘못된 것입니다. 저도 삽질을 하다가 get, watch, list 의 권한을 제대로 넣지 않아서 이런 문제가 발생했었습니다.
프로메테우스의 Service Discovery 에서 대상 파드가 아예 나오지도 않는다면, 권한 설정을 다시 한번 확인해보면 좋을 것 같습니다.
- DOWN
Get "http://<pod-ip>:<port>/metrics": dial tcp <pod-ip>:<port>: connect: connection refused
Targets 에는 파드들이 잡히는데, 파드 리스트에서 Error 부분에 이런 메시지가 보인다면 메트릭을 노출하는 경로나 포트 설정이 잘못되었을 확률이 높습니다. 저는 앱 컨테이너 내에서 35761 포트에 /metrics 라는 경로로 메트릭을 export 하고 있었는데, prometheus.yml 에서 35761 포트 설정을 잘못(보통 오타나 누락..)했을때 이런 에러를 봤습니다.
- Get "https://<apiserver-endpoint>/api/v1/pods": context deadline exceeded
이 에러도 위와 비슷하게 Targets 에는 파드들이 잡히는데, Error 에서 보일때가 간혹 있습니다.
보통 이런 경우엔 프로메테우스 설정엔 포트나 경로가 잘 설정되었는데, 쿠버네티스 설정중 containerPort 에 대한 설정을 하지 않았거나, 설정한 포트를 보안그룹의 인바운드룰에 추가하지 않아 접근이 되지 않아서 발생할 때였습니다.
간혹 쿠버네티스 API 서버의 응답 자체가 느리면 이런 경우가 발생하기도 하는데, 사실 이런 케이스는 거의 못본 것 같습니다.
여기까지 쿠버네티스 클러스터 내부에 있지 않은 프로메테우스에서 쿠버네티스 클러스터 내의 리소스에 접근해 메트릭을 수집하는 방법에 대해 알아봤습니다. 지금 적은 말에 또 다른 답이 있는데요. 사실 프로메테우스를 쿠버네티스 클러스터 내로 옮기면 훨씬 간단하게 kubernetes_sd_configs 를 구성할 수도 있습니다. 다음 포스팅에선 그 방식에 대해 알아보겠습니다.
'Infrastructure > Prometheus' 카테고리의 다른 글
Prometheus Pushgateway with Node.Js (2) | 2021.04.10 |
---|---|
Node.js Cluster mode 모니터링 (0) | 2021.04.04 |
Node.js 어플리케이션 모니터링 (0) | 2021.03.27 |
Prometheus Node Exporter 모니터링 (0) | 2021.03.20 |
Prometheus 란? (0) | 2021.03.14 |