dullwhaleのメモ帳

何度も同じことを調べなくてよいように...

IncusでPrometheusを構築せずに超ざっくりコンテナのRAM使用量をモニタリングする

スニペット

バックグラウンドで10秒ごとにコンテナのAvailable領域のbyte数をmemory-available.txtへ1行ずつ追記する。

nohup watch --interval 10 "incus query /1.0/metrics | sed -n 's/^incus_memory_MemAvailable_bytes{.*}\ \([0-9\.]\+\)e+\([0-9]\+\)/\1 * 10^\2/p' | bc | cut -d. -f1 >> memory-available.txt" &

出力例

$ tail -F memory-available.txt
7936969952
7936969952
7936969952
7936969952
7936969952
7936969952
7936969952
7936900320
7936900320
7936900320
7936900320
7936900320

アイデア

Incusはメトリクスデータを取得するためのAPIエンドポイントを持っている。 これはPrometheusが読み取るように設計されていて、Incus公式のドキュメント通りにちゃんと構築すればメトリクスデータを蓄積できるのだろう。 ただ、Prometheusや可視化のためのGrafanaを構築運用するのもそれなりの人的コストが掛かる。 長期的な運用ではなく、実験のために1日未満で落としてしまうようなコンテナのリソース使用量を把握するのには過剰だ。 そこで、この記事では簡素な方法でIncus上のコンテナのRAM使用量をざっくり把握するアイデアのメモを残しておく。

まず初めに、Incusが提供するメトリクスデータはCLIでも確認できる。 次の公式ドキュメントに書かれているように、以下のコマンドで情報が得られる。

incus query /1.0/metrics

How to monitor metrics - Incus documentation

このコマンドで得られるメトリクスデータは非常に多く、コンテナごとのリソース使用量までわかる。 メモリに関してはfreeコマンドで得られる粒度の情報まで取得できる。 ということは、Totalの値からAvailableの値を減算すればざっくりRAMの使用量が分かる。

出力を抜き出すとTotalは次のように書かれていた。 ここではdebian13testは検証のために立ち上げたDebianのコンテナの名前である。

# HELP incus_memory_MemTotal_bytes The amount of used memory.
# TYPE incus_memory_MemTotal_bytes gauge
incus_memory_MemTotal_bytes{name="debian13test",project="default",type="container"} 7.95822e+09

指数表記になっていて分かりづらいが、約7,590 MiB使えることが分かる。

7.95822 * 10 ^ 9 [B] = 7,958,220,000 [B] ≈ 7,590 [MiB]

同様にAvailableの値を抜き出すと以下のように出力されていた。

# HELP incus_memory_MemAvailable_bytes The amount of available memory.
# TYPE incus_memory_MemAvailable_bytes gauge
incus_memory_MemAvailable_bytes{name="debian13test",project="default",type="container"} 7.93690032e+09

同じように分かりやすい単位に直すとAvailableは約7,569 MiBだと分かる。

7.93690032 * 10 ^ 9 [B] = 7,936,900,320 [B] ≈ 7,569 [MiB]

減算して約 20 MiB使っていると言える。

Total - Available = 7,958,220,000 [B] - 7,936,900,320 [B] = 21,319,680 [B] ≈ 20 [MiB]

Total領域の方は基本的にあまり変化しないから、Available領域の変化だけを記録しておけばRAM使用量の簡単なモニタリングができる。 ここで、なるべく高頻度で値を取得したいが先の公式ドキュメントに8秒間結果がキャッシュされると書かれている。

they are cached for 8 seconds.

だからキャッシュが切れる10秒間隔でwatchする。

最後に、モニタリング結果を他のツールで利用するための障壁として指数表記の問題がある。 より単純な整数値として保存しておきたい。 この変換にはsedとbcを使っている。 sedで「e+」の表記を「* 10 ^」という表記に変えてしまい、後続のbcコマンドで小数点計算を行っている。 bcコマンドが使えない環境ではawkなどが代替案になるかもしれない。 更に後続のcutは「.00000」のような無駄な小数点以下の文字を消すために入れている。 bcコマンドだけで処理しようとすると、計算の途中で変に丸められてしまう可能性があるからわざわざcutで処理している。

Debian 13.6にIncusをWeb UI付きでインストールして初期設定

Debian 13.6にIncusをWeb UI付きでインストールする

# OSバージョン確認
$ cat /etc/os-release | grep VERSION
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.6

インストール

インストール方法は公式のドキュメントに書かれている

How to install Incus - Incus documentation

