いんふら女子めも

('ω')ノ★ 現役インフラエンジニアです.

prometheus+garfanaで遊んでみるよ

この前Prometheusを初めて使ってみたので、復習を兼ねてPrometheusで取得したメトリクスをGrafanaで可視化してみたいと思います。

Prometheus?

  • オープンソースの監視ツールです。
  • プル型なのでPrometehusサーバーが監視先サーバーに聞きまわり、監視メトリクスをかき集めているイメージです。
  • 可視化ツールのGrafanaと親和性が高いです。
  • Prometehusのデフォルトのダッシュボードがありますが、可視化には強くないので取得したメトリクスを分かりやすく可視化したい場合はGrafanaを使います。
  • セットアップが非常に簡単で、バイナリをインストールして起動させるだけで監視開始させることができます。

環境

  • CentOS7.6
  • Prometheus server v2.32
  • Prometheus node v0.16

Exporterのインストール

導入は本当に簡単です。さっと終わります。

#インストール先のディレクトリを作成する
$ mkdir /etc/prometheus
$ cd /etc/prometehus
#バイナリファイルをインストールする
$ wget https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz
#インストールしたバイナリを解凍する
tar xvzf node_exporter-0.16.0.linux-amd64.tar.gz
#ディレクトリ名を変更する
$ mv node_exporter-0.16.0.linux-amd64.tar.gz node_exporter
#exporterが動くかテストする
$ cd node_exporter
$ ./node_exporter

以下のようにデータ取得できていればOKです。

$ ./node_exporter
INFO[0000] Starting node_exporter (version=0.16.0, branch=HEAD, revision=d42bd70f4363dced6b77d8fc311ea57b63387e4f)  source="node_exporter.go:82"
INFO[0000] Build context (go=go1.9.6, user=root@a67a9bc13a69, date=20180515-15:52:42)  source="node_exporter.go:83"
INFO[0000] Enabled collectors:                           source="node_exporter.go:90"
INFO[0000]  - arp                                        source="node_exporter.go:97"
INFO[0000]  - bcache                                     source="node_exporter.go:97"
INFO[0000]  - bonding                                    source="node_exporter.go:97"
INFO[0000]  - conntrack                                  source="node_exporter.go:97"
INFO[0000]  - cpu                                        source="node_exporter.go:97"
INFO[0000]  - diskstats                                  source="node_exporter.go:97"
INFO[0000]  - edac                                       source="node_exporter.go:97"
INFO[0000]  - entropy                                    source="node_exporter.go:97"
INFO[0000]  - filefd                                     source="node_exporter.go:97"
INFO[0000]  - filesystem                                 source="node_exporter.g

動作確認できたら、exporterをサービス化します。

#サービスファイルの作成
$ vi /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
Documentation=https://github.com/prometheus/node_exporter

[Service]
Type=simple
ExecStart=/etc/prometheus/node_exporter/node_exporter
Restart=always

[Install]
WantedBy=multi-user.target

サービスを有効にするためにデーモンをリロードし、サービスを起動する

