TelegrafをARMv6で使う
こんにちは。ナウア株式会社の柳です。
私たちは、測定装置とエッジAI端末を組み合わせた調査機器を屋外と屋内に置いて運用しています。
各端末の死活とシステムのメトリクスは、TelegrafでAWS IoT Coreに送っています。
手に入りやすいRaspberry Pi Zero W(以下、ラズパイ)も、軽いデータ取得などに使えるハードウェアです。
このラズパイに同じTelegrafを入れようとすると、公式の配布物が思いのほか大きいことが分かりました。
バイナリは260.3MBあり、ラズパイでの常駐メモリは121.4MBになるため、手軽には入れられません。
そこで、必要なプラグインだけを入れて自前でビルドしました。
ビルドには、Telegrafのリポジトリにあるcustom_builderを使います。
!
この記事のまとめ
送り直しや溜める量の上限といった障害時の動作を設定で指定できるため、端末からの送信にはTelegrafを使っています
custom_builderで必要なプラグインだけを入れると、バイナリは260.3MBから32.0MBに、常駐メモリは121.4MBから21.5MBに減りました
ARMv6向けには、custom_builder自体は手元のPC向けにビルドし、実行時にだけGOARCH=armとGOARMを渡します
背景
Telegrafは、InfluxDataが開発しているメトリクス収集のエージェントです。
CPUやディスクの値を集める入力と、InfluxDBやMQTTへ送る出力を、プラグインとして組み合わせて使います。
ラズパイのTelegrafにさせる仕事は、次の2つです。
ディスク、温度、稼働時間、ネットワークの送受信量、Telegraf自身のメモリを1分ごとに集める
集めた値を1つのJSONにまとめ、TLSで暗号化したMQTTでAWS IoT Coreに送る
一方、Raspberry Pi Zero Wのリソースは限られています。
項目
Raspberry Pi Zero W
CPU
ARMv6、1コア
メモリ
512MB(OSから使えるのは426MiB)
ストレージ
microSDカード
ラズパイにはデータ取得などの本来の仕事があるため、監視用の常駐プログラムにはリソースをなるべく使わせたくありません。
また、モバイル回線は速度制限がかかると下りの速度が大きく下がり、配布するファイルが大きいほど転送に時間がかかります。
この記事では、速度制限時の参考値として下り200kbpsで計算します。
Telegrafを使う理由
平常時に値を送るだけなら、MQTTのライブラリを使った数十行のスクリプトで十分です。
スクリプトとTelegrafの違いは、回線や送り先が不調なときの動作に表れます。
AWSのIoT Lensには、端末のソフトウェアが備えるべきこととして次の項目が挙がっています1。
切れたら自動でつなぎ直す。つなぎ直す間隔は指数的に延ばし、端末ごとに乱数でずらす
つながらない間は、送るべきデータを端末に溜める。使う容量に上限を設け、あふれたら古いものから上書きする
つながったら、溜めた分を送る
信頼性が試された標準のライブラリを使う
スクリプトで書く場合、つなぎ直しはMQTTのライブラリに任せられることが多いでしょう。
一方で、溜める量と捨て方や送れなかった分の扱いは、自分でコードを書いて組み立てます。
このコードは障害が起きたときにしか動かないため、試される機会が限られます。
Telegrafで対応する設定と動作は、次の表のとおりです。
障害時に必要なこと
Telegrafの設定と動作
切れたらつなぎ直す
MQTT出力が、初期設定で自動的につなぎ直す
送れなかった分を後で送る
書き込みに失敗したメトリクスをバッファに残し、次の送信で送り直す2
溜める量の上限と捨て方
metric_buffer_limitで上限を決める。あふれると古いものから上書きし、捨てた件数をログに出す32:1
電源が落ちても残す
実験的な機能のbuffer_strategy = "disk"で、ディスクに溜める3:1
多数の端末の送信を重ねない
flush_jitterで、送る時刻を乱数でずらす3:2
Telegrafはアプリとは別のプロセスで動くため、送信の仕組みをアプリの外に置けます。
アプリの中でMQTTの接続を持つと、再起動や更新のたびに接続が切れます。
retainedのメッセージやLWTのような終了時の後始末も、アプリ側の責任です。
送信を別のプロセスに分けておけば、アプリの不具合や再起動があっても送信は止まりません。
端末の種類が増えても、送り方を同じ書式の設定でそろえられます。
応答を待つ時間のような回線に合わせた調整も、どの端末でも同じ項目を直せば済みます。
送る値を足すときも、多くは入力プラグインを設定に1つ足すだけです。
送受信量の毎秒の値のように、前回の値との差を取る計算も集計プラグインで書けます。
弱点は、公式の配布物が大きく、小さな端末には入れにくいことです。
送る値が数個で増やす予定もなく、欠けても困らないのであれば、スクリプトで十分です。
ほかの選択肢との比較
ほかの選択肢も同じ条件で、2026年9月時点の公式の文書やソース、配布物を調べました4。
Zero Wの実機で動かしたのはTelegrafだけです。
候補
ARMv6向けの入手先
AWS IoT CoreへMQTTで送る
送れない間に溜める
Telegraf
公式のarmel版とarmhf版
MQTT出力
メモリに溜める。ディスクは実験的な機能。あふれると古い方から上書き
スクリプトとMosquittoのブリッジ
Raspberry Pi OSのapt
ブリッジで転送
local_cleansession falseのときだけ溜める。あふれると新しく来た方を捨てる
Vector
名前がARMv6向けの配布物はあるが、中身はARMv7向けで、本体は134.7MB
mqtt sink。beta版で、送達はbest effort
メモリかディスク。ディスクは最小約256MiB。あふれると待つか、新しく来た方を捨てる
Fluent Bit
公式のRaspberry Pi OS向けのリポジトリ。bookwormまで
MQTTの出力が無い
ディスクに溜め、上限を超えると古い方から捨てる
collectd
Raspberry Pi OSのapt
mqttプラグイン。リリース版は独自の形式で送り、JSONにできない
溜めない
AWS IoT Device Client
無い。対応の一覧にarmv6lが無い
できる。集めるのは通信量や接続の値だけ
文書に記述なし
あふれたときに捨てるデータも、ツールによって違いました。
IoT Lensが勧める「古いものから上書き」になるのは、この中ではTelegrafとFluent Bitです。
MosquittoとVectorは、新しく来た方を捨てます。
Mosquittoのブリッジは、local_cleansessionがtrueだと、切断中のメッセージを捨てます。
local_cleansessionを書かなければ、cleansessionと同じ値が使われる仕様です。
AWSのブログにあるブリッジの設定例は、cleansession trueです5。
この設定例のまま使うと、切断中のメッセージは届きません。
AWS IoT Greengrassは、Java版と軽量版のnucleus liteのどちらも、armv6lに対応していません6。
AWSの文書には、端末の値をAWS IoTにMQTTで送るエージェントとして、次の3つが挙がっています7。
AWS IoT Device Client
osqueryとMQTTクライアントの組み合わせ
TelegrafのMQTT出力
全部入りのTelegraf
Telegrafは、ARM向けにarmelとarmhf、arm64の版を配布しています。
まずarmel版のv1.35.1を、そのままラズパイに入れました。
動作はしますが、telegraf --versionを表示するだけで7.8秒かかりました。
大きさの理由は、起動時のログから分かります。
ログの時刻は省いています。
I! Starting Telegraf 1.35.1 brought to you by InfluxData the makers of InfluxDB
I! Available plugins: 238 inputs, 9 aggregators, 34 processors, 26 parsers, 65 outputs, 6 secret-stores
ログに出ているとおり、入力のプラグインだけでも238個です。
TelegrafはGoで書かれており、依存するライブラリも含めて静的にリンクされます。
そのため、Kafkaのクライアントや各クラウドのSDKのように、使わないプラグインが依存するものもバイナリに入ります。
項目
全部入り(公式のarmel版)
バイナリ
260.3MB(配布のtar.gzは69.9MB)
常駐メモリ(RSS)
121.4MB
常駐メモリは、OSから使えるメモリの27%にあたる量でした。
custom_builderの仕組み
Telegrafのリポジトリには、tools/custom_builderというツールが入っています8。
custom_builderに設定ファイルを渡すと、使っているプラグインだけでTelegrafをビルドできます。
プラグインの選び分けには、Goのビルドタグを使う仕組みです。
--dry-runと--tagsを付けると、ビルドせずに選ばれるプラグインだけを確認できます。
今回の設定ファイルでの結果は、次のとおりです。
ログの時刻は省いています。
$ /tmp/custom_builder --config build.conf --tags --dry-run
I! Importing configuration file(s)...
I! Found 1 configuration files...
-------------------------------------------------------------------------------
Enabled plugins:
-------------------------------------------------------------------------------
aggregators (1):
derivative plugins/aggregators/derivative
-------------------------------------------------------------------------------
inputs (5):
disk plugins/inputs/disk
net plugins/inputs/net
procstat plugins/inputs/procstat
system plugins/inputs/system
temp plugins/inputs/temp
-------------------------------------------------------------------------------
outputs (1):
mqtt plugins/outputs/mqtt
-------------------------------------------------------------------------------
parsers (0):
-------------------------------------------------------------------------------
processors (0):
-------------------------------------------------------------------------------
secretstores (0):
-------------------------------------------------------------------------------
serializers (1):
json plugins/serializers/json
-------------------------------------------------------------------------------
Build tags: custom,aggregators.derivative,inputs.disk,inputs.net,inputs.procstat,inputs.system,inputs.temp,outputs.mqtt,serializers.json
I! DRY-RUN: Skipping build.
設定ファイルのdata_format = "json"の行から、JSONのシリアライザーも選ばれています。
READMEには、使うパーサーとシリアライザーが一覧に入っているかを確かめるよう書かれています8:1。
ビルドの際、custom_builderはTelegrafのMakefileを呼び出します。
Makefileの中で実行されるgo buildは、次のとおりです。
CGO_ENABLED=0 go build -tags "custom,aggregators.derivative,inputs.disk,inputs.net,inputs.procstat,inputs.system,inputs.temp,outputs.mqtt,serializers.json" -ldflags " -X github.com/influxdata/telegraf/internal.Commit=f9ce32be -X github.com/influxdata/telegraf/internal.Branch=HEAD -X github.com/influxdata/telegraf/internal.Version=1.35.1" ./cmd/telegraf
設定ファイルの全体は、後半の「AWS IoT Coreに送る設定」に載せました。
ARMv6向けのクロスコンパイル
ビルドはx86_64の手元のPCで行い、できたバイナリをラズパイへコピーします。
このとき、ARM向けの環境変数を渡す場所に注意が必要です。
custom_builderは、手元のPCの上で動くGoのプログラムです。
GOARCH=armを設定したままcustom_builderをビルドすると、ARM向けのバイナリができます。
このバイナリは、手元のPCでは実行できません。
golang:1.24のコンテナで試した結果は、次のとおりです。
$ GOOS=linux GOARCH=arm GOARM=5 go build -o /tmp/custom_builder ./tools/custom_builder
$ /tmp/custom_builder --config build.conf
sh: 1: /tmp/custom_builder: Exec format error
そこで、ビルドを2段階に分けます。
custom_builderは、ARM向けの環境変数を設定せずに手元のPC向けにビルドする
custom_builderを実行するときにだけ、GOOSとGOARCH、GOARMを渡す
custom_builderは、自分の環境変数にBUILDTAGSを加えてmakeを呼び出します。
そのため、2段目で渡した値は中のgo buildまで届く仕組みです。
READMEの手順どおりmake build_toolsで作る場合は、この問題は起きません。
MakefileがGOOSとGOARCH、GOARMを外してからgo buildするためです9。
注意が必要なのは、custom_builderだけをgo buildで作る場合です。
GOARMは、ARMのどの世代向けにビルドするかを決める環境変数で、5から7のいずれかを指定します10。
クロスコンパイルで省くとARMv7向けの7になるため、ARMv6のラズパイ向けには値を明示します。
5は浮動小数点の計算をソフトウェアで行い、6と7はハードウェアで行います。
Telegrafの公式の配布物は、armel版がGOARM=5、armhf版がGOARM=6でビルドされています9:1。
今回は、ラズパイでの動作を確認したarmel版に合わせて5を選びました。
実際に使っているスクリプトは、次のとおりです。
Goは、公式のDockerイメージに含まれるものを使います。
build.sh
#!/bin/sh
使うプラグインだけの Telegraf を ARMv6(Raspberry Pi Zero と Zero W)向けに作る
set -eu
git clone --depth 1 --branch v1.35.1 influxdata/telegraf src
cp telegraf.conf src/build.conf
docker run --rm -v "$PWD/src:/src" -w /src -e HOME=/tmp \
--user "$(id -u):$(id -g)" golang:1.24 sh -ec '
1段目: custom_builder はこの PC 向けに作る
go build -o /tmp/custom_builder ./tools/custom_builder
2段目: custom_builder から呼ばれる Telegraf のビルドだけを ARMv6 向けにする
GOOS=linux GOARCH=arm GOARM=5 /tmp/custom_builder --config /src/build.conf'
ls -l src/telegraf
私たちのPCでは、cloneを含めて約20秒でビルドが終わりました。
$ file src/telegraf
src/telegraf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=10cc34f12e15cb0226e198d2e2fd34f59e92ac71, with debug_info, not stripped
静的にリンクされているため、ラズパイ側にGoや追加のライブラリは不要です。
大きさとメモリ
必要なプラグインだけの版を起動したときのログは、次のとおりです。
このログは、手元のPC向けに同じ設定でビルドした版で取りました。
I! Starting Telegraf 1.35.1 (customized) brought to you by InfluxData the makers of InfluxDB
I! Available plugins: 5 inputs, 1 aggregators, 0 processors, 1 parsers, 1 outputs, 0 secret-stores
全部入りの版との比較は、次の表のとおりです。
項目
全部入り(公式のarmel版)
使うプラグインだけ
入っているプラグイン
入力238、集計9、加工34、パーサー26、出力65、シークレットストア6
入力5、集計1、パーサー1、出力1
バイナリ
260.3MB
32.0MB
圧縮したとき
69.9MB(tar.gz)
15.4MB(gzip -9)
下り200kbpsで送る時間(計算値)
約47分
約10分
常駐メモリ(RSS)
121.4MB
21.5MB
常駐メモリは、ラズパイで同じ設定ファイルを使い、systemdのサービスとして動かしたときにpsで見た値です11。
Goのプログラムは、リンクされたパッケージの初期化処理を起動時にすべて実行します。
そのため、使わないプラグインの分も初期化でメモリを使っていると考えられます。
公式の配布物は、リンカーのオプション-w -sでデバッグ情報とシンボル表を削除しています9:2。
一方、上のfileの出力のとおり、今回のバイナリにはデバッグ情報が残っています。
2段目の環境変数にLDFLAGS="-w -s"を加えると、Makefileがリンカーのオプションに反映します。
その結果、バイナリは22.3MBまで小さくなり、gzip -9で圧縮すると7.9MBでした。
パーサーが1つ入っているのは、依存関係で自動的に入ったCSVのパーサーのためです。
READMEにも、依存関係で一覧に出ないプラグインが入る場合があると書かれています8:2。
スクリプトとも比べました。
送る値をそろえるため、入力をdiskとtemp、systemの3つに絞ったTelegrafを用意しました。
比べたのは、同じ項目を同じ形のJSONで送る、MQTTのライブラリを使ったPythonのスクリプトです。
ラズパイでの常駐メモリはTelegrafが20.3MB、スクリプトが20.1MBで、ほぼ同じでした12。
常駐メモリの点ではTelegrafの弱点がなくなり、残るのは32.0MBある配布ファイルの大きさです。
AWS IoT Coreに送る設定
ラズパイで使っている設定を、記事用に整理したものを載せます。
送り先、証明書のパス、JSONのキーは置き換えました。
この1つのファイルを、custom_builderとラズパイのTelegrafの両方に渡します。
telegraf.conf
[agent]
interval = "60s"
round_interval = true
flush_interval = "60s"
omit_hostname = true
回線が戻ったときに、溜まった分を一度に送らない
metric_batch_size = 60
metric_buffer_limit = 120
[[inputs.disk]]
mount_points = ["/"]
[[inputs.temp]]
[[inputs.system]]
[[inputs.net]]
interfaces = ["eth0"]
ignore_protocol_stats = true
Telegraf 自身のメモリ(実行ファイルの名前で探す)
[[inputs.procstat]]
exe = "telegraf-slim"
net の累積バイト数から毎秒の値を作る
[[aggregators.derivative]]
namepass = ["net"]
period = "60s"
drop_original = false
suffix = "_per_sec"
[[outputs.mqtt]]
servers = ["ssl://xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com:8883"]
client_id = "device-0001-telegraf"
topic = "devices/device-0001/health"
qos = 1
keep_alive = 30
tls_ca = "/etc/telegraf/AmazonRootCA1.pem"
tls_cert = "/etc/telegraf/device.pem.crt"
tls_key = "/etc/telegraf/private.pem.key"
data_format = "json"
layout = "batch"
json_transformation = '''
(
$d := metrics[name="disk"];
$t := metrics[name="temp"];
$s := metrics[name="system"];
$p := metrics[name="procstat"];
$n := metrics[name="net" and $exists(fields.bytes_sent_per_sec)];
{
"ts": $max(metrics.timestamp),
"uptime_s": $s.fields.uptime,
"disk_free_gib": $round($d.fields.free / 1073741824, 2),
"disk_used_pct": $round($d.fields.used_percent, 1),
"temp_c": $max($t.fields.temp),
"rss_mib": $round($max($p.fields.memory_rss) / 1048576, 1),
"tx_kbps": $round($sum($n.fields.bytes_sent_per_sec) * 8 / 1000, 1),
"rx_kbps": $round($sum($n.fields.bytes_recv_per_sec) * 8 / 1000, 1)
}
)
'''
QoS
AWS IoT Coreが対応しているMQTTのQoSは0と1だけで、QoS 2には対応していません13。
TelegrafのMQTT出力のサンプル設定では、qosの行が# qos = 2になっています。
コードの初期値は0です。
サンプルのコメントを外すだけではAWS IoT Coreに合わないため、qos = 1を明示しました。
client_id
AWS IoT Coreでは、すでに使われているclient_idで新しく接続すると、先に接続していた側が切断されます14。
このときの切断理由はDUPLICATE_CLIENTIDです。
同じ端末の別のプログラムが同じclient_idを使うと、互いに相手の接続を切断します。
どちらも自動で再接続する作りなら、この切断が繰り返されます。
私たちは、Telegrafのclient_idの末尾に-telegrafを付けて区別しました。
メッセージのまとめ方
MQTT出力のlayoutの初期値はnon-batchです。
この設定では、メトリクス1つごとに1つのメッセージが送られます。
今回の設定は入力が5つあるため、1分ごとに少なくとも5つのメッセージが別々に届きます。
layout = "batch"では、同じトピックに送るメトリクスを1つのメッセージにまとめて送ります15。
メトリクスは、JSONのmetricsという配列に入る形です。
v1.25.2で非推奨になったbatch = trueは、v1.35.1では起動時のエラーになります。
E! DeprecationError: Option "batch" of plugin "outputs.mqtt" deprecated since version 1.25.2 and will be removed in 1.35.0: use 'layout = "batch"' instead
E! loading config file telegraf.conf failed: error parsing mqtt array, plugin options "batch" deprecated
JSONの形
TelegrafのJSONは、メトリクスごとの入れ子の形です。
1つのメトリクスは、nameとtagsとfieldsとtimestampのキーを持ちます。
受け手が平らなJSONを求める場合は、json_transformationにJSONataの式を書きます15:1。
layout = "batch"のときは、式に{"metrics": [...]}の形のJSONが渡されます。
そのため、metrics[name="disk"]のようにしてメトリクスを取り出します。
Telegrafが使っているJSONataは1.5.4です。
JSONataの試し場で式を試すときは、そのバージョンを選んでください15:2。
手元のPCで、送り先を手元のMQTTブローカーに替えて動かしました。
届いたメッセージは次のとおりで、値はPCのものです。
{"disk_free_gib":20.71,"disk_used_pct":97.7,"rss_mib":24.6,"rx_kbps":63.3,"temp_c":62,"ts":1790658710,"tx_kbps":40.9,"uptime_s":441385}
起動してしばらくの間は、tx_kbpsとrx_kbpsが含まれません。
aggregators.derivativeは2つの時点の値の差から毎秒の値を計算するため、最初のうちは値を出しません。
JSONataは値の無いキーを出力しないため、この2つのキーはメッセージに含まれません。
設定を変えるとき
この設定ファイルはビルドの設定も兼ねているため、プラグインを足したらビルドし直してください。
ビルドに入っていないプラグインを設定に書くと、Telegrafは起動しません。
outputs.fileの無いバイナリにoutputs.fileを書いた設定を渡すと、次のエラーで止まります。
E! loading config file telegraf.conf failed: error parsing file array, undefined but requested output: file
プラグインの種類を間違えた場合は、custom_builderがビルドの前に止まります。
たとえばderivativeはaggregatorsにあり、processorsにはありません。
I! filtering packages failed: configured but unknown packages "processors.derivative"
このメッセージには、情報を表すI!の印が付いています。
それでもcustom_builderは終了コード1で終わり、バイナリは作られません。
ビルドのスクリプトでは、set -eなどで終了コードを確認して止まるようにしてください。
JSONataの式を調整するときは、同じ設定ファイルで手元のPC向けのバイナリも作ると、すぐに試せます。
custom_builderをGOOSやGOARCHなしで実行すれば、手元のPCで動く版ができます。
送り先を手元のMQTTブローカーに替えれば、ビルドに入っているプラグインのまま、届くJSONの確認が可能です。
形が決まってからARM向けをビルドしてラズパイへ転送すれば、遅い回線での転送は1回で済みます。
まとめ
端末から送る仕組みで差が出るのは障害時の動作で、Telegrafは障害時の動作を設定で指定できます
custom_builderで必要なプラグインだけを入れると、バイナリは260.3MBから32.0MBに、常駐メモリは121.4MBから21.5MBに減りました
ARMv6向けには、custom_builderを手元のPC向けにビルドし、実行時にだけGOOS=linux GOARCH=arm GOARM=5を渡します
AWS IoT Coreに送るときは、QoSを1にし、client_idを端末のほかの接続と分けます
脚注
AWS Well-Architected Framework IoT LensのFailure managementのIOTREL10、IOTREL11、IOTREL12です。標準のライブラリの例として挙げられているのはFreeRTOSやAWSのSDKで、Telegrafは含まれていません。 ↩︎
Telegrafの出力を受け持つ処理(models/running_output.go)では、書き込みに失敗したメトリクスが次の書き込みのために残ります。バッファがあふれて捨てたときは、その件数が警告のログに出ます。 ↩︎ ↩︎
Telegrafの設定のドキュメントのagentの節です。 ↩︎ ↩︎ ↩︎
調べた版と資料は次のとおりです。Mosquittoは、mosquitto.confの説明と、v2.0.21のソースで確かめました。ソースはsrc/database.cとsrc/bridge.cです。溜める上限のmax_queued_messagesの初期値は1000件です。Vectorは、v0.58.0のmqtt sinkとバッファの説明を読みました。arm-unknown-linux-musleabi版の本体のELFの属性も見ています。属性はTag_CPU_archがv7で、NEONも含まれていました。Fluent Bitは、v5.1.2のプラグインの一覧でMQTTが入力だけであることを確認しました。バッファの扱いは、バッファの説明によります。collectdは、2020年9月の5.12.0のsrc/collectd.conf.podとsrc/mqtt.cです。AWS IoT Device Clientは、READMEと2025年5月のv1.10.1を参照しています。 ↩︎
How to Bridge Mosquitto MQTT Broker to AWS IoTの、2020年5月の更新版を参照しました。 ↩︎
Greengrass nucleusの説明と、nucleus liteのセットアップの文書です。Java版の文書では、一覧に無い環境について、動くかもしれないが試験はしていないとしています。 ↩︎
AWS IoT Device Defender detect feature availability changeです。Device DefenderのDetect機能は、2026年8月31日から新規の顧客に提供されなくなりました。この文書はそれに合わせたもので、想定しているのは待ち受けポートや通信量などのセキュリティ向けの値です。 ↩︎
custom_builderのREADMEを参照しました。 ↩︎ ↩︎ ↩︎
TelegrafのMakefileによると、build_toolsはenv -u GOOS -u GOARCH -u GOARM -- go buildで作られます。配布物はarmel版がGOARM := 5、armhf版がGOARM := 6で、リンカーのオプションは-w -sです。 ↩︎ ↩︎ ↩︎
go help environmentのGOARMの項に書かれています。goコマンドのドキュメントでも読めます。 ↩︎
常駐メモリは、確認用にoutputs.fileも加えてビルドした版で測りました。設定はJSONのキーなどが記事のものと少し異なりますが、入力と集計のプラグインは同じです。MBは1,000,000バイトとし、psの値(KiB)から換算しています。 ↩︎
スクリプトは起動から約20秒後、Telegrafは約80秒後にpsで見た値でした。 ↩︎
AWS IoT CoreのMQTTのドキュメントに、QoS 2が要求されてもブローカーはPUBACKやSUBACKを返さないと書かれています。 ↩︎
AWS IoT Coreのライフサイクルイベントのドキュメントにある、切断理由の表を参照しました。 ↩︎
JSONシリアライザーのREADMEです。バッチのときにmetricsという配列が付くことと、JSONataが1.5.4に限られることが書かれています。 ↩︎ ↩︎ ↩︎
Mentions
TelegrafをARMv6で使う こんにちは。ナウア株式会社の柳です。 私たちは、測定装置とエッジAI端末を組み合わせた調査機器を屋外と屋内に置いて運用しています。 各端末の死活とシステムのメトリクスは、TelegrafでAWS IoT Coreに送っています。 手に入りやすいRaspberry Pi Zero W(以下、ラズパイ)も、軽いデータ取得などに使えるハードウェアです。 このラズパイに同じTelegrafを入れようとすると、公式の配布物が思いのほか大きいことが分かりました。 バイナリは260.3MBあり、ラズパイでの常駐メモリは121.4MBになるため、手軽には入れられません。 そこで、必要なプラグインだけを入れて自前でビルドしました。 ビルドには、Telegrafのリポジトリにあるcustom_builderを使います。 ! この記事のまとめ 送り直しや溜める量の上限といった障害時の動作を設定で指定できるため、端末からの送信にはTelegrafを使っています custom_builderで必要なプラグインだけを入れると、バイナリは260.3MBから32.0MBに、常駐メモリは121.4MBから21.5MBに減りました ARMv6向けには、custom_builder自体は手元のPC向けにビルドし、実行時にだけGOARCH=armとGOARMを渡します 背景 Telegrafは、InfluxDataが開発しているメトリクス収集のエージェントです。 CPUやディスクの値を集める入力と、InfluxDBやMQTTへ送る出力を、プラグインとして組み合わせて使います。 ラズパイのTelegrafにさせる仕事は、次の2つです。 ディスク、温度、稼働時間、ネットワークの送受信量、Telegraf自身のメモリを1分ごとに集める 集めた値を1つのJSONにまとめ、TLSで暗号化したMQTTでAWS IoT Coreに送る 一方、Raspberry Pi Zero Wのリソースは限られています。 項目 Raspberry Pi Zero W CPU ARMv6、1コア メモリ 512MB(OSから使えるのは426MiB) ストレージ microSDカード ラズパイにはデータ取得などの本来の仕事があるため、監視用の常駐プログラムにはリソースをなるべく使わせたくありません。 また、モバイル回線は速度制限がかかると下りの速度が大きく下がり、配布するファイルが大きいほど転送に時間がかかります。 この記事では、速度制限時の参考値として下り200kbpsで計算します。 Telegrafを使う理由 平常時に値を送るだけなら、MQTTのライブラリを使った数十行のスクリプトで十分です。 スクリプトとTelegrafの違いは、回線や送り先が不調なときの動作に表れます。 AWSのIoT Lensには、端末のソフトウェアが備えるべきこととして次の項目が挙がっています1。 切れたら自動でつなぎ直す。つなぎ直す間隔は指数的に延ばし、端末ごとに乱数でずらす つながらない間は、送るべきデータを端末に溜める。使う容量に上限を設け、あふれたら古いものから上書きする つながったら、溜めた分を送る 信頼性が試された標準のライブラリを使う スクリプトで書く場合、つなぎ直しはMQTTのライブラリに任せられることが多いでしょう。 一方で、溜める量と捨て方や送れなかった分の扱いは、自分でコードを書いて組み立てます。 このコードは障害が起きたときにしか動かないため、試される機会が限られます。 Telegrafで対応する設定と動作は、次の表のとおりです。 障害時に必要なこと Telegrafの設定と動作 切れたらつなぎ直す MQTT出力が、初期設定で自動的につなぎ直す 送れなかった分を後で送る 書き込みに失敗したメトリクスをバッファに残し、次の送信で送り直す2 溜める量の上限と捨て方 metric_buffer_limitで上限を決める。あふれると古いものから上書きし、捨てた件数をログに出す32:1 電源が落ちても残す 実験的な機能のbuffer_strategy = "disk"で、ディスクに溜める3:1 多数の端末の送信を重ねない flush_jitterで、送る時刻を乱数でずらす3:2 Telegrafはアプリとは別のプロセスで動くため、送信の仕組みをアプリの外に置けます。 アプリの中でMQTTの接続を持つと、再起動や更新のたびに接続が切れます。 retainedのメッセージやLWTのような終了時の後始末も、アプリ側の責任です。 送信を別のプロセスに分けておけば、アプリの不具合や再起動があっても送信は止まりません。 端末の種類が増えても、送り方を同じ書式の設定でそろえられます。 応答を待つ時間のような回線に合わせた調整も、どの端末でも同じ項目を直せば済みます。 送る値を足すときも、多くは入力プラグインを設定に1つ足すだけです。 送受信量の毎秒の値のように、前回の値との差を取る計算も集計プラグインで書けます。 弱点は、公式の配布物が大きく、小さな端末には入れにくいことです。 送る値が数個で増やす予定もなく、欠けても困らないのであれば、スクリプトで十分です。 ほかの選択肢との比較 ほかの選択肢も同じ条件で、2026年9月時点の公式の文書やソース、配布物を調べました4。 Zero Wの実機で動かしたのはTelegrafだけです。 候補 ARMv6向けの入手先 AWS IoT CoreへMQTTで送る 送れない間に溜める Telegraf 公式のarmel版とarmhf版 MQTT出力 メモリに溜める。ディスクは実験的な機能。あふれると古い方から上書き スクリプトとMosquittoのブリッジ Raspberry Pi OSのapt ブリッジで転送 local_cleansession falseのときだけ溜める。あふれると新しく来た方を捨てる Vector 名前がARMv6向けの配布物はあるが、中身はARMv7向けで、本体は134.7MB mqtt sink。beta版で、送達はbest effort メモリかディスク。ディスクは最小約256MiB。あふれると待つか、新しく来た方を捨てる Fluent Bit 公式のRaspberry Pi OS向けのリポジトリ。bookwormまで MQTTの出力が無い ディスクに溜め、上限を超えると古い方から捨てる collectd Raspberry Pi OSのapt mqttプラグイン。リリース版は独自の形式で送り、JSONにできない 溜めない AWS IoT Device Client 無い。対応の一覧にarmv6lが無い できる。集めるのは通信量や接続の値だけ 文書に記述なし あふれたときに捨てるデータも、ツールによって違いました。 IoT Lensが勧める「古いものから上書き」になるのは、この中ではTelegrafとFluent Bitです。 MosquittoとVectorは、新しく来た方を捨てます。 Mosquittoのブリッジは、local_cleansessionがtrueだと、切断中のメッセージを捨てます。 local_cleansessionを書かなければ、cleansessionと同じ値が使われる仕様です。 AWSのブログにあるブリッジの設定例は、cleansession trueです5。 この設定例のまま使うと、切断中のメッセージは届きません。 AWS IoT Greengrassは、Java版と軽量版のnucleus liteのどちらも、armv6lに対応していません6。 AWSの文書には、端末の値をAWS IoTにMQTTで送るエージェントとして、次の3つが挙がっています7。 AWS IoT Device Client osqueryとMQTTクライアントの組み合わせ TelegrafのMQTT出力 全部入りのTelegraf Telegrafは、ARM向けにarmelとarmhf、arm64の版を配布しています。 まずarmel版のv1.35.1を、そのままラズパイに入れました。 動作はしますが、telegraf --versionを表示するだけで7.8秒かかりました。 大きさの理由は、起動時のログから分かります。 ログの時刻は省いています。 I! Starting Telegraf 1.35.1 brought to you by InfluxData the makers of InfluxDB I! Available plugins: 238 inputs, 9 aggregators, 34 processors, 26 parsers, 65 outputs, 6 secret-stores ログに出ているとおり、入力のプラグインだけでも238個です。 TelegrafはGoで書かれており、依存するライブラリも含めて静的にリンクされます。 そのため、Kafkaのクライアントや各クラウドのSDKのように、使わないプラグインが依存するものもバイナリに入ります。 項目 全部入り(公式のarmel版) バイナリ 260.3MB(配布のtar.gzは69.9MB) 常駐メモリ(RSS) 121.4MB 常駐メモリは、OSから使えるメモリの27%にあたる量でした。 custom_builderの仕組み Telegrafのリポジトリには、tools/custom_builderというツールが入っています8。 custom_builderに設定ファイルを渡すと、使っているプラグインだけでTelegrafをビルドできます。 プラグインの選び分けには、Goのビルドタグを使う仕組みです。 --dry-runと--tagsを付けると、ビルドせずに選ばれるプラグインだけを確認できます。 今回の設定ファイルでの結果は、次のとおりです。 ログの時刻は省いています。 $ /tmp/custom_builder --config build.conf --tags --dry-run I! Importing configuration file(s)... I! Found 1 configuration files... ------------------------------------------------------------------------------- Enabled plugins: ------------------------------------------------------------------------------- aggregators (1): derivative plugins/aggregators/derivative ------------------------------------------------------------------------------- inputs (5): disk plugins/inputs/disk net plugins/inputs/net procstat plugins/inputs/procstat system plugins/inputs/system temp plugins/inputs/temp ------------------------------------------------------------------------------- outputs (1): mqtt plugins/outputs/mqtt ------------------------------------------------------------------------------- parsers (0): ------------------------------------------------------------------------------- processors (0): ------------------------------------------------------------------------------- secretstores (0): ------------------------------------------------------------------------------- serializers (1): json plugins/serializers/json ------------------------------------------------------------------------------- Build tags: custom,aggregators.derivative,inputs.disk,inputs.net,inputs.procstat,inputs.system,inputs.temp,outputs.mqtt,serializers.json I! DRY-RUN: Skipping build. 設定ファイルのdata_format = "json"の行から、JSONのシリアライザーも選ばれています。 READMEには、使うパーサーとシリアライザーが一覧に入っているかを確かめるよう書かれています8:1。 ビルドの際、custom_builderはTelegrafのMakefileを呼び出します。 Makefileの中で実行されるgo buildは、次のとおりです。 CGO_ENABLED=0 go build -tags "custom,aggregators.derivative,inputs.disk,inputs.net,inputs.procstat,inputs.system,inputs.temp,outputs.mqtt,serializers.json" -ldflags " -X github.com/influxdata/telegraf/internal.Commit=f9ce32be -X github.com/influxdata/telegraf/internal.Branch=HEAD -X github.com/influxdata/telegraf/internal.Version=1.35.1" ./cmd/telegraf 設定ファイルの全体は、後半の「AWS IoT Coreに送る設定」に載せました。 ARMv6向けのクロスコンパイル ビルドはx86_64の手元のPCで行い、できたバイナリをラズパイへコピーします。 このとき、ARM向けの環境変数を渡す場所に注意が必要です。 custom_builderは、手元のPCの上で動くGoのプログラムです。 GOARCH=armを設定したままcustom_builderをビルドすると、ARM向けのバイナリができます。 このバイナリは、手元のPCでは実行できません。 golang:1.24のコンテナで試した結果は、次のとおりです。 $ GOOS=linux GOARCH=arm GOARM=5 go build -o /tmp/custom_builder ./tools/custom_builder $ /tmp/custom_builder --config build.conf sh: 1: /tmp/custom_builder: Exec format error そこで、ビルドを2段階に分けます。 custom_builderは、ARM向けの環境変数を設定せずに手元のPC向けにビルドする custom_builderを実行するときにだけ、GOOSとGOARCH、GOARMを渡す custom_builderは、自分の環境変数にBUILDTAGSを加えてmakeを呼び出します。 そのため、2段目で渡した値は中のgo buildまで届く仕組みです。 READMEの手順どおりmake build_toolsで作る場合は、この問題は起きません。 MakefileがGOOSとGOARCH、GOARMを外してからgo buildするためです9。 注意が必要なのは、custom_builderだけをgo buildで作る場合です。 GOARMは、ARMのどの世代向けにビルドするかを決める環境変数で、5から7のいずれかを指定します10。 クロスコンパイルで省くとARMv7向けの7になるため、ARMv6のラズパイ向けには値を明示します。 5は浮動小数点の計算をソフトウェアで行い、6と7はハードウェアで行います。 Telegrafの公式の配布物は、armel版がGOARM=5、armhf版がGOARM=6でビルドされています9:1。 今回は、ラズパイでの動作を確認したarmel版に合わせて5を選びました。 実際に使っているスクリプトは、次のとおりです。 Goは、公式のDockerイメージに含まれるものを使います。 build.sh #!/bin/sh 使うプラグインだけの Telegraf を ARMv6(Raspberry Pi Zero と Zero W)向けに作る set -eu git clone --depth 1 --branch v1.35.1 influxdata/telegraf src cp telegraf.conf src/build.conf docker run --rm -v "$PWD/src:/src" -w /src -e HOME=/tmp \ --user "$(id -u):$(id -g)" golang:1.24 sh -ec ' 1段目: custom_builder はこの PC 向けに作る go build -o /tmp/custom_builder ./tools/custom_builder 2段目: custom_builder から呼ばれる Telegraf のビルドだけを ARMv6 向けにする GOOS=linux GOARCH=arm GOARM=5 /tmp/custom_builder --config /src/build.conf' ls -l src/telegraf 私たちのPCでは、cloneを含めて約20秒でビルドが終わりました。 $ file src/telegraf src/telegraf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=10cc34f12e15cb0226e198d2e2fd34f59e92ac71, with debug_info, not stripped 静的にリンクされているため、ラズパイ側にGoや追加のライブラリは不要です。 大きさとメモリ 必要なプラグインだけの版を起動したときのログは、次のとおりです。 このログは、手元のPC向けに同じ設定でビルドした版で取りました。 I! Starting Telegraf 1.35.1 (customized) brought to you by InfluxData the makers of InfluxDB I! Available plugins: 5 inputs, 1 aggregators, 0 processors, 1 parsers, 1 outputs, 0 secret-stores 全部入りの版との比較は、次の表のとおりです。 項目 全部入り(公式のarmel版) 使うプラグインだけ 入っているプラグイン 入力238、集計9、加工34、パーサー26、出力65、シークレットストア6 入力5、集計1、パーサー1、出力1 バイナリ 260.3MB 32.0MB 圧縮したとき 69.9MB(tar.gz) 15.4MB(gzip -9) 下り200kbpsで送る時間(計算値) 約47分 約10分 常駐メモリ(RSS) 121.4MB 21.5MB 常駐メモリは、ラズパイで同じ設定ファイルを使い、systemdのサービスとして動かしたときにpsで見た値です11。 Goのプログラムは、リンクされたパッケージの初期化処理を起動時にすべて実行します。 そのため、使わないプラグインの分も初期化でメモリを使っていると考えられます。 公式の配布物は、リンカーのオプション-w -sでデバッグ情報とシンボル表を削除しています9:2。 一方、上のfileの出力のとおり、今回のバイナリにはデバッグ情報が残っています。 2段目の環境変数にLDFLAGS="-w -s"を加えると、Makefileがリンカーのオプションに反映します。 その結果、バイナリは22.3MBまで小さくなり、gzip -9で圧縮すると7.9MBでした。 パーサーが1つ入っているのは、依存関係で自動的に入ったCSVのパーサーのためです。 READMEにも、依存関係で一覧に出ないプラグインが入る場合があると書かれています8:2。 スクリプトとも比べました。 送る値をそろえるため、入力をdiskとtemp、systemの3つに絞ったTelegrafを用意しました。 比べたのは、同じ項目を同じ形のJSONで送る、MQTTのライブラリを使ったPythonのスクリプトです。 ラズパイでの常駐メモリはTelegrafが20.3MB、スクリプトが20.1MBで、ほぼ同じでした12。 常駐メモリの点ではTelegrafの弱点がなくなり、残るのは32.0MBある配布ファイルの大きさです。 AWS IoT Coreに送る設定 ラズパイで使っている設定を、記事用に整理したものを載せます。 送り先、証明書のパス、JSONのキーは置き換えました。 この1つのファイルを、custom_builderとラズパイのTelegrafの両方に渡します。 telegraf.conf [agent] interval = "60s" round_interval = true flush_interval = "60s" omit_hostname = true 回線が戻ったときに、溜まった分を一度に送らない metric_batch_size = 60 metric_buffer_limit = 120 [[inputs.disk]] mount_points = ["/"] [[inputs.temp]] [[inputs.system]] [[inputs.net]] interfaces = ["eth0"] ignore_protocol_stats = true Telegraf 自身のメモリ(実行ファイルの名前で探す) [[inputs.procstat]] exe = "telegraf-slim" net の累積バイト数から毎秒の値を作る [[aggregators.derivative]] namepass = ["net"] period = "60s" drop_original = false suffix = "_per_sec" [[outputs.mqtt]] servers = ["ssl://xxxxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com:8883"] client_id = "device-0001-telegraf" topic = "devices/device-0001/health" qos = 1 keep_alive = 30 tls_ca = "/etc/telegraf/AmazonRootCA1.pem" tls_cert = "/etc/telegraf/device.pem.crt" tls_key = "/etc/telegraf/private.pem.key" data_format = "json" layout = "batch" json_transformation = ''' ( $d := metrics[name="disk"]; $t := metrics[name="temp"]; $s := metrics[name="system"]; $p := metrics[name="procstat"]; $n := metrics[name="net" and $exists(fields.bytes_sent_per_sec)]; { "ts": $max(metrics.timestamp), "uptime_s": $s.fields.uptime, "disk_free_gib": $round($d.fields.free / 1073741824, 2), "disk_used_pct": $round($d.fields.used_percent, 1), "temp_c": $max($t.fields.temp), "rss_mib": $round($max($p.fields.memory_rss) / 1048576, 1), "tx_kbps": $round($sum($n.fields.bytes_sent_per_sec) * 8 / 1000, 1), "rx_kbps": $round($sum($n.fields.bytes_recv_per_sec) * 8 / 1000, 1) } ) ''' QoS AWS IoT Coreが対応しているMQTTのQoSは0と1だけで、QoS 2には対応していません13。 TelegrafのMQTT出力のサンプル設定では、qosの行が# qos = 2になっています。 コードの初期値は0です。 サンプルのコメントを外すだけではAWS IoT Coreに合わないため、qos = 1を明示しました。 client_id AWS IoT Coreでは、すでに使われているclient_idで新しく接続すると、先に接続していた側が切断されます14。 このときの切断理由はDUPLICATE_CLIENTIDです。 同じ端末の別のプログラムが同じclient_idを使うと、互いに相手の接続を切断します。 どちらも自動で再接続する作りなら、この切断が繰り返されます。 私たちは、Telegrafのclient_idの末尾に-telegrafを付けて区別しました。 メッセージのまとめ方 MQTT出力のlayoutの初期値はnon-batchです。 この設定では、メトリクス1つごとに1つのメッセージが送られます。 今回の設定は入力が5つあるため、1分ごとに少なくとも5つのメッセージが別々に届きます。 layout = "batch"では、同じトピックに送るメトリクスを1つのメッセージにまとめて送ります15。 メトリクスは、JSONのmetricsという配列に入る形です。 v1.25.2で非推奨になったbatch = trueは、v1.35.1では起動時のエラーになります。 E! DeprecationError: Option "batch" of plugin "outputs.mqtt" deprecated since version 1.25.2 and will be removed in 1.35.0: use 'layout = "batch"' instead E! loading config file telegraf.conf failed: error parsing mqtt array, plugin options "batch" deprecated JSONの形 TelegrafのJSONは、メトリクスごとの入れ子の形です。 1つのメトリクスは、nameとtagsとfieldsとtimestampのキーを持ちます。 受け手が平らなJSONを求める場合は、json_transformationにJSONataの式を書きます15:1。 layout = "batch"のときは、式に{"metrics": [...]}の形のJSONが渡されます。 そのため、metrics[name="disk"]のようにしてメトリクスを取り出します。 Telegrafが使っているJSONataは1.5.4です。 JSONataの試し場で式を試すときは、そのバージョンを選んでください15:2。 手元のPCで、送り先を手元のMQTTブローカーに替えて動かしました。 届いたメッセージは次のとおりで、値はPCのものです。 {"disk_free_gib":20.71,"disk_used_pct":97.7,"rss_mib":24.6,"rx_kbps":63.3,"temp_c":62,"ts":1790658710,"tx_kbps":40.9,"uptime_s":441385} 起動してしばらくの間は、tx_kbpsとrx_kbpsが含まれません。 aggregators.derivativeは2つの時点の値の差から毎秒の値を計算するため、最初のうちは値を出しません。 JSONataは値の無いキーを出力しないため、この2つのキーはメッセージに含まれません。 設定を変えるとき この設定ファイルはビルドの設定も兼ねているため、プラグインを足したらビルドし直してください。 ビルドに入っていないプラグインを設定に書くと、Telegrafは起動しません。 outputs.fileの無いバイナリにoutputs.fileを書いた設定を渡すと、次のエラーで止まります。 E! loading config file telegraf.conf failed: error parsing file array, undefined but requested output: file プラグインの種類を間違えた場合は、custom_builderがビルドの前に止まります。 たとえばderivativeはaggregatorsにあり、processorsにはありません。 I! filtering packages failed: configured but unknown packages "processors.derivative" このメッセージには、情報を表すI!の印が付いています。 それでもcustom_builderは終了コード1で終わり、バイナリは作られません。 ビルドのスクリプトでは、set -eなどで終了コードを確認して止まるようにしてください。 JSONataの式を調整するときは、同じ設定ファイルで手元のPC向けのバイナリも作ると、すぐに試せます。 custom_builderをGOOSやGOARCHなしで実行すれば、手元のPCで動く版ができます。 送り先を手元のMQTTブローカーに替えれば、ビルドに入っているプラグインのまま、届くJSONの確認が可能です。 形が決まってからARM向けをビルドしてラズパイへ転送すれば、遅い回線での転送は1回で済みます。 まとめ 端末から送る仕組みで差が出るのは障害時の動作で、Telegrafは障害時の動作を設定で指定できます custom_builderで必要なプラグインだけを入れると、バイナリは260.3MBから32.0MBに、常駐メモリは121.4MBから21.5MBに減りました ARMv6向けには、custom_builderを手元のPC向けにビルドし、実行時にだけGOOS=linux GOARCH=arm GOARM=5を渡します AWS IoT Coreに送るときは、QoSを1にし、client_idを端末のほかの接続と分けます 脚注 AWS Well-Architected Framework IoT LensのFailure managementのIOTREL10、IOTREL11、IOTREL12です。標準のライブラリの例として挙げられているのはFreeRTOSやAWSのSDKで、Telegrafは含まれていません。 ↩︎ Telegrafの出力を受け持つ処理(models/running_output.go)では、書き込みに失敗したメトリクスが次の書き込みのために残ります。バッファがあふれて捨てたときは、その件数が警告のログに出ます。 ↩︎ ↩︎ Telegrafの設定のドキュメントのagentの節です。 ↩︎ ↩︎ ↩︎ 調べた版と資料は次のとおりです。Mosquittoは、mosquitto.confの説明と、v2.0.21のソースで確かめました。ソースはsrc/database.cとsrc/bridge.cです。溜める上限のmax_queued_messagesの初期値は1000件です。Vectorは、v0.58.0のmqtt sinkとバッファの説明を読みました。arm-unknown-linux-musleabi版の本体のELFの属性も見ています。属性はTag_CPU_archがv7で、NEONも含まれていました。Fluent Bitは、v5.1.2のプラグインの一覧でMQTTが入力だけであることを確認しました。バッファの扱いは、バッファの説明によります。collectdは、2020年9月の5.12.0のsrc/collectd.conf.podとsrc/mqtt.cです。AWS IoT Device Clientは、READMEと2025年5月のv1.10.1を参照しています。 ↩︎ How to Bridge Mosquitto MQTT Broker to AWS IoTの、2020年5月の更新版を参照しました。 ↩︎ Greengrass nucleusの説明と、nucleus liteのセットアップの文書です。Java版の文書では、一覧に無い環境について、動くかもしれないが試験はしていないとしています。 ↩︎ AWS IoT Device Defender detect feature availability changeです。Device DefenderのDetect機能は、2026年8月31日から新規の顧客に提供されなくなりました。この文書はそれに合わせたもので、想定しているのは待ち受けポートや通信量などのセキュリティ向けの値です。 ↩︎ custom_builderのREADMEを参照しました。 ↩︎ ↩︎ ↩︎ TelegrafのMakefileによると、build_toolsはenv -u GOOS -u GOARCH -u GOARM -- go buildで作られます。配布物はarmel版がGOARM := 5、armhf版がGOARM := 6で、リンカーのオプションは-w -sです。 ↩︎ ↩︎ ↩︎ go help environmentのGOARMの項に書かれています。goコマンドのドキュメントでも読めます。 ↩︎ 常駐メモリは、確認用にoutputs.fileも加えてビルドした版で測りました。設定はJSONのキーなどが記事のものと少し異なりますが、入力と集計のプラグインは同じです。MBは1,000,000バイトとし、psの値(KiB)から換算しています。 ↩︎ スクリプトは起動から約20秒後、Telegrafは約80秒後にpsで見た値でした。 ↩︎ AWS IoT CoreのMQTTのドキュメントに、QoS 2が要求されてもブローカーはPUBACKやSUBACKを返さないと書かれています。 ↩︎ AWS IoT Coreのライフサイクルイベントのドキュメントにある、切断理由の表を参照しました。 ↩︎ JSONシリアライザーのREADMEです。バッチのときにmetricsという配列が付くことと、JSONataが1.5.4に限られることが書かれています。 ↩︎ ↩︎ ↩︎