思うところあってcloud-initを使ってUbuntu ServerをRasPiにインストールする方法を勉強しました。 仕上がった設定ファイルと解説をGitHubのリポジトリとして公開しています。
cloud-initとは
cloud-initは名前の通りもともとはAmazon Web Serviceのクラウド・サーバーを設定するために作られた仕組みです。クラウド・コンピューティングでは多数のリモートサーバーを設定しなければならないことが多くありますので手作業でやっていては間に合いません。cloud-initは設定をあらかじめファイルに記述することで設定作業を自動化することをもくろんでいます。当初はAWS用だったcloud-initですが現在はCanonicalが管理しています。
最初はクラウド・コンピューティング用に使われていましたが、今ではローカルでの設定にも用いられています。Raspberry PiへのUbuntu Serverのインストールにも使用することができます。そこでここ最近いじっていたRasPiへのインストールに活用しようとした次第です。
試験した環境
- Raspberry Pi 3 model A+
- Ubuntu Server 22.04.1 LTS
Raspberry Pi Zero 2は昨年壊した後も流通が復活しないため入手できていません。しかし、今回公開した設定がそのまま使えるはずです。
躓いた点など
設定ファイルの説明については上述のレポジトリを参照してください。ここでは、勉強中に躓いたことや気が付いたことを書いておきます。
write_filesは1回しか使えない
設定ファイルuser-dataではターゲットシステムに対して3つのファイルを書き込んでいます。この書き込みを以下のように記述したところ、ファイルcしか書き込まれませんでした。
write_files: - path: a write_files: - path: b write_files: - path: c
この問題についてはものすごく苦しんだのですが、結論から書けば「write_filesはuser-data中で1回しか使ってはならない」という制限に抵触していました。
cloud-initのModule Referenceには以下のように書かれています。
Module frequency: once-per-instance
cloud-init module reference
once-per-instanceとは、「インスタンス(PC)へインストール時に1回」という意味です。ですから軸通り解釈すればcloud-dataファイルでの出現回数には制限がないはずです。故に「複数回現れたらそれぞれがインスタンスへのインストール時に1度ずつ実行」だと理解していたのですが、これが失敗の原因でした。
ドキュメントの記述にはまだ納得していませんが、とにかくこの制限を回避するには以下のように書きます
write_files: - path: a - path: b - path: c
Wi-FiのRegional Domain
Wi-Fiが使用する周波数帯は多くの用途に使われており、それらとぶつからないようにWi-Fiが衝突する周波数を譲ることが求められています。この「衝突する周波数」は国ごとに異なっています。LinuxでのWi-Fi運用が法に触れないよう、Wi-Fiの使用時にはどの国の制限に従うのか設定しなければなりません。
この設定には/etc/default/crdaファイルが使用されていました。実際、ネット上の情報の多くはcloud-initでこのファイルを正しく設定しろと書いてあります。ところが、Ubuntuは22.04からこのファイルによる設定を廃止しています。
このファイルによる設定が廃止された裏には、Wi-Fiの地域による設定をユーザーランドからカーネルに移したいという方針があったようです。地域による設定をユーザーに自由に触らせると、「法律に抵触した運用することで広い周波数を使える」という悪質な行いがカジュアルに広がるかもしれません。これに一定の制限をかけたかったようですが、結果的にUbuntu 22.04からユーザーが永続的にWi-Fiの地域を指定する方法がなくなりました。
- Need option to specify wifi regulatory domain
- Wifi location setting doesn’t work because CRDA is deprecated since Ubuntu 22.04 #511
結局RasPi向けのUbuntu 22.10ではnetplanで地域指定を許すことになりました。しかしUbuntu 22.04では問題が残ったままです。ですので公開しているnetwork-configファイルではnetplanのregulatory-domainをコメントアウトしています。必要に応じてコメントアウトを外してください。
Wi-Fi情報の保護
user-dataのruncmdの最後でnetwork-configを塗りつぶしています。
network-configにはWi-Fiアクセスポイントのパスワードが含まれており、SSDを盗んだ人がWindows PCのUSBポートに挿せば簡単に読み取ることができます。そこでこの手のお手軽な犯罪に対するハードルを上げるために当該ファイルを消しています。
この対策をとっても/etc/netplanから読み取ることができますが、こちらについてはRasPiの運用の問題ですのでcloud-initのuser-dataでは対策していません。
- dd if=/dev/random of=/boot/firmware/network-config bs=512 count=16 - rm /boot/firmware/network-config
有線LAN(RTL8152)しか使えない場合
このブログの過去のエントリで書いたように、RTL8152を使ったLAN接続にはちょっとした設定が必要です。この設定はcloud-initの中で行えますので公開したuser-dataの中でも設定を行っています。ただし、こうやって設定したRTL8152を使って通信ができるのは再起動後に限られます。
つまり、cloud-initの中ではRTL8152を使った通信が行えません。
これは困ります。cloud-initのuser-dataではGitHubのアカウントからSSHの公開鍵を取得しています。もしWi-Fiが使えないとなったら、この情報を取得できないことになります。また、apt update/apt upgradeもできません。
仕方がないので有線LANしか使えない場合には次のようにします。
- apt update / apt upgradeはしない。
- SSHの公開鍵をuser-dataで明示的に設定する。あるいはSSHでパスワード・ログインを許す。
こうすれば、再起動後にSSHで有線LANからログインし、手動でapt update / apt upgradeを実行できます。
まとめ
cloud-initを使った設定はIoT機器の試作のようなスクラップ&ビルドを繰り返す際に便利に使えます。特にコンソールやキーボードをRasPiに接続しなくても、10分も放置しておけばSSHに接続できる環境が整う点が気に入っています。