Featured image of post 自作Exporter+Prometheus+Alertmanager+GrafanaをまとめてDocker Composeで動かす

自作Exporter+Prometheus+Alertmanager+GrafanaをまとめてDocker Composeで動かす

Exporterの動作確認を楽しくしたかった

やったことのまとめ

  • 自作Exporter, Prometheus, Alertmanager, GrafanaをまとめてDocker Composeで動かした
  • nginxコンテナを追加してリバースプロキシした

Prometheus用のExporterを自作するときに動作確認の時点でGrafanaのグラフが見られたりAlertmanagerで通知されるメッセージとかが確認できるとメトリクスやラベルの設計がしやすい(気がする)ので,
それらが全部入りの環境をDocker Composeで作ってみた.

version: '3.8'
services:
exporter: # 自作Exporter
build: ./
container_name: exporter
prometheus:
image: prom/prometheus:v2.24.1
container_name: prometheus
command:
[
"--config.file=/etc/prometheus/prometheus.yml",
"--web.external-url=http://localhost/prometheus",
"--web.route-prefix=/",
]
volumes:
[
"./deployment/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml",
"./deployment/prometheus/rules.yml:/etc/prometheus/rules.yml",
]
alertmanager:
image: prom/alertmanager:v0.21.0
container_name: alertmanager
command:
[
"--config.file=/etc/alertmanager/alertmanager.yml",
"--web.external-url=http://localhost/alertmanager",
"--web.route-prefix=/",
]
volumes:
[
"./deployment/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml",
]
grafana:
image: grafana/grafana:7.3.7
container_name: grafana
volumes:
[
"./deployment/grafana/grafana.ini:/etc/grafana/grafana.ini",
"./deployment/grafana/datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yaml",
"./deployment/grafana/dashboard.yaml:/etc/grafana/provisioning/dashboards/dashboard.yaml",
"./deployment/grafana/dashboard.json:/var/lib/grafana/dashboards/dashboard.json",
]
nginx:
image: nginx:stable
container_name: nginx
volumes:
[
"./deployment/nginx/default.conf:/etc/nginx/conf.d/default.conf",
"./deployment/nginx/index.html:/usr/share/nginx/html/index.html",
]
ports:
- 80:80

その他もろもろの設定ファイル

つかうもの

やったこと

とりあえず起動する

それぞれDocker imageが公式で提供されているのでそれをそのまま起動すれば良さそう.

自作Exporterの動作確認をしたときと同様に適当にdocker-compose.ymlを書いてみる.

version: '3.8'
services:
exporter: # 自作Exporter
build: ./
container_name: exporter
ports:
- 2112:2112
prometheus:
image: prom/prometheus:v2.24.1
container_name: prometheus
volumes:
- ./deployment/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./deployment/prometheus/rules.yml:/etc/prometheus/rules.yml
ports:
- 9090:9090
alertmanager:
image: prom/alertmanager:v0.21.0
container_name: alertmanager
volumes:
- ./deployment/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
ports:
- 9093:9093
grafana:
image: grafana/grafana:7.3.7
container_name: grafana
volumes:
- ./deployment/grafana/grafana.ini:/etc/grafana/grafana.ini
- ./deployment/grafana/datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yaml
- ./deployment/grafana/dashboard.yaml:/etc/grafana/provisioning/dashboards/dashboard.yaml
#- ./deployment/grafana/dashboard.json:/var/lib/grafana/dashboards/dashboard.json
ports:
- 3000:3000

重要なのは以下の設定ファイルをそれぞれのコンテナにマウントしていること.

  • Prometheus
    • 自作Exporterなどをスクレイプするための設定(prometheus.yml)
      • Docker Composeで起動しているので他のコンテナについてはすべてコンテナ名で名前解決できる
    • アラートルール(rules.yml)
      • 任意のルールで良い
  • Alertmanager
    • アラート通知設定(alertmanager.yml)
      • 任意の設定で良い
  • Grafana
    • 基本設定(grafana.ini)
    • Data Source設定(datasource.yaml)
      • Prometheusコンテナを指定する
    • Dashboard設定(dashboard.yaml, dashboard.json)
      • dashboard.jsonは後から作っても良い
