클라우드 네이티브 구현을 위한 핵심 소프트웨어는 쿠버네티스 => 프로메테우스를 통해 운영 및 관리
ref: 모니터링의 새로운 미래 관측 가능성
파드에서 익스포터를 통해 서비스 지표를 프로메테우스에 보내주고, (프로메테우스 익스포터)
해당 지표를 통해 오토스케일링을 파드를 증가시키고, (프로메테우스 어댑터)
오퍼레이터 내 서비스모니터, 파드모니터를 통해 서비스 디스커버리 기능을 제공한다 (프로메테우스 오퍼레이터)
쿠버네티스는 어플리케이션을 포함한 컨테이너를 운영하고 스케쥴링하는 것이라면, 프로메테우스는, 쿠버네티스 기반의 어플리케이션이 원활하게 돌아가도록 다양하고 복잡한 역할을 수행한다
TODO) 프로메테우스 설치 및 서비스 등록까지 해볼 것!
프로메테우스 데이터는 다음과 같은 구조를 띈다.
ref: https://jjon.tistory.com/entry/prometheus-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EA%B5%AC%EC%A1%B0
프로메테우스 서버는 특정 칼럼에 대한 인덱싱을 통해 스크래핑을 하게 되는데 이때 높은 카디널리티일 경우 처리해야 될 데이터가 무수히 많아져서 성능 이슈로 이어진다
=> 이때는 로그 기반 시스템에서 처리하는 것을 권장
프로메테우스 시계열 데이터베이스는
root@bakery:/home/ubuntu/prometheus$ tree
.
...
├── 01E24YV8YFHGSES1WJ92FYMG6K -> 블록
│ ├── chunks
│ │ └── 000001 -> 블록 Chunk 파일
│ ├── index -> 색인을 위한 index 파일
│ ├── meta.json -> 메타데이터
│ └── tombstones -> 삭제 여부를 나타내는 파일
├── 01E24YX3HF1GTZ4CPF24XZ3MKR
│ ├── chunks
│ │ └── 000001
│ ├── index
│ ├── meta.json
│ └── tombstones
├── lock -> lock 파일 (여러 개의 프로메테우스 실행 방지)
├── queries.active -> 현재 실행 중인 쿼리를 저장. 쿼리 중 crash 시 확인 용도로 쓰임.
└── wal -> WAL (write ahead logging) 파일
├── 00006966 -> 개별 WAL 파일들
├── 00006967
├── 00006968
├── 00006969
├── 00006970
└── checkpoint.006965 -> 복구를 위한 체크포인트 지점
└── 00000000
16 directories, 36 files
ref: https://blog.naver.com/PostView.nhn?blogId=alice_k106&logNo=221829384846
WAL 파일: 아직 청크로 플러시되지 않은 데이터에 대한 로그 선행 기입(write ahead logging, WAL)
프로메테우스는 메모리에 우선 저장하고, 주기적으로 플러시해서 디스크에 청크를 생성한다. 청크를 생성하기 전에 메모리에 있는 데이터를 백업하는 용도로 WAL을 생성하고, 프로메테우스 장애 발생시 WAL 을 사용해 장애 발생시 복구할 수 있도록 설계되어있다.
storage.tsdb.min-block-duration
, storage.tsdb.max-block-duration
를 적절히 조절하여 효율적으로 블록들이 병합할 수 있도록 한다storage.tsdb.min-block-duration=2
라면 한 블록 당 저장된 시간이 2시간이다storage.tsdb.max-block-duration=12
라면 한 블록 당 최대로 저장될 수 있는 시간이 12시간이다메모리 -> 로그 선행 기입 -> 디스크
minikube 를 이용해서 프로메테우스 구성하는 방법
> brew install minikube
// docker 서비스를 활성화한 후
> minikube start
> git clone https://github.com/prometheus-operator/kube-prometheus.git
> cd kube-prometheus
> kubectl create -f manifests/setup
> kubectl create -f manifests
> k get crd -n monitoring
NAME CREATED AT
alertmanagerconfigs.monitoring.coreos.com 2024-02-25T01:28:46Z
alertmanagers.monitoring.coreos.com 2024-02-25T01:28:46Z
podmonitors.monitoring.coreos.com 2024-02-25T01:28:47Z
probes.monitoring.coreos.com 2024-02-25T01:28:47Z
prometheusagents.monitoring.coreos.com 2024-02-25T01:28:47Z
prometheuses.monitoring.coreos.com 2024-02-25T01:28:47Z
prometheusrules.monitoring.coreos.com 2024-02-25T01:28:47Z
scrapeconfigs.monitoring.coreos.com 2024-02-25T01:28:47Z
servicemonitors.monitoring.coreos.com 2024-02-25T01:28:47Z
thanosrulers.monitoring.coreos.com 2024-02-25T01:28:47Z
k9s 를 사용해 포드 포워딩한다
서비스 모니터를 다수 생성해서 멀티 클러스터 등의 복잡한 런타임 환경에 대응하도록 구성할 수 있다. 즉, 쿠버네티스가 클라우드 네이티브를 위한 동적인 런타임 환경이라면, 프로메테우스는 자주 변경되는 쿠버네티스 리소스를 쉽게 탐색할 수 있어야 하는데 이를 프로메테우스 오퍼레이터를 사용하면 쉽게 구현할 수 있다.
타깃 정보는 프로메테우스 config 파일에서 관리한다. 그러나 타깃이 변경될 떄 config 를 수동으로 변경하면 실수할 가능성이 있다. 이 때문에 타깃이 변경되면 서비스 모니터/파드 모니터를 담당하는 오퍼레이터에서 자동으로 이를 추적할 수 있도록 한다.
쿠버네티스의 서비스는 레이블 셀렉터로 파드를 발견하고 이를 IP 주소 목록으로 엔드포인트에 추가한다. 프로메테우스 오퍼레이터 서비스 모니터는 차례로 해당 엔트포인트를 검색하고 파드를 모니터링 하도록 프로메테우스를 구성한다. 다음은 오퍼레이터에서 기본적으로 설치한 서비스 모니터이다.
> k get servicemonitor -n monitoring
NAME AGE
alertmanager-main 20m
blackbox-exporter 20m
coredns 20m
grafana 20m
kube-apiserver 20m
kube-controller-manager 20m
kube-scheduler 20m
kube-state-metrics 20m
kubelet 20m
node-exporter 20m
prometheus-adapter 20m
prometheus-k8s 20m
prometheus-operator 20m
기본적으로 검색된 엔드포인트는 메타데이터와 레이블을 저장하고 있다.
이제 sample-app 을 만들고 서비스가 어떻게 등록되는지 확인해보자
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-app
labels:
app: sample-app
spec:
replicas: 1
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- image: luxas/autoscale-demo:v0.1.2
name: metrics-provider
ports:
- name: http
containerPort: 8080
apiVersion: v1
kind: Service
metadata:
name: sample-app
labels:
app: sample-app
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
app: sample-app
type: ClusterIP
kind: ServiceMonitor
apiVersion: monitoring.coreos.com/v1
metadata:
name: sample-app
labels:
app: sample-app
spec:
selector:
matchLabels:
app: sample-app
endpoints:
- port: http
위 리소스를 생성한 후 프로메테우스에서 서비스가 등록되었는지 확인해보자
1. 서비스 디스커버리
2. 메트릭 확인
helm chart reference: https://github.com/philllipjung/o11ybook/tree/main/3.5
이전에 사용했던 환경을 제거한 후 다시 태초마을 상태부터 시작한다
> minikube stop
> minikube delete
> minikube start
> k create namespace monitoring
이후 위에 언급한 레퍼런스로부터 헬름차트를 이용해 프로메테우스 설치한다
> helm install prom .
NAME: prom
LAST DEPLOYED: Sun Feb 25 11:19:43 2024
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
TEST SUITE: Noneinstall prom .
# 만약 다음과 같이 Install Error 가 발생하면 helm dependency build 를 실행한 후 다시 시도한다
Error: INSTALLATION FAILED: An error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies: found in Chart.yaml, but missing in charts/ directory: kube-state-metrics
> helm dependency build
어댑터는 discovery 규칙을 통해 노출할 메트릭과 이를 노출하는 방법을 결정한다. 각 규칙은 독립적으로 실행되며, 어댑터가 API 에서 메트릭을 노출하기 위해 수행해야 하는 각 단계를 지정한다.
seriesQuery: '{__name__=~"^container_.total",containrt!="POD",namespace!="",pod!=""}'
seriesFilters:
- isNot:"^continer_."_seconds_total"
name:
matches: *^(.*)_total$"
as: "${1}_per_second"
metricsQuery: "sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[2m])) by (<<.GroupBy>>)
apiVersion: apps/v1
kind: Deployment
metadata:
name: autoscaling-deploy
namespace: custom-metrics
spec:
replicas: 1
template:
metadata:
labels:
app: autoscaling
release: prom
spec:
containers:
- name: autoscaling
image: quay.io/brancz/prometheus-example-app
ports:
- containerPort: 8080
selector:
matchLabels:
app: autoscaling
release: prom
=> 위 리소스를 생성한 후 해당 어플리케이션에 부하를 주어 http_requests_total
를 증가시키면 프로메테우스 어댑터에서 해당 지표를 보고 hpa 를 통해 파드를 증가시킨다
(내 컴퓨터는 arm 이고 위에서 제공하는 이미지는 x86 아키텍쳐라 실행이 되지 않음 ㅠㅠ)
1. 알람 규칙을 작성하면
2. 규칙매니저에서 주기적으로 규칙에 따라 평가한다. 만약 특정 기간동안 실패한다면
3. 알람 매니저를 통해 외부로 통보한다
해당 알람은 프로메테우스 Alert 에서 확인 가능하다
이후 미미르 또는 로키에서 데이터소스에 프로메테우스를 연결하여 메트릭에 기반한 알람을 생성할 수도 있다
프로메테우스 구성을 위한 기보넉인 가이드라인은 높은 카디널리티 메트릭 생성을 지양하고, 샤딩을 구성하는 것이다. 샤딩을 구성하는 방법은 수직 샤딩과 수평 샤딩이 있다.
단일 프로메테우스 인스턴스만으로는 충분하지 않을 때 스케일링을 위한 좋은 출발점은 스크래핑 작업을 논리 크룹으로 분할한 후, 그룹을 다른 프로메테우스 인스턴스에 할당하는 것이다
하나의 프로메테우스 서버가 여러 인스턴스를 갖는 것을 의미하며, 각 인스턴스는 주어진 작업에 대한 타깃 하위 세트를 스크래핑한다. 즉, 하나의 프로메테우스 서버를 여러 개로 분산하여 수평으로 분할한다.
각 서비스를 스크래핑하는 하위 프로메테우스 서버로부터 프로메테우스 글로벌 서버가 집계한다
그러나 페더레이션 아키텍쳐는 다음과 같은 단점이 있다.
다수의 프로메테우스를 관리할 경우 유지관리가 어려울 수 있다. 이를 해결하기 위해 타노스가 해결책이 될 수 있다
프로메테우스는 클러스터링을 지원하지 않고, 로컬스토리지를 사용하기 때문에 대용향 데이터를 스토리지 확장하기 어렵고 장기관 보관하기에 한계가 있다. 타노스를 도입하면 다음과 같은 장점이 있다.
-글로벌 뷰: 반환된 시계열을 집계하고 중복을 제거하면서 동일한 위치에서 모든 프로메테우스 인스턴스를 쿼리한다
타노스 아키텍쳐는 사이드카 방식과 리시버 방식이 있지만 '모니터링에 새로운 미래 관측 가능성' 책에서는 사이드카 방식을 주로 설명하고 있다.
ref: 모니터링에 새로운 미래 관측 가능성 p179
타노스 사이드카 아키텍쳐에서는 원격 읽기 방식(pull 방식)을 사용하며, 스토어 API 를 통해 메트릭을 쿼리한다.
원격 읽기 방식은 pull 방식을 사용하고 있는데 이러한 방식은 방화벽 등 보안 이슈가 발생하고, 사이드카를 주입해야 하다보니 확장할 때 추가적인 리소스 비용이 발생한다. 이를 해결하기 위해 현재 타노스 아키텍쳐는 원격 쓰기 방식(push 방식)을 사용하는 리시버 방식을 채택했다고 한다.