
目次
はじめに
下記記事にあるようにThingsBoard Community Editionを利用して、IoTデバイスのセンサ情報をグラフ化していました。しかし、Community Editionでは、データのエクスポートができないなど不都合があるため、今回はInfluxDBにデータを格納し、そのデータをGrafanaでグラフ化してみます。
Grafanaのダッシュボードはつぎのような画面になります。

Dockerのインストール
システムの更新と依存関係のインストール
まず、パッケージリストを更新し、HTTPS経由でリポジトリを利用するために必要なパッケージをインストールします。
sudo apt update && sudo apt upgrade -y
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
Dockerの公式GPGキーを追加
Dockerパッケージの信頼性を検証するために、公式のGPGキーを追加します。
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Dockerリポジトリを設定
APTパッケージマネージャーにDockerの公式リポジトリを追加します。
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Docker Engineをインストール
リポジトリを追加した後、再度パッケージリストを更新し、Docker Community Edition(CE)をインストールします。
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y
sudo権限なしでDockerを実行できるようにする
sudo usermod -aG docker $USER
su - ${USER}
Dockerサービスの起動と有効化
インストール後、Dockerサービスを起動し、システムの起動時に自動で立ち上がるように設定します。
sudo systemctl enable --now docker
インストールの確認
最後に、Dockerが正常に動作しているか確認します。
sudo systemctl status docker
各種設定
ディレクトリ構成
project-root/
├─ docker-compose.yml
├─ .env
├─ nginx/
│ └─ nginx.conf
├─ telegraf
│ └─ telegraf.conf
├─ certbot/
環境変数を定義(.env)
.envの内容は漏洩しないよう注意してください。
INFLUXDB_ADMIN_USER=admin
INFLUXDB_ADMIN_PASSWORD=任意のパスワード
INFLUXDB_ORG=任意のORG
INFLUXDB_BUCKET=任意のBUCKET
INFLUXDB_TOKEN=influxdbから取得したトークン(あとで取得)
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=任意のパスワード
DOMAIN=任意のドメイン
docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:1.27.5
container_name: nginx
depends_on:
- telegraf
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certbot/www:/var/www/certbot
- ./certbot/letsencrypt:/etc/letsencrypt
restart: unless-stopped
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./certbot/www:/var/www/certbot
- ./certbot/letsencrypt:/etc/letsencrypt
entrypoint: /bin/sh -c
influxdb:
image: influxdb:2.7
container_name: influxdb
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=${INFLUXDB_ADMIN_USER}
- DOCKER_INFLUXDB_INIT_PASSWORD=${INFLUXDB_ADMIN_PASSWORD}
- DOCKER_INFLUXDB_INIT_ORG=${INFLUXDB_ORG}
- DOCKER_INFLUXDB_INIT_BUCKET=${INFLUXDB_BUCKET}
volumes:
- influxdb-data:/var/lib/influxdb2
restart: unless-stopped
grafana:
image: grafana/grafana:11.4.0
container_name: grafana
environment:
- GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
- GF_SERVER_ROOT_URL=https://${DOMAIN}/grafana/
- GF_SERVER_SERVE_FROM_SUB_PATH=true
volumes:
- grafana-data:/var/lib/grafana
restart: unless-stopped
telegraf:
image: telegraf:1.27
container_name: telegraf
depends_on:
- influxdb
volumes:
- ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
environment:
- INFLUX_TOKEN=${INFLUXDB_TOKEN}
- INFLUXDB_ORG=${INFLUXDB_ORG}
- INFLUXDB_BUCKET=${INFLUXDB_BUCKET}
restart: unless-stopped
volumes:
influxdb-data:
external: true
grafana-data:
external: true
nginx/nginx.conf
load_module modules/ngx_http_js_module.so;
events {}
http {
js_path "/etc/nginx/njs/";
js_import telegraf_filter from telegraf_filter.js;
client_body_buffer_size 16k;
server {
listen 80;
server_name example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name example.com;
error_log /var/log/nginx/error.log info;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location /grafana/ {
proxy_pass http://grafana:(grafana用の任意のポート)/grafana/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /influxdb/ {
proxy_pass http://influxdb:(influxdb用の任意のポート)/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /telegraf/ {
proxy_pass http://telegraf:(telegraf用の任意のポート)/telegraf/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
IoTデバイスからのPOST例
今回はIoTデバイスに1nceのsimを利用しているため、センサーデータも1nceのCloudIntengrationからWebhookでPOSTします。
POSTされるJSONデータは次のようなデータです。
{
"payload": {
"type": "JSON",
"value": {
"humi": 61.197834,
"rain": 0,
"temp": 30.637064,
"press": 10.351074,
"deviceid": 1,
"lux": 0
}
},
"received": "xxxxx",
"id": "xxxxx",
"source": "UDP",
"type": "TELEMETRY_DATA",
"version": "1.0.0",
"device": {
"iccid": "xxxxx",
"ip": "xxxxx",
"imsi": "xxxxx"
}
}
telegraf/telegraf.conf
POSTされたJSONデータを解析し、InfluxDBにデータを格納する処理を行います。
tagについては、不要であれば削除してもよいです。
[agent]
interval = "10s"
omit_hostname = true
[[outputs.influxdb_v2]]
urls = ["http://influxdb:(influxdb用の任意のポート)"]
token = "${INFLUX_TOKEN}"
organization = "${INFLUXDB_ORG}"
bucket = "${INFLUXDB_BUCKET}"
[[inputs.http_listener_v2]]
service_address = ":(telegraf用の任意のポート)"
paths = ["/telegraf","/telegraf/"]
methods = ["POST"]
data_format = "json_v2"
[[inputs.http_listener_v2.json_v2]]
measurement_name = "telemetry_data" # measurement名は任意で
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.value.deviceid"
[[inputs.http_listener_v2.json_v2.field]]
path = "payload.value.humi"
[[inputs.http_listener_v2.json_v2.field]]
path = "payload.value.rain"
[[inputs.http_listener_v2.json_v2.field]]
path = "payload.value.temp"
[[inputs.http_listener_v2.json_v2.field]]
path = "payload.value.press"
[[inputs.http_listener_v2.json_v2.field]]
path = "payload.value.lux"
[[inputs.http_listener_v2.json_v2.field]]
path = "payload.received"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.device.iccid"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.device.ip"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.device.imsi"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.id"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.source"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.type"
[[inputs.http_listener_v2.json_v2.tag]]
path = "payload.version"
Dockerボリューム作成
sudo docker volume create grafana-data
sudo docker volume create influxdb-data
Docker compose起動
sudo docker compose down
sudo docker compose up -d
CertbotによるLet’s encrypt証明書取得・自動更新
初回証明書取得
nginxの443設定を一時的にコメントアウトし、80のみで起動
sudo docker compose restart nginx
別ターミナルで次のコマンドを実行
sudo docker compose run --rm --entrypoint '' certbot certbot certonly --webroot -w /var/www/certbot -d example.com
証明書取得後、nginx.confの443設定を有効化し、nginxを再起動
自動更新(cron例)cron例(毎週月曜3:30に実行)
crontab -eで次を編集
0 3 * * 1 cd /path/to/project-root && docker-compose run --rm certbot renew --webroot --webroot-path=/var/www/certbot && docker-compose exec nginx nginx -s reload
InfluxDB のtoken取得
取得したトークンを .envのINFLUXDB_TOKENに設定します。
sudo docker compose exec influxdb influx auth list
Grafanaの設定
- Grafanaの管理画面にログイン
https://example.com/grafana/
にブラウザでアクセスし、.env に設定したユーザー名・パスワードにてログインする。 - [Data Sources] → [Add data source] → [InfluxDB]を選択
- Query Languageで
Flux
選択 - URLに
http://influxdb:(influxdb用の任意のポート)
を指定 - InfluxDB Detailsに、Organization(任意のもの), Bucket(任意のもの), Token(上記で取得したトークン)を入力してSave & Test
- ダッシュボードやパネルを作成しグラフ表示
データのテスト送信
下記コマンドでデータを送信し、Grafanaからデータが閲覧できることを確認する。
curl -X POST "https://wohlcloud.com/telegraf/" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"type": "JSON",
"value": {
"humi": 61.197834,
"rain": 0,
"temp": 30.637064,
"press": 10.351074,
"deviceid": 1,
"lux": 0
}
},
"received": "xxxxx",
"id": "xxxxx",
"source": "UDP",
"type": "TELEMETRY_DATA",
"version": "1.0.0",
"device": {
"iccid": "xxxxx",
"ip": "xxxxx",
"imsi": "xxxxx"
}
}'
データの全削除
テストデータを削除する場合には、influxdbのbucketを削除し、再作成する。
docker exec -it influxdb influx bucket delete --name production --org wohlcloud --token influxdbのトークン
docker exec -it influxdb influx bucket create --name production --org wohlcloud --retention 0 --token influxdbのトークン
FAQ
-
なぜThingsBoard Community EditionからInfluxDB+Grafana構成に移行したのですか?
-
ThingsBoard Community Editionではデータのエクスポート機能が制限されているなどの不都合があったため、より柔軟なデータ管理・可視化を求めてInfluxDB+Grafanaへ移行しました。
-
docker-compose.ymlの主なサービス構成は?
-
nginx, certbot, influxdb, grafana, telegrafの5サービスで構成されています。
-
.envファイルにはどのような環境変数を設定しますか?
-
InfluxDBやGrafanaの管理ユーザー名・パスワード、組織名、バケット名、トークン、ドメイン名などを設定します。
-
IoTデバイスからのデータはどのように受信・格納されますか?
-
IoTデバイスからWebhookでPOSTされたJSONデータをTelegrafが受信し、指定のフィールド・タグを抽出してInfluxDBに格納します。
-
GrafanaでInfluxDBのデータソースを追加する際の設定方法は?
-
Data Source追加画面でInfluxDBを選択し、Fluxクエリ言語を指定、URL・Organization・Bucket・Token等を入力してSave & Testします。
-
nginxのリバースプロキシ設定のポイントは?
-
各サービス(grafana, influxdb, telegraf)ごとにlocationディレクティブでproxy_pass先を指定し、ヘッダー情報も適切に付与します。
-
Let’s Encrypt証明書の取得・自動更新はどのように行いますか?
-
初回はnginxの443設定を一時的に外し80番のみで起動後、certbotで証明書取得。その後443設定を戻し、cronで自動更新を設定します。
-
InfluxDBのトークンはどのように取得し、どこに設定しますか?
-
influx auth listコマンドで取得し、.envのINFLUXDB_TOKENに設定します。
-
GrafanaでIoTデータのグラフ化はどのように行いますか?
-
ダッシュボード作成画面でInfluxDBデータソースを選択し、必要なクエリを記述してパネルを作成します。
-
テストデータの送信方法は?
-
curlコマンドでJSON形式のデータを指定エンドポイント(/telegraf)にPOSTします。
-
データを全削除したい場合はどうすればよいですか?
-
influxdbのbucketを削除・再作成することで全データを消去できます。
-
Dockerボリュームの作成の目的は?
-
influxdb-data, grafana-dataのボリュームを作成し、データの永続化を確保します。