global:
scrape_interval: 10s
evaluation_interval: 10s
alerting:
alertmanagers:
- static_configs:
- targets:
- "alertmanager:9093"
rule_files:
- "rules.yml"
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["prometheus:9090"]
- job_name: "alertmanager"
static_configs:
- targets: ["alertmanager:9093"]
- job_name: "grafana"
static_configs:
- targets: ["grafana:3000"]
- job_name: "example-exporter"
static_configs:
- targets: ["exporter:2112"]
view raw prometheus.yml hosted with ❤ by GitHub

(rules.yml, alertmanager.ymlは何でも良いので前回のものを流用)

rules.yml

alertmanager.yml

##################### Grafana Configuration Example #####################
#
# Everything has defaults so you only need to uncomment things you want to
# change
# possible values : production, development
;app_mode = production
# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
;instance_name = ${HOSTNAME}
#################################### Anonymous Auth ######################
[auth.anonymous]
# enable anonymous access
;enabled = false
enabled = true
# specify organization name that should be used for unauthenticated users
;org_name = Main Org.
# specify role for unauthenticated users
;org_role = Viewer
org_role = Editor
# mask the Grafana version number for unauthenticated users
;hide_version = false
view raw grafana.ini hosted with ❤ by GitHub
# config file version
apiVersion: 1
# list of datasources that should be deleted from the database
deleteDatasources:
- name: Prometheus
orgId: 1
# list of datasources to insert/update depending
# what's available in the database
datasources:
# <string, required> name of the datasource. Required
- name: Prometheus
# <string, required> datasource type. Required
type: prometheus
# <int> org id. will default to orgId 1 if not specified
orgId: 1
# <string> url
url: prometheus:9090
view raw datasource.yaml hosted with ❤ by GitHub
apiVersion: 1
providers:
# <string> an unique provider name. Required
- name: "Example"
# <string> name of the dashboard folder.
folder: ""
# <string> provider type. Default to 'file'
type: file
# <bool> disable dashboard deletion
disableDeletion: true
# <int> how often Grafana will scan for changed dashboards
updateIntervalSeconds: 10
# <bool> allow updating provisioned dashboards from the UI
allowUiUpdates: false
options:
# <string, required> path to dashboard files on disk. Required when using the 'file' type
path: /var/lib/grafana/dashboards
# <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: true
view raw dashboard.yaml hosted with ❤ by GitHub

(dashboard.jsonはあらかじめ作成済みのものがなければこの後作成する)

あとはこれらのファイルが以下のように配置されている状態でDocker Composeでコンテナを立ち上げる.

# ローカルでビルドしない場合はDockerfileとGo関連のファイルは不要
$ tree .
.
├── Dockerfile
├── deployment
│   ├── alertmanager
│   │   └── alertmanager.yml
│   ├── grafana
│   │   ├── dashboard.json
│   │   ├── dashboard.yaml
│   │   ├── datasource.yaml
│   │   └── grafana.ini
│   └── prometheus
│       ├── prometheus.yml
│       └── rules.yml
├── docker-compose.yml
├── go.mod
├── go.sum
└── main.go

# コンテナを起動(コードを編集したなどの理由で再度ビルドしたい場合はさらに--buildを付与する)
$ docker-compose up -d --force-recreate

$ docker-compose ps
    Name                  Command               State           Ports
------------------------------------------------------------------------------
alertmanager   /bin/alertmanager --config ...   Up      0.0.0.0:9093->9093/tcp
exporter       ./app                            Up      0.0.0.0:2112->2112/tcp
grafana        /run.sh                          Up      0.0.0.0:3000->3000/tcp
prometheus     /bin/prometheus --config.f ...   Up      0.0.0.0:9090->9090/tcp