$systemctl daemon-reload
$systemctl enable node_exporter
$systemctl start node_exporter
$systemctl status node_exporter
● prometheus_node.service - Node Exporter
   Loaded: loaded (/etc/systemd/system/prometheus_node.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2019-07-07 06:43:19 UTC; 34min ago
     Docs: https://github.com/prometheus/node_exporter
 Main PID: 8700 (node_exporter)
   CGroup: /system.slice/prometheus_node.service
           mq8700 /etc/prometheus/node_exporter/node_exporter

Jul 07 06:43:19 localhost.localdomain node_exporter[8700]: time="2019-07-07T0...
Jul 07 06:43:19 localhost.localdomain node_exporter[8700]: time="2019-07-07T0...
Jul 07 06:43:19 localhost.localdomain node_exporter[8700]: time="2019-07-07T0...

ステータスがアクティブになっていればOKです。

Prometheus_serverのインストール

続いて、Prometheus_serverの準備をしていきます。

#prometheus serverのインストール
$ wget https://github.com/prometheus/prometheus/releases/download/v2.3.2/prometheus-2.3.2.linux-amd64.tar.gz
#バイナリファイルを解凍する
$ tar xvzf prometheus-2.3.2.linux-amd64.tar.gz
#ディレクトリ名を変更する
$ mv prometheus-2.3.2.linux-amd64 prometheus_server
$ cd prometheus_server
#設定ファイルの修正
$ vi prometheus.yml
# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'node_exporter' #変更箇所

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
    - targets: ['localhost:9100']  #変更箇所

今回は同じホストでexporterを起動させているので、ターゲット先は"localhost:9100"となります。exporterによって指定するポートが違うので注意が必要です。

prometheusを起動させ、正常に監視開始するか確認します。"Server is ready to receive web requests."とうメッセージが表示されていればOKです。

$ ./prometheus
level=info ts=2019-07-07T08:12:19.556134535Z caller=main.go:222 msg="Starting Prometheus" version="(version=2.3.2, branch=HEAD, revision=71af5e29e815795e9dd14742ee7725682fa14b7b)"
level=info ts=2019-07-07T08:12:19.556251007Z caller=main.go:223 build_context="(go=go1.10.3, user=root@5258e0bd9cc1, date=20180712-14:02:52)"
level=info ts=2019-07-07T08:12:19.556276083Z caller=main.go:224 host_details="(Linux 3.10.0-957.10.1.el7.x86_64 #1 SMP Mon Mar 18 15:06:45 UTC 2019 x86_64 localhost.localdomain (none))"
level=info ts=2019-07-07T08:12:19.556296925Z caller=main.go:225 fd_limits="(soft=1024, hard=4096)"
level=info ts=2019-07-07T08:12:19.556926921Z caller=main.go:533 msg="Starting TSDB ..."
level=info ts=2019-07-07T08:12:19.559585106Z caller=web.go:415 component=web msg="Start listening for connections" address=0.0.0.0:9090
level=info ts=2019-07-07T08:12:19.570862184Z caller=main.go:543 msg="TSDB started"
level=info ts=2019-07-07T08:12:19.570898772Z caller=main.go:603 msg="Loading configuration file" filename=prometheus.yml
level=info ts=2019-07-07T08:12:19.573468239Z caller=main.go:629 msg="Completed loading of configuration file" filename=prometheus.yml
level=info ts=2019-07-07T08:12:19.573559206Z caller=main.go:502 msg="Server is ready to receive web requests."

起動確認ができたら、サービス化ファイルを作成します。

$ vi /etc/systemd/system/prometheus_server.serivice
[Unit]
Description=Prometheus
Documentation=https://prometheus.io/docs/introduction/overview/
After=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/etc/prometheus/prometheus_server/prometheus \
  --config.file=/etc/prometheus/prometheus_server/prometheus.yml \

[Install]
WantedBy=multi-user.target

#デーモンをリロードする
$systemctl daemon-reload
#サービスを有効にする
$systemctl enable prometheus_server
#サービスを起動する
$systemctl start prometheus_server
$systemctl status prometheus_server
● prometheus_server.service - Prometheus
   Loaded: loaded (/etc/systemd/system/prometheus_server.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2019-07-07 08:24:42 UTC; 6s ago
     Docs: https://prometheus.io/docs/introduction/overview/
 Main PID: 16275 (prometheus)
   CGroup: /system.slice/prometheus_server.service
           mq16275 /etc/prometheus/prometheus_server/prometheus --config.file...

Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...
Jul 07 08:24:42 localhost.localdomain prometheus[16275]: level=info ts=2019-0...

サービスがアクティブであることを確認できたらOKです。

prometheusのGUI画面を確認する

"http://[prometheus_server_IPaddress]:9100/graph"にアクセスすると、下記のような画面が表示されます。[Execuse]ボタン横のドロップダウンからグラフ化したいメトリクスを選択し、[Execuse]ボタンをクリックするとメトリクスの時系列グラフが表示されます。今回は、nodeのディスクIOの現在値を表示してみました。
f:id:akngo22:20190708214912j:plain

Grafanaにデータソース登録する

prometheusのGUI画面にてメトリクスを取得できていることを確認できたら、Grafanaにデータソース登録していきます。
Grafanaにログイン後、prometheusをデータソースに登録していきます。URLは9090ポートを指定し「Save&Test」をクリックし問題なければ登録完了となります。
f:id:akngo22:20190708215708j:plain

既存のテンプレートを使ってダッシュボートをインポートする

Grafanaは個人でダッシュボード開発している方がいるので、公式ドキュメント見るとテンプレートが豊富にあります。せっかくなので使えるものは使っていきます。今回は以下のPrometheusサーバーの状態を示すダッシュボートを使用しました。
grafana.com

上記のURLにアクセスしてダッシュボードIDをコピーした後、GrafanaGUI画面の右上「▼」から「Import Dashboard」をクリックしダッシュボードIDを入力します。
f:id:akngo22:20190814174228j:plain
後はちょこちょこっと微調整すれば簡単にダッシュボード作成できました!わーい!
f:id:akngo22:20190814174448j:plain

今回はこんな感じで。
おしまい

Grafanaのトップ画面をユーザーグループごとに変えたい

Grafana便利だよね

Grafana便利ですよね。最近はGrafanaを使って監視ダッシュボードの開発をメインにしているので、Grafana職人なのかなって思うくらい使っています。

今回は、ユーザー(グループ)ごとに見せたいダッシュボードを変えたいときの実例について書きます。管理者と閲覧者に見せる画面を変えて閲覧権限を制限したりなどができるかと思います。

やりたいこと

管理者と閲覧者のトップページ(ログイン後の画面)を変えて、アクセスできるダッシュボードに制限をかけたいと思います。
イメージは以下のようなものを想定しています。
f:id:akngo22:20190814110149p:plain

お試し環境

今回は、Grafana6.16で試しました。

手順

①管理者でログインしユーザーを作成する

「configuration」⇒「users」⇒「invite」をクリックして、必要事項を入力します。
※ユーザー名とロールは必須事項となっているので入力してください。ユーザー追加は招待形式なので、E-mailで招待をもらいたい場合はメールアドレスを入力する必要があります。
f:id:akngo22:20190813175848j:plain

②作成したユーザーを認証する

ユーザーを作成すると「Pending Invites」一覧に表示されると思うので、ユーザー右の「Conpy Invite」をクリックしコピーされたURLにアクセスします。
※おそらくURLがlocalhostになっているので、IPアドレスでGrafanaGUI画面にアクセスしている場合はURLを書き換えてください。
f:id:akngo22:20190813180611j:plain
ログインするためのパスワードを入力し「Sign Up」をクリックすると、追加したユーザーでログインできると思います。
f:id:akngo22:20190813180824j:plain
管理者のページでユーザーが「Pending Invites」からユーザー一覧に表示されていることを確認します。
f:id:akngo22:20190813180846j:plain

③チームを作成する

Grafanaはユーザーをチームというユーザーグループで管理するようになっており、チーム別にトップ画面を変更することができます。先ほど作成したユーザーは閲覧者のため、Viewerというチームを作成することとします。
「Teams」タブ⇒「New team」をクリックし、チーム名を入力した後「Create」します。
f:id:akngo22:20190813182054j:plain

チームが作成されたらユーザーを追加します。
「Add member」⇒「Add to team」でユーザーを追加していきます。
f:id:akngo22:20190814102139j:plain
一覧に表示されればOKです。
f:id:akngo22:20190814102231j:plain

④チームの設定を変更する

ここでチームのホームダッシュボードを変更します。
「Teams」タブから作成したチームをクリックします。
f:id:akngo22:20190814103426j:plain
「Settings」タブ⇒「Home dashboard」で変更可能です。
※ホームダッシュボードは、スターを付けているダッシュボードからしか選択できない仕様なので、ドロップダウンリストに表示されない場合はダッシュボードにスターを付けてから実施してください。
f:id:akngo22:20190814103542j:plain

⑤ログインして確認

作成したユーザーでログインし、ホーム画面が指定したダッシュボードになっていればOKです。ログインユーザーは閲覧権限しかないので、パネルを編集しようとしてもできないようになっています。
f:id:akngo22:20190814104609j:plain

ダッシュボードの閲覧権限変更したい

このままだとダッシュボードの権限はデフォルトのままなので、トップページ変更したとしても他のダッシュボードにアクセスできてしまいます。そのため、ダッシュボードをフォルダごとで閲覧権限を変更しておきます。(※ダッシュボードごとにも権限を変更することは可能ですが、面倒なのでフォルダごとにやります。)
イメージとしては閲覧者と管理者用のフォルダを作成し、管理者用のフォルダには閲覧者の権限を外すようにします。
f:id:akngo22:20190814113330j:plain

①フォルダを作成する

画面右上の「▼」をクリックし、「New Folder」を選択します。
フォルダ作成したらダッシュボードの格納フォルダを変更します。(ダッシュボードのSettingsから変更可能)
f:id:akngo22:20190814113547j:plain

②フォルダ権限を変更する

フォルダのSettingsから「Permissions」タブを選択し、今回は管理者用のフォルダなので閲覧者の権限を外すためViewerの「×」をクリックします。これで管理者フォルダに格納されているダッシュボードはロールがViewerの場合見れないようになりました。
f:id:akngo22:20190814114606j:plain

とはいえ全部GUIでやるのめんどくさい

めんどくさいので、GrafanaAPIでできるようにシェルスクリプト書きます。流れとしては、トークン取得からユーザー作成、チーム作成、チームにメンバー追加、ダッシュボードの検索、作成チームのトップ画面変更までをスクリプト化しました。

#!/bin/bash

#obtain api token
API_TOKEN=`curl -X POST -H "Content-Type: application/json" -d '{"name":"api-test-key","role":"Admin"}' http://[admin_user]:[admin_pass]@localhost:3000/api/auth/keys | jq -r .key`
echo $API_TOKEN

#create user
USER_ID=`curl -X POST -u '[admin_user]:[admin_pass]' -H "Content-Type: application/json" -d '{"name":"test-user","email":"test-user@localhost","login":"test-user","password":"hogehoge"}' http://localhost:3000/api/admin/users | jq -r .id`
echo $USER_ID

#create team
TEAM_ID=`curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${API_TOKEN}" -d '{"name":"test-team","email":"test-team@localhost"}' http://localhost:3000/api/teams | jq -r .teamId`
echo $TEAM_ID

#add team member
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${API_TOKEN}" -d '{"userId":'$USER_ID'}' http://localhost:3000/api/teams/$TEAM_ID/members

#search dashboard
DASHBOARD_ID=`curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer ${API_TOKEN}" http://localhost:3000/api/search?query=VM%20information | jq -r .[].id`

#star the dashboard
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${API_TOKEN}" http://localhost:3000/api/user/stars/dashboard/$DASHBOARD_ID

#update team preference
curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer ${API_
TOKEN}" -d '{"theme":"dark","homeDashboardId":'$DASHBOARD_ID',"timezone":""}' ht
tp://localhost:3000/api/teams/$TEAM_ID/preferences

GrafanaAPIを使ってスクリプト書くとき、気を付けたいのがものによって認証方法が違うことです。APIトークンを使う(管理者権限がいらない)Bearer認証とAdmin情報が必要な(管理者権限のいる)Basic認証の2つがあります。
上記のスクリプトの場合、ユーザー作成のときはBasic認証でそれ以外はBearer認証となっています。見分け方は基本的にリクエスト例のAuthorizationがBearerかBasicかで判断することができますが、時々公式ドキュメントが間違えているのでうまくいかない場合は認証方法を変更してみてください。
grafana.com

おしまい。

GrafanaのAPIを使ってみよう

API使って楽したい

grafanaでGUI画面からぽちぽちデータソース追加したりダッシュボード作ったりするのも良いですが、ちょっと楽したいなと思ったときAPI使って自動化し作業負荷減らしたいですよね。
公式ドキュメントには、APIの使い方の詳細があまり書かれておらず多少戸惑いましたが、実際に触ってみて使い方が分かったのでまとめました。

APIトークンを取得する

ダッシュボード上から取得する場合

まずはAPIを使うためのトークンを取得していきます。
grafanaのAPIトークンはGUI画面から取得できるので、grafanaにログインし画面左の[configuration]から[API key]を選択します。
f:id:akngo22:20190711223329j:plain
 
[Add API Key]をクリックしユーザー名とロールを入力します。
f:id:akngo22:20190711223535j:plain

[Add]をクリック後キーが発行されるのでコピーしておきます。
f:id:akngo22:20190711223819j:plain

キー発行のポップアップにコマンド例があるので実際にレスポンスが返ってくるか試してみましょう。

#ホームのダッシュボード情報がJSONで返ってきます
$ curl -H "Authorization: Bearer {API_TOKEN}" http://[grafana_ip_address]:3000/api/dashboards/home

{"meta":{"isHome":true,"canSave":false,"canEdit":true,"canAdmin":false,"canStar":false,"slug":"","url":"","expires":"0001-01-01T00:00:00Z","created":"0001-01-01T00:00:00Z","updated":"0001-01-01T00:00:00Z","updatedBy":"","createdBy":"","version":0,"hasAcl":false,"isFolder":false,"folderId":0,"folderTitle":"General","folderUrl":"","provisioned":false},"dashboard":{"annotations":{"list":[]},"editable":true,"folderId":null,"gnetId":null,"graphTooltip":0,"hideControls":true,"id":null,"links":[],"panels":[{"content":"\u003cdiv class=\"text-center dashboard-header\"\u003e\n  \u003cspan\u003eHome Dashboard\u003c/span\u003e\n\u003c/div\u003e","editable":true,"gridPos":{"h":3,"w":24,"x":0,"y":0},"id":1,"links":[],"mode":"html","style":{},"title":"","transparent":true,"type":"text"},{"folderId":0,"gridPos":{"h":17,"w":12,"x":0,"y":6},"headings":true,"id":3,"limit":30,"links":[],"query":"","recent":true,"search":false,"starred":true,"tags":[],"title":"","transparent":false,"type":"dashlist"},{"editable":true,"error":false,"gridPos":{"h":17,"w":12,"x":12,"y":6},"id":4,"links":[],"title":"","transparent":false,"type":"pluginlist"},{"gridPos":{"h":4,"w":24,"x":0,"y":3},"id":123123,"type":"gettingstarted"}],"rows":[],"schemaVersion":17,"style":"dark","tags":[],"templating":{"list":[]},"time":{"from":"now-6h","to":"now"},"timepicker":{"hidden":true,"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"],"type":"timepicker"},"timezone":"browser","title":"Home","version":0}}

curlコマンドから取得する場合

上記では、GUI画面からAPIトークン取得する方法を説明しましたが、もちろんCLIでも取得できます。やっていることは上記と一緒です。-dオプションの後に"name"でキー名、"role"で管理者権限なのか、閲覧者のみなのか等指定し、URL指定するときにGrafanaにログインするときのユーザー・パスワードを指定します。

# CLIでAPIトークンを取得する
$ curl -X POST -H "Content-Type: application/json" -d '{"name":"apikeytest", "role": "Admin"}' http://[user_name]:[password]@[grafana_server_IP]:3000/api/auth/keys | jq
{
  "name": "apikeytest",
  "key": "eyJrIjoiQTRubUlONGU1N1lJbG92NzlEV0VXcEdqxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=="
}

#取得したトークンをそのまま変数にいれるときはjqコマンドでキーだけ表示させるようにすると良い
$ API_KEY=`curl -X POST -H "Content-Type: application/json" -d '{"name":"apikeytest", "role": "Admin"}' http://[user_name]:[password]@[grafana_server_IP]:3000/api/auth/keys | jq -r .key`
$ echo $API_KEY
eyJrIjoiQTRubUlONGU1N1lJbG92NzlEV0VXcEdqxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==

APIを使ってみよう

curlコマンドでレスポンスが確認できたら、実際にAPIを使って色々試してみます。
JSONを見やすくするため、jqコマンドは事前にインストールしておきましょう。
 
APIでどういうことができるかはドキュメントに書かれています。今回は、データソースAPIを使います。
grafana.com

データソース一覧を取得

登録しているデータソース一覧を出力します。

#トークン長いので変数に入れる
$API_TOKEN="Authorization: Bearer [API_TOKEN]"
$ curl -X GET -H "${API_TOKEN}" http://[grafana_ip_address]:3000/api/datasources |  jq

[
  {
    "id": 2,
    "orgId": 1,
    "name": "Prometheus",
    "type": "prometheus",
    "typeLogoUrl": "public/app/plugins/datasource/prometheus/img/prometheus_logo.svg",
    "access": "proxy",
    "url": "http://localhost:9090",
    "password": "",
    "user": "",
    "database": "",
    "basicAuth": false,
    "isDefault": false,
    "jsonData": {
      "httpMethod": "GET",
      "keepCookies": []
    },
    "readOnly": false
  },
  {
    "id": 1,
    "orgId": 1,
    "name": "Zabbix",
    "type": "alexanderzobnin-zabbix-datasource",
    "typeLogoUrl": "public/plugins/alexanderzobnin-zabbix-datasource/img/zabbix_app_logo.svg",
    "access": "proxy",
    "url": "http://localhost/zabbix/api_jsonrpc.php",
    "password": "",
    "user": "",
    "database": "",
    "basicAuth": false,
    "isDefault": true,
    "jsonData": {
      "addThresholds": false,
      "alerting": false,
      "alertingMinSeverity": 3,
      "dbConnectionDatasourceId": null,
      "dbConnectionEnable": false,
      "disableReadOnlyUsersAck": false,
      "keepCookies": [],
      "password": "zabbix",
      "trends": false,
      "username": "Admin",
      "zabbixVersion": 4
    },
    "readOnly": false
  }
]

データソース名を指定して詳細表示

データソース名を指定することで対象のデータソースの詳細を出力できます。

$ curl -X GET -H "${API_TOKEN}" http://[grafana_ip_address]:3000/api/datasources/name/Prometheus | jq
{
  "id": 2,
  "orgId": 1,
  "name": "Prometheus",
  "type": "prometheus",
  "typeLogoUrl": "",
  "access": "proxy",
  "url": "http://localhost:9090",
  "password": "",
  "user": "",
  "database": "",
  "basicAuth": false,
  "basicAuthUser": "",
  "basicAuthPassword": "",
  "withCredentials": false,
  "isDefault": false,
  "jsonData": {
    "httpMethod": "GET",
    "keepCookies": []
  },
  "secureJsonFields": {},
  "version": 2,
  "readOnly": true
}

データソースを削除

登録されているデータソースを削除します。

$ curl -X DELETE -H "${API_TOKEN}" http://[grafana_ip_address]:3000/api/datasources/name/Prometheus-1 | jq

{
  "message": "Data source deleted"
}

データソースを追加

最後にデータソースの登録です。

$ curl -X POST -H "${API_TOKEN}" -H "Content-Type: application/json" -d '{
"name":"prometheus-test",
"type":"prometheus",
"url":"http:localhost:9090",
"access":"proxy",
"basicAuth":false
}' http://[grafana_ip_address]:3000/api/datasources

