自作Exporter
Prometheusでスクレイプする用のExporterを自作してみた.
やったことのまとめ
Go
のPrometheus
クライアント1を使って, 自分で設定したメトリクスを表示できるExporter
を作成した- 作成した
Exporter
とPrometheus
をDocker
で動かし, スクレイプできることを確認した
https://github.com/uzimihsr/example-exporter
つかうもの
- macOS Mojave 10.14
- go version go1.14.6 darwin/amd64
- prometheus/client_golang v1.7.1
- Docker Desktop for Mac 2.1.0.3
- Docker version 19.03.2
- docker-compose version 1.24.1
やったこと
Exporterの作成
# 作業用ディレクトリとgo.modの作成
$ pwd
/path/to/workspace
$ mkdir example-exporter && cd example-exporter
$ go mod init github.com/uzimihsr/example-exporter
go: creating new go.mod: module github.com/uzimihsr/example-exporter
$ touch main.go
main.go
はこんな感じで作る.
書き方はDocsの例2とPrometheus
クライアントのサンプルコード3を参考にした.
package main | |
import ( | |
"math/rand" | |
"net/http" | |
"time" | |
"github.com/prometheus/client_golang/prometheus" | |
"github.com/prometheus/client_golang/prometheus/promauto" | |
"github.com/prometheus/client_golang/prometheus/promhttp" | |
) | |
// メトリクスの準備 | |
var ( | |
// Counter | |
exampleCounter = promauto.NewCounterVec( | |
prometheus.CounterOpts{ | |
Name: "example_total", | |
Help: "Example Counter", | |
}, | |
[]string{"hoge"}, | |
) | |
// Gauge | |
exampleGauge = promauto.NewGaugeVec( | |
prometheus.GaugeOpts{ | |
Name: "example_number", | |
Help: "Example Gauge", | |
}, | |
[]string{"fuga"}, | |
) | |
) | |
// 30秒ごとにCounterの値を1つ増やす関数 | |
func count() { | |
for { | |
exampleCounter.With(prometheus.Labels{"hoge": "hogehoge"}).Inc() | |
time.Sleep(30 * time.Second) | |
} | |
} | |
// 10秒ごとにGaugeに乱数をセットする関数 | |
func setRandomValue() { | |
for { | |
rand.Seed(time.Now().UnixNano()) | |
n := -1 + rand.Float64()*2 | |
exampleGauge.With(prometheus.Labels{"fuga": "fugafuga"}).Set(n) | |
time.Sleep(10 * time.Second) | |
} | |
} | |
func main() { | |
// 各メトリクスの値を更新する関数をgo routineで実行 | |
go count() | |
go setRandomValue() | |
// /metricsへのリクエストを処理 | |
http.Handle("/metrics", promhttp.Handler()) | |
http.ListenAndServe(":2112", nil) | |
} |
ポイントは/metrics
へのリクエストをハンドリングする処理と別にgo routine
を使ってメトリクスを更新する処理を入れているところ.
こうすることで各メトリクスが並行に更新され, リクエストが来るたびにメトリクスの最新の値を返すことができる.
試しに動かしてみる.
# exporterの実行
$ go run main.go
ブラウザで http://localhost:2112/metrics を開く.
こんな感じでPrometheus
が読めるフォーマットのメトリクスが表示された.
メトリクス定義に記述したメトリクス名, 説明文, ラベルが反映されていることがわかる.
# HELP example_number Example Gauge
# TYPE example_number gauge
example_number{fuga="fugafuga"} -0.0056473753420378525
# HELP example_total Example Counter
# TYPE example_total counter
example_total{hoge="hogehoge"} 13
Prometheusでスクレイプ
せっかくなので, Prometheus
でスクレイプしてみる.
今回は試しにDocker
上でPrometheus
のコンテナと今回作った example-exporter のコンテナを同時に動かす.
example-exporter 用のDockerfile
の書き方はGoアプリをDockerのscratchイメージで動かすを参考にする.
# ビルド用イメージ | |
FROM golang:1.14 | |
# mainパッケージがあるディレクトリ(.)をまるごとコピー | |
COPY . ./goapp | |
WORKDIR ./goapp | |
# goapp内のgo.mod, go.sumで依存関係を管理している場合に使用 | |
RUN go mod download | |
# クロスコンパイル | |
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /app . | |
# バイナリを載せるイメージ | |
FROM scratch | |
WORKDIR goapp | |
# ビルド済みのバイナリをコピー | |
COPY --from=0 /app ./ | |
# httpsで通信を行う場合に使用 | |
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt | |
ENTRYPOINT ["./app"] |
さらにPrometheus
の設定ファイルprometheus.yml
と,
2つのコンテナを動かすためにdocker-compose.yml
を作成する.
global: | |
scrape_interval: 15s | |
evaluation_interval: 15s | |
scrape_configs: | |
- job_name: 'prometheus' | |
static_configs: | |
- targets: ['localhost:9090'] | |
- job_name: 'example-exporter' | |
static_configs: | |
- targets: ['example-exporter:2112'] # docker-composeで起動していればコンテナ名で名前解決できる |
version: '3' | |
services: | |
prometheus: | |
image: prom/prometheus | |
container_name: prometheus | |
volumes: | |
- ./prometheus.yml:/etc/prometheus/prometheus.yml | |
ports: | |
- 9090:9090 | |
example-exporter: | |
build: ./ # ディレクトリの内容をビルドしたimageを使う | |
container_name: example-exporter | |
ports: | |
- 2112:2112 |
この状態でdocker-compose
で2つのコンテナを起動する.
# ディレクトリの状態
$ tree .
.
├── Dockerfile
├── docker-compose.yml
├── go.mod
├── go.sum
├── main.go
└── prometheus.yml
# docker-composeでコンテナを起動
$ docker-compose up -d
Creating network "example-exporter_default" with the default driver
Creating example-exporter ... done
Creating prometheus ... done
コンテナが起動した状態で http://localhost:9090/graph をホストのブラウザで開くと, Prometheus
の画面が表示される.
無事に起動できていれば example-exporter がスクレイプできている.
試しに example-exporter のメトリクス名でクエリを投げてみると, ちゃんと時系列の値が表示される.
example_total はmain.go
で設定した通り30秒ごとに値が加算され,
example_number はmain.go
で設定した値の変化の間隔(10秒)がPrometheus
のscrape_interval
(15秒)より短いために15秒ごとに値が変化している.
やったぜ.
自作のExporter
をスクレイプして, 設定したとおりにメトリクスが変化していることが確認できた.
おわり
Prometheus
でスクレイプできるかんたんなExporter
を自作してみた.Prometheus
自体がGo
で書かれているだけあって, Go
だとかなり楽に記述できた. と思う.
特にgo routine
のおかげでメトリクスとHTTPハンドラの並行処理が簡単に書けるのがいいと思った.
自作のAPIとかにこんな感じでExporter
を実装すれば監視がめちゃめちゃ楽になりそう.