基本的にはincusというパッケージをインストールすれば完了する。 ただし、Debian公式のaptリポジトリではなくZabblyなるリポジトリからインストールした方が良い。 Debian公式のリポジトリにはWeb UIが入っていないが、Zabblyの方には入っている。

Zabblyのパッケージリポジトリを追加する

GitHubのREADMEにインストール手順が書かれている。

GitHub - zabbly/incus: Incus package repository · GitHub

mkdir -p /etc/apt/keyrings/
# パッケージの署名の検証を通すために公開鍵をダウンロードする
# curl版
sudo curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc
# wget版
sudo wget -O /etc/apt/keyrings/zabbly.asc https://pkgs.zabbly.com/key.asc


# aptパッケージに追加
sudo sh -c 'cat <<EOF > /etc/apt/sources.list.d/zabbly-incus-stable.sources
Enabled: yes
Types: deb
URIs: https://pkgs.zabbly.com/incus/stable
Suites: $(. /etc/os-release && echo ${VERSION_CODENAME})
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/zabbly.asc

EOF'

# パッケージの情報を持ってくる
sudo apt update

Incusをインストール

ここではコンテナだけでなく仮想マシンにも対応したフル機能のものをインストールする。 incus-ui-canonicalがWeb UIを提供する。

sudo apt install incus incus-ui-canonical

初期設定

まずはCLI上で

# 自身をincusの管理者としてグループに追加
sudo adduser $USER incus-admin
newgrp incus-admin

# デフォルトの設定で初期化
incus admin init --minimal

ここからWeb UI

なんとIncusはパスワード認証が使えない。 先進的すぎるが提供されていないものは仕方ないので対処する。 以下のURLにアクセスすると、証明書を生成して信頼させる手順が書かれた画面に飛ばされる。 その手順に従う。

https://サーバのホスト:8443

pfxファイルの方はTLS認証時にブラウザが証明書として提示できるよう設定しておく。 crtファイルは画面に従い、サーバ側に何らかの方法で転送した後、以下のコマンドで追加する。

incus config trust add-certificate ダウンロードした証明書.crt

まだクライアント側が信頼されていないので、信頼させる、 Web画面の指示に従い信頼させようとすると以下のようにトークン文字列が出力される。

$ incus config trust add incus-ui
Client incus-ui certificate add token:
BASE64の長いトークン

このトークンをWeb画面側に張り付けてようやくWeb UIにログインできるようになる。

LinuxでHDDに対する書き込みテストとデータ消去

前提

ここに書いているのはあくまでHDDにだけ通用する内容であって、SSDでは異なるアプローチが必要であることに注意する。

HDDに対する書き込みテスト

HDDの大まかな情報はS.M.A.R.T.を読み取れば分かるが、全セクタにわたって本当に問題がないのか疑わしいときは、実際に全セクタへbyte列を書き込み、読み取りテストしてみなければ分からない。 そのようなテストに、Linuxではbadblocksコマンドが使える。

badblocksはbyte列を実際にストレージに書き込んでから読み出すことでセクタが壊れていないか確認する。 この原理のため、現代の大容量のHDDではとてつもない時間がかかることには注意が必要だ。

次は書き込みモード-wで/dev/sdaをテストする。

sudo badblocks -b 4096 -wsv -o badblocks.txt /dev/sda

書き込みモードでは対象のデバイスにデータがあろうが破壊的にbyte列を書き込むので注意

-b 4096でブロックサイズサイズ(セクタのサイズ)が4096 byteであることを伝え、少しでも高速化を期待している。 このブロックサイズはHDDに固有だから個別に調べる必要がある。 -sは進捗を表示させ、-vはverboseに出力させる。 -o badblocks.txtは発見した不良セクタの番号をbadblocks.txtに書き込むことを指示している。

さらに、ここでは書き込むbyte列を指定していないからデフォルトの動作になる。 デフォルトの動作では以下のようにテストが進められる。

  1. 0xaa(0b10101010)を書き込む
  2. 読み出して0xaa(0b10101010)と一致するか確認する
  3. 0x55(0b01010101)を書き込む
  4. 読み出して0x55(0b01010101)と一致するか確認する
  5. 0xff(0b11111111)を書き込む
  6. 読み出して0xff(0b11111111)と一致するか確認する
  7. 0x00(0b00000000)を書き込む
  8. 読み出して0x00(0b00000000)と一致するか確認する

USB 2.0接続の500 GBのポータブルHDDを上記コマンドでテストしたところ、全て完了するまでに27時間強がかかった。

HDDのデータ消去

