Raspberry PiでKubernetesクラスタを組む(その2: サーバー監視編)

監視体制の準備

サーバー運用といえばまず監視である(?)。Kubernetesクラスタを立ち上げる前に、まずRaspberry Piの監視体制を組んでみることにした。

構成については『ラズパイk8s用の監視システム(Node Exporter + Prometheus + InfluxDB + Grafana)』を参考にした。ダッシュボードはインターネットからアクセスしたいが、インターネットからLANへのアクセスは可能な限りしたくないということで、InfluxDBとGrafanaは元から契約していたVPS上に構築することにした。

参考記事の公開が2020年なのだが、それからInfluxDB 2.0がリリースされたようで、ここでPrometheusのRemote Write APIのサポートが削除されている。代わりにTelegrafにPrometheus write parserが実装されているので、今回は"Prometheus → Telegraf → InfluxDB → Grafana"という構成を取ることにする。

Docker Composeで監視コンポーネントを動かす準備

VPS上ではDockerが動かせる状態になっているので、Composeを使うことにした。次のようなdocker-compose.ymlを用意した。

version: '3'
services:
  influxdb:
    image: influxdb:2.2
    expose:
      - 8086
    volumes:
      - influxdb2:/var/lib/influxdb2
    networks:
      - influxdb
  telegraf:
    image: telegraf:1.22
    expose:
      - 8080
    volumes:
      - ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
    networks:
      - influxdb
      - telegraf
  grafana:
    image: grafana/grafana
    expose:
      - 3000
    volumes:
      - grafana-storage:/var/lib/grafana
    networks:
      - grafana
      - telegraf

volumes:
  influxdb2:
    external: true
  grafana-storage:
    external: true

networks:
  influxdb:
    external: true
  grafana:
    external: true
  telegraf:
    external: true

ボリュームやネットワークはexternalにしてあるので先に作っておく。

$ docker volume create influxdb2
$ docker volume create grafana-storage
$ docker network create influxdb
$ docker network create grafana
$ docker network create telegraf

Telegrafの設定

Telegrafだけは設定ファイルを作っておく必要がある。

前述の通りInfluxDB 2.0でPrometheus Remote Write APIのサポートがなくなってしまったが、InfluxDataがPrometheus Remote Write Support with InfluxDB 2.0という記事を公開している。この記事にある通り、次の3つのプラグインを使ってPrometheus Remote Writeに対応する。

  • HTTP Listener v2 Input Plugin
  • Prometheus Remote Write Parser
  • InfluxDB v2 Output Plugin

ちなみにプラグインといっても同梱されているものなので、設定さえ書いておけば使える状態になっている。

HTTP Listener v2 Input Pluginが入力を担当する。Prometheus Remote WriteはHTTPでAPIを呼び出すので、その受け口となるプラグインである。その中身を解釈するのがPrometheus Remote Write Parserである。そして解釈されたデータをInfluxDBに送るのがInfluxDB v2 Output Plugin、という構成になっている。

docker-compose.ymlと同じディレクトリに以下の内容のtelegraf.confを作る。

[[inputs.http_listener_v2]]
  service_address = ":8080"
  paths = ["/telegraf"]
  data_format = "prometheusremotewrite"

[[outputs.influxdb_v2]]
  urls = ["http://influxdb:8086"]
  token = "$INFLUX_TOKEN"
  organization = "$INFLUX_ORG"
  bucket = "$INFLUX_BUCKET"

まずHTTP Listener v2 Input Pluginの設定だが、service_addressにプラグインが待ち受けるポートを指定する。docker-compose.ymlexposeに指定したポート番号と一致させる。パスは今回/telegrafとしているが、これは任意に決めてよい。data_format = prometheusremotewriteとすることでPrometheus Remote Write Parserが有効になる。

次にInfluxDB v2 Output Pluginの設定である。urlsにはdocker-compose.ymlのサービス名でInfluxDBのインスタンスを指定する(同一のComposeプロジェクト内で同じネットワークに属するのでサービス名で名前解決ができる)。organization, bucketについては後ほどInfluxDBの初期設定で作成する値を指定しておく。また、tokenについても初期設定後にInfluxDBのUIから作成するので仮置きする(とりあえず指定がおかしくてもリクエストに失敗するだけで起動はするはず)。

https-portalの設定と起動

他のアプリケーションでhttps-portalを使っているので、これを流用することにした。そのため、ポートはホストにバインドせず単にexposeするだけにしている。networksに指定したネットワークでhttps-portalのコンテナと接続する。また、DNS設定で適当なサブドメインをInfluxDBとGrafanaにアクセスするために割り当てる。以上の準備をした上で、https-portal側のdocker-compose.ymlを抜粋するとこんな感じになる。

services:
  web:
    image: steveltn/https-portal
    # ...
    networks:
      - influxdb
      - grafana
      - telegraf
    environment:
      DOMAINS: influxdb.example.com -> http://influxdbgrafana_influxdb_1:8086, grafana.example.com -> http://influxdbgrafana_grafana_1:3000, telegraf.example.com -> http://influxdbgrafana_telegraf_1:8080

これでhttps-portalを再起動する。

InfluxDBの設定

