0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ProxmoxのQDevice(qnetd)をRaspberry PiのRootless Podmanで安全に構築する

0
Last updated at Posted at 2026-10-13

はじめに

Proxmox VE (PVE) を2台で運用すると、1台が止まった時点で過半数を割ってクォーラムを失います。これを防ぐ定番の方法が、外部投票ノード(QDevice / corosync-qnetd)の導入です。ただ、そのためだけに物理マシンを用意するのはもったいないので、余っているRaspberry Piなどで動かしたいところです。

私の場合、ラズパイは他の用途にも使っています。ホストの環境を汚さず、権限も最小限にするため、Rootless Podman(一般ユーザー権限) のコンテナで運用することにしましたが、ここで壁にぶつかりました。

Proxmox標準のセットアップコマンド pvecm qdevice setup <IP> は、相手先ホストのrootユーザーへSSH接続(既定はポート22)して、証明書の生成と配置を行う作りになっています。qnetdはコンテナの中にあり、標準の手順ではsshでコンテナ内に入れないので、そのままではセットアップに失敗します。かといって、両者の証明書データベース(NSSDB)を手作業で何往復もコピーして構築するのは手間がかかり、入力ミスや鍵の取り扱いミスも起こしやすくなります。

そこで、次の方法を取りました。

  • セットアップの間だけ、コンテナ内でsshdを起動する(実行ごとにランダムな一時パスワードを生成)
  • PVE側のssh設定でポートを2222に振り替え、標準の pvecm qdevice setup をそのまま通す
  • 10分たつとコンテナ内のタイマーがsshdを終了させ、rootパスワードもロックする

コードはGitHubに公開しています。
👉 https://github.com/t-inada-shokai/podman-proxmox-qdevice


設計のポイント

  1. Rootlessコンテナ: コンテナ内のrootは、ホストでは一般ユーザーに対応します。コンテナ内で何かあっても、ホストのroot権限までは及びません。ただし、後述の network_mode: host ではコンテナがホストのネットワークに直接つながるため、LAN上の他のサービスへ到達できる点には注意が必要です。
  2. sshdのオンデマンド運用: 通常時にコンテナが待ち受けているのは qnetd(ポート5403)だけです。セットアップ時にだけ、./start-auth-wait.sh がコンテナ内でsshd(ポート2222)を起動します。
    • 実行のたびにランダムな一時パスワードを生成し、画面に表示します。固定パスワードは使いません。
    • 期限(既定10分)はコンテナ内の timeout が管理します。ホスト側のスクリプトが終了しても、SSHセッションが切れても、sshdは期限で終了します。
    • sshd終了後と、コンテナ起動時には、rootパスワードをロックします。
    • 窓が開いている間のリスク(LANから2222番に到達できること)は残るので、LoginGraceTime 30 と MaxAuthTries 3 で試行を絞っています。
    • pvecm qdevice setup の途中で、PVEノードの公開鍵がコンテナ内の authorized_keys に追加されます。パスワードのロックは公開鍵認証を止めないので、sshdが起動している間は、セットアップを実行したPVEノードのrootの鍵で入れます(コンテナを作り直すと消えます)。
  3. ホストネットワークモード: クラスタノードの送信元IPを正しく認識させるため、network_mode: host で動かします。2222番と5403番はどちらも非特権ポート(1024以上)なので、Rootlessでもバインドできます。

構築手順の概要

詳しいファイル構成やコードはGitHubリポジトリを参照してください。大まかな流れは次のとおりです。

1. QDevice側(Raspberry Piなど)の準備と起動

リポジトリを一般ユーザー権限でクローンし、ホストの前提条件を確認してから起動します。

git clone https://github.com/t-inada-shokai/podman-proxmox-qdevice.git
cd podman-proxmox-qdevice
./bootstrap-host.sh        # subuid / linger / podman-restart / 5403番の開放などを確認
podman compose up -d --build

この時点でコンテナが待ち受けているのは 5403 だけで、SSHポート 2222 は閉じています。

2. 認証待ち受けを開始する

セットアップの直前に、ラズパイ側で次を実行します。

./start-auth-wait.sh

実行すると、コンテナ内でsshd(ポート2222)が起動し、一時パスワードと有効期限が表示されます。途中で閉じたいときは ./start-auth-wait.sh stop です。

3. Proxmox側でセットアップする

事前に、各PVEノードで corosync-qdevice パッケージがインストールされている必要があります (apt install corosync-qdevice)。

PVEノード(作業する1台)の /root/.ssh/config に、次を追記します。pvecm が2222番に接続するようにするためです。

Host 192.168.xxx.xxx
    Port 2222
    User root

一度手動でSSH接続し、ホストキーを承諾します。パスワードは手順2で表示された一時パスワードです。

ssh root@192.168.xxx.xxx
exit

続いて、標準のセットアップコマンドを実行します。

pvecm qdevice setup 192.168.xxx.xxx -f

途中で ssh-copy-id のパスワード入力を求められたら、同じ一時パスワードを入力します。-f は、PVE各ノード側に残った古いQDevice用の証明書DBを作り直すためのオプションです。新規構築で古い証明書が無ければ不要なこともあります。
実行中に Certificate database ... already exists. Delete it ... と表示されますが、qnetd側のNSSDBはコンテナ起動時に初期化済みのためで、想定どおりの表示です。

既にQDeviceが設定されているクラスタの場合
最後に Qdevice already configured, must be removed before setting up new one! と出て止まります。これは、クラスタ設定(corosync.conf)に既存のQDevice設定があるためです。証明書の再発行は、このエラーが出る前の段階で完了しています。
接続先が今回のホストと同じなら、設定はそのまま使えるので、新しい証明書を読み込ませるために、各ノードで systemctl restart corosync-qdevice を1台ずつ実行すれば足ります。
接続先が違う場合や、やり直したい場合は、両ノードがオンラインの状態で、先に pvecm qdevice remove を実行してから、もう一度 pvecm qdevice setup を実行してください。

4. 後片付け

  • 10分たつと、コンテナ内のタイマーがsshdを終了させ(ポート2222が閉じる)、rootパスワードがロックされます。
  • PVE側の /root/.ssh/config に追記した Host の記述は、セットアップ後に削除してください。残しておくと、以降のsshが意図せず2222番に向かいます。

NSSDBのバックアップと復元

qnetdの証明書DB(NSSDB)には秘密鍵が含まれます。ベアメタルが壊れたときに、 restore-nssdb.sh でボリュームを復元して起動するだけで戻せるよう、ageで暗号化してGitで管理します。暗号化した情報は公開リポジトリには置かず、別の非公開リポジトリに保存します。

# 初回のみ: age の鍵を作り、秘密鍵はリポジトリ外(紙やオフライン媒体)にも保管する
mkdir -p ~/.config/age
age-keygen -o ~/.config/age/qnetd.key
age-keygen -y ~/.config/age/qnetd.key > recipients.txt

# 初回のみ: 空の非公開リポジトリを作り ~/qnetd-backup に紐付ける
# cd ~/qnetd-backup
git init -b main ~/qnetd-backup
git -C ~/qnetd-backup remote add origin <非公開リポジトリのURL>
# (中身のある非公開リポジトリを使う場合は、上2行の代わりに次の行を実行してください)
git clone <非公開リポジトリのURL> ~/qnetd-backup

# バックアップ(初回のみ push -u origin main、、2回目以降は git push でよい)
./backup-nssdb.sh --commit && git -C ~/qnetd-backup push -u origin main

# 復元(新しいホストでは、先に非公開リポジトリを ~/qnetd-backup に clone し、
#      ageの秘密鍵を ~/.config/age/qnetd.key に置いてから実行)
./restore-nssdb.sh --up

状態の確認

PVE側で、QDeviceが1票を持ってクォーラムを支えていることを確認できます。

root@pve001:~# pvecm status
...
Votequorum information
----------------------
Expected votes:   3
Highest expected: 3
Total votes:      3
Quorum:           2
Flags:            Quorate Qdevice
...
root@pve001:~# corosync-qdevice-tool -s
...
QNetd host:             192.168.xxx.xxx:5403
State:                  Connected

ラズパイ側では、両ノードが接続しているかを確認できます。

podman exec qnetd corosync-qnetd-tool -l

corosync-qdevice を再起動しても Connected に戻ること、コンテナを作り直しても(ボリュームを消さなければ)再接続できることも確認しました。


検証環境

項目 バージョン
Proxmox pve-manager 9.2.21
Raspberry Pi(OS / アーキテクチャ) Debian 13 trixie / aarch64
Podman 5.4.2
コンテナのベース Debian trixie (debian:trixie-slim)

おわりに

ProxmoxのQDeviceは非常に軽量ですが、標準のセットアップがSSH前提のため、コンテナ化やRootless運用は敬遠されがちでした。「セットアップの間だけコンテナ内でsshdを起動し、ランダムなパスワードと期限で窓を絞る」ことで、公式の自動セットアップをそのまま使いながら、Rootless環境でQDeviceを運用できました。

窓が開いている間のリスクがゼロになるわけではないので、LAN内の信頼できる環境で、必要なときだけ実行する運用をおすすめします。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?