[Grafana] Opentelemetry: metric ๊ตฌ์ฑํ๊ธฐ
otel collector์ prometheus๋ฅผ ์ฌ์ฉํด์ ๊ธฐ๋ณธ metric์ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ๊ฐ๋จํ ์ ๋ฆฌํด๋ณด๊ฒ ๋ค. ๊ธฐ๋ฐ ํ๊ฒฝ์ docker compose๋ค.
Grafana dashboard์ ๋ํด์ ์ฝ๊ฐ ์๋ค๊ณ ๊ฐ์ ํ๋ค.
otel collector
Trace์ ์ฌ์ฉํ๋ Grafana Tempo ๊ฐ์ ๊ฒฝ์ฐ์๋ ์์ฒด์ ์ผ๋ก opentelemetry API ๊ท๊ฒฉ์ ์ถฉ์กฑํ๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ์ ์ธ ์ธํฐํ์ด์ค๊ฐ ํ์ํ์ง๋ ์๋ค.
๋ฐ๋ฉด metric์๋ ๋ณดํต prometheus ๊ฐ์ ์๊ณ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๋๋ฐ, prometheus๋ opentelemetry์ ์๋ฌด๋ฐ ์ฐ๊ด์ ๋ ์๋ค.
๊ทธ๋์ ์์ฆ์ prometheus๋ก metric์ ๊ตฌ์ฑํ๋ค๊ณ ํ๋ฉด otel-collector ๊ฐ์ ์ค๊ฐ ์ธํฐํ์ด์ค ๊ตฌํ์ ๋ฌ์ ๊ท๊ฒฉํ๋ ํํ๋ก ์ ์ฅํ๋๋ก ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
์, ๊ทธ๋ผ ์์ํด๋ณด์.
otel-collector๋ฅผ ๋์ฐ๊ธฐ ์ํ config๋ฅผ ๋จผ์ ๊ตฌ์ฑํ๋ค.
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
exporters:
prometheus:
endpoint: "0.0.0.0:8889"
service:
pipelines:
metrics:
receivers: [otlp]
exporters: [prometheus]
traces:
receivers: [otlp]
exporters: [otlp]
telemetry:
metrics:
address: 0.0.0.0:8888
level: detailed
receivers๋ ์ด otel-collector๊ฐ ์ด๋ค ๋ฆฌ์ค๋๋ฅผ ์ด์ง๋ฅผ ์ ์ํ๋ ๋ถ๋ถ์ด๋ค.
otel-collector๋ http์ grpc๋ฅผ ๋ชจ๋ ์ง์ํ๋๋ฐ, http๋ 4318, grpc๋ 4317 ํฌํธ๋ฅผ ์ฐ๋๊ฒ ๊ธฐ๋ณธ์ด๋ค.
exporters๋ ๋ฐ์ดํฐ๋ฅผ ์ด๋๋ก ์ ์กํ๊ฒ ํด์ค์ง๋ฅผ ์ ์ํ๋ ๋ถ๋ถ์ด๋ค.
์ ์ํ ์ ์, ์ด๊ฒ ๋ฐ๋ก ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ ์ก์ํค๋๊ฒ ์๋๋ ๊ฒ์ด๋ค. 8889 ํฌํธ๋ก export API๋ฅผ ์ด์ด๋๊ณ , ๊ทธ๊ฑธ ๋ค๋ฅธ metric ์ ์ฅ์๊ฐ ์คํฌ๋ฉํ๊ฒ ํ๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ๊ณ ์๋ค.
๋๋จธ์ง๋ prometheus ์ ์์ ์ด์ด์ ๋ค๋ฃจ๊ฒ ๋ค.
์๋ฌดํผ ์ ์ค์ ์ ๋ฐ์์ ์ด๋ฏธ์ง๋ฅผ ๋ง๊ฒ๋ Dockerfile์ ๊ตฌ์ฑํ๊ณ
FROM otel/opentelemetry-collector-contrib:latest
COPY ./otel-collector-config.yaml /etc/otel-collector-config.yaml
docker compose์๋ ์ด๋ ๊ฒ ์ ์ํ๋ค.
services:
otel-collector:
build:
context: .
dockerfile: Dockerfile.otel
command: ["--config", "/etc/otel-collector-config.yaml"]
ports:
- "4317:4317"
- "4318:4318"
- "8888:8888"
depends_on:
- prometheusPrometheus ๊ตฌ์ฑ
์ด๋ฒ์ prometheus๋ฅผ ๊ตฌ์ฑํด๋ณด์.
prometheus๊ฐ ์ฃผ์ฒด์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ๊ฐ์ผ ํ๊ธฐ ๋๋ฌธ์, ์ฌ๊ธฐ์๋ otel-collector๋ฅผ ์ฝ๋ ๋ถ๋ถ์ด ์ ์๋๋ค.
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 10s
static_configs:
- targets: ['otel-collector:8889']
15์ด๋ง๋ค ํ๋ฒ์ฉ ๋๋ฉด์ ์๊น exporter๋ก ์ฐ ์๋ํฌ์ธํธ๋ฅผ ์ฐ๋ฌ ๋ฐ์ดํฐ๋ฅผ ๋ชจ์ผ๋ ๊ฒ์ด๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก Dockerfile ๋ง๊ณ
FROM prom/prometheus:latest
COPY ./prometheus.yaml /etc/prometheus.yaml
docker compose๋ก ๋์ฐ๋๋ก ํ๋ค.
services:
prometheus:
build:
context: .
dockerfile: Dockerfile.prometheus
command:
- --config.file=/etc/prometheus.yaml
- --web.enable-remote-write-receiver
- --enable-feature=exemplar-storage
- --enable-feature=native-histograms
volumes:
- prometheus_data:/prometheus
ports:
- "9090:9090"
volumes:
prometheus_data:
driver: local
๊ทธ๋ฆฌ๊ณ ๊ทธ๋ผํ๋๋ ํฌํจํด์ ํจ๊ป ๋์๋ณด์.
grafana:
environment:
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
entrypoint:
- sh
- -euc
- |
mkdir -p /etc/grafana/provisioning/datasources
cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
uid: prometheus
access: proxy
orgId: 1
url: http://prometheus:9090
basicAuth: false
isDefault: false
version: 1
editable: false
jsonData:
httpMethod: GET
EOF
/run.sh
image: grafana/grafana:latest
ports:
- "13000:3000"
volumes:
- grafana_data:/var/lib/grafana
- grafana_etc:/etc/grafana
volumes:
grafana_data:
driver: local
grafana_etc:
driver: local์ ํ๋ฆฌ์ผ์ด์ ์์ agent ๊ตฌ์ฑ (go)
๊ทผ๋ฐ ์ ๊ฒ๋ง ๋๋ ์์ผ๋ฉด ๋ญํ๊ฒ ๋? ๊ฐ๋จํ ์๋ฒ ํ๋ ๋์์ ๋ฉํธ๋ฆญ์ ์๊ฒ ํด๋ณด์.
๊ธฐ๋ณธ metric์ ์๋ฒ์ ์ฐ๊ด์ด ์๊ธฐ ๋๋ฌธ์ ํ๋ ์์ํฌ์ ์ข
์์ ์ด์ง ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ด๊ธฐํ ์ฝ๋๋ง ์ฌ์ด์ ์ง์
์ ์์ ์คํํ๊ฒ ๋๋ฉด ๋์ด๋ค.
func initMetric() *metric.MeterProvider {
ctx := context.Background()
metricExporter, err := otlpmetrichttp.New(ctx, otlpmetrichttp.WithEndpointURL(
"http://localhost:4318",
), otlpmetrichttp.WithInsecure())
if err != nil {
panic(err)
}
meterProvider := metric.NewMeterProvider(
metric.WithReader(metric.NewPeriodicReader(metricExporter, metric.WithInterval(3*time.Second))),
metric.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("go-server"),
semconv.ServiceNamespaceKey.String("dev"),
)),
)
if err != nil {
panic(err)
}
otel.SetMeterProvider(meterProvider)
err = runtime.Start(runtime.WithMinimumReadMemStatsInterval(time.Second))
if err != nil {
panic(err)
}
return meterProvider
}
์ฝ๋๋ฅผ ์คํํ๊ณ ๊ธฐ๋ค๋ ค๋ณด๋ฉด ๋ญ๊ฐ ์์ผ ๊ฒ์ด๋ค.
์๊ณ์ด ํ๋ ๊ฐ์ ธ๋ค๊ฐ ์กฐํํด๋ณด๋ฉด

go ๋ฐํ์ ๊ด๋ จ๋ ์์ง๊ตฌ๋ ํ ์ต์ ๋ค์ด๋, up ๊ฐ์ ์์กด์ ํธ๋ค์ด ์์ฌ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.

์ถ๊ฐ์ ์ธ ๊ตฌ์ฑ์ด ์๋ค๋ฉด ๊ธฐ๋ณธ ๋ฉํธ๋ฆญ์ ์ด๋ฐ ๋จ์ํ ์ ๋ณด๋ค๋ง ๋ด๋ ค์ค๋ค.
trace, API์ ๊ธฐ๋ฐํ ์์น ํต๊ณ๋ค์ด ํ์ํ๋ค๋ฉด spanmetric ๊ฐ์ ์ถ๊ฐ ๊ตฌ์ฑ์ด ํ์ํ๋ค.
๊ทธ๊ฑด ๋ค์ ํฌ์คํธ์์ ๋ฐ๋ก ๋ค๋ฃจ๊ฒ ๋ค.