Nextcloudが Internal Server Error を返すようになって困った

NextcloudのWeb版にアクセスすると Internal Server Error が帰ってくるようになっていました.

20210119 00:01:55 1076844

Internal Server Error

The server encountered an internal error and was unable to complete your request.
Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.
More details can be found in the server log.

別のユーザで試すとログイン画面は表示されて認証機能は動作します.しかしログイン後同じように Internal Server Error このときAndroid版アプリでは普通に利用できていそうです.

よくあるのがサポート対象外になったレガシーなアプリを導入すると同じような状態になることがあります.
しかし,前回利用できていたときと現在の間に特にディストリビューション, Nextcloud, Nextcloudアプリ共にアップデートはしていないはずです.

ログを確認するとhttpdのaccess/errorのlogは特に問題なさそう.
nextcloud.logでそれらしいのは file_put_contents failed でしょうか?

logはNextcloudの設定ファイルの config.php で確認できる.
$ grep log config/config.php
  'log_type' => 'file',
  'logfile' => '/var/log/nextcloud.log',
  'loglevel' => 0,
$ tail -f /var/log/nextcloud.log | jq .
errorっぽいところ?
{
  "reqId": "DVQsgBekfOCY3dvjYO6w",
  "level": 3,
  "time": "2021-01-18T14:59:53+00:00",
  "remoteAddr": "180.131.110.140",
  "user": "matoken",
  "app": "core",
  "method": "GET",
  "url": "/index.php/apps/files/",
  "message": {
    "Exception": "OCP\\Files\\GenericFileException",
    "Message": "file_put_contents failed",
    "Code": 0,
    "Trace": [
      {

まずは手動でファイルとデータベースのバックアップを取っておきます.

バックアップ例
$ sudo -u www-data php /var/www/files.matoken.org/occ maintenance:mode --on (1)
$ sudo -u www-data tar cvf - ${NEXTCLOUD_PATH} | xz > ${BACKUP_PATH}/nextcloud-`date +%F_%T`.tar.xz (2)
$ sudo -u www-data tar cvf - ${NEXTCLOUD_DATA_PATH} | xz > ${BACKUP_PATH}/nextcloud-data-`date +%F_%T`.tar.xz (3)
$ mysqldump --opt --all-databases --events | xz > ${BACKUP_PATH}/nextcloud-`date +%F_%T`.sql.xz (4)
$ sudo -u www-data php /var/www/files.matoken.org/occ maintenance:mode --off (5)
1 メンテナンスモードにする
2 Nextcloud自体のバックアップ
3 Nextcloudデータのバックアップ
4 データベースのバックアップ
5 メンテンスモードを終了

occmaintenance:repair コマンドを試します.

$ sudo -u www-data php ${NEXTCLOUD_PATH}/occ maintenance:repair
 - Repair MySQL collation
     - All tables already have the correct collation -> nothing to do
 - Repair mime types
  : 以下略

コマンド終了後webを再読込するとエラーは解消されました. :)

しかしファイルの一覧が表示されません.最新ファイルは表示されるのでそのファイルを確認すると表示されます.

次に occ files:scan を試してみました.

$ sudo -u www-data php ${NEXTCLOUD_PATH}/occ files:scan --all
Starting scan for user 1 out of 7 (user1)
  : ※省略
+---------+-------+--------------+
| Folders | Files | Elapsed time |
+---------+-------+--------------+
| 20752   | 34164 | 00:04:33     |
+---------+-------+--------------+

これでは変わらなかったようです.多分必要なかった.

次に occ files:scan-app-data を試します.

$ sudo -u www-data php ${NEXTCLOUD_PATH}/occ files:scan-app-data
Scanning AppData for files

+---------+-------+--------------+
| Folders | Files | Elapsed time |
+---------+-------+--------------+
| 84      | 97    | 00:00:01     |
+---------+-------+--------------+

これが当たりだったようで復活しました!

ログを見るとこの問題が発生している間も他のNextcloudアプリは動作していたようだし,Androidアプリ版ではファイルの自動アップロードも動いていたようなので恐らくNextcloud Web版の部分が壊れていたのではないかと思います.

しかし治ったのはいいけどなぜこれが起こったかが謎なのが気持ち悪いです…….

環境
$ sudo -u www-data php /var/www/files.matoken.org/occ -V
Nextcloud 20.0.5
$ dpkg-query -W php mariadb-server
mariadb-server  1:10.3.27-0+deb10u1
php     2:7.3+69
$ lsb_release -dr
Description:    Debian GNU/Linux 10 (buster)
Release:        10
$ uname -m
x86_64

Nextcloud 20.0.4のセキュリティ&セットアップ警告に対応

先日 Nextcloud 19.0.6 から 20.0.4 にアップデートしました.
すると「セキュリティ&セットアップ警告」画面にいくつか警告が出てきたのでその対応メモです.

20201227 19:12:04 2470200

セキュリティ&セットアップ警告
サーバーのセキュリティとパフォーマンスにとって重要なことは、すべてが正確に設定されていることです。あなたの助けとなるよう、Nextcloudでは一部の自動チェックを行っています。詳細な情報は、リンク先のドキュメントを参照してください。

セットアップに関して警告がいくつかあります。
The old server-side-encryption format is enabled. We recommend disabling this. For more details see the documentation.
データベースにいくつかのインデックスがありません。 大きなテーブルにインデックスを追加すると、自動的に追加されないまでに時間がかかる可能性があるためです。 "occ db:add-missing-indices"を実行することによって、インスタンスが実行し続けている間にそれらの欠けているインデックスを手動で追加することができます。 インデックスが追加されると、それらのテーブルへのクエリは通常はるかに速くなります。
テーブル "oc_cards"のインデックス "cards_abiduri"が見つかりません。
The database is missing some primary keys. Due to the fact that adding primary keys on big tables could take some time they were not added automatically. By running "occ db:add-missing-primary-keys" those missing primary keys could be added manually while the instance keeps running.
Missing primary key on table "oc_federated_reshares".
Missing primary key on table "oc_systemtag_object_mapping".
Missing primary key on table "oc_comments_read_markers".
Missing primary key on table "oc_collres_resources".
Missing primary key on table "oc_collres_accesscache".
Missing primary key on table "oc_filecache_extended".
データベース内のいくつかの列で、big intへの変換が行われていません。 大きなテーブルでカラムタイプを変更すると時間がかかることがあるため、自動的には変更されませんでした。 'occ db:convert-filecache-bigint'を実行することによって、それらの保留中の変更は手動で適用できます。 この操作は、インスタンスがオフラインの間に行う必要があります。 詳細についてはこれに関するドキュメントページを読んでください。
federated_reshares.share_id
filecache_extended.fileid
share_external.id
share_external.parent
インストールガイド ↗を再確認して、 ログ にあるすべてのエラーや警告を確認してください。

データベースにいくつかのインデックスがありません。

データベースから修正していきます.まあ書いてあるコマンドを叩くだけですが.

$ sudo -u www-data php ${NEXTCLOUDPATH}/occ db:add-missing-indices
Check indices of the share table.
Check indices of the filecache table.
Check indices of the twofactor_providers table.
Check indices of the login_flow_v2 table.
Check indices of the whats_new table.
Check indices of the cards table.
Adding cards_abiduri index to the cards table, this can take some time...
cards table updated successfully.
Check indices of the cards_properties table.
Check indices of the calendarobjects_props table.
Check indices of the schedulingobjects table.
Check indices of the oc_properties table.

The database is missing some primary keys.

The database is missing some primary keys. Due to the fact that adding primary keys on big tables could take some time they were not added automatically. By running “occ db:add-missing-primary-keys” those missing primary keys could be added manually while the instance keeps running.
Missing primary key on table “oc_federated_reshares”.
Missing primary key on table “oc_systemtag_object_mapping”.
Missing primary key on table “oc_comments_read_markers”.
Missing primary key on table “oc_collres_resources”.
Missing primary key on table “oc_collres_accesscache”.
Missing primary key on table “oc_filecache_extended”.

$ sudo -u www-data php ${NEXTCLOUDPATH}/occ db:add-missing-primary-keys
Check primary keys.
Adding primary key to the federated_reshares table, this can take some time...
federated_reshares table updated successfully.
Adding primary key to the systemtag_object_mapping table, this can take some time...
systemtag_object_mapping table updated successfully.
Adding primary key to the comments_read_markers table, this can take some time...
comments_read_markers table updated successfully.
Adding primary key to the collres_resources table, this can take some time...
collres_resources table updated successfully.
Adding primary key to the collres_accesscache table, this can take some time...
collres_accesscache table updated successfully.
Adding primary key to the filecache_extended table, this can take some time...
filecache_extended table updated successfully.

データベース内のいくつかの列で、big intへの変換が行われていません。

データベース内のいくつかの列で、big intへの変換が行われていません。 大きなテーブルでカラムタイプを変更すると時間がかかることがあるため、自動的には変更されませんでした。 ‘occ db:convert-filecache-bigint’を実行することによって、それらの保留中の変更は手動で適用できます。 この操作は、インスタンスがオフラインの間に行う必要があります。

$ sudo -u www-data php ${NEXTCLOUDPATH}/occ db:convert-filecache-bigint
Following columns will be updated:

* federated_reshares.share_id
* filecache_extended.fileid
* share_external.id
* share_external.parent

This can take up to hours, depending on the number of files in your instance!
Continue with the conversion (y/n)? [n] y

The old server-side-encryption format is enabled. We recommend disabling this.

ここはE2EEで使うサーバサイドの暗号化形式で古い形式が有効になっているのを無効にしたほうがいいよって警告のようです.

The old server-side-encryption format is enabled. We recommend disabling this. For more details see the documentation.

古い形式が使われているかを確認します.

$ sudo -u www-data php ${NEXTCLOUDPATH}/occ encryption:scan:legacy-format
Scanning all files for legacy encryption
Scanning all files for matoken
Scanning all files for hoge
  :

encryption:scan:legacy-format

古い形式は使われていなかったので設定( ${NEXTCLOUDPATH/config/config.php )で明示的に無効にしてしまいます.

-  'encryption.legacy_format_support' => false,
+  'encryption.legacy_format_support' => true,

もし古い形式が残っていて移行したいでもマスターキーを設定していないという場合は該当ファイルの所持ユーザーにデータをコピーし直してもらう必要がありそうです.あまりやりたくない作業ですね.(以下のページを見るとクライアントがアップロードし直しをしてくれるのかもしれない)

これで再読込するとすべてのチェックに合格しました :)

20201227 19:12:47 2533788

環境
$ sudo -u www-data php /var/www/files.matoken.org/occ -V
Nextcloud 20.0.4
$ dpkg-query -W php mariadb-server
mariadb-server  1:10.3.27-0+deb10u1
php     2:7.3+69
$ lsb_release -dr
Description:    Debian GNU/Linux 10 (buster)
Release:        10
$ uname -vm
#1 SMP Debian 4.19.160-2 (2020-11-28) x86_64

v4l2loopbackモジュールで作られるビデオデバイスへの名前の付け方

v4l2loopback moduleを利用して仮想カメラなどを利用しています.

このモジュールを呼び出すときにオプションを指定して複数のデバイスにしたり,それぞれにデバイスに名前をつけたり出来ます.

If you need several independent loopback devices, you can pass the “devices” option, when loading the module; e.g.

# modprobe v4l2loopback devices=4
Will give you 4 loopback devices (e.g. /dev/video1 …​ /dev/video5)

You can also specify the device IDs manually; e.g.

# modprobe v4l2loopback video_nr=3,4,7
Will create 3 devices (/dev/video3, /dev/video4 & /dev/video7)

# modprobe v4l2loopback video_nr=3,4,7 card_label=”device number 3″,”the number four”,”the last one”
Will create 3 devices with the card names passed as the second parameter:

/dev/video3 → device number 3
/dev/video4 → the number four
/dev/video7 → the last one

お手本通りモジュールを呼び出すと,

$ sudo modprobe v4l2loopback video_nr=3,4,7 card_label="device number 3","the number four","the last
one"

想定通りに設定されました.(最後のIntegrated Cameraは内蔵カメラでこのモジュールとは無関係)

$ v4l2-ctl --list-devices
device number 3" (platform:v4l2loopback-000):
        /dev/video3

"the number four" (platform:v4l2loopback-001):
        /dev/video4

"the last one (platform:v4l2loopback-002):
        /dev/video7

Integrated Camera: Integrated C (usb-0000:00:1a.0-1.6):
        /dev/video0
        /dev/video1
        /dev/media0

しかしこの設定を永続化しようと,
/etc/modprobe.d/v4l2loopback.conf
というファイルを用意してこの設定を書いて呼び出すとおかしなことになります.

$ sudo rmmod v4l2loopback (1)
$ echo 'options v4l2loopback video_nr=3,4,7 card_label="device number 3","the number four","the last one"' | sudo tee /etc/modprobe.d/v4l2loopback.conf (2)
options v4l2loopback video_nr=3,4,7 card_label="device number 3","the number four","the last one"
$ sudo modprobe -v v4l2loopback (3)
insmod /lib/modules/5.10.0-1-amd64/updates/dkms/v4l2loopback.ko video_nr=3,4,7 card_label="device number 3","the number four","the last one"
$ v4l2-ctl --list-devices | grep v4l2loopback -A1 (4)
device number 3" (platform:v4l2loopback-000):
        /dev/video3
--
"the number four" (platform:v4l2loopback-001):
        /dev/video4
--
"the last one (platform:v4l2loopback-002):
        /dev/video7
  1. モジュールのアンロード
  2. 設定ファイルへ書き込み
  3. モジュールの再読込
  4. デバイス名の確認

ダブルクオーテーションの扱いが変わってしまうようです.更に名前自体にダブルクオーテーションが含まれてしまいます.

とりあえず全体を1セットのダブルクオーテーションで囲むと大丈夫なようです.

$ echo 'options v4l2loopback video_nr=3,4,7 card_label="device number 3,the number four,the last one"' | sudo tee /etc/modprobe.d/v4l2loopback.conf
options v4l2loopback video_nr=3,4,7 card_label="device number 3,the number four,the last one"
$ sudo modprobe -v v4l2loopback
insmod /lib/modules/5.10.0-1-amd64/updates/dkms/v4l2loopback.ko video_nr=3,4,7 card_label="device number 3,the number four,the last one"
$ v4l2-ctl --list-devices | grep v4l2loopback -A1
device number 3 (platform:v4l2loopback-000):
        /dev/video3
--
the number four (platform:v4l2loopback-001):
        /dev/video4
--
the last one (platform:v4l2loopback-002):
        /dev/video7

ちなみにダブルクオーテーションなしだとこうなりました.

$ sudo modprobe -v v4l2loopback
insmod /lib/modules/5.10.0-1-amd64/updates/dkms/v4l2loopback.ko video_nr=3,4,7 card_label=device number 3,the number four,the last one
$ v4l2-ctl --list-devices | grep v4l2loopback -A1
device (platform:v4l2loopback-000):
        /dev/video3
--
Dummy video device (0x0001) (platform:v4l2loopback-001):
        /dev/video4
--
Dummy video device (0x0002) (platform:v4l2loopback-002):
        /dev/video7

最近リリースされた OBS Studio 26.1でLinux版, macOS版にも仮想カメラ機能が入りました.
これも v4l2loopback を利用しているのですが,ダブルクオーテーションが含まれる場合うまく動かないようです.

環境
$ dpkg-query -W v4l2loopback-* v4l-utils
v4l-utils       1.20.0-2
v4l2loopback-dkms       0.12.5-1
v4l2loopback-modules
v4l2loopback-utils      0.12.5-1
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -mv
#1 SMP Debian 5.10.4-1 (2020-12-31) x86_64

センサーのログをNextcloudのSensorloggerで記録してみる

この記事は 日本Androidの会秋葉原支部ロボット部 Advent Calendar 2020 の20日分の記事です.
日本Androidの会秋葉原支部ロボット部は現在月に一回勉強会を行い様々な話題で盛り上がっています.
次の勉強会はちょうど今日(20日)です.興味のある方は覗いてみてください.

センサーのログなどをアップロードするのに色々なwebサービスを使ったり,Googleスプレッドシートに書いたりしています.
便利なんだけどロックインになるのは嫌だなって思ったりします.

Nextcloudというファイル共有サービス+αなOSSがあります.アプリケーションを追加して機能を増やすことが出来ます.例えばテレビ電話や,オンラインオフィスとか,マップサービスとか様々なアプリがあります.
これを個人的に立てて便利に使っています

この中のアプリを眺めているとSensorloggerというセンサーのログを保存できそうなものを見つけたので試してみました.

まずNextcloudですが,とりあえず試すだけならsnapを利用するのがお手軽です.Raspberry Pi + Raspberry Pi OSなどでもOKです.

Debian sid amd64/Ubuntu 20.04 LTS/Raspberry Pi OS armhfでは以下の手順でOKでした.

$ sudo apt update && sudo apt upgrade   (1)
$ sudo apt install snapd    (2)
$ sudo snap install nextcloud   (3)
  1. システムのパッケージを最新にする
  2. snapを使えるように snapd パッケージを導入
  3. snapでnextcloudを導入

10分位待つと導入が終わります.ウェブブラウザにIPアドレスを入力するとセットアップ画面が表示されるので管理者ID/PASSWORDを設定します.

これでとりあえず使えるようになったと思います.

この後Sensorloggerを導入します.
管理者権限のアカウントでNextcloudの右上のメニューから「アプリ」を開きます.

20201219 20:12:45 2014278

次に上の検索バーに「Sensorlogger」とかの文字列で検索して「有効」ボタンを押して導入します.

20201219 20:12:42 2017785

Tip
Nextcloudのアプリケーションはコマンドラインから導入することも出来ます.
$ sudo -u www-data occ app:install sensorlogger #通常導入した場合
$ sudo /snap/bin/nextcloud.occ app:install sensorlogger #snapで導入した場合

ここからは一般ユーザでOKです.

Nextcloudの上部から「Sensorlogger」のアイコンをクリックするとSensorloggerの画面が表示されます.

20201219 20:12:03 2021911

はじめはデータがないのでまっさらです.「Device」辺りでデバイスの登録をするのかな?と思いましたが出来ません.
「Read SensorLogger Wiki Devices」と書かれているのでWikiを参照してみます.

データを送ると自動的にデバイスが出来るようです.Simple, Complexの2種類のデータタイプがあるようです.Simpleは温度,湿度のようでとりあえずこれを試してみます.

以下の辺りから post.php を持ってきて使います.このscriptはダミーのランダムな温度と湿度データを作ってSensourloggerにデータを投げます.

何箇所か書き換えます.
* $url = ` を自分のNextcloudのURLに変更します.
* `$array = array("deviceId" ⇒
uuidgen コマンドなどで生成したUUIDに変更します.
* $username = をNextcloudの自分のユーザーに変更します.
* $token = に「設定」「セキュリティ」ページの「デバイスとセッション」の一番下の「新しいアプリパスワードを作成」で作成したトークンに修正します.

そしてphpとphp-curlが必要なので導入します.

Debian sid amd64/Ubuntu 20.04 LTS/Raspberry Pi OS armhfでの例
$ sudo apt install php-cli php-curl

この状態で post.php を実行して成功すると以下のようなメッセージが帰ってきます.

$ php ./post.php
{"success":true,"message":"Sensor Log successfully stored","data":null}

Sensorloggerのページの List を見るとエータがアップロードされているのが解ります :)

手動で実行するのは大変なのでcrontabにこんな感じで登録してみます.5分に一回データを送信します.

$ crontab -e (1)
$ crontab -l | grep post.php (2)
*/5 * * * *     php ~/tmp/post.php 2&>1 > ~/tmp/post.php.log
  1. crontabの編集
  2. crontabに登録されたか確認

同様にRaspberry Piの温度も送ってみます.温度の $temperature を以下のような感じで書き換えて,UUIDも書き換えるとOK.これもcrontabに登録します.

    $temperature = system( '/opt/vc/bin/vcgencmd measure_temp | awk -F "[=\']" \'{print $2 }\' | tr -d \'\n\'' );

しばらく動かしてからダッシュボードを設定するとこんな感じのチャートが表示できました.

20201219 20:12:13 2035392

密集してよくわからない部分はマウスドラッグで矩形選択するとその部分がズームされます.

20201219 22:12:30 2180945

という感じでとりあえず動きました.ドキュメントが未だ充実していな買ったり使い勝手も悪いですが最低限の機能はあるかなという感じです.
興味があったら試してみてください.
若しくはおすすめのアプリやサービスを教えてください.

PCでAndroid端末の画面転送と操作が出来るscrcpy

Debian sid amd64環境ではパッケージがあるので簡単です,armhf/amd64/i386環境ではsnap版が存在します.その他幾つかのLinuxディストリビューションではパッケージがあったり,WindowsやmacOSでも動作するようです.

手元ではDebian sid amd64で動作しました.(Raspberry Pi OS armhfにsnap版を入れた環境ではエラーが発生.内容は未だ未確認)

Debian sid amd64環境だと以下のような感じで導入できました.このときAndroid端末は「開発者向けオプション」が有効になっていて,「USBデバッグ」が有効になっている状態でUSB接続されている必要があります.

Debian sid amd64環境での導入例
$ sudo apt install adb scrcpy (1)
$ lsusb (2)
  :
Bus 002 Device 013: ID 05c6:9024 Qualcomm, Inc. SDM439-MTP _SN:472BF8D8
  :
$ echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="05c6" ATTR{idProduct}=="9024", MODE="0660", GROUP="plugdev", SYMLINK+="android%n"' \
| sudo tee -a /etc/udev/rules.d/51-android.rules (3)
$ sudo udevadm control --reload (4)
$ adb devices (5)
* daemon not running; starting now at tcp:5037
* daemon started successfully
List of devices attached
976d6a56        device
  1. 必要パッケージの導入
  2. AndroidのVID/PIDを確認(ここでは 05c6:9024 )
  3. adbコマンドが利用できるようにAndroid端末をudev roureに登録
  4. udev ruleを反映する
  5. adbコマンドで認識出来るのを確認

この状態で,scrcpy を実行することでAndroidの画面転送が出来ました.普通に操作も出来ます.
スリープ状態のときは画面が真っ黒ですが,マウス右クリックで解除されます.

$ scrcpy
INFO: scrcpy 1.14 <https://github.com/Genymobile/scrcpy>
/usr/share/scrcpy/s...93 bytes in 0.008s)
[server] INFO: Device: TINNO C330 (Android 9)
INFO: OpenGL shaders: ENABLED
INFO: Created renderer: opengl
INFO: Renderer: opengl
INFO: OpenGL version: 3.0 Mesa 20.2.4
INFO: Trilinear filtering enabled
INFO: Initial texture: 720x1280

20201210 21:12:59 2112960.resized20201210 21:12:31 2113779.resized20201210 21:12:30 2115127.resized

導入も簡単だしこれは便利.しかしメイン端末ではPCにUSB接続するとすぐに充電しなくなってしまうので長時間は使えません.

adb のワイヤレス接続の設定をすると別の端末や充電器で充電しながら利用できそうなので試してみました.

対象のAndroid端末をPCにUSB接続した状態で tcpip コマンドでリモート接続できるようにします.

$ adb tcpip 5555
restarting in TCP mode port: 5555

この状態でPCからAndroid端末を取り外し,Wi-Fi接続のIPアドレスを確認します.

PCでadbコマンドでAndroid端末に接続します.

$ adb connect <ANDROID_IP>>:5555

この状態で scrcpy コマンドを実行すると画面が表示され操作できます.充電器などに接続した状態でも利用できます :)

scrcpy には幾つかオプションがあります.便利そうなものとしては最大解像度を指定する -m, --max-size value で解像度を下げて表示できます,
-n, --no-control で表示だけで操作できなくします.
-r, --record file で画面を録画します.
-w, --stay-awake でscrcpyを実行中Android画面をロック,消灯しません.
-S, --turn-screen-off Android端末のスクリーンを消したまま操作できます.

ショートカットでは
Ctrl + h, マウス中キー でホームボタン,
Ctrl + r でAndroid画面回転,
Ctrl + s でアプリケーション切り替え,
辺りが便利そうです,

Ctrl + c でクリップボードのコピーなのですが,一旦Android側でコピーした後に Ctrl + c でPCへのクリップボードコピーのようです,Ctrl + v の貼り付けもAndroid感での貼り付けで,PCからAndroidのクリップボード貼り付けは Ctrl + Shift + v でした.

詳細は scrcpy --help を参照してください.

これでElectronアプリでPCで動かしているアプリをスマホで……とも思ったのですが日本語入力などはちょっと面倒.もう少し様子見しようと思います.

Raspberry Pi の温度管理をソフトウェアで頑張る

この記事は日本Androidの会秋葉原支部ロボット部 Advent Calendar 2020 の12/07分の記事です.

内容は 日本Androidの会秋葉原支部ロボット部 第96回勉強会 で発表した内容を加筆修正したものです.

はじめに

Raspberry Pi という英国発の教育向けとして2012年に発売された安価なシングルボードコンピュータがあります.教育向けとして発売されましたが趣味にもよく使われています.OSは標準ではLinux(DebianベースのRaspberry Pi OS)が採用されています.

私はもっぱら省電力のLinuxマシンとして使うことが多いです.

トラブル

今夏空調のない部屋の自宅サーバの横でRaspberry Pi 3 model B + Raspberry Pi OS arm64(β)で計算をさせていたのですが,しばらく動かしていると固まるようになりました.

再起動すればしばらく動きますがしばらくするとやはり固まります.これをどうにか出来ないかと調べてみました.

ログの取得

まずはログを録ってみます.

crontabで1分毎に情報を記録
* * * * *       printf "`date +\%s`,`cat /sys/class/thermal/thermal_zone0/temp`,`echo "obase=2; ibase=16; \`vcgencmd get_throttled | cut -f2 -dx\`" | bc`,`vcgencmd measure_clock arm|cut -f2 -d=`\n" >> ~/.temp.log

内容はこんな感じです.(外気温度も録ればよかった)

UNIX Time
date +%s
SoC温度
/sys/class/thermal/thermal_zone0/temp
スロットリング周りのフラグ
vcgencmd get_throttled
arm周波数
vcgencmd measure_clock arm

ログがファイルに書かれる間にフリーズしてデータが失われるのを防ぐために /etc/fstab のマウントオプションに sync オプションも付けておきます.(再起動かremountで反映)

ログを取得している状態で負荷を掛けます.今回は /dev/urandom をcatすることで計算させました.今回のRaspberry Pi 3 model Bは4coreあるので4つ動かしています.

今回のテストで使った負荷(いつもはvanity address/vttとかとか)
$ cat /dev/urandom > /dev/null &
$ cat /dev/urandom > /dev/null &
$ cat /dev/urandom > /dev/null &
$ cat /dev/urandom > /dev/null &

熱が原因?

しばらく動かしてRaspberry Piが固まった後にログを確認してみます.
SoCの温度が85度を何度か記録した後に固まっているようです.
85度というのはRaspberry Pi OSでの標準のSoC制限温度のようです.この温度の5度前(標準では80度)からサーマルスロットリングが始まるようです.

サーマルスロットリングでクロックが下がって温度が下がれば問題無さそうだけど80度からクロックが下がっても85度を超えて固まってしまっているようです.
ベータ版のRaspberry Pi OS amd64を使っているせいかもしれないと思い,標準のRaspberry Pi OS armhf(32bit)版に変更して同様に試してみましたが同様の動きのようです.

正攻法としてはヒートシンク,ファンの増設や空調を入れるとよさそうですが,金欠なのでとりあえずソフトだけでどうにか出来ないかと試しました.

SoC制限温度を下げる

まずSoCの制限温度ですが,公式フォーラムで70度以下にしたほうがいいという書き込みを見かけました.逆に100度でも大丈夫という人も居るのですが安全側の70度にしてみます.

この設定は /boot/config.txt でパラメータを設定できます.以下は70度に設定たときの例です.この状態で再起動すると反映されます.

temp_limit=70

再起動後以下のコマンドで設定が反映されているか確認が出来ます.

$ vcgencmd get_config int | grep ^temp_limit=
temp_limit=70

この状態で負荷を掛けると70度を越えるくらいで固まりました.やはり制限温度を越えると固まってい舞うようです.

SoCの最大周波数を下げてみる

Raspberry Pi 3 model B のSoCは最大周波数1.2GHzです.これを下げてみます.

/boot/config.txtarm_freq= で設定できます.以下は800MHzに設定したときの例です.再起動で反映されます.

arm_freq=800

再起動後に設定が反映されているか確認します.

$ vcgencmd get_config int | grep ^arm_freq=
arm_freq=800

この状態で負荷を掛けるとやはり固まります.まあサーマルスロットリングが効いても固まるので仕方がない感じです.

SoCの最小周波数を下げてみる(これが効くのでは?)

次にSoC最小周波数を下げてみます.既定値は600MHzで,サーマルスロットリングでもここまで下がっているのでこれを更に下げると温度が下がりそうな気がします.

/boot/config.txtarm_freq_min= で設定できます.以下は400MHzに設定したときの例です.再起動で反映されます.

arm_freq_min=400

しかし再起動後に確認してみると600MHzより下には設定できないみたいで600MHzになってしまいます.

$ vcgencmd get_config int | grep ^arm_freq_min=
arm_freq_min=600

この状態で負荷を掛けるとやはり600Mhzまでしか下がらず固まります.

残念ながらRaspberry Pi のスロットリングでは無理そうです.

maxcpusでコアを制限してみる

Linuxのブートパラメータで maxcpus を指定することでコアを制限できます.Raspberry Pi の場合は /boot/cmdline.txt で設定できます.

設定後以下のコマンドで確認できます.

$ grep -o -E 'maxcpus=.{0,9} ' /proc/cmdline
maxcpus=1
$ grep ^processor /proc/cpuinfo | wc -l
1

これでCPU core1津で動作しています.しかし最大周波数を600MHzかつ1coreでも同様にフリーズしてしまいました.

cpufreqでクロック制御

IntelCPUのNotePCなどではcoufreqを使ってこのあたりの制御をするのですが,これでも600mHzより下には下げられないようで駄目でした.

LimitCPUで指定プロセスの制限を行う

LimitCPUは指定プロセスを監視し,CPU利用率や%で制限するプログラムです.Linux, MacOS, *BSDなどのUNIX-Likesystemで利用できます.
Raspberry Pi OSではcpulimitパッケージとしてパッケージングされており,コマンドもcoulimitです.

cpulimitの導入
$ sudo apt install cpulimit

cpulimitコマンドに制限したいプロセスIDやプロセス名と制限を指定することで動作します.

cat からはじまるプロセスを50%に制限
$ pgrep ^cat | xargs -n1 -I{} sh -c "cpulimit -p {} -l 50 -v &"

cpulimitで50%に制限してみたt頃温度が下がるのを確認できました.数日動かしても固まらなくなったようです.
定期的にSoCの温度を確認して制限を変更していくと良さそうでうs.

LimitCPUはCPUlimitの開発が止まった後のフォークですが,その後CPUlimitが新しく開発が始まっているようです.詳細は以下のページを参照してください.

cgroupでCPUリソース制限(未確認)

LimitCPUが効いたので恐らくcgroupでのCPUリソース制限でも大丈夫そうです.(未確認)

おわりに

現在は気温も下がり制限などしなくても問題ありません.でもきっと来夏にまた起こると思うのでそこでまた確認するつもりです.

しかし,今回の解決方法はCPUのリソースを制限して温度を下げて居るので計算量は減っています.空調を入れたりCPUファンを導入するのが正攻法になるのかなと思います.
CPUファンはサードパーティーから各種発売されているのでそれらを使うかDIYする感じになると思います.

そういえば最近Raspberry Pi OSの設定コマンドの raspi-config の中に Set behaviour of GPIO fan というメニューが出来たり,Raspberry Pi 4には公式のCPUファンが発売されているのでこれらを使うのが良さそうです.

IFTTTで過去に設定したアプレットを参照する

IFTTTからお知らせメールが届きました.(同じものが2通!)

Hey there,

As of today, your current IFTTT Standard plan no longer supports creating more than 3 Applets from scratch. You still have access to enable unlimited published Applets.

All but 3 of your recently active Applets have been archived. Sign in to view your Applets.

You may unarchive all of your archived Applets by upgrading to IFTTT Pro. Upgrading to Pro also unlocks our best tools for creators and unlimited Applet creation.

Upgrade

For more information, see What happens if I do not upgrade to Pro?

Or reply to this email and we’ll do our best to answer your questions.

—The IFTTT Team

無償アカウントの制限が始まったようです.

そんなに大事なものはもう無かったはずだけどと思いながら確認に行くとアプレットは3つだけしか操作できず,2つだけがアクティブで1つは非アクティブになっていました.非アクティブなアプレットは有効にすることが可能でした.

4つ目以降のアプレットはアーカイブされていてアーカイブページで一覧が確認でします.

しかし,タイトルくらいしか見えなくて中身が見えなくて内容が確認できません.

20201115 06:11:43 2814050

どうにか中が見えないかなと「Account settings」 → 「Export my data」でエクスポートを試してみました.

20201115 05:11:44 2769448

するとメールでjsonデータが飛んできました.
早速jqに食わせてみるとエラー.

$ jq . ~/Downloads/matoken.json
parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 2, column 3

このメッセージは改行があったりするパターンぽいてことで削ってみます.また違うエラー.

$ cat ~/Downloads/matoken.json | tr -d '\n' | jq .
parse error: Invalid escape at line 1, column 18812

ファイルをよく見ると改行コードは \r\n で更にその後ろにスペースが入っているようです.

$ od -xc --endian=big ~/Downloads/matoken.json | lv
0001720    222c    226e    616d    6522    3a22    4946    5454    0d0a
          "   ,   "   n   a   m   e   "   :   "   I   F   T   T  \r  \n
0001740    2054    227d    7d2c    7b22    6465    7669    6365    5f74
              T   "   }   }   ,   {   "   d   e   v   i   c   e   _   t

てことでこんな感じでパースできました.

$ cat ~/Downloads/matoken.json | tr -d '\r\n ' | jq . | head
{
  "data": {
    "me": {
      "login": "matoken",
      "email": "matoken@gmail.com",
      "id": "126299",
      "profile_image_url": "https://fastly.4sqi.net/img/user/220x220/2608683-JGYT1JCMXPVUF2KL.jpg",
      "profile_username": "KenichiroMatohara",
      "timezone": "Osaka",
      "bio": null,

しかしWebから見るよりはいいけど詳細は載っていないようです.例えばアプレットの利用するモジュール名などはわかるけど,その詳細はわからない感じです.
でもだいたい何をやっていたかはわかるかな?

というのはIFTTTに止められる前にやるべきでしたね…….

環境
$ dpkg-query -W jq coreutils lv
coreutils       8.32-4+b1
jq      1.6-1
lv      4.51-7
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64

GNU Bashのbracketed pasteの設定

Debian sid amd64環境で最近Bashにテキストを貼り付けると貼り付けた文字列が反転して即時反映されないようになっていました.
何らかの操作をすると反転は解除されて反映されます.改行の含まれた文字列を貼り付けて誤って実行されるというようなことが抑制できていい感じです.でも貼り付けただけで実行されたつもりになってしまうこともあったり.

便利だけどこれなんだろうと確認してみました.

Changelogを見てみます.
/usr/share/doc/bash/changelog.Debian.gz は殆どUpstreamへの追従.
/usr/share/doc/bash/changelog.gz を見るとそれらしいものが載っていました.

bash-4.4-alpha, bash-4.3-release.から Bracketed paste mode が入ったようです.
そしてbash-5.1-alpha, bash-5.0-releaseから既定値になたようです.(そして気づいた)

bash-4.4-alpha, bash-4.3-release.

b. There is a new bindable variable, `enable-bracketed-paste’, which enables
support for a terminal’s bracketed paste mode.

bash-5.1-alpha, bash-5.0-release.

h. Bracketed paste mode is enabled by default.

infoを見ると enable-bracketed-paste という項目で設定できるようです.

info bash
enable-bracketed-paste (On)
       When set to On, readline will configure the terminal in a way that will enable it to insert each paste into the editing buffer as a single string of characters, instead of treating
       each character as if it had been read from the keyboard.  This can prevent pasted characters from being interpreted as editing commands.
info bash
Readline Variables
    Readline has variables that can be used to further customize its behavior.  A variable may be set in the inputrc file with a statement of the form
       set variable-name value
or using the bind builtin command (see SHELL BUILTIN COMMANDS below).

実際に叩いてみます.こんな感じでoff/onできました.

$ bind 'set enable-bracketed-paste off'
$ bind 'set enable-bracketed-paste on'

~/.bashrc 辺りに書いておくと次回のbash起動時に反映されます.

その他
  • byobu-screenでは enable-bracketed-paste on しても利用できない?
  • tmuxでのCtrl+b Ctrl + ] での貼付け時には無視される?
  • Ubuntu 20.10 amd64の5.0-6ubuntu2では既定値で無効になっているけど enable-bracketed-paste on で有効に出来る
環境
$ dpkg-query -W bash
bash    5.1~rc2-1
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64

Byobu tmuxでファンクションキーを無効にする

アドホックに切り替える

Ctrl+b shift + F12 でトルグ

設定ファイルに設定する

~/.byobu/keybindings.tmux の1行目に
source /usr/share/byobu/keybindings/f-keys.tmux.disable を追記.

Byobu tmuxを起動し直すか,Ctrl+b : :source-file ~/.byobu/keybindings.tmux で反映する.

Byobu GNU screenの場合はこちら

環境
$ dpkg-query -W byobu tmux
byobu   5.133-1
tmux    3.1b-1
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64