概要
rc.localで自動起動に失敗したときにすぐに原因がわかるようにする対策をメモした。
背景と目的
Raspberry Pi上で、AWS IoT Device SDKを使ったPythonスクリプトを作成し、rc.localで自動起動しようとして失敗したので、エラー原因を探るためにやったことをメモしておく。
詳細
対策1: そもそもrc.localで起動する場合は、まず標準出力、エラーをファイルに吐かせておく
ログも何もないせいで、原因がわからず右往左往するのは非常に時間の無駄なので、そもそもrc.localで起動する場合は、標準出力、エラーをファイルに吐いておき、起動失敗時にすぐ原因をわかるようにする。正式運用の方法としてふさわしいかどうかは置いておいて。
こちらにあるとおり、なんでもいいから標準出力、エラーをファイルに履いておく。
1.1 まず自動起動したいcommandの標準出力、エラーをファイル/path/to/logfileに吐くシェルスクリプトxxx.shを作成
command > /path/to/logfile 2>&1
1.2 /etc/rc.local
作成したシェルスクリプトをバックグラウンド実行するコマンドを記入。バックグラウンドの指定&は忘れないように。
sudo bash /path/to/xxx.sh &
ここまでで、起動失敗しても最低でも何かしらの情報は残る。
念のため、
sudo bash /etc/rc.local
を実行して、動き出すか確認。
対策2: AWS IoT Device SDKを使ったプログラムへの対策
起動しない原因としてありがちなのは、
起動直後のせいでAWS IoTのエンドポイントの名前解決ができないために、AWSIoTClient.connectでエラーが発生する
というもの。
Traceback (most recent call last): File "/path/to/aws_iot_application.py", line 78, in <module> myMQTTClient.connect() File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/MQTTLib.py", line 513, in connect return self._mqtt_core.connect(keepAliveIntervalSecond) File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 196, in connect self.connect_async(keep_alive_sec, self._create_blocking_ack_callback(event)) File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 223, in connect_async raise e File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 211, in connect_async rc = self._internal_async_client.connect(keep_alive_sec, ack_callback) File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/core/protocol/internal/clients.py", line 122, in connect rc = self._paho_client.connect(host, port, keep_alive_sec) File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/core/protocol/paho/client.py", line 665, in connect return self.reconnect() File "/usr/local/lib/python3.5/dist-packages/AWSIoTPythonSDK/core/protocol/paho/client.py", line 789, in reconnect sock = socket.create_connection((self._host, self._port), source_address=(self._bind_address, 0)) File "/usr/lib/python3.5/socket.py", line 694, in create_connection for res in getaddrinfo(host, port, 0, SOCK_STREAM): File "/usr/lib/python3.5/socket.py", line 733, in getaddrinfo for res in _socket.getaddrinfo(host, port, family, type, proto, flags): socket.gaierror: [Errno -3] Temporary failure in name resolution
なので、超簡単な対策としては、
/etc/rc.local
sleep 10 # 少し待つ sudo python /path/to/aws_iot_application.py >/path/to/logfile 2>&1
とする。秒数が足らない可能性もあるので、より確実にするには、hostコマンドなどを使って、名前解決ができるか調べてから起動するようにするとより良い。
/etc/rc.local
# host のレスポンスにアドレスが含まれるようになるまで待つ while : do resp=`host *******************.iot.ap-northeast-1.amazonaws.com` if [[ $resp =~ .+' has address '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} ]] ; then break fi sleep 1 echo "sleeping..." done sudo python /path/to/aws_iot_application.py > /path/to/logfile 2>&1
まとめと今後の課題
rc.localで自動起動失敗時の原因探索のための対策をまとめた。