"datasource":{"id":4,"orgId":1,"name":"prometheus-test","type":"prometheus","typeLogoUrl":"","access":"proxy","url":"http:localhost:9090","password":"","user":"","database":"","basicAuth":false,"basicAuthUser":"","basicAuthPassword":"","withCredentials":false,"isDefault":false,"jsonData":{},"secureJsonFields":{},"version":1,"readOnly":false},"id":4,"message":"Datasource added","name":"prometheus-test"}

ちなみにデータソースを追加する場合は、上記のように「-H "Content-Type: application/json"」を入れないと以下のエラーが出力されるので注意です。

[{"fieldNames":["Name"],"classification":"RequiredError","message":"Required"},{"fieldNames":["Type"],"classification":"RequiredError","message":"Required"},{"fieldNames":["Access"],"classification":"RequiredError","message":"Required"}]

GrafanaのAPI関連の記事は以下のQiitaがおすすめです。
qiita.com

今回はデータソースAPIを使いましたが、それ以外にもダッシュボードを作成したりスナップショットを取得したりすることができます。
公式ドキュメントは少しわかりにくいですが、実際使ってみると結構簡単にできたのでぜひ使ってみると良いと思います。

おしまい。

ZabbixでCPUコアごとの使用率を出したい

Zabbix上ではデフォルトのテンプレート(Template OS Linux)で全CPUの使用率を求めるアイテムはデフォルトで入っていますが、CPUコアごとに出せるんだっけ?と思ったので調べました。

