Prometheus: 개요
개요
- 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
helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo updatekubectl create ns prometheus-stackhelm 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])")
}