HDDを処分する際のデータ消去方法として、Linuxではshredコマンドとddコマンドを用いる方法をよく見かける。 ここではshredコマンドを使った方法について説明する。

shredコマンドはファイルシステム上の単一のファイルに対して実行することもできるが、ブロックデバイスに対して実行することもできる。 次は/dev/sdaを2回-n 2ランダムなbyteデータで書き込み、最後に0-zで埋める。

sudo shred -n 2 -vz /dev/sda

-vはverboseを表し、進捗を表示する。

新しいHDDは一回の書き込みで十分だとされているから、そのようなものは0埋めだけで十分かもしれない。

Raspberry Pi 3 Model BにDebian 13ベースRaspberry Pi OS 64bitをインストール

久々にRaspberry PiのOSインストールと初期セットアップを行おうとしたら以前の記事を書いたときから微妙な変化があった。

前提

  • サーバとして運用するからGUI環境は不要
  • ネットワークにはEthernet接続しかしない
  • インストール先のメディアは16 GBのSDカード

OSイメージの入手からインストールまで

Raspberry Pi OSの公式ページからダウンロードする。 Raspberry Pi OS (64-bit)のRaspberry Pi OS LiteにあるDownloadボタンを押す。 XZ圧縮されたOSイメージがダウンロードされる。 ダウンロード時点では次のファイル名だった。

2025-12-04-raspios-trixie-arm64-lite.img.xz

イメージをSDカードに書き込む際のツールとしてRufusをつかった。 上記のXZ圧縮されたイメージを展開することなく直接指定して良い。

初回起動前の設定

消費電力削減とセキュリティ向上のため、不要な機能をOFFにする。 まずは先ほどOSイメージを書き込んだSDカードのFAT32パーティション領域をマウントする。 マウントしたディレクトリ直下にconfig.txtが存在することを確認する。

SSHデーモンの有効化

ディスプレイやキーボード、マウスをいちいち付外ししたくないからSSH接続できるようにしたい。 Raspberry Pi公式の説明によると sshファイルかssh.txtファイルがあるとブート時にSSHサーバが有効化されるようだ。

ssh or ssh.txt

When this file is present, enables SSH at boot. SSH is otherwise disabled by default. The contents do not matter. Even an empty file enables SSH.

ここではマウントしたディレクトリ直下に空のsshファイルを作成した。

不要な機能を無効化する

消費電力削減とセキュリティ向上のため、不要な機能をOFFにする。 ディレクトリ直下のconfig.txtを開き以下の設定を追加する。

# オンボードのサウンドカードをOFFにする。
dtparam=audio=off
# 有線接続しかしないから、BluetoothをOFFにする。
dtoverlay=disable-bt
# 有線接続しかしないから、Wi-FiをOFFにする。
dtoverlay=disable-wifi

詳しい設定内容はconfig.txtのドキュメントを参照せよ。 dtoverlayで設定するものについてはGitHubのfirmwareのREADMEを参照しないといけない場合がある。

ユーザを作成する

以前はデフォルトユーザとしてユーザ名pi、パスワードraspberryが作成されていたが、現在は作られなくなった。 headlessインストールではこの仕様は困る。 ただし、ドキュメントによるとuserconf.txtを作成し、そこに1行のユーザ情報を記載しておけば作成してくれる。

This file should contain a single line of text, consisting of <username>:<password>: your desired username, followed immediately by a colon, followed immediately by an encrypted representation of the password you want to use.

これは/etc/shadowの1行分を記載する必要がある。 必然的に<password>の部分はハッシュ化されたものを書き込む必要がある。 そのパスワードハッシュはopensslコマンドで次のようにして作成できる。

# ソルトをtest、パスワードをtestとするSHA-512ハッシュの生成
$openssl passwd -6 -salt 'test' 'test'
$6$test$s73HObLPm3spffEErq3RSoFse8b43m.tVitc.rEapP4nbLqdmZZabQpuXHItK6ZdlYGqOs5nbhFsWb.ZHZlYa0

<username>userとした場合、最終的にuserconf.txtの中身は次のようになる。

user:$6$test$s73HObLPm3spffEErq3RSoFse8b43m.tVitc.rEapP4nbLqdmZZabQpuXHItK6ZdlYGqOs5nbhFsWb.ZHZlYa0

ソルト長はNISTガイドラインで少なくとも32 bitとされているから、4文字以上が望ましい

初回起動と最低限の初期設定

LANケーブルを繋ぎ、SDカードを挿した状態で電源を供給する。 しばらく待つとDHCPサーバ側でIPリースが行われたことが分かるから、次のようにしてラズパイにSSHする。

