📌 이 내용은 책 내용 메모입니다.
개인적인 생각과 경험 그리고 여러 잡담이 있으니, 책을 읽으며 의견을 나누고싶은분이 봐주시면 좋겠습니다.
이번 3장에서는 프로메테우스에 대해 이야기 하고있다.
프로메테우스는 프로메테우스 자체를 잘 사용하기 위한 말 그대로의 생태계를 구축하고있다.
프로메테우스 생태계와 내부 원리를 이해하고있다면 문제가 발생했을 때 근본적인 해결책을 제시할 수 있기때문에 이해하는것이 매우 중요하다.
3.1 프로메테우스 바이너리 구성
프로메테우스는 2012년 시작되었고, 독립적으로 개발되고있는 오픈소스이다.
2016년에 Kubernetes에 이어 두 번째로 Cloud Native Computing Foundation에 가입했다. Prometheus는 클라우드 네이티브 환경에서 정말 중요한 역할을 하고 있다는것 그리고 Kubernetes와 Prometheus는 긴밀하게 연계되어 있다는걸 추측해볼 수있다.
프로메테우스는 프로메테우스 자체 서버 외에도 프로메테우스 생태계를 구축하고있다.
여기에서는 프로메테우스 서버자체가 아니라 생태계에 포함된 Exporter, Operator, Adapter를 소개한다.
Prometheus 기본개념 설명
FAQ페이지에는 이렇게 프로메테우스를 이렇게 정의하고있다. (참고)
Prometheus is an open-source systems monitoring and alerting toolkit with an active ecosystem. It is the only system directly supported by Kubernetes and the de facto standard across the cloud native ecosystem.
즉, 프로메테우스는 활발할 생태계를 가진 모니터링 및 알람 툴킷이다. 또한 클라우드 네이티브 생태계 전반에 걸쳐 사실상의 표준 이라고 말하고 있다. 멋진 소개글이다. 😚👏👏
이 책에서는 이렇게 말하고 있다.
"쿠버네티스의 주요 역할이 애플리케이션을 포함한 컨테이너를 운영하고 스케줄링 하는것이라면, 프로메테우스는 쿠버네티스 기반의 애플리케이션이 원활하게 돌아가도록 다양하고 복잡한 역할을 수행한다."
다시 생각해보면, 어떤 오픈소스를 사용하던지 helm으로 설치하면 대부분 prometheus exporter ("/metric")을 포함하고 있었다. 정말 쿠버네티스 환경에서의 사실상의 표준이 맞는것 같다.
뒤로 넘어가기 전에 기능과 컴포넌트를 공식문서 에서 베껴왔다. 이해하는데 도움이 될것같다.
- 프로메테우스 기능
- a multi-dimensional data model with time series data identified by metric name and key/value pairs
-> 이건 뒤에서 설명한다. - PromQL, a flexible query language to leverage this dimensionality
- no reliance on distributed storage; single server nodes are autonomous
- time series collection happens via a pull model over HTTP
- pushing time series is supported via an intermediary gateway
- targets are discovered via service discovery or static configuration
- multiple modes of graphing and dashboarding support
- a multi-dimensional data model with time series data identified by metric name and key/value pairs
- 프로메테우스 컴포넌트
- 프로메테우스 생태계는 여러 컴포넌트로 구성되며, 대부분 옵셔널하게 적용할수 있다.
- Prometheus server (scrapes and stores time series data)
- client libraries
- push gateway
- exporters.
- alertmanager
Prometheus 주요 컴포넌트
Prometheus는 다양한 도구를 통해 거의 모든 유형의 인프라와 어플리케이션을 모니터링하고 운영 자동화 기능을 사용할 수 있다.
이를 위한 몇가지 중요한 부분을 살펴본다.
- Prometheus Operator
- Kubernetes 환경 내에서 Prometheus의 배포와 관리를 자동화할 수있다.
- Prometheus Operator의 Service Monitor와 Pod Monitor를 통해 Kubernetes 서비스 디스커버리 기능을 제공한다.
- 서비스와 파드의 증감을 모니터링 하며, 증감 발생 시 프로메테우스 구성파일을 업데이트 한다.
- Prometheus Exporter
- Exporter는 Prometheus가 직접적으로 메트릭을 수집할 수 없는 다양한 소스로부터 메트릭을 수집하여 Prometheus가 이해할 수 있는 형식으로 변환하는 역할을 한다.
- 기본적으로 제공하는 Exporter가 존재하며, 그 외에도 커스텀 메트릭 개발을 위한 API,SDK를 제공한다.
- Prometheus Adapter
- Adapter는 주로 Kubernetes 환경에서 Prometheus에서 수집한 메트릭을 사용하여 Kubernetes의 자동 스케일링 기능(예: Horizontal Pod Autoscaler, HPA)과 연동하는 역할을 한다. Prometheus의 메트릭을 Kubernetes의 Custom Metrics API를 통해 사용할 수 있도록 변환하는 중간자 역할을 수행한다.
아래 그림은 PrometheusThanos 관련 아키텍쳐인데, 여기 안에 Operator, Exporter, Adapter가 모두 쉽게 표시되어있어 가져왔다.
3. 2 프로메테우스 시계열 데이터베이스
3.2.1. 데이터 형식
Prometheus Exporter가 /metrics 경로를 통해 데이터를 제공하면, prometheus 는 pull방식으로 데이터를 수집하여 시계열 데이터베이스에 저장한다.
이 데이터 형식을 보면, http_requests_total 이라는 metric이름으로 여러 레이블이 있다.
status 레이블은 "200", "400", "500" 등의 값이 있을 수 있고, method 레이블은 "GET", "POST"값을 가질 수 있다고 가정할 때 Prometheus는 각각의 레이블 조합에 대해 별도의 시계열 데이터를 생성한다.
- http_requests_total {status="200", method="GET"}
- http_requests_total {status="200", method="POST"}
- http_requests_total {status="400", method="GET"}
- http_requests_total {status="400", method="POST"}
- http_requests_total {status="500", method="GET"}
- http_requests_total {status="500", method="POST"}
여기에서 중요한 개념이 카디널리티이다.
- 카디널리티란?
- 특정 메트릭에 대해 고유한 레이블 조합의 총 수를 말한다.
- 예를들어 http_requests_total 메트릭에 대해 status와 method 라벨이 각각 세 가지와 두 가지 가능한 값을 가질 수 있다고 할 때, 최대 카디널리티는 6(status의 3개 값 × method의 2개 값)이며, Prometheus에 의해 별도의 시계열로 관리된다.
- 카디널리티가 왜 중요한가?
- 각 시계열 데이터를 관리하는 데 필요한 리소스와 시스템의 성능에 영향을 미친다.
- 메트릭에 수업이 조합된 여러 차원은 프로메테우스에서 소위 카디널리티 스파이크를 야기할 수있다.
3.2.2. 데이터 관리
Prometheus에서 스크래핑 된 데이터는 데이터베이스에 저장된다.
프로메테우스에서 시계열 데이터에 어떻게 저장하고 관리하는지 확인해보자.
프로메테우스 Time Series Database(TSDB)는 시계열 데이터베이스이며 이런 특징이 있다.
- 프로메테우스 TSDB특징
- LRU 알고리즘을 사용하여, 가장 오랫동안 참조하지 않은 페이지를 교체한다.
- 메모리 페이징(paging)을 사용하는데, 일정 크기인 페이지로 분할해서 메모리에 적재하는 방식이다.
- 수집된 데이터(앞으로는 chunk 라는 용어로 부른다)는 블록형태로 만들어 디스크에 저장한다.
- 블록은 다수의 펑크를 포함하여 인덱스 등의 데이터로 구성된다. 인덱스는 데이터의 위치와 참조에 대한 정보 뿐만 아니라 데이터를 빠르게 조회할 수 있는 기능을 제공한다.
- 데이터셋은 다수 데이터그룹을 의미하며, 데이터 포인트는 대시보드에서 시계열로 출력되는 개별 데이터를 말한다.
- 프로메테우스 데이터 구조
- 실제 데이터가 어디에 저장되었는지 보려면 ps로 확인해볼 수 있다.
# 프로메테우스 스토리지 어디인지 확인하기
/prometheus $ ps
PID USER TIME COMMAND
1 1000 12:09 /bin/prometheus --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=24h (나머지생략)
77 1000 0:00 /bin/sh
# 구조 확인하기
/prometheus $ tree
.
├── 01HQ4SP85M2HZ1T160MKJ8ETAX
│ ├── chunks
│ │ └── 000001
│ ├── index
│ ├── meta.json
│ └── tombstones
├── 01HQ53DJWQYFHF0R0W81TP1M51
│ ├── chunks
│ │ └── 000001
│ ├── index
│ ├── meta.json
│ └── tombstones
├── 01HQ57N0M547EXEQF95J3H077B # 블록
│ ├── chunks # 청크파일
│ │ └── 000001
│ ├── index # 색인을 위한 레이블과 시간 인덱스 파일
│ ├── meta.json # 블록의 메타데이터
│ └── tombstones # 삭제여부 표시 파일
├── chunks_head # 청크헤드
│ ├── 000007
│ └── 000008
├── lock
├── queries.active
└── wal # wal 파일
├── 00000004
├── 00000005
├── 00000006
├── 00000007
└── checkpoint.00000003 # 복구를 위한 checkpoint wal파일
└── 00000000
- 블록(Blocks)
- Prometheus는 시계열 데이터를 불변의 블록으로 저장한다.
- 각 블록은 특정 시간 범위의 데이터를 포함하고 있으며, 여기서 01HQ57N0M547EXEQF95J3H077B 같은 디렉토리는 개별 블록을 나타낸다.
- 블록의 구성요소
- chunks: 실제 시계열 데이터 샘플이 저장된 파일이며, 청크 파일(000001 등)은 시간에 따른 데이터 포인트를 압축하여 저장한다.
- index: 시계열 데이터를 효율적으로 쿼리할 수 있도록 돕는 인덱스 파일이다. 메트릭 이름, 레이블, 타임스탬프 등에 대한 인덱스를 포함하여, 쿼리 시 해당 시계열 데이터를 빠르게 찾을 수 있게 한다.
- meta.json: 해당 블록의 메타데이터를 포함하는 파일입니다. 블록의 시간 범위, 버전 정보, 블록에 대한 다른 메타데이터 등이 포함되며 사람이 읽을 수 있다.
- tombstones: 삭제된 시계열 데이터를 표시하는 파일이다. 데이터 삭제 요청이 있을 경우, 실제 데이터는 즉시 삭제되지 않고, 이 파일에 삭제 마크가 표시된다.
- 청크 헤드(chunks_head)
- 현재 쓰기 작업 중인 시계열 데이터를 저장하는 임시 공간이다.
- Prometheus는 새로운 데이터 포인트를 먼저 이곳에 저장한 후, 일정 시간이 지나면 불변 블록으로 데이터를 옮긴다.
- WAL(Write-Ahead Logging)
- wal: WAL은 쓰기 선행 로깅(Write-Ahead Logging)의 약자로, 데이터를 블록으로 옮기기 전에 모든 쓰기 작업을 로깅한다. 이는 데이터 무결성과 복구 메커니즘을 보장하기 위한 것이다.
- checkpoint.00000003: 체크포인트 파일은 WAL의 특정 시점에서의 스냅샷을 나타낸다.
이는 시스템 재시작 시 WAL의 전체 스캔 없이 빠른 복구를 가능하게 합니다. 프로메테우스에서 장애가 발생해서 메모리에 있는 데이터에 문제가 생기면 WAL를 하용해 메모리에서 관리하는 데이터를 복구한다.
- 기타 파일
- lock: 동시성 제어와 같은 목적으로 사용되는 락 파일
- queries.active: 현재 진행 중인 쿼리 정보를 저장하는 파일
3.2.3. 블록관리
- 샘플
- 샘플(sample)은 시계열 데이터 포인트를 의미하며, 시계열 데이터의 핵심 단위이다.
- 각각의 샘플은 특정 시점에서의 메트릭 값과 그 시점을 나타내는 타임스탬프로 구성된다.
- 메트릭값(float64): 측정하고자 하는 실제 데이터 값이다. 예를 들어, http_requests_total 메트릭의 샘플 값은 특정 시점에서의 HTTP 요청 총 수를 의미한다.
- 타임스탬프: 메트릭 값이 기록된 정확한 시간이다.
- 블록 생성
- 시계열은 시간순으로 인덱싱 되는 숫자데이터 포인트의 시퀀스로 정의할 수 있다.
- 프로메테우스 데이터 포인트는 일정한 시간 간격으로 수집되며, 이런 형식을 그래픽 형식으로 표한하자면 x축은 시간, y축은 데이터 값이다. (시간에 따른 변화 표시)
- 메모리에 수집된 샘플은 기본 두시간 단위로 디스크로 플러시 되고 블록이 생성된다.
- 블록 병합
- 크기가 작은 파일가 데이터가 다수 존재하면 모든 파일에 대한 인덱스를 만들고 검색해야하므로 조회속도가 느려진다. 반면 파일 크기가 너무 크면 효율성이 떨어진다.
- 파일의 개수와 파일의 크기를 적절하게 유지하는것이 중요하다.
- tsdb와 관련된 주요 옵션이다.
- --storage.tsdb.min-block-duration :
TSDB에서 생성될 수 있는 최소 블록의 시간 범위를 설정한다. 이 시간 범위 동안의 데이터를 하나의 블록으로 저장한다.
이 값은 Prometheus가 데이터를 얼마나 자주 컴팩션(compaction, 여러 블록을 병합하는 과정)할지를 결정하는 데 영향을 준다. - --storage.tsdb.min-block-duration:
최대 블록 기간을 설정한다. max-block-duration은 컴팩션 과정에서 여러 개의 미니멈 블록을 하나의 큰 블록으로 병합할 때 생성될 수 있는 최대 블록의 시간 범위를 정의하며, 이 설정을 통해 긴 시간 동안의 데이터를 효율적으로 관리할 수 있다.
Prometheus에서는 min-block-duration으로 설정된 시간 동안의 데이터를 하나의 블록으로 저장하고, 여러 개의 이런 블록이 max-block-duration에 도달하면 이들을 하나의 큰 블록으로 병합된다. - --storage.tsdb.retention.time=24h : 데이터를 얼마나 오래 보관할지를 정하며, 그 이전의 데이터는 자동으로 삭제한다.
- --storage.tsdb.path=/prometheus : 데이터가 어디에 저장될지 지정한다.
- --storage.tsdb.min-block-duration :
- 프로메테우스 로컬 스토리지
- 프로메테우스는 로컬스토리지에 데이터를 저장한다.
- 최상위 레벨에서 프로메테우스 스토리지 디자인은 현재 저장된 모든 레이블 목록과 자체 시계열 형식을 사용하는 색인의 조합으로 이루어져있다.
- 데이터 흐름
- 메모리
- 최신 데이터 배치는 기본 최대 2시간 동안 메모리에 저장한다.
- 수집된 데이터는 하나이상의 데이터 청크(chunk) 형태로 메모리에 저장된다. 이 방식은 쿼리 응답 속도를 빠르게 하며, 디스크 I/O를 줄인다. 메모리에 데이터를 저장함으로써, 자주 액세스하는 최신 데이터에 대한 쿼리 속도가 향상되고, 반복적인 디스크 쓰기가 방지된다.
- 헤드 청크 (Head Chunks)
- 헤드 청크는 Prometheus에서 현재 활성화되어 데이터가 수집되는 메모리 내의 청크를 의미한다.
- 청크는 가장 최신의 시계열 데이터를 포함하고 있으며, 데이터가 지속적으로 이 청크에 추가된다.
- 헤드 청크는 일정 시간이 지나거나 청크가 특정 크기에 도달하면 디스크에 저장되는 불변 청크(immutable chunks)로 변환된다.
- 에버터블 청크 (Evictable Chunks, LRU 기반)
- 에버터블 청크는 메모리 관리를 위해 LRU (Least Recently Used) 알고리즘에 따라 메모리에서 제거될 수 있는 청크를 의미한다.
- Prometheus는 메모리 사용량을 관리하기 위해 일정 시간 동안 쿼리에 사용되지 않은 청크를 메모리에서 해제한다.
- 로그 선행 기입 (Write-Ahead Logging, WAL)
- Prometheus는 데이터 손실을 방지하기 위해 Write-Ahead Logging (WAL)을 사용한다.
- 메모리에 저장된 데이터가 시스템 장애와 같이 예상하지못한 상황에도 안전하게 보호될 수 있도록한다.
- 데이터가 디스크에 안전하게 저장되기 전에 먼저 로그로 기록되는 방식으로, 시스템 재시작 후에도 데이터 복구가 가능하게된다.
- 디스크
- 설정된 시간(기본적으로 2시간)이 지나면, 메모리에 있는 데이터 청크는 디스크로 옮겨지며, 이때 청크는 불변(immutable)의 형태로 저장된다.
- 데이터 삭제가 필요한 경우, Prometheus는 삭제 표시를 위한 'tombstone' 파일을 생성합니다. 이는 실제 데이터를 즉시 삭제하지 않고, 나중에 컴팩션(compaction) 과정에서 물리적으로 제거될 데이터를 표시한다.
- 메모리
프로메테우스에서 제공하는 내부 메트릭을 통해 플러시 상태, WAL,TSDB의 상태와 크기, 적재되는 메트릭의 개수등을 모니터링 할 수 있다.
프로메테우스는 클러스터링이 되지 않고 빈번한 장애 발생으로 인해 메트릭의 유실이 발생하므로 주의해야 한다.
3. 3 프로메테우스 쿠버네티스 구성
helm chart로 설치하면 내부 구조를 이해하는게 쉽지 않아, 바이너리를 다운받고, 구설파일을 작성하고 설치하는 방법을 알려준다.
프로메테우스 오퍼레이터 (https://github.com/prometheus-operator/kube-prometheus)를 사용하여 설치한다.
# 로컬 minikube 시작
minikube start
이때, 내 minikube에 할당된 cpu/mem값을 잘 확인해야한다.
🔥 Creating docker container (CPUs=2, Memory=8100MB) ...
이제 소스코드를 다운받고 몇가지 수정해주어야 한다.
로컬에 띄우는거라 리소스가 모자라서 Replica 및 할당 크기를 좀 줄여줘야 한다.
# 소스 다운로드
git clone https://github.com/prometheus-operator/kube-prometheus.git
# 디렉토리 이동
cd kube-prometheus
# manifests/alertmanager-alertmanager.yaml 수정
spec:
replicas: 1
resources:
limits:
cpu: 50m
memory: 50Mi
requests:
cpu: 4m
memory: 50Mi
# manifests/prometheus-prometheus.yaml 수정
spec:
replicas: 1
# manifests/prometheusAdapter-deployment.yaml 수정
spec:
replicas: 1
그리고 setup을 먼저 돌린다.
kubectl create -f manifests/setup
# 출력결과
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusagents.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/scrapeconfigs.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com created
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com created
namespace/monitoring created
그다음 나머지도 생성해준다.
kubectl create -f manifests
# 출력결과
alertmanager.monitoring.coreos.com/main created
networkpolicy.networking.k8s.io/alertmanager-main created
poddisruptionbudget.policy/alertmanager-main created
prometheusrule.monitoring.coreos.com/alertmanager-main-rules created
secret/alertmanager-main created
service/alertmanager-main created
serviceaccount/alertmanager-main created
servicemonitor.monitoring.coreos.com/alertmanager-main created
clusterrole.rbac.authorization.k8s.io/blackbox-exporter created
clusterrolebinding.rbac.authorization.k8s.io/blackbox-exporter created
configmap/blackbox-exporter-configuration created
deployment.apps/blackbox-exporter created
networkpolicy.networking.k8s.io/blackbox-exporter created
service/blackbox-exporter created
serviceaccount/blackbox-exporter created
servicemonitor.monitoring.coreos.com/blackbox-exporter created
secret/grafana-config created
secret/grafana-datasources created
configmap/grafana-dashboard-alertmanager-overview created
configmap/grafana-dashboard-apiserver created
configmap/grafana-dashboard-cluster-total created
configmap/grafana-dashboard-controller-manager created
configmap/grafana-dashboard-grafana-overview created
configmap/grafana-dashboard-k8s-resources-cluster created
configmap/grafana-dashboard-k8s-resources-multicluster created
configmap/grafana-dashboard-k8s-resources-namespace created
configmap/grafana-dashboard-k8s-resources-node created
configmap/grafana-dashboard-k8s-resources-pod created
configmap/grafana-dashboard-k8s-resources-workload created
configmap/grafana-dashboard-k8s-resources-workloads-namespace created
configmap/grafana-dashboard-kubelet created
configmap/grafana-dashboard-namespace-by-pod created
configmap/grafana-dashboard-namespace-by-workload created
configmap/grafana-dashboard-node-cluster-rsrc-use created
configmap/grafana-dashboard-node-rsrc-use created
configmap/grafana-dashboard-nodes-darwin created
configmap/grafana-dashboard-nodes created
configmap/grafana-dashboard-persistentvolumesusage created
configmap/grafana-dashboard-pod-total created
configmap/grafana-dashboard-prometheus-remote-write created
configmap/grafana-dashboard-prometheus created
configmap/grafana-dashboard-proxy created
configmap/grafana-dashboard-scheduler created
configmap/grafana-dashboard-workload-total created
configmap/grafana-dashboards created
deployment.apps/grafana created
networkpolicy.networking.k8s.io/grafana created
prometheusrule.monitoring.coreos.com/grafana-rules created
service/grafana created
serviceaccount/grafana created
servicemonitor.monitoring.coreos.com/grafana created
prometheusrule.monitoring.coreos.com/kube-prometheus-rules created
clusterrole.rbac.authorization.k8s.io/kube-state-metrics created
clusterrolebinding.rbac.authorization.k8s.io/kube-state-metrics created
deployment.apps/kube-state-metrics created
networkpolicy.networking.k8s.io/kube-state-metrics created
prometheusrule.monitoring.coreos.com/kube-state-metrics-rules created
service/kube-state-metrics created
serviceaccount/kube-state-metrics created
servicemonitor.monitoring.coreos.com/kube-state-metrics created
prometheusrule.monitoring.coreos.com/kubernetes-monitoring-rules created
servicemonitor.monitoring.coreos.com/kube-apiserver created
servicemonitor.monitoring.coreos.com/coredns created
servicemonitor.monitoring.coreos.com/kube-controller-manager created
servicemonitor.monitoring.coreos.com/kube-scheduler created
servicemonitor.monitoring.coreos.com/kubelet created
clusterrole.rbac.authorization.k8s.io/node-exporter created
clusterrolebinding.rbac.authorization.k8s.io/node-exporter created
daemonset.apps/node-exporter created
networkpolicy.networking.k8s.io/node-exporter created
prometheusrule.monitoring.coreos.com/node-exporter-rules created
service/node-exporter created
serviceaccount/node-exporter created
servicemonitor.monitoring.coreos.com/node-exporter created
clusterrole.rbac.authorization.k8s.io/prometheus-k8s created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-k8s created
networkpolicy.networking.k8s.io/prometheus-k8s created
poddisruptionbudget.policy/prometheus-k8s created
prometheus.monitoring.coreos.com/k8s created
prometheusrule.monitoring.coreos.com/prometheus-k8s-prometheus-rules created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s-config created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s created
rolebinding.rbac.authorization.k8s.io/prometheus-k8s created
role.rbac.authorization.k8s.io/prometheus-k8s-config created
role.rbac.authorization.k8s.io/prometheus-k8s created
role.rbac.authorization.k8s.io/prometheus-k8s created
role.rbac.authorization.k8s.io/prometheus-k8s created
service/prometheus-k8s created
serviceaccount/prometheus-k8s created
servicemonitor.monitoring.coreos.com/prometheus-k8s created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
clusterrole.rbac.authorization.k8s.io/prometheus-adapter created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-adapter created
clusterrolebinding.rbac.authorization.k8s.io/resource-metrics:system:auth-delegator created
clusterrole.rbac.authorization.k8s.io/resource-metrics-server-resources created
configmap/adapter-config created
deployment.apps/prometheus-adapter created
networkpolicy.networking.k8s.io/prometheus-adapter created
poddisruptionbudget.policy/prometheus-adapter created
rolebinding.rbac.authorization.k8s.io/resource-metrics-auth-reader created
service/prometheus-adapter created
serviceaccount/prometheus-adapter created
servicemonitor.monitoring.coreos.com/prometheus-adapter created
clusterrole.rbac.authorization.k8s.io/prometheus-operator created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-operator created
deployment.apps/prometheus-operator created
networkpolicy.networking.k8s.io/prometheus-operator created
prometheusrule.monitoring.coreos.com/prometheus-operator-rules created
service/prometheus-operator created
serviceaccount/prometheus-operator created
servicemonitor.monitoring.coreos.com/prometheus-operator created
crd를 확인해본다.
설치된 svc도 확인해본다.
파드도 한번 확인해본다.
그리고 포트포워딩 해서 prometheus 에 접속해보자
kubectl -n monitoring port-forward svc/prometheus-k8s 9090
3. 4 프로메테우스 오퍼레이터
Prometheus Operator의 역할은 Service Discovery, 즉, 동적으로 변하는 쿠버네티스 리소스를 쉽게 탐색하고 검색하는 기능을 제공한다.
프로메테우스의 타깃은 Config파일에서 관리한다, 이때 Configmap또는 별도 파일로 관리하는것은 좋은 방법이 아니다.
Prometheus Operator를 사용하면 Kubernetes 클러스터 내의 서비스가 동적으로 변경될때 변화를 자동으로 감지하고 Prometheus의 타깃 목록을 업데이트 할 수 있다.
Custom Resource Definitions (CRDs)를 통해 모니터링 하는 방법을 선언적으로 정의하는데, CRDs 중 하나가 ServiceMonitor이다.
- ServiceMonitor: 특정 쿠버네티스 서비스를 모니터링 대상으로 지정하고, Prometheus가 해당 서비스의 엔드포인트를 어떻게 스크래핑할지 세부 사항을 정의한다.
- PodMonitor: ServiceMonitor와 유사하지만, 서비스 대신 개별 파드를 직접 모니터링 대상으로 지정한다.
- PrometheusRule: 경고 규칙을 정의하여 Prometheus Alertmanager가 사용할 수 있도록 한다.
아래에서 Node를 위한 ServiceMonitor 예시를 확인할 수 있다.
# Node Exporter를 위한 서비스 모니터 (샘플)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 1.7.0
name: node-exporter
namespace: monitoring
spec:
endpoints: # 모니터링할 엔드포인트 목록
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
interval: 15s
port: https
relabelings: # 타겟의 라벨을 재설정하는 규칙
- action: replace
regex: (.*)
replacement: $1
sourceLabels:
- __meta_kubernetes_pod_node_name
targetLabel: instance
scheme: https
tlsConfig:
insecureSkipVerify: true
jobLabel: app.kubernetes.io/name # 작업(job) 이름을 식별하는 데 사용하는 라벨
selector: # 라벨 셀렉터
matchLabels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
레이블의 변경, 제거 및 개수 줄이기등의 작업을 통해 시계열 데이터 관리를 최적화 할 수 있다.
- relabel_configs:
- 메트릭을 수집한 후 레이블을 변경한다.
- 수집된 메트릭을 처리하고 필요하지 않은 메트릭을 제거하거나 라벨을 변경하는데 사용한다.
- metric_relabel_configs:
- 수집된 메트릭을 저장하기 전에 변환하거나 삭제한다.
- 스크래핑할 메트릭을 선택하거나, 타겟을 재구성하는 데 사용한다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 1.7.0
name: node-exporter
namespace: monitoring
spec:
endpoints:
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
interval: 15s
port: https
relabelings:
- action: replace
regex: (.*)
replacement: $1
sourceLabels:
- __meta_kubernetes_pod_node_name
targetLabel: instance
scheme: https
tlsConfig:
insecureSkipVerify: true
# 추가된 relabel_configs 예시
relabel_configs:
- sourceLabels: [__address__] # 원본라벨
targetLabel: instance_address # 최종라벨
- targetLabel: __address__ # 원본라벨
replacement: 127.0.0.1:9090 # 고정라벨로 수정
# 추가된 metric_relabel_configs 예시
metric_relabel_configs:
- sourceLabels: [job]
regex: 'node-exporter'
action: drop
jobLabel: app.kubernetes.io/name
selector:
matchLabels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
app.kubernetes.io/part-of: kube-prometheus
3. 5 프로메테우스 오토스케일링
3.5.1 프로메테우스 어뎁터
프로메테우스 어뎁터는 Prometheus에서 수집한 메트릭을 사용하여 Kubernetes의 자동 스케일링 기능(예: Horizontal Pod Autoscaler, HPA)과 연동하는 역할을한다.
이 책에서는 자세히 소개하지만, 프로메테우스 어뎁터를 많이 사용하지도 않고 이 책에서도 KEDA를 사용하도록 추천하고있어 간단히만 확인하고 넘어간다.
Prometheus Adapter은 ConfigMap에 정의된 데로 동작하며, Prometheus Adapter Deployment에 마운트 된다.
아래 설정파일에서는 어떤 Prometheus Metric을 사용할것인지, HPA에서 어떻게 참조하는지 볼 수있다.
# http_requests_total 메트릭에 대한 2분 동안의 비율(rate)을 계산하여,
# http_requests_per_second라는 메트릭 이름으로 제공
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-adapter-config
namespace: custom-metrics
data:
config.yaml: |
rules:
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
name:
matches: "^(.*)$"
as: "http_requests_per_second"
metricsQuery: 'sum(rate(http_requests_total{namespace="my-ns",job="web-app"}[2m])) by (pod)'
---
# http_requests_per_second 메트릭이 100을 초과하는 경우
# Pod수를 늘리도록 설정
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
namespace: my-ns
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: your_deployment_name
minReplicas: 1
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 100
3.5.2 KEDA 오토스케일
위와 같은 조건으로 동작하는 KEDA ScaledObject 정의파일이다.
같은 조건인데, HPA를 따로 설정하지 않고, 메트릭 변환을 위한 ConfigMap설정도 수정하지 않고, ScaledObject 하나만 생성하면 되니 매우 간단하다.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: prometheus-scaledobject
namespace: my-ns
spec:
scaleTargetRef: # 스케일링할 대상 리소스
name: your_deployment_name
pollingInterval: 30 # 폴링 간격을 초 단위로 설정 (기본값은 30초)
cooldownPeriod: 300 # 스케일 다운 전 쿨다운 시간을 초 단위로 설정 (기본값은 300초)
minReplicas: 1 # 최소 Replica 수
maxReplicas: 10 # 최대 Replica 수
triggers: # 트리거 조건 지정
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring
metricName: http_requests_per_second
threshold: '100'
query: |
sum(rate(http_requests_total{namespace="my-ns",job="web-app"}[2m])) by (pod)
3. 6 프로메테우스 알람
이 책에서는 Rule Manager, Alert manager 컴포넌트가 모두 독립적인 서비스로 실행되는것처럼 설명하지만, 최신버전(2.50)에서는 Rule Manager의 역할이 ALERTING RULES 기능으로 프로메테우스 서버 내부에 내제 되어있는것으로 보인다.
- Prometheus에서 구성할 수 있는 두가지 유형의 규칙
- recording_rules
- 복잡하거나 자주 사용되는 쿼리의 결과를 새로운 시계열로 저장하여, 이후 쿼리의 성능을 향상시키고, 쿼리를 단순화한다.
- 데이터 처리 및 질의응답 시간을 개선한다.
- alerting_rules
- 특정조건을 만족할때 외부 서비스에 경고 실행에 대한 알림을 보낼 수 있다.
- Prometheus 쿼리 언어(PromQL)를 사용하여 정의되며, 조건이 참이 되면 경고상태가 되어 AlertManager로 전송된다.
- 경고 조건의 평가 자체는 Prometheus에 저장된 시계열 데이터를 사용하지만, "경고의 상태"나 "경고가 발생했다는 사실"이 Prometheus의 데이터베이스에 별도의 시계열 데이터로 저장되지 않는다. - 참고1, 참고2
- Prometheus에서 알람 이력(history)를 저장하고 있지 않는것 같은데 이 책에서는 별도의 시계열 데이터로 저장한것으로 나와있다(163-164p). Grafana에서 알람을 발생시킨경우 Grafana의 RDB에 Alart이력이 저장되어있었다. (맞나?)
- recording_rules
- Alert Manager
- Prometheus 서버는 경고 규칙에 따라 발생한 경고를 Alertmanager에 전송하고, Alertmanager는 이러한 경고를 처리하여 최종 사용자에게 알린다.
# Prometheus 알람 규칙
# 평균요청 대기 시간이 5분동안 0.5초보다 큰 "HighRequestLatency"알람 정의
groups:
- name: HighRequestLatencyAbove0.5s
rules:
- alert: HighRequestLatency
expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5
for: 10m
labels:
severity: 2
name: HighRequestLatencyAbove0.5s
annotations:
summary: High request latency
- name: HighRequestLatencyAbove1s
rules:
- alert: HighRequestLatency
expr: job:request_latency_seconds:mean5m{job="myjob"} > 1
for: 10m
labels:
severity: 1
name: HighRequestLatencyAbove1s
annotations:
summary: High request latency
# AlertManager 라우팅 규칙
route:
receiver: 'devops-team'
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
group_by: ['job', 'severity']
routes:
- match:
name: 'HighRequestLatencyAbove1s'
severity: '1'
receiver: 'devops-team'
receivers:
- name: 'devops-team'
email_configs:
- to: 'devops@example.com'
from: 'alertmanager@example.com'
smarthost: 'smtp.example.com:25'
또, 이전에 알람을 설정하면서 Prometheus 알람과 Grafana 알람이 뭐가 다른건지 궁금했는데, 이 책에서는 이 둘은 차이가 없고 동일한 알람 기능을 제공한다고 되어있다. (그라파나 서버는 프로메테우스에서 갈라져서 나와 개발된 오픈소스이며, 프로메테우스를 기준으로 개발 된 알람 규칙은 그라파나 서버에서도 동일하게 작동한다.)
고려해야할 사항
- 로그의 경우 레코딩 규칙을 개발하고 메트릭 형식으로 적재하고 규칙을 개발한다.
- 추적의 경우에는 직접 레코딩 규칙을 개발할 수 없으므로, 스팬 메트릭을 사용해서 메트릭(버킷)을 생성하고 규칙을 개발한다.
- 프로파일은 레코딩 규칙을 개발할 수 없으며, 프로파일을 메트릭으로 반출(export)하고 규칙을 개발한다.
- 알람과 통지는 상태를 갖는다. 알람을 생성하고 통지하는 라이프사이클을 설계하고 상태를 관리해야한다.
주의사항
- 다양한 기술세트를 사용하면 추후 관리가 어렵기때문에 알림 규칙을 프로메테우스로 단일화 한다.
- 가급적 메트릭으로만 알람을 관리하고, 스테이트 타임라인차트로 시각화한다.
- SLO지표와 연계한다.
3. 7 프로메테우스 샤딩 아키텍쳐
프로메테우스 구성을 위한 기본적인 가이드라인은 높은 카디널리티 메트릭 생성(label userid)을 피하는것 (참고: 카디널리티 줄이기 블로그)그리고 샤딩을 구성하는것이다.
Prometheus는 기본적으로 단일 인스턴스로 운영되며 로컬디스크에 데이터를 저장한다.
이는 대규모 환경에서는 한계가 있다. 이때 필요한것이 샤딩과 페더레이션 이다.
3.7.1 샤딩 아키텍쳐
샤딩이란, 스크래핑 타깃 목록을 2개 이상의 프로메테우스로 분할하는것을 뜻하며,
구성하는 방법에 따라 수직샤딩, 수평 샤딩 두가지로 나눌 수 있다.
- 수직샤딩:
- 프로메테우스 서버를 여러개를 운영하며, 특정 기준(예: 조직별, 팀별)에 따라 서버를 분할 한다.
- 각 서버는 독립적으로 특정 메트릭을 수집하고 관리한다.
- 수평샤딩: (이해못함)
- 샤드를 기준으로 메트릭을 수집한다.
- 하나의 프로메테우스 서버가 여러 인스턴스를 갖는것을 의미한다.
3.7.2 페더레이션 아키텍쳐
페더레이션이란, 여러 Prometheus 서버들 사이에서 메트릭을 집계하고 관리하는 구조를 말한다.
- 계층적 페더레이션
- 상위 프로메테우스 서버 아래에 여러 프로메테우스가 존재하는 아키텍쳐이다.
- 하위 프로메테우스가 수집하는 메트릭을 상위 프로메테우스에서 다시 스크랩하여 전체적인 내용을 상위레벨에서 취합하여 모니터링할 수 있게 된다.
- 동일 레벨 페더레이션 (교차서비스)
- 한 프로메테우스 서버에서 다른 하나의 프로메테우스 서비스를 스크랩 하도록 구성한다.
- 단일서버에서 두 데이터셋에 대한 쿼리가 가능해진다.
위에서 설명한 샤딩과 페더레이션 기술을 사용하여 Prometheus 클러스터링 구성을 구현한것이 바로 Thanos, Mimir이다.
Prometheus의 확장성과 장기 데이터 저장 및 고가용성 문제를 해결하도록 설계되어있으며 바로 뒤에서 Thanos, 그리고 아마도 4장에서 Mimir를 언급하게 된다.
3. 8 타노스 운영
3.8.1 타노스 운영
단일 Prometheus는 계속 반복해서 말하지만, 확장성(수평확장 불가)과 장기 데이터 저장 및 고가용성 문제가 존재한다.
이런 문제는 Thanos를 도입함으로써 해결할 수 있다.
- Thanos 장점 (=컴포넌트)
- 글로벌 뷰여러 Prometheus서버에서 생성된 데이터를 하나의 인스턴스에서 쿼리할 수 있다. (Thanos Querier)
- 다운샘플링: 다운샘플링을 자동으로 생성하여 오랜기간에 걸친 데이터를 쿼리하는것이 가능하다. (Thanos compactor)
- 규칙: 프로메테우스 샤드의 메트릭을 혼합하는 글로벌 알람 규칙과 레코딩 규칙을 생성할 수 있다. (Thanos Ruler)
- 장기보관: 객체 스토리지를 활용해 스토리지의 내구성, 신뢰성, 확장성 문제를 해결한다. (Thanos StoreGateway)
Thanos는 사이드카 혹은 리시버 방식 이 두가지 유형으로 운영될 수 있으며 ,아래에서 알아보도록 한다.
추가적으로 이 블로그의 글이 사이드키 방식과 리시버 방식의 차이점을 잘 설명해준것 같다.
3.8.2 타노스 사이드카 방식
Thanos Sidecar 방식은 여러 Prometheus 서버에 Thanos사이드카 컨테이너를 함께 운영하는 아키텍쳐를 말한다.
┌────────────┬─────────┐ ┌────────────┬─────────┐ ┌─────────┐
│ Prometheus │ Sidecar │ ... │ Prometheus │ Sidecar │ │ Rule │
└────────────┴────┬────┘ └────────────┴────┬────┘ └┬────────┘
│ │ │
Blocks Blocks Blocks
│ │ │
v v v
┌──────────────────────────────────────────────────┐
│ Object Storage │
└──────────────────────────────────────────────────┘
# https://thanos.io/tip/thanos/design.md/
책에서 나오는 원격읽기에 대해 이해하지 못했다.
사이드카방식은 원격읽기, 리시버 방식은 원격쓰기를 사용한다고 한다.
- 쓰기:
- 타노스 사이드카는 프로메테우스 인스턴스와 연계해서 메트릭의 수집을 처리하고, 적재된 TSDB블록을 객체 스토리지로 전달한다.
- 쓰기의 핵심 컴포넌트는 사이드카이다.
- 사이드카는 Prometheus의 로컬 스토리지에서 읽으므로 TSDB에 추가 로컬 스토리지(PV)가 필요하지 않다.
- 기록 데이터가 객체 스토리지를 통해 내구성 있고 쿼리 가능하게 만들어지는 동안 2시간마다 업로드되므로 Prometheus 로컬 스토리지의 TSDB 보존 시간이 단축된다.
- 읽기:
-
- 타노스 스토어는 스토어 API를 이용해 블록을 검색하고, 결과를 타노스 쿼리에 반환한다.
- 읽기의 핵심은 타노스 스토어와 사이드카 이다.
- 쿼리가 발생했을때 타노스 스토어와 사이드카 양쪽으로 조회를 요청한다. 사이드카는 블록생성 이전 메모리에 있는 데이터를 조회하는데 사용하고, 타노스스토어는 블록 생성 이후 객체 스토리지에 있는데이터를 조회하는데 사용한다.
3.8.3 타노스 리시버 방식
쓰기를 처리해주는 별도의 Receiver가 존재하는 아키텍쳐 이다.
┌─────────────┐ ┌─────────────┐ ┌─────────┐
│ Prometheus │ ... │ Prometheus │ │ Rule │
└───────┬─────┘ └───────┬─────┘ └───┬─────┘
v v v
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ Thanos │ │ Thanos │ │ Thanos │
│ Receiver │ │ Receiver │ │ Receiver │
└───────┬────────┘ └──────────┬─────┘ └─────────┬──────┘
└───────────┬───────────┘ │
│ │
v v
┌──────────────────────────────────────────────┐
│ Object Storage │
└──────────────────────────────────────────────┘
- 쓰기
- 위의 사이드카 방식에서 Prometheus TSDB블록이 바로 ObjectStorage에 쓰였다면,
리시버 방식은 Prometheus에서 지속적으로 데이터를 Reciver에게 보내고, TSDB블록은 Reciver에 의해서 오브젝트 스토리지에 저장된다. - Reciver StatefulSet이 배포되어야 한다. (+PV)
- 위의 사이드카 방식에서 Prometheus TSDB블록이 바로 ObjectStorage에 쓰였다면,
- 읽기
- 정확한 부분은 내용이 없지만, 아키텍쳐나 다른 문서를 확인해봤을때 동작 방식은 거의 사이드카와 비슷한것 같다.
- 다만, 메모리에 있는 최근 데이터를 검색하는 위치가 Thanos Reciver가 된다.
3.8.4 타노스 구성
Step.1 minio 스토리지 구성
스토리지로 사용할 minio를 다운받고 실행시킨다.
# 참고: https://min.io/download#/macos
# 서버 다운로드
curl --progress-bar -O https://dl.min.io/server/minio/release/darwin-arm64/minio
# minio가 사용할 디렉토리 생성
mkdir minio-dir
# minio 실행
chmod +x minio
MINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=password ./minio server ./minio-dir --console-address ":9001"
이렇게 실행시키면 로컬에서 브라우저로 접속할 수 있다. (http://127.0.0.1:9001)
사용할 버킷을 하나 만들어준다.
Step.2 Prometheus 실행
먼저, 프로메테우스가 메트릭을 가져가야 하기때문에, 가장 간단한 node-exporter를 설치하여 수집할 수있는 메트릭을 만들어주자
brew install node_exporter
brew services start node_exporter
# 실행 후 확인 방법 curl http://localhost:9100/metrics
# 테스트 종료 후 brew services stop node_exporter && brew uninstall node_exporter 명령어로 삭제
이제 프로메테우스를 실행해보자.
위에서 만들어놓은 node_exporter의 메트릭을 수집하도록 한다.
# 바이너리 다운로드
wget https://github.com/prometheus/prometheus/releases/download/v2.50.1/prometheus-2.50.1.darwin-arm64.tar.gz
# 압축해제
tar zxvf prometheus-2.50.1.darwin-arm64.tar.gz
# 프로메테우스를 위한 디렉토리 생성
mkdir prometheus-tsdb
# prometheus.yml파일에 thanos를 위한 라벨 설정 추가
cd prometheus-2.50.1.darwin-arm64
vi prometheus.yml
----------------------------------------
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: "test-cluster"
environment: "local-test"
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
- job_name: "local-node-exporter"
static_configs:
- targets: ['localhost:9100']
----------------------------------------
# 실행
./prometheus --config.file=prometheus.yml \
--storage.tsdb.path=../prometheus-tsdb \
--storage.tsdb.min-block-duration=2h \
--storage.tsdb.max-block-duration=2h
여기까지 잘 실행되었다면 http://0.0.0.0:9090/에 접속할 수 있다.
접속 후 node_memory_inactive_bytes 등 node_exporter에서 수집된 메트릭도 확인할 수 있다.
Step.3 Thanos 바이너리 파일 다운로드 및 빌드
타노스 구성을 위해 https://github.com/thanos-io/thanos/releases 에서 바이너리 파일을 빌드하자..
mac m1을 사용하는데, 바이너리 실행이 안되서 빌드 했다......... 😭😭😭😭😭
# 다운로드 및 설치
# go 1.21 이상 설치되어있어야 함
wget https://github.com/thanos-io/thanos/archive/refs/tags/v0.34.1.tar.gz
tar zxvf v0.34.1.tar.gz
cd thanos-0.34.1
go mod tidy
make build
# 빌드가 완료되면 바이너리 파일이 생성되는데, 이 바이너리를 사용해야하므로 위치를 잘 확인해야함
Step.4 Thanos sidecar 실행
./thanos sidecar \
--prometheus.url=http://localhost:9090 \
--grpc-address=localhost:10901 \
--http-address=localhost:10902 \
--tsdb.path ./prometheus-tsdb \ # 프로메테우스의 TSDB경로
--objstore.config-file=./bucket.yml
Step.5 Thanos store 실행
Thanos Store를 실행시킨다.
# 버킷 설정
cat <<EOF > bucket.yml
type: S3
config:
bucket: bucket
access_key: admin
secret_key: password
endpoint: 127.0.0.1:9000
insecure: true
EOF
# store 임시 디렉토리 생성
mkdir thanos-store
# 실행
./thanos store \
--data-dir=./thanos-store \
--objstore.config-file=./bucket.yml \
--http-address=localhost:10906 \
--grpc-address=localhost:10905
Step.6 Thanos query 실행 및 동작 확인
./thanos query \
--http-address=0.0.0.0:29090 \
--grpc-address=localhost:10903 \
--store=localhost:10901 \
--query.replica-label prometheus-1
여기까지 실행했다면 http://localhost:29090/ 여기로 접속해보자.
thanos UI가 실행된다.
정상적으로 실행 되었다면, 아까 prometheus UI에서 검색했던것 그대로 여기에서도 쿼리할 수 있어야 한다.