公式ドキュメントを見る

まずは、公式ドキュメントをみてみます。
www.zabbix.com

CPU使用率を求めるアイテムは、"system.cpu.util[cpu,type,mode]"ですね。括弧に中に設定する値は以下の通りです。

- cpu - CPU番号(デフォルトは全CPU)
- type - 何のCPU使用率を出すか:idle, nice, user(デフォルト)、system (Windowsでのデフォルト)、 iowait, interrupt, softirq, steal
- mode - CPU使用率を何分間平均で出すか指定する:avg1 (1分間の平均、デフォルト)、avg5 (5分間の平均)、avg15 (15分以内の平均)

ここで沸いた疑問が「CPU番号は何を指しているのか分からない・・・」。
CPUコアのことなのかCPUの数を指しているのかな。

 調べてみると、CPU番号はCPUコアごとっぽいことは分かりました。
http://www.zabbix.jp/node/674

しかし、確証は得られていないので引き続き調査したところ、Zabbixのローレベルディスカバリ機能にてCPUのコア情報が取得できることが判明しました。ディスカバリルールの設定時に“system.cpu.discovery”をディスカバリルールのキーにして、アイテムsystem.cpu.utilのcpu番号のところに{#CPU.NUMBER}というマクロを設定すると自動でCPUコアの数分の使用率を取得してくるようです。
www.zabbix.com

ローレベルディスカバリ機能を使う

実際に設定してみます。

ディスカバリールールを作成

f:id:akngo22:20190710210811j:plain

プロトタイプの作成

アイテムのキーはマクロを使って以下のように設定します。
system.cpu.util[{#CPU.NUMBER},user,avg1]
f:id:akngo22:20190710203916j:plain

後はデータ取得されるまで少し待つだけ。
その結果、CPUコア数は48個であることが分かりました。

ここでまた疑問を持ちました。
このCPUコア数は物理CPUのコア数?、または論理CPUのコア数?

もう一度、ドキュメント読んでみました。下記の文言を発見。
CPU のハイパースレッド処理が有効である場合、物理か論理か区別できなさそうでした。

To note, a clear distinction cannot be made between actual, physical processors, cores and hyperthreads.

監視対象サーバーを確認してみる

実際に監視サーバーのCPU情報見れば良いかと思い、/proc/cpuinfoファイルを見てみました。
調べるのは物理CPUの数、CPUごとのコア数、論理プロセッサーの数です。grepコマンド駆使して見ると分かりやすいです。

#物理CPUの数(physical idを抜き出して重複箇所はまとめて行カウント)
$ grep physical.id /proc/cpuinfo | sort -u | wc -l
#CPUごとのコア数
$ grep cpu.cores /proc/cpuinfo | sort -u
#論理プロセッサーの数
$ grep processor /proc/cpuinfo | wc -l

コマンド実行した結果です。

物理CPUが2個でCPUごとのコア数が12個なので、全部でコア数は2x12=24個。
しかし、論理プロセッサが48個なのでハイパースレッド機能が有効になっており、各コアが2つのスレッドに分かれていることが分かりました。つまり、論理プロセッサ(論理コア数)は2x(12x2)=48個です。

このことから、Zabbixで検出しているCPUコア数は論理コア数である確証が得られました。

私の頭の中のイメージはこんなです。
f:id:akngo22:20190710225516p:plain

Grafana画面に反映する

すっきりしたので、あとは画面反映するだけです。
イメージはCPUコア数1個しかないですが、複数あれば時系列グラフにその数分表示されます。
アイテムのところを/cpu util per core/としているのは、cpuコア数が複数ある場合「cpu util per core 0」、「cpu util per core 1」という風に末尾の数字が増えていくだけなので、「cpu util per core」がアイテム名にあるものを全部出力させるようにスラッシュで囲っています。
f:id:akngo22:20190710211341j:plain

おしまい。