ssh ${前節で作成したユーザ}@${リースされたIPアドレス}

SSH後の初期設定

raspi-configを使ってTUIで各種設定する。

sudo raspi-config

後から変更できるものが多いため、そこまで慎重にならなくてよい。

  • Interface Options
    • SSHサーバを有効化
  • Localisation Options
    • ロケールをja_JP.UTF-8に変更
    • タイムゾーンをTokyoに変更

パッケージの調整

vimをインストール

sudo apt install vim-nox

不要パッケージをまとめてアンインストールする。 ここでは特に、不要なデーモンを停止してRAMの使用量を少しでも削減することに重きを置いている。

sudo apt purge alsa-utils avahi-daemon bluez modemmanager nano wpasupplicant
sudo apt autoremove

それぞれのパッケージが不要な理由

  • alsa-utils オーディオを使わないから
  • avahi-daemon mDNSを使わないから
  • bluez Bluetoothを使わないから
  • modemmanager モバイル回線経由でのネットワーク接続などしないから
  • nano 代わりにvimを使うから
  • wpasupplicant Wi-Fiを使わないから

IPアドレスの固定化

NetworkManagerと対話することで固定のIPアドレスを設定できる。 ここでは少ない操作で設定可能なnmcliを使う。 例えばGWのIPv4アドレスを192.168.1.254/24、自ホストの固定IPアドレスを192.168.1.1/24の場合なら次のように設定すればよい。

sudo nmcli con modify 'Wired connection 1' ipv4.method manual ipv4.addresses 192.168.1.1/24 ipv4.gateway 192.168.1.254 connection.autoconnect yes

modifyの次の接続の識別子はUUIDでの指定もできる。 そのUUIDは次のコマンドで確認できる。

nmcli connection

以前はdhcpcd.confファイルを変更して修正していたが、Debian 13では機能しないことに注意せよ。

再起動と固定したIPアドレスでのSSH再接続

sudo reboot

してしばらく待ち、固定後のアドレスでsshしてみる。 IPが変わっているためssh時にman-in-the-middle攻撃を受けているかも警告が出ることがある。 ~/.ssh/known_hostsから該当する行を削除すれば接続できる。

組み込み向けの軽量SSH実装であるDropbearを使う際の設定

組み込みシステムやネットワーク機器など、極端に計算機資源が限られる環境ではOpenSSHに代わってDropbearというSSH実装が用いられることがある。

よく、OpenSSHを代替するかのように説明されるが、ネットワークプロトコルとしての互換性はともかく、設定方法やコマンドは互換性が無いものも多いことに注意する。 この記事は、そのような互換性が無い挙動について、自分のユースケースの観点から問題になる部分についてメモしている。

Dropbearには設定ファイルが無い

OpenSSHは設定ファイルを用いてSSHクライアント/サーバの挙動を制御できるが、Dropbearには設定ファイルが無い。 Dropbearは全ての挙動をコマンドラインオプションを用いて制御する。

Dropbearでは鍵ペアを生成するコマンドとファイル形式が異なる

秘密鍵のファイルフォーマットの違い

OpenSSHでは普通、ssh-keygenコマンドを使って鍵ペアを生成する。

一方Dropbearではdropbearkeyというコマンドを使って鍵ペアを生成する。 更に重要なのは秘密鍵のファイルフォーマットの互換性がないことだ。 この違いは単純にファイルを標準出力するだけでも確認できる。

OpenSSHの秘密鍵は次のような形式になっているが

-----BEGIN OPENSSH PRIVATE KEY-----
BASE64エンコードされているバイナリ
-----END OPENSSH PRIVATE KEY-----

Dropbearの秘密鍵は次のような形式になっている。

ssh-${アルゴリズム}@${文字化けするような生のバイナリ列}

だからssh-keygenコマンドで生成された秘密鍵のファイルをそのままDropbearで使うことはできないだろう。

dropbearkeyコマンドを用いてDropbearが認識できる秘密鍵を生成する

dropbearkeyを用いてed25519鍵ペアを生成するには次のようにすれば良い。

# ed25519アルゴリズムで秘密鍵を~/.ssh/id_dropbear、公開鍵を~/.ssh/id_dropbear.pubとして鍵ペアを生成する
dropbearkey -t ed25519 -f ~/.ssh/id_dropbear

ssh-keygenと異なり、-fオプションを用いて明示的に秘密鍵のファイル名を指定する必要があることに注意する。 また、そのファイルパスは同コマンドのヘルプテキストに書かれているように、特別な理由がないなら次のパスを指定することが望ましい。

