ARMボード色々でおうちDockerSwarmクラスタ prometheus/grafana/cadvisor編

クラスタを作っている所(進行形)なのでそのメモを残していきます。
この記事ではおうちARMボードをモニタリングできるようにしていきます。

今回は クラスタの状態を可視化したくなったのでPrometheusとその周りを整えてみます。

# おうちクラスタシリーズ
- 第1弾: [ハードウェア編](https://qiita.com/Domao/items/093c93ff5f3ee6f49cea) 
- 第2弾: Portainer編
- 第3弾: Ceph編(失敗)
- 第4弾: SeaweedFS編
- 第5弾: traefik編
- 第6弾: prometheus/grafana編

# 使うソフトウェアの紹介
今回は複数のソフトウェアを使うのでそれぞれ書きます

## Prometheusについて
https://prometheus.io/

監視システムの基盤の一種です。メトリクスという形で死活情報を提供しているサービスから、ログを収集したり、ログに異常があればアラートを発行したり、ログを可視化したりできます。しかしながら、Prometheus自体はそれぞれの"基盤"(API)のみとなっており、ログを提供するExporter、実際にアラートを送るAlertManager、ログを可視化するVisualizationツールとともに利用する前提となっているようです。

## cAdvisorについて
https://github.com/google/cadvisor

Dockerコンテナのリソース使用量やパフォーマンスなどのログを提供するExporterの一種です。(Dockerデフォルトでも[Metrics-Port](https://docs.docker.com/config/daemon/prometheus/)を設定すればDocker自体からメトリクスを吐いてくれるようなのですが、触れられている記事が少なかったので、とりあえずcAdvisorを使ってみることにします)

## node-exporterについて
https://github.com/prometheus/node_exporter

https://hub.docker.com/r/prom/prometheus

動作しているOS自体のCPU/メモリ使用率などを提供するExporterの一種です。DockerHubを見たところ、ARM64/ARMv7に対応しているようだったのでそのまま使うことができます。が、DockerSwarmではこのまま使うと面倒なことになります(後述)

## grafanaについて
https://github.com/grafana/grafana

https://grafana.com/

Prometheus等様々な監視基盤の情報を可視化できるVisualizationツールです。現在の状態を可視化することが目的なので、細かく1つ1つログが見れるとかいうものではありません。(アプリの動作ログとかを可視化するなら elasticstack等?)

# 導入
ここまでで、PortainerとSeaweedFSをセットアップしたので、WebUIからサービスを追加できる、/mnt/seaweedfsに設定ファイルを保存できるという想定で進めます。

## 1 SwarmPromをよく読む
https://github.com/stefanprodan/swarmprom

かなり古くてアーカイブまでされてしまっていますが、今でも参考になるプロジェクトです。ARMには対応していないので対応するイメージを多少探す必要がありますが、まずはこれを読みましょう。

### node-exporterの独自イメージ
https://github.com/stefanprodan/swarmprom/blob/master/node-exporter/conf/docker-entrypoint.sh

DockerSwarm内で動かすと、(SeaweedFSを導入する時に困ったのと同様に) 1サービスの各ノードで動かすコンテナそれぞれに対して同じ環境変数しか渡せないという課題があります。そのため、普通に渡すと各ノードのnode-exporterの名前が全て同じになってしまい、うまく可視化できなくなってしまいます。SeaweedFSのSwarm構成で私がやろうとしたように、ノードそれぞれを別サービスにして1台ずつ環境変数を渡して動かすこともできますが、設定が非常に不格好になります。そこで、このイメージにはホスト名をコンテナ起動時のShellで読み出し、設定ファイルに書き込むことで解決をしているようでした。今回は同様の措置をやっている[4ヶ月前の野良ビルド](https://hub.docker.com/r/dakotairene/swarmprom-node-exporter/)をお借りしました。(プロダクションではちゃんと自分でビルドしましょう)

### grafanaの独自イメージ
https://github.com/stefanprodan/swarmprom/blob/master/grafana/Dockerfile

このイメージは単にはじめからSwarm用のダッシュボードを入れているだけのようです。最新のgrafanaのコンテナのボリュームとして、ここにあるダッシュボード群をマウントすれば代用可能です。DockerHubの公式イメージを見たところ、ARM64(v8)/ARMv7に対応しているようだったので最新版イメージをそのまま使うことができます。

### prometheusの独自イメージ
https://github.com/stefanprodan/swarmprom/blob/master/prometheus/Dockerfile

このイメージは単にはじめからPrometheus用の設定ファイルを入れているだけのようです。最新のprometheusのコンテナのボリュームとして、ここにある設定ファイル群をマウントすれば代用可能です。DockerHubの公式イメージを見たところ、ARM64(v8)/ARMv7に対応しているようだったので最新版イメージをそのまま使うことができます。

### cadvisor
https://github.com/stefanprodan/swarmprom/blob/master/docker-compose.yml

SwarmPromでは公式イメージをそのまま使っています。ARM用ビルドがなかったので、[このIssue](https://github.com/google/cadvisor/issues/1236)を見て、一番新しそうな[5ヶ月前の野良ビルド](https://hub.docker.com/r/zcube/cadvisor)をお借りしました。(プロダクションではちゃんと自分でビルドしましょう)

### caddy
https://caddyserver.com/

caddyはGo製のWebサーバーの一種です。各ページのアクセスにBASIC認証をかけるために入れているようですが、今回はひとまず省略します。

### alertmanager
https://prometheus.io/docs/alerting/latest/alertmanager/

負荷が高くなってもうヤバいってなったときにSlackなどに通知するやつです。今回は最低限で組みたいので省略します。(後日 [LINE-Notifyとかさせる](https://github.com/be99inner/line-notify-gateway)やつ使いたいな)

### unsee
https://github.com/cloudflare/unsee

アラート履歴をWeb上で見れるようにするもののようですが、3年前で更新が止まっています。フォークを追った感じだと、今は [karma](https://github.com/prymitive/karma)っていうのが使われているらしい?です。alertmanagerが無いので、どちらにせよ導入しないことにします。


## 2 下記ymlをデプロイする
ということで現時点で最新の野良イメージなどを入れたものがこちらになります

```shell:monitor-swarm.yml
version: "3.4"

services:
  cadvisor:
    image: zcube/cadvisor:v0.37.5
    command: -logtostderr
    networks:
      - monitoring
    volumes:
      - /:/rootfs:ro
      - /sys:/sys:ro
      - /var/run:/var/run:rw
      - /var/lib/docker/:/var/lib/docker:ro
    deploy:
      mode: global
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      restart_policy:
        condition: on-failure
  node-exporter:
    image: dakotairene/swarmprom-node-exporter:latest
    networks:
      - monitoring
    environment:
      - NODE_ID={{.Node.ID}}
      - HOST_HOSTNAME=/etc/nodename
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/host/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.textfile.directory=/etc/node-exporter/'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
      - '--no-collector.ipvs'
    volumes:
      - /:/host/rootfs
      - /proc:/host/proc
      - /sys:/host/sys
      - /etc/hostname:/etc/nodename
    deploy:
      mode: global
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      restart_policy:
        condition: on-failure
  prometheus:
    image: prom/prometheus:v2.28.1
    networks:
      - monitoring
    ports:
      - '9054:9090'
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
    volumes:
      - /:/rootfs:ro
      - /sys:/sys:ro
      - /var/run:/var/run:rw
      - /var/lib/docker/:/var/lib/docker:ro
      - /mnt/seaweedfs/prometheus/volume:/prometheus
      - /mnt/seaweedfs/prometheus/config:/etc/prometheus
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      resources:
        limits:
          memory: 2048M
        reservations:
          memory: 128M
  grafana:
    image: grafana/grafana:7.5.10
    ports:
      - '9055:3000'
    networks:
      - monitoring
    environment:
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning/
      - GF_SECURITY_ADMIN_USER=grafana-admin
      - GF_SECURITY_ADMIN_PASSWORD=grafana-password-admin
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - GrafanaVolume:/var/lib/grafana
      - /mnt/seaweedfs/grafana/datasources:/etc/grafana/provisioning/datasources
      - /mnt/seaweedfs/grafana/swarmprom_dashboards.yml:/etc/grafana/provisioning/dashboards/swarmprom_dashboards.yml:ro
      - /mnt/seaweedfs/grafana/dashboards:/etc/grafana/dashboards
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
networks:
  monitoring:
    driver: overlay
    attachable: true
volumes:
  GrafanaVolume:
    driver: local
```

## 2.5 デプロイ
(Portainerから 放り込むだけなので省略)

## 3 起動後に画面を開いてみる
わーかっこいー!(小学生並の感想)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/0b6f1abc-3096-7bf5-c71b-7f8e874f7892.png)

## 完走した感想
激寒ギャグ

### SeaweedFSくんが思ったよりよくないかもしれない
自分でDockerイメージ作るのが面倒なので全設定ファイルを/mnt/seaweedfsに置いたのですが、Traefikでもやらかしたように、読み書きがそこそこ発生するファイルでは NULに化けたりしてなんだかんだファイルが壊れました。(そこで /var/lib/grafanaは マウントせずにVolumeになっている) 読み取り専用のものを置く分には問題ないんですが、なかなか厄介な子みたいです。

### 温度表示がない
ラズパイの熱暴走が怖いので、温度が表示できることを期待して導入したのですが どうやら cAdvisorでは取ってこれない様子です。(ダッシュボードをカスタマイズして node_thermal_zone_temp を出そうとするも取得できなかった) 別途温度情報を出せるエクスポーターの追加が要りそうです。

## 参考
https://knowledge.sakura.ad.jp/27501/

https://qiita.com/MetricFire/items/4aa2d9889c49148a3d7f

https://dockerlabs.collabnix.com/play-with-docker/docker-prometheus-swarm/

https://github.com/stefanprodan/swarmprom

https://www.codenotary.com/blog/docker-swarm-monitoring/

https://github.com/collabnix/dockerlabs/blob/master/play-with-docker/docker-prometheus-swarm/README.md

https://dockerswarm.rocks/swarmprom/

https://qiita.com/moritalous/items/f2c7243fca6aaa9a552a