あとはそれぞれのエンドポイントで動作確認する.




dashboard.jsonが未作成の場合はここで動作確認も兼ねてGrafana上でダッシュボード(自作Exporterのメトリクスがグラフ化できれば何でも良い)を作成し, ShareExportSave to fileからJSONをダウンロードして以降はそれを使うようにする.

設定が正しく効いていれば予めPrometheusData Sourceとして登録されていて, 全コンテナのメトリクスがスクレイプできていることも確認できる.

リバースプロキシする

このままでもいいんだけどせっかくなのでnginxリバースプロキシする.

docker-compose.ymlnginxコンテナを追加して, 以前やったときと同様の設定ファイルを作成してマウントする.

(リバースプロキシしているので, nginx以外のそれぞれのコンテナのポートは閉じておく)

version: '3.8'
services:
exporter: # 自作Exporter
build: ./
container_name: exporter
prometheus:
image: prom/prometheus:v2.24.1
container_name: prometheus
command:
[
"--config.file=/etc/prometheus/prometheus.yml",
"--web.external-url=http://localhost/prometheus",
"--web.route-prefix=/",
]
volumes:
[
"./deployment/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml",
"./deployment/prometheus/rules.yml:/etc/prometheus/rules.yml",
]
alertmanager:
image: prom/alertmanager:v0.21.0
container_name: alertmanager
command:
[
"--config.file=/etc/alertmanager/alertmanager.yml",
"--web.external-url=http://localhost/alertmanager",
"--web.route-prefix=/",
]
volumes:
[
"./deployment/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml",
]
grafana:
image: grafana/grafana:7.3.7
container_name: grafana
volumes:
[
"./deployment/grafana/grafana.ini:/etc/grafana/grafana.ini",
"./deployment/grafana/datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yaml",
"./deployment/grafana/dashboard.yaml:/etc/grafana/provisioning/dashboards/dashboard.yaml",
"./deployment/grafana/dashboard.json:/var/lib/grafana/dashboards/dashboard.json",
]
nginx:
image: nginx:stable
container_name: nginx
volumes:
[
"./deployment/nginx/default.conf:/etc/nginx/conf.d/default.conf",
"./deployment/nginx/index.html:/usr/share/nginx/html/index.html",
]
ports:
- 80:80
  • Prometheus
    • prometheus.yml, rules.yml: そのまま
    • command(CMD)にリバースプロキシ用の設定1を追加
  • Alertmanager
    • alertmanager.yml: そのまま
    • command(CMD)にリバースプロキシ用の設定を追加
  • Grafana
    • datasource.yaml, dashboard.yaml, dashboard.json : そのまま
    • grafana.ini
      • リバースプロキシ用の設定2を追加
  • nginx
    • リバースプロキシ設定(default.conf)
    • リンク用ページ(index.html)