https-portalが正常に起動した後、ブラウザからInfluxDBにアクセスすると初期設定が始まる。最近はCTログからドメインを特定するらしく、どこにも公開してないのにあっという間にいろいろな楽しいリクエストが飛んでくるようになるので、早めに初期設定しておこう。もしくは一時的にポートをホストにバインドしてローカルからアクセスして初期設定をするとか、docker execでCLIからやってもよいと思う。Docker Hubのinfluxdbのページも参考になるだろう。

初期設定した後にリロードするとダッシュボードが表示される。最初に"Data"が選択されていると思うが、この右端に"API Tokens"というタブがある。このタブを選択して"Generate API Token"をクリックして"Read/Write API Token"を選択、後は書き込み対象のバケットを選択するとAPIトークンが生成される。トークン一覧から今作成したトークンをクリックすればAPIトークンの値を確認できるので、この値をtelegraf.confに転記する。

Prometheusの準備

全ノードにnode_exporterをインストール、マスターノードにのみprometheusをインストールする。また、Raspberry Pi特有のメトリクスを公開してくれるraspberrypi_exporterも導入する。

$ sudo apt install prometheus-node-exporter
$ sudo apt install prometheus
$ curl -fsSL "https://raw.githubusercontent.com/fahlke/raspberrypi_exporter/master/installer.sh" | sudo bash

/etc/prometheus/prometheus.ymlが設定ファイルである。まずサンプルが入っているので、適当に弄っていく。

  • scrape_intervalが15秒になってたりするが、そんなに細かく取得してくれなくてよいのでデフォルトとされる1分に戻す。
  • evaulation_intervalも同様
  • external_labelsmonitor=mykubeといった感じで適当な名前を振っておく
  • static_configs以下
    • prometheusそのものをscrapeする設定が入っているが、localhost:9090ではなくてノード名(kube-0.local)で指定する
    • node_exporterからscrapeする設定を書く
  • metric_relabel_configsで、node_nameにノード名を付与する
    • instanceから適当に抜き出すだけだが、気持ちと見た目の問題が大きい
    • ちなみにmetric_*じゃないrelabel_configsだと動かなかった(これで何日も潰した)
global:
  scrape_interval:     1m
  evaluation_interval: 1m

  external_labels:
      monitor: 'mykube'

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['kube-0.local:9090']
    metric_relabel_configs:
      - source_labels: ["instance"]
        regex: '([^:]+):.+'
        replacement: $1
        target_label: node_name

  - job_name: node
    static_configs:
      - targets:
        - 'kube-0.local:9100'
        - 'kube-1.local:9100'
        - 'kube-2.local:9100'
    metric_relabel_configs:
      - source_labels: ["instance"]
        regex: '([^:]+):.+'
        replacement: $1
        target_label: node_name

remote_write:
  - url: "https://telegraf.example.com/telegraf"

設定が済んだらreloadさせる。

$ sudo systemctl reload prometheus

raspberrypi_exporterは定期的にシェルスクリプトを実行して /var/lib/node_exporter/textfile_collector/raspberrypi-metrics.prom にPrometheusのフォーマットで値を書き出すようになっている。これをnode_exporterのTextfile collectorを通して公開する。そのためにはnode_exporterにオプションを渡す必要があるので、/etc/default/prometheus-node-exporterを修正する。

ARGS="--collector.textfile.directory=/var/lib/node_exporter/textfile_collector"

node_exporterも再起動する。

$ sudo systemctl restart prometheus-node-exporter

しばらく待ってからInfluxDBのUIを見て、node_nameでフィルタをかける。ノード名(.local:9100が入ってない名前)でフィルタして、_fieldで大量の項目が出てきたら成功している。適当なフィールドを選んで"Submit"すればグラフが表示される。このスクリーンショットは3台のロードアベレージを表示させたところである。

InfluxDB Graph

Grafanaの設定

https-portalの設定を済ませてブラウザからアクセスする。初期ユーザー・パスワードは admin:admin と分かりやすいので、こちらも起動したらとりあえずログインしてパスワードを設定しておく。

左下の歯車 (Configuration) から"Data Sources"を選ぶ。“Add data source"のページで対応データソースの一覧が出るので、InfluxDBを選択する。今回はクエリ言語に"Flux"を選択した。URLにInfluxDBのURLを指定するが、今回はコンテナ内通信で完結できるので http://influxdbgrafana_influxdb_1:8086 のようにコンテナ名を指定すればよい。

Fluxを選択した場合は認証にトークンを使うことができる。Telegrafからの送信設定のときと同様にトークンを作成して、“InfluxDB Details"のTokenの項目に入力する。Organizationも埋めたら"Save & Test"を押して、“1 buckets found"の表示が出れば設定完了である。

Grafanaからクエリができるかを確認してみよう。サイドバーの"Explore"を選ぶと、適当なクエリを入力してその場で結果を確認できるページに移る。Fluxについては公式のGet started with Fluxなどを参照してもらうとして、試しにCPU温度をクエリしてみた結果が次の通り。

Raspberry Pi Temperature Graph by Grafana

アラート設定とかは何もしてないけど、とりあえず状態を見られるようになったので今回はここまで。