~/.ssh/id_dropbear

-f filename Use filename for the secret key. ~/.ssh/id_dropbear is recommended for client keys.

GnuCashの勘定科目コード設計メモ

GnuCashにいくつかあるインポート機能の中に、CSVを用いた取引のインポートがある。 このCSVインポート時に、安全にしたいなら勘定科目コードをCSV中に記載する。 ただし、そのためには先に既存の勘定科目にコードを設定しておく必要がある。

この記事では、勘定科目コードの決め方についてGnuCashの推奨事項を考慮しつつ、自分にとって扱いやすいコードとなるよう設計する大枠の方針を残しておく。

設計方針

  • 勘定科目科目コードに使う文字集合は[0-9a-z]
  • 葉/末端の勘定科目コードは最下位の文字が非ゼロ
  • 枝/親の勘定科目コードは最下位が0
  • 勘定科目コードの桁数は最大の深さを持つ勘定科目に合わせて決める
  • 雑益・雑損のような「その他」の性質を持つ勘定科目のコードは最下位の文字をzにしておく。

CSVインポート時の手順と注意

CSVを用いた取引のインポート時、いくつかの列指定の方法がある。 ここでは元となるCSVファイルが作成しやすい「総勘定元帳」のような形式のものを想定する。

  1. メニューバーから「ファイル(F)」>「インポート(I)」 >「CSVから取引をインポート(T)...」をクリックする。
  2. ウィザードのウィンドウが開くから、読み込むファイルを選択した直後まで進める。
  3. ウィンドウ上部の「勘定科目」プルダウンでベースとなる つまり総勘定元帳の勘定科目を選択する。
  4. CSVファイルの中身がプレビューされている下部の表示では、反対の勘定科目コードを「資金移動先勘定科目」として指定する。
  5. 残りの必須の列「日付」、「金額(符号反転)/金額」、「説明」の列を指定する。
  6. 「進む(N)」ボタンでCSVファイルを処理させ、必要なら除外や調整をしてインポートをcommitする。

設計の根拠となるGnuCashの仕様と推奨事項

GnuCashに付属のマニュアル中の「Creating a Chart of Accounts」節には以下の記載がある。

ここで、英文中のaccountが異なる意味で使われていることに注意せよ。 1つ目の文中のaccountsは勘定科目を意味し、2つ目の文中のaccountsは銀行口座を意味する。

The best way to conceptualize a chart of accounts is as a tree. The main branches represent entire categories or groups, while the leaves of the tree denote individual bank accounts or expense categories.

ようは木構造となるようにコードを設計すべきだと言っている。 そして、より具体的なコードの付け方として以下の記載がある。

It’s customary to have the leaf accounts end in non-zero digits, while parent nodes have increasing numbers of zeros.

葉の勘定科目は非ゼロの数字で終わり、その親の勘定科目は末端が0のものが増えていくようにするのが慣例だと言っている。 例えば以下のように決めるのが慣例だと言っている。

300          費用
|
+-- 310      新聞図書費
|    |
|    +-- 311 書籍代
|
+-- 320      水道光熱費
|    |
|    +-- 321 ガス代
|    |
|    +-- 322 水道代

そして最後に重要な仕様と制限について記載がある。

GnuCash does not prevent duplicate numbering, although we would encourage you to avoid this. Account codes are treated as numbers in base-36, thus, if you run out of numbers, you can use the letters, a through z.

なんとGnuCashは勘定科目コードの重複を禁止しない。 人間が気を付けて採番する必要がある。

勘定科目コードはBASE 36として扱われるから、葉の勘定科目が増えて数字が足りなくなったらaからzの文字を使うことができる。 別の言い方をすると、BASE 36で定義されている文字集合しか使えない。

高速な非暗号学的ハッシュアルゴリズムxxHashを使う

ハッシュの利用目的が改ざんの検知などでは「ない」とき、定番のアルゴリズムであるSHA(secure hash algorithm)やMD5(message digest algorithm 5)は不適なことがある。 そのような場合にxxHashアルゴリズムの利用を検討すると良い。

非暗号学的な利用においては、ハッシュ値の計算速度が重要な場合がある。 既に脆弱と言われているMD5SHA1ですら、暗号学的ハッシュとして設計されているから、その用途の観点で見ると無駄な演算が発生し遅い。

非暗号学的用途に特化して設計されていて、ある程度普及しているハッシュアルゴリズムとしてxxHashがある。 オリジナルはC言語で実装されているようだが、主要な言語向けの移植が揃っている。

cf. xxHash - Extremely fast non-cryptographic hash algorithm