##################### Grafana Configuration Example #####################
#
# Everything has defaults so you only need to uncomment things you want to
# change
# possible values : production, development
;app_mode = production
# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
;instance_name = ${HOSTNAME}
#################################### Server ####################################
[server]
# Protocol (http, https, h2, socket)
;protocol = http
# The ip address to bind to, empty will bind to all interfaces
;http_addr =
# The http port to use
;http_port = 3000
# The public facing domain name used to access grafana from a browser
;domain = localhost
# Redirect to correct domain if host header does not match domain
# Prevents DNS rebinding attacks
;enforce_domain = false
# The full public facing url you use in browser, used for redirects and emails
# If you use reverse proxy and sub path specify full url (with sub path)
;root_url = %(protocol)s://%(domain)s:%(http_port)s/
root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/
# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons.
;serve_from_sub_path = false
serve_from_sub_path = true
# Log web requests
;router_logging = false
# the path relative working path
;static_root_path = public
# enable gzip
;enable_gzip = false
# https certs & key file
;cert_file =
;cert_key =
# Unix socket path
;socket =
#################################### Anonymous Auth ######################
[auth.anonymous]
# enable anonymous access
;enabled = false
enabled = true
# specify organization name that should be used for unauthenticated users
;org_name = Main Org.
# specify role for unauthenticated users
;org_role = Viewer
org_role = Editor
# mask the Grafana version number for unauthenticated users
;hide_version = false
view raw grafana.ini hosted with ❤ by GitHub
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /exporter/ {
proxy_pass http://exporter:2112/;
}
location /prometheus/ {
proxy_pass http://prometheus:9090/;
}
location /alertmanager/ {
proxy_pass http://alertmanager:9093/;
}
location /grafana/ {
proxy_pass http://grafana:3000/;
}
}
view raw default.conf hosted with ❤ by GitHub
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>nginx</title>
</head>
<body>
<header>
<div class="title">
<h1>nginx</h1>
</div>
</header>
<div class="main">
<ul class="link">
<li><a href="/exporter/metrics">Exporter</a></li>
<li><a href="/prometheus">Prometheus</a></li>
<li><a href="/alertmanager">Alertmanager</a></li>
<li><a href="/grafana">Grafana</a></li>
</ul>
</div>
<footer></footer>
</body>
</html>
view raw index.html hosted with ❤ by GitHub

再度コンテナを起動する.

$ tree .
.
├── Dockerfile
├── deployment
│   ├── alertmanager
│   │   └── alertmanager.yml
│   ├── grafana
│   │   ├── dashboard.json
│   │   ├── dashboard.yaml
│   │   ├── datasource.yaml
│   │   └── grafana.ini
│   ├── nginx
│   │   ├── default.conf
│   │   └── index.html
│   └── prometheus
│       ├── prometheus.yml
│       └── rules.yml
├── docker-compose.yml
├── go.mod
├── go.sum
└── main.go

$ docker-compose up -d --force-recreate

$ docker-compose ps
    Name                  Command               State         Ports
--------------------------------------------------------------------------
alertmanager   /bin/alertmanager --config ...   Up      9093/tcp
exporter       ./app                            Up
grafana        /run.sh                          Up      3000/tcp
nginx          /docker-entrypoint.sh ngin ...   Up      0.0.0.0:80->80/tcp
prometheus     /bin/prometheus --config.f ...   Up      9090/tcp

ここまでの設定に問題がなければそれぞれのパスでコンテナの動作確認ができる.

もしくは, http://localhost/でリンクを張ったHTML(index.html)が表示できるのでそこから飛んでも良い.

最後に一応Alertmanagerの動作確認をする.

rules.ymlInstanceDown(upが0になるだけで発火)のアラートルールを設定しているので, 試しに自作Exporterのコンテナを落としてみる.

$ docker-compose stop exporter

$ docker-compose ps
    Name                  Command               State          Ports
---------------------------------------------------------------------------
alertmanager   /bin/alertmanager --config ...   Up       9093/tcp
exporter       ./app                            Exit 2
grafana        /run.sh                          Up       3000/tcp
nginx          /docker-entrypoint.sh ngin ...   Up       0.0.0.0:80->80/tcp
prometheus     /bin/prometheus --config.f ...   Up       9090/tcp

それぞれのコンテナでメトリクスの変化に対応した処理が行われていることが確認できる.



アラートはAlertmanagerからGmail経由で送る設定にしているのでメールが届くことも確認できる.

やったぜ.

自作ExporterとPrometheus, Alertmanager, Grafanaを同時に動かして動作確認することができた.

おわり

終わってみれば大したことはないんだけど, 一回この構成をつくっておくと自作Exporterの開発が楽しくなる(メトリクスがすぐ可視化されアラートの動作確認までできる)のでやってよかったと思う.

Docker Composeの練習にもなってよかった.

おまけ