なぜBlackbox Exporterが必要なのか
自分の監視環境はPrometheus + Grafanaで15台のサーバーを管理していて、ユーザーから障害報告が来る前に問題を検知したことも何度かある。ただ、一つ大きな死角があった。サーバーのCPU・RAM・ディスクは正常だと分かっても、ウェブサイトが実際にレスポンスを返しているか、DNSが正しく名前解決できているか、SSL証明書があと何日で切れるかが把握できていなかった。
Blackbox Exporterはまさにその問題を解決してくれる。各サーバーにエージェントをインストールするホワイトボックス監視とは違い、外部からチェックする――つまり、ユーザーが実際にブラウザでURLを入力するのと同じ視点で確認できる。HTTP・HTTPS・DNS・TCP・ICMPでエンドポイントをプローブし、結果をPrometheusがスクレイプする仕組みだ。
実際に経験したケース:あるサブドメインのSSL証明書が期限切れになっても誰も気づかず、ブラウザでエラーが出てから発覚した。Blackboxで「残り14日」のアラートを設定してからは、Telegram通知を早めに受け取って余裕を持って更新できるようになり、深夜に慌てて対処する羽目にならなくなった。
Blackbox Exporterのインストール
シンプルな構成なのでDockerは使わず、Prometheusが動いているサーバーに直接インストールする。
バイナリのダウンロードとインストール
# 最新バージョンをダウンロード(github.com/prometheus/blackbox_exporterで確認)
wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.25.0/blackbox_exporter-0.25.0.linux-amd64.tar.gz
tar xvf blackbox_exporter-0.25.0.linux-amd64.tar.gz
cd blackbox_exporter-0.25.0.linux-amd64
# バイナリと設定ファイルをコピー
sudo cp blackbox_exporter /usr/local/bin/
sudo mkdir -p /etc/blackbox_exporter
sudo cp blackbox.yml /etc/blackbox_exporter/
systemdサービスの作成
sudo tee /etc/systemd/system/blackbox_exporter.service <<EOF
[Unit]
Description=Prometheus Blackbox Exporter
After=network.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/blackbox_exporter \
--config.file=/etc/blackbox_exporter/blackbox.yml \
--web.listen-address=:9115
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now blackbox_exporter
sudo systemctl status blackbox_exporter
完了したら http://<server-ip>:9115 にアクセスしてサービスが起動していることを確認する。設定済みモジュールの一覧を表示するシンプルなWebインターフェースが表示される。
プローブモジュールの設定
ファイル /etc/blackbox_exporter/blackbox.yml で「モジュール」を定義する。各モジュールは異なる種類のチェックを表す。以下は実際のプロダクション環境で使っている設定だ:
modules:
# HTTP 2xxチェック — 一般的なWebサイト向け
http_2xx:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 201, 301, 302]
method: GET
follow_redirects: true
preferred_ip_protocol: "ip4"
# HTTPS + SSL証明書チェック
http_2xx_tls:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200]
method: GET
follow_redirects: true
tls_config:
insecure_skip_verify: false # SSL検証を必須にする
# TCPポートの開放チェック(MySQL、Redis、カスタムサービス)
tcp_connect:
prober: tcp
timeout: 5s
# DNS名前解決チェック
dns_check:
prober: dns
timeout: 5s
dns:
query_name: "google.com" # チェックするドメイン名
query_type: "A" # A、AAAA、MX、CNAMEなど
valid_rcodes:
- NOERROR
Prometheusスクレイプの設定
ここがBlackbox Exporterと通常のエクスポーターとの大きな違いだ。直接スクレイプする代わりに、Prometheusはリラベリングの仕組みを使ってスクレイプ時にターゲットURLを渡す。つまり、1つのBlackboxインスタンスで何十ものURLをプローブでき、複数のプロセスを起動する必要がない。MySQLやPostgreSQLを専用Exporterで監視している場合も、このrelabelの考え方は共通している:
# prometheus.ymlに追加
scrape_configs:
# WebサイトのHTTP/HTTPSチェック
- job_name: 'blackbox_http'
metrics_path: /probe
params:
module: [http_2xx_tls]
static_configs:
- targets:
- https://itfromzero.com
- https://example.com
- https://api.yourdomain.com/health
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115 # Blackbox ExporterのIPアドレス
# TCPポートチェック
- job_name: 'blackbox_tcp'
metrics_path: /probe
params:
module: [tcp_connect]
static_configs:
- targets:
- db-server:3306 # MySQL
- cache-server:6379 # Redis
- app-server:8080 # アプリポート
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
# DNSチェック
- job_name: 'blackbox_dns'
metrics_path: /probe
params:
module: [dns_check]
static_configs:
- targets:
- 8.8.8.8 # チェック対象のDNSサーバー
- 1.1.1.1
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
設定変更後にPrometheusをリロードする:
curl -X POST http://localhost:9090/-/reload
結果の確認とアラート設定
Prometheusを待たずにcurlで素早くテスト
次のスクレイプサイクルを待つ必要はない――Blackboxのエンドポイントに直接リクエストしてすぐに確認できる:
# HTTPチェック
curl -s "http://localhost:9115/probe?target=https://itfromzero.com&module=http_2xx_tls" | grep probe_success
# 期待する結果: probe_success 1
# SSL証明書の残り有効秒数
curl -s "http://localhost:9115/probe?target=https://itfromzero.com&module=http_2xx_tls" | grep ssl_earliest_cert_expiry
# probe_ssl_earliest_cert_expiry 1.7XXXXXXXXX+09 ← 証明書の有効期限のUnixタイムスタンプ
# TCPチェック
curl -s "http://localhost:9115/probe?target=db-server:3306&module=tcp_connect" | grep probe_success
PrometheusのAlertingルール
アラートルールこそが、Blackboxを「眺めるだけのツール」から本格的な監視システムへと変える要素だ。管理しやすいよう別ファイルに分けている:
# /etc/prometheus/rules/blackbox.yml
groups:
- name: blackbox_alerts
rules:
# サイトダウン
- alert: WebsiteDown
expr: probe_success{job="blackbox_http"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "サイトダウン: {{ $labels.instance }}"
description: "{{ $labels.instance }} が2分以上応答していません。"
# HTTPレスポンスタイムが遅い
- alert: SlowResponseTime
expr: probe_duration_seconds{job="blackbox_http"} > 3
for: 5m
labels:
severity: warning
annotations:
summary: "レスポンス遅延: {{ $labels.instance }}"
description: "レスポンスタイム {{ $value | humanizeDuration }} が3秒を超えています。"
# SSL証明書の期限切れが近い(14日前)
- alert: SSLCertExpiringSoon
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 14
for: 1h
labels:
severity: warning
annotations:
summary: "SSL期限切れ間近: {{ $labels.instance }}"
description: "証明書の残り有効期限: {{ $value | humanize }} 日。今すぐ更新してください!"
# SSL証明書が期限切れ
- alert: SSLCertExpired
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 0
for: 0m
labels:
severity: critical
annotations:
summary: "SSL期限切れ: {{ $labels.instance }}"
# TCPポートがダウン
- alert: TCPPortDown
expr: probe_success{job="blackbox_tcp"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "ポートダウン: {{ $labels.instance }}"
description: "{{ $labels.instance }} に接続できません。"
prometheus.ymlにルールファイルを追加する:
rule_files:
- "/etc/prometheus/rules/*.yml"
Grafanaダッシュボード
Grafana.comからダッシュボードID 7587 をインポートするだけでよい――ゼロから構築する必要はない。このダッシュボードにはプローブのステータス・レスポンスタイム・SSL残日数・HTTPステータスコードがすべて表示される。自分はこれをメインのオーバービュー画面として使っている。
カスタマイズが必要な場合に自分でパネルを作るためのPromQLクエリをいくつか紹介する:
# SSL証明書の残り日数
(probe_ssl_earliest_cert_expiry{job="blackbox_http"} - time()) / 86400
# 24時間のアップタイム率(%)
avg_over_time(probe_success{job="blackbox_http"}[24h]) * 100
# HTTPステータスコード
probe_http_status_code{job="blackbox_http"}
実運用での注意点
- ファイアウォール: Blackboxを動かすサーバーはインターネットへの通信(ポート80・443・53)が必要だ。プライベートネットワーク内にあってNAT/プロキシがない場合、外部へのHTTPプローブが失敗する――サイトがダウンしていると誤認しやすいので注意。
- DNSモジュール: デフォルト設定では
query_nameにgoogle.comを使っている。内部DNSサーバーを確認したい場合は内部ドメインに変更すること――内部DNS経由でgoogle.comをチェックしてもあまり意味がない。 - タイムアウトとスクレイプ間隔: タイムアウトはスクレイプ間隔より短く設定する必要がある。Prometheusのデフォルトスクレイプ間隔は30秒なので、HTTPのタイムアウトを30秒以上にするとプローブが重複してメトリクスが不正確になる。HTTPは10秒、TCP/DNSは5秒にしておけば問題ない。
- TLS insecure設定: プロダクション環境では絶対に
insecure_skip_verify: trueを設定しないこと。BlackboxのコアミッションはSSL障害の検知なので、検証をスキップするのは自分の足を撃つようなものだ。 - アラートルーティング:
severity: criticalはTelegramに、warningはメールに振り分けている。深夜のcriticalアラートをメールだけで受け取っても翌朝まで気づかない――手遅れになってからでは対処が間に合わない。
