[Prometheus] 개요
Updated:
개요
- https://prometheus.io/docs/introduction/overview/
- CNCF Graduated Project
- 오픈 소스 시스템 모니터링 및 경고 툴킷
- 매트릭을 시계열 형태로 수집하고 저장
특징
- 기존 push 방식이 아닌 pull 방식을 채택
- Pushgateway를 통해 push 방식도 지원
- Prometheus에 수집할 엔드포인트와 주기를 설정하면 주기마다 해당 url를 http get하여 결과를 저장하는 방식
- 직접적인 확장을 지원하지는 않으며 Prometheus에 Prometheus를 연결하거나 Thanos를 이용하여 확장
- PromQL(Prometheus Query Language) 사용
- 메트릭을 시각화 해주는 오픈소스인 Grafana와 함께 사용되는 경우가 많음
적합한 경우
- 숫자 시계열 저장이 필요한 경우
부적합한 경우
- 100% 정확도가 필요한 경우 수집된 데이터가 부정확할 수 있음
config
- https://prometheus.io/docs/prometheus/latest/configuration/configuration/
- scrape_interval : 수집 주기
- scrape_timeout : 수집 타임아웃
- scrape_configs : 수집 정보
- scrape_configs.job_name, scrape_configs.metrics_path, scrape_configs.static_configs.targets
prometheus.yml: | global: scrape_interval: 15s scrape_timeout: 10s scrape_configs: - job_name: test-1 metrics_path: /metrics static_configs: - targets: - 127.0.0.1:10000
설치
- prometheus-community/helm-charts
vim kube-prometheus-stack-values.yaml
- values.yaml을 참조하여 설정
prometheus: service: type: NodePort grafana: service: type: NodePort nodePort: 30100
- values.yaml을 참조하여 설정
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
kubectl create ns prometheus-stack
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack -f kube-prometheus-stack-values.yaml -n prometheus-stack
삭제
helm uninstall kube-prometheus-stack -n prometheus-stack
UI 접속 정보
- Prometheus
http://127.0.0.1:30090/
- Grafana:
http://127.0.0.1:30100/
metric_types
- https://prometheus.io/docs/concepts/metric_types/
- Counter
- 0부터 증가만 가능한 단일 숫자 누적 매트릭
- Gauge
- 특정 값, 증가, 감소가 가능한 단일 숫자 매트릭
- Histogram
- 관찰한 값 들에 대해 관찰 카운트, 관찰 된 값의 합, 관찰 버킷에 대한 누적 카운터를 제공
- Summary
- Histogram과 유사
- 관찰한 값 들에 대해 관찰 카운트, 관찰 된 값의 합, φ-quantiles를 제공
metric exporter example code
- https://github.com/prometheus/client_golang
- http://ip:10000에 접속하여 메트릭 값을 변경
- http://ip:10000/metrics에 접속하여 매트릭 값 확인
- 자동으로 레지스트리에 추가되는 것을 원하지 않으면 promauto.NewXXX() 대신 prometheus.NewXXX()를 쓰고 prometheus.MustRegister()로 개별 등록
package main import ( "log" "math/rand" "net/http" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" ) var ( counterTest = promauto.NewCounter( prometheus.CounterOpts{ Namespace: "namespace_test", Subsystem: "subsystem_test", Name: "counter_test", Help: "counter test help", }) gaugeTest = promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "namespace_test", Subsystem: "subsystem_test", Name: "gauge_test", Help: "gauge test help", }) histogramTest = promauto.NewHistogram(prometheus.HistogramOpts{ Namespace: "namespace_test", Subsystem: "subsystem_test", Name: "histogram_test", Help: "histogram test help", Buckets: prometheus.LinearBuckets(20, 5, 5), }) summaryTest = promauto.NewSummary(prometheus.SummaryOpts{ Namespace: "namespace_test", Subsystem: "subsystem_test", Name: "summary_test", Help: "summary test help", Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }) ) func handler(w http.ResponseWriter, r *http.Request) { counterTest.Inc() counterTest.Add(1) // gaugeTest.SetToCurrentTime() // gaugeTest.Set(1) gaugeTest.Inc() gaugeTest.Dec() gaugeTest.Add(1) gaugeTest.Sub(-1) histogramTest.Observe(float64(rand.Intn(10) + 1)) summaryTest.Observe(float64(rand.Intn(10) + 1)) w.Write([]byte("ok")) } func main() { http.HandleFunc("/", handler) http.Handle("/metrics", promhttp.Handler()) log.Fatal(http.ListenAndServe(":10000", nil)) }
Prometheus HTTP API example code
- https://github.com/prometheus/client_golang
- Prometheus에 쿼리 전송 및 결과 출력
package main import ( "context" "fmt" "os" "time" "github.com/prometheus/client_golang/api" v1 "github.com/prometheus/client_golang/api/prometheus/v1" ) func query(address, query string) { client, err := api.NewClient(api.Config{ Address: address, }) if err != nil { fmt.Printf("new client error : %s\n", err.Error()) os.Exit(1) } v1api := v1.NewAPI(client) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result, warnings, err := v1api.Query(ctx, query, time.Now()) if err != nil { fmt.Printf("query error : (%s)\n", err.Error()) os.Exit(1) } if len(warnings) > 0 { fmt.Printf("query warnings : %v\n", warnings) } fmt.Printf("%v", result) } func queryRange(address, query string) { client, err := api.NewClient(api.Config{ Address: address, }) if err != nil { fmt.Printf("new client error : %s\n", err.Error()) os.Exit(1) } v1api := v1.NewAPI(client) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() r := v1.Range{ Start: time.Now().Add(-time.Hour), End: time.Now(), Step: time.Minute, } result, warnings, err := v1api.QueryRange(ctx, query, r) if err != nil { fmt.Printf("query range error : (%s)\n", err.Error()) os.Exit(1) } if len(warnings) > 0 { fmt.Printf("query range warnings : %v\n", warnings) } fmt.Printf("%v", result) } func main() { query("http://127.0.0.1:31005", "up") fmt.Printf("\n=========================================================\n\n") queryRange("http://127.0.0.1:31006", "rate(namespace_test_subsystem_test_counter_test[5m])") }