[monitoring] Prometheus 설치 가이드(+exporter)
안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 Prometheus에 관해서 정리를 해보려고 합니다. 필자가 이전 회사에서는 EKS를 운용하다 보니, helm을 통해서 프로메테우스를 설치했었습니다. helm은 한번에 익스포터부터 모든것을 설치하는 것으로 알고 있습니다. 그러다보니 내부적인 설정이을 건드린것이 전혀 없었습니다.
이번에는 익스포터의 역할과 설치하는 과정에 대해서 정리를 하려고 합니다.
1. Node-exporter 설치하기
쿠버네티스 클러스터를 구축한 뒤로, 각 worker 노드에 대해서 메트릭(cpu, memory, disk)을 수집하기 위해서는 해당 worekr 노드에 대한 정보를 수집할 수 있는 api를 제공해주어야 프로메테우스가 풀 방식으로 가져갑니다. 여기서 api를 제공해주기 위해 설치하는 것이 Node-exporter입니다. 각 Node들에 대해서 메트릭을 exporting하는 어플리케이션을 설치한다고 보면 됩니다.
각 worekr node마다 하나씩 설치하게 되어있기 때문에, daemonset으로 올리게 됩니다.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
hostIPC: true
hostPID: true
containers:
- name: node-exporter
image: prom/node-exporter:v1.0.1
imagePullPolicy: IfNotPresent
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
resources:
requests:
cpu: 10m
memory: 100Mi
limits:
cpu: 100m
memory: 100Mi
ports:
- name: scrape
containerPort: 9100
hostPort: 9100
volumeMounts:
- mountPath: /host/proc
name: proc
readOnly: true
- mountPath: /host/sys
name: sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
type: ""
- name: sys
hostPath:
path: /sys
type: ""
여기서 중요한 것은, worker에 데몬셋으로 올리긴하지만, 실제로는 host의 file system과 network를 공용해서 사용하기 떄문에 worker에 native하게 설치하는 것과 동일한 효과라고 보면 될 것입니다. 설치를 완료하고나서 실제로 9100/metircs라고 호출을 하면 다음과 같은 값들이 출력 됩니다.
...
node_load5 0.4
# HELP node_memory_Active_anon_bytes Memory information field Active_anon_bytes.
# TYPE node_memory_Active_anon_bytes gauge
node_memory_Active_anon_bytes 1.596526592e+09
# HELP node_memory_Active_bytes Memory information field Active_bytes.
# TYPE node_memory_Active_bytes gauge
node_memory_Active_bytes 3.758211072e+09
# HELP node_memory_Active_file_bytes Memory information field Active_file_bytes.
# TYPE node_memory_Active_file_bytes gauge
node_memory_Active_file_bytes 2.16168448e+09
# HELP node_memory_AnonHugePages_bytes Memory information field AnonHugePages_bytes.
# TYPE node_memory_AnonHugePages_bytes gauge
node_memory_AnonHugePages_bytes 0
...
메모리에 대한 정보를 보여주는 것이고, 실제로 worker에 대해서 다양한 값들을 api를 통해서 가져갈 수 있도록 plain text 형식으로 제공해줍니다.
$ kubectl get pod -n monitoring
pod/node-exporter-47xj5 1/1 Running 0 46h
pod/node-exporter-5cbvh 1/1 Running 0 46h
pod/node-exporter-6sc87 1/1 Running 0 46h
pod/node-exporter-7s45x 1/1 Running 0 46h
pod/node-exporter-dx6sf 1/1 Running 0 46h
pod/node-exporter-gx6g7 1/1 Running 0 46h
pod/node-exporter-kxh7z 1/1 Running 0 46h
pod/node-exporter-wcfdb 1/1 Running 0 46h
pod/node-exporter-wpzgk 1/1 Running 0 46h
pod/node-exporter-z9zlx 1/1 Running 0 46h
모니터링 namespace에 보이는 것처럼, 데몬셋으로 pod들이 올라온것을 확인할 수 있습니다.
2. Kube-state-metric 설치
kube-state-metirc은 kubernetes 클러스터 내부의 Pod가 사용중인 리소스들에 대해서 수집을 진행합니다. Kubernetes-api를 통해서 실제 데이터를 서버로부터 요청하여 가져오기 때문에 cluster안에는 deployment를 통해서 하나의 component만을 배포합니다.
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.1.0
name: kube-state-http-metrics-nodeport
namespace: kube-system
spec:
type: NodePort
selector:
app.kubernetes.io/name: kube-state-metrics
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 31000 # 외부에 31000번 포트로 Pod의 8080번 포트를 라우팅
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.1.0
name: kube-state-metrics
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.1.0
name: kube-state-metrics
rules:
- apiGroups:
- ""
resources:
- configmaps
- secrets
- nodes
- pods
- services
- resourcequotas
- replicationcontrollers
- limitranges
- persistentvolumeclaims
- persistentvolumes
- namespaces
- endpoints
verbs:
- list
- watch
- apiGroups:
- apps
resources:
- statefulsets
- daemonsets
- deployments
- replicasets
verbs:
- list
- watch
- apiGroups:
- batch
resources:
- cronjobs
- jobs
verbs:
- list
- watch
- apiGroups:
- autoscaling
resources:
- horizontalpodautoscalers
verbs:
- list
- watch
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- list
- watch
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
- volumeattachments
verbs:
- list
- watch
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
verbs:
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- networkpolicies
- ingresses
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.1.0
name: kube-state-metrics
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kube-state-metrics
subjects:
- kind: ServiceAccount
name: kube-state-metrics
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.1.0
name: kube-state-metrics
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: kube-state-metrics
template:
metadata:
labels:
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.1.0
spec:
containers:
- image: k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.1.0
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 5
name: kube-state-metrics
ports:
- containerPort: 8080
name: http-metrics
- containerPort: 8081
name: telemetry
readinessProbe:
httpGet:
path: /
port: 8081
initialDelaySeconds: 5
timeoutSeconds: 5
securityContext:
runAsUser: 65534
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: kube-state-metrics
위의 내용에 대해서는 궁금한게 좀 있는데, 이부분은 좀더 서칭을 해봐야될 것 같다는 생각을 했습니다. 우선 1개의 container가 배포가 됩니다. 1개의 kube-metric pod가 배포가 되며, NodePort를 통해서 외부로 요청을 했을경우, 호출이 되도록 하였습니다. 각각의 역할에 대해서 현재로서는 정확하게 판단이 안되지만, 어쩃든 kubernetes cluster의 api-server를 통해서 cadvisor로부터 metirc들을 수집하는거까지 간단한게 정리하면 될 것 같습니다.
설치를 완료하게 되면, 보이는 것과 같이 1개의 deploy에 의해서 1개의 pod가 생성되는 것을 볼 수 있습니다 .
kube-state-metrics-995496786-czggl 1/1 Running 0 20m
2. Prometheus 설치하기
위의 내용에서는 클러스터에 exporter 2가지를 설치해 봤습니다. 정상적으로 설치 하게 되면, 우선 절반은 완료가 된것입니다. 이제 해당 exporter로 부터 데이터를 주기적으로 가져가는 어플리케이션인 Prometheus를 설치해보겠습니다.
프로메테우스는 SoundCloud사에서 만든 오픈소스 모니터링 툴입니다. go 언어로 만들어졌으며, kubernetes 환경에서 모니터링 하기 원하는 리소스로부터 metric을 수집하고 해당 메트릭을 이용해서 모니터링하는 기능을 제공합니다.
프로메테우스에는 여러가지 특징이 있는데 가장큰 특징은 다음과 같습니다
- Pull 방식
exporter에 프로메테우스가 직접 접속하여 수집한 메트릭을 가져오는 방식입니다. 아무래도 pull방식으로 수집을 하다보니, 부하가 생길 염려가 없습니다. Push방식으로 보내게 되면 받을수 없는 상황(부하 발생)임에도 불구하고 더큰 부하를 줄 수 도 있습니다.
2-1. 환경 구성
필자 같은 경우, 추후에 2개의 프로메테우스 서버를 타노스로 묶어주기 위해서(가용성 유지) 2개의 linux instance를 준비했습니다.
서버 사양 : [STAND] 4vCPU, 16GB Mem [g2]
서버 OS : CentOS 7.8 (64-bit)
서버 스토리지 : 50 GB /dev/xvda
2대의 서버에는 모두 사전작업으로 도커가 기본적으로 설치 되어있고, 추가적으로 도커 컴포오즈도 역시 설치가 되어있어야 합니다.
2-2. 프로메테우스 설치 폴더 구성
docker/
└── prometheus
├── docker-compose.yml
├── prometheus.yml
└── prometheus_data
├── 01F9B272CJJSBTN6K6EXPNTB4M
├── lock
├── queries.active
└── wal
설치는 위와 같이 진행했습니다. 특정 폴더 (필자는 /data 하위로 작성)에 docker라틑 폴더를 생성합니다. 그리고 하위로 프로메테우스 폴더를 생성하고 해당 위치에는 다음과 같은 파일 및 폴더를 위치시킵니다.
- docker-compose.yml : docker를 올리기 위한 구성 파일
- prometheus.yml : 프로메테우스 설정 파일
- prometheus_data : 프로메테우스 데이터 저장소
2-3. 프로메테우스 설정 파일
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
external_labels:
cluster: prometheus-1
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['127.0.0.1:9090']
- job_name: 'node_exporter'
static_configs:
- targets: [{워커아이피}:{exporter 포트}]
- global
- Scrape_interval : 몇 초에 한번씩 metricdㅡㄹ 수집할 것인지에 관한 옵션입니다. 해당 값을 설정하지 않는다면 default로 1m 값이 설정됩니다.
- scrape_timeout: metric을 scrape하는데 time out을 얼마나 둘 것인지에 관한 옵션입니다. default는 10s 입니다.
- evaluation_interval: 몇 초에 한번씩 규칙을 평가할 것인지 확인하는 옵션입니다. default 값은 1m 입니다.
- scrape_configs
- job_name이 하나의 key값이 되어, exporter로부터 metric을 수집합니다.
샘플 설정 파일
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: null
name: prometheus-server-conf
namespace: monitoring
data:
prometheus.yaml: |-
global:
scrape_interval: 15s
scrape_timeout: 10s
evaluation_interval: 15s
rule_files:
- "/etc/prometheus-rules/*.rules"
alerting:
alertmanagers:
- scheme: http
static_configs:
- targets:
- "alertmanager-http.monitoring.svc:9093"
scrape_configs:
- job_name: 'kubernetes-nodes'
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: '(.*):10250'
replacement: '${1}:10255'
target_label: __address__
- job_name: 'kubernetes-service-endpoints'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_pod_node_name]
target_label: instance
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)(?::\d+);(\d+)
replacement: $1:$2
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
- job_name: 'kubernetes-services'
metrics_path: /probe
params:
module: [http_2xx]
kubernetes_sd_configs:
- role: service
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
action: keep
regex: true
- source_labels: [__address__]
target_label: __param_target
- target_label: __address__
replacement: blackbox
- source_labels: [__param_target]
target_label: instance
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
target_label: kubernetes_name
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
- source_labels: [__meta_kubernetes_pod_container_port_number]
action: keep
regex: 9\d{3}
- job_name: 'kubernetes-cadvisor'
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
- job_name: 'kube-state-metrics'
static_configs:
- targets: ['kube-state-metrics-http.monitoring:8080']
상위으 설정파일은 좀더 세밀하게 조정을 하는 내용입니다.
2-4. docker-compose 파일
version: '3.7'
services:
prometheus:
image: prom/prometheus
container_name: prometheus
volumes:
- /data/docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- /data/docker/prometheus/prometheus_data:/prometheus
ports:
- 9090:9090
restart: always
사실 docker-compose 파일에 대해서는 큰 내용은 없습니다. volume 구성으로 작성된 프로메테우스 설정파일과 데이터 저장폴더를 지정해주는 내용입니다.
3. Prometheus 실행
이제 준비가 다 됐습니다. 실제로 docker-compose를 올려보도록 하겠습니다.
$ docker-compose up -d
Creating network "prometheus_default" with the default driver
Creating prometheus ... done
9090포트를 사용하기로 하였으므로, 설치한 인스턴스의 아이피에 9090포트로 접속을 해봅니다.
/targets로 접속을 하게 되면, 현재 job config에 의해서 targeting 되는 내용들이 노출됩니다.
설치가 완료되었습니다. 이렇게 해서 2대의 prometheus를 동일하게 셋팅을 할 예정입니다.
4. 마치며..
프로메테우스는 docker를 통해서 손쉽게 올릴 수 있었습니다. 그리고 현재까지는 아주 심플하게 올릴 수 있었지만, 나중에는 좀 더 심화된 설정에 대해서 정리를 좀 해보려고 합니다. 다음시간에는 프로메테우스에 대한 HA구성을 어떤식으로 하면되는지 현재 설치된 프로메테우스에 사이드카로 타노스를 사용할 예정입니다.
5. 출처
https://ooeunz.tistory.com/139?category=893464