Linux
RaspberryPi
systemd
raspbian

RaspberryPI 緊急メンテナンス用 microSD 作成のススメ(その2: 配布イメージに含まれている設定ファイルの変更)

本ページはその1からの続きとなります。内容としては

  1. 新規ディスクのマウント
  2. 新規インストール用の配布イメージに含まれている、そのまま使ってはダメなファイルの改変
  3. 必須ではないものの、改造しておいたほうが良いその他のファイルを修正

までとなります。なお、全ての作業は既存のラズパイ環境(Linux)の中で行ってください。

新規ディスクのマウント

ここは機械的な処理なので淡々と

[hoge@fuga tmp]$ pwd
/tmp
# マウントポイントの作成
[hoge@fuga tmp]$ mkdir raspbian_root
# 新環境のルートをマウント
[hoge@fuga tmp]$ sudo mount /dev/sda2 /tmp/raspbian_root
[sudo] hoge のパスワード:
# 新環境の /boot をマウント
[hoge@fuga tmp]$ sudo mount /dev/sda1 /tmp/raspbian_root/boot
# マウントされたか確認
[hoge@fuga tmp]$ df -h
ファイルシス                               サイズ  使用  残り 使用% マウント位置
dev                                          418M     0  418M    0% /dev
run                                          454M  316K  453M    1% /run
/dev/mmcblk0p2                                57G  8.4G   45G   16% /
tmpfs                                        454M     0  454M    0% /dev/shm
tmpfs                                        454M     0  454M    0% /sys/fs/cgroup
tmpfs                                        454M     0  454M    0% /tmp
/dev/mmcblk0p1                               489M   71M  418M   15% /boot
tmpfs                                         91M     0   91M    0% /run/user/1000
/dev/sda2                                     15G  1.9G   12G   14% /tmp/raspbian_root
/dev/sda1                                     43M   22M   21M   52% /tmp/raspbian_root/boot
[hoge@fuga tmp]$

新しく作成したマウントポイント /tmp/raspbian_root にレスキュー環境SDで2番目のパーテーションをマウント、その後、たった今マウントした root 配下には予め boot 用のマウントポイントが存在するので、そこに 1番目のパーテーションをマウントして終了。

デフォルト状態ではダメなファイルの改造

/boot/cmdline.txt

オリジナルファイルの内容は次のようになっています。

[hoge@fuga tmp]$ cat ./raspbian_root/boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=4d3ee428-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh
[hoge@fuga tmp]$ 

このファイルに対する変更内容は以下の通りです。


root=PARTUUID=4d3ee428-02 : 要変更

ここに記載されている PARTUUID の値は、RaspberryPI 財団が所有する、配布イメージを作成したマシンにあるディスクのパーテーションIDであって、今刺している SD のルートパーテーションが持つ ID ではありません。従って、この値は書き換える必要があります。この問題を修正するためには、今刺している SD の PARTUUID の値を知る必要があります。そこでおもむろに次のコマンドを打ってみます。
# PARTUUID を画面に表示させつつ、同時にこの結果を /tmp/sda2_blkid にリダイレクト
[hoge@fuga tmp]$ sudo blkid /dev/sda2 | tee /tmp/sda2_blkid
[sudo] hoge のパスワード:
/dev/sda2: LABEL="rootfs" UUID="fd695ef5-f047-44bd-b159-2a78c53af20a" TYPE="ext4" PARTUUID="f4638fd2-02"
[hoge@fuga tmp]$

新環境の PARTUUID が分かりましたね。そしてこの値をコピペしましょう。


init=/usr/lib/raspi-config/init_resize.sh : 要削除

指定されているスクリプトは、ディスクイメージを書き込んだSDで初めて起動した際にのみ実行されるスクリプトです。このスクリプトが実行する内容は、上の問題箇所を自動修正し、その後パーテーション+ファイルシステムの拡張を行って再起動をかける、という内容です。じゃあこのスクリプトを利用してもいいんじゃ?とお思いでしょうが、既にパーテーションのサイズもファイルシステムも拡張済みですよね?そして再起動をかけられると元の環境から流用したい /etc/passwd ファイルなどがロックされてしまいますからダメなんです。つまり完全に不要な部分です。

fsck.repair=yes : 要削除

ファイルシステムを拡張する前に fsck が必要となりましたよね?上に挙げたスクリプトを走らせる前に必要だから記載されているだけなので、この設定が記載されたままだと、起動のたびに fsck が走ってしまいます。不要です。

quiet : 要削除

ブートログの出力を抑制するための設定。このディスクで起動する状況を考えたら、ないほうが良い

console=serial0,115200 : 人によっては不要

USB シリアルケーブルを持っていない人にはこの部分は不要となります

ipv6.disable=1 : 好みに応じて追加

IPv6を使わないならば、ついでにここで追加してしまいましょう

上記の変更をすべて適用した結果がこれです

[hoge@fuga tmp]$ cp -pf ./raspbian_root/boot/cmdline.txt ./raspbian_root/boot/cmdline.txt.bak
[hoge@fuga tmp]$ vi ./raspbian_root/boot/cmdline.txt
(編集)
[hoge@fuga tmp]$ cat ./raspbian_root/boot/cmdline.txt
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=f4638fd2-02 rootfstype=ext4 elevator=deadline rootwait ipv6.disable=1
[hoge@fuga tmp]$

/etc/fstab

オリジナルのファイル内容を表示するとこうなっています

[hoge@fuga tmp]$ cat ./raspbian_root/etc/fstab
proc            /proc           proc    defaults          0       0
PARTUUID=4d3ee428-01  /boot           vfat    defaults          0       2
PARTUUID=4d3ee428-02  /               ext4    defaults,noatime  0       1

# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that
[hoge@fuga tmp]

変更内容は以下の通り


パーテーション名

デフォルト状態のパーテーション名も PARTUUID 値がでたらめなので、旧来からの方式であるデバイス名でのマウントに切り替え。
  • /boot 行は /dev/mmcblk0p1
  • / 行は /dev/mmcblk0p2


マウントオプション

フラッシュメモリ・SSD用のオプションを追加
  • /boot に noatime
  • ext4 の/ に discard 追加
  • SSD向けマウントオプションの解説はここを参照
/ パーテーションの fsck 無効化
最後の数字を 1 から 0 にします
# 最終的な結果はこうなる
[hoge@fuga tmp]$ cat ./raspbian_root/etc/fstab
proc            /proc           proc    defaults          0       0
#PARTUUID=4d3ee428-01  /boot           vfat    defaults          0       2
#PARTUUID=4d3ee428-02  /               ext4    defaults,noatime  0       1

/dev/mmcblk0p1  /boot   vfat    defaults,noatime        0       0
/dev/mmcblk0p2  /       ext4    defaults,noatime,discard        0       0

# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that
[hoge@fuga tmp]

/etc/ssh/ 配下のホストキーファイル群と/etc/ssh/sshd_config

そもそもSDにディスクイメージを書き込んだ直後には、ホストキーペアは一切存在しません。
この状態で sshd を走らせようとすると systemd の regenerate_ssh_host_keys.service が自動的に ssh-keygen コマンドを呼び出して、新しいキーペアをモリモリ生成してしまいます。よって、既存環境のキーペアをコピー。ついでに sshd_config もコピー。

[hoge@fuga tmp]$ sudo cp -pf /etc/ssh/ssh_host_*_key* ./raspbian_root/etc/ssh/
[hoge@fuga tmp]$ sudo cp -pf /etc/ssh/sshd_config ./raspbian_root/etc/ssh/

アカウント関連ファイル群(passwd,shadow,group,gshadow,sudoers)

既存環境のファイルオーナー/パーミッションを確認・変更したりする必要が生じたとき,ログイン名とUID/GIDの一貫性が保たれていなければいけませんから、アカウント関連のファイルはそのまま新環境に流用する必要があります。そしてこの措置によって、はじめて新環境で起動した際にやるべき作業である、不要ユーザーの削除、新規ユーザーの追加、パスワード変更といった煩雑な作業を省くこともできます。

# 現在の環境にあるファイルで上書きコピーするだけでOK
[hoge@fuga tmp]$ for F in passwd shadow group gshadow sudoers; do sudo mv ./raspbian_root/etc/$F ./raspbian_root/etc/$F.bak; sudo cp -pf /etc/$F ./raspbian_root/etc/; done

ここで注意が必要です。既存環境も Raspbian/Ubuntu といった Debian 系ディストリビューションなら問題はほぼ発生しないハズですが、既存環境が RedHat系(Fedora,SuSE等)、ArchLinux 等の場合ですと、システムアカウント命名規則や UID/GID の割り当て規則体系が Debian 系とかけ離れすぎていますので、Raspbian ブート時に「このデーモンを起動するために必要なアカウント/グループがねぇよ」と怒られてしまう可能性があります。その場合は上記コマンドでバックアップした Raspbian-lite のデフォルトデータから必要な行を抜き出して追加コピペしてください(passwd + syadow はペア、group + gshadow もペアです)

/home 配下の全サブディレクトリ

容量の少ない SD のホームディレクトリに巨大ファイルを多数置いている人はそうそういないハズですし、1枚のSD に10人分以上のログイン可能アカウントを作成しているわけはないので丸々コピーします。主たる目的は .ssh/ をはじめとするユーザー定義環境のバックアップです。
(ホームディレクトリの下で他ディレクトリの中にあるファイルへのシンボリックリンクを張りまくっている人は要注意)

# 配布イメージに含まれていたものは全部削除、既存環境にあるものをコピーして終了
[hoge@fuga tmp]$ sudo rm -Rf ./raspbian_root/home/*
[hoge@fuga tmp]$ sudo cp -pRf /home/* ./raspbian_root/home/

ネットワーク環境ファイル

そのままコピーすれば済むもの ( /etc/hostname, /etc/hosts )

[hoge@fuga tmp]$ sudo cp -pf /etc/hosts ./raspbian_root/etc/
[hoge@fuga tmp]$ sudo cp -pf /etc/hostname ./raspbian_root/etc/

(3B 以降で) そのままコピーすればいいもの /etc/wpa_supplicant/*.conf

既存環境からコピーします

[hoge@fuga tmp]$ sudo cp -pf /etc/wpa_supplicant/*.conf ./raspbian_root/etc/wpa_supplicant/

要改造: dhcpcd 設定ファイル( 既存環境で 64bit版 Linux を使っている人のみ必須 )

既存環境が aarch64 版の方は、32bit 版であるレスキュー環境の新ルートに chroot できませんので、ある時点から、レスキュー環境で再起動してレスキュー環境構築作業を継続する必要が生じます。その際、ネットワーク関連の設定は Raspban がデフォルトで起動する dhcpcd (DHCP クライアントデーモン)サービス経由で行われることになりますので、このプログラム向けの設定ファイルを修正しておく必要があります。

dhcpcd は udev が発見した各ネットワークデバイスや wpa_supplicant が発見し、接続可能な SSID に対しそれぞれ

  • 固定 IP 設定があり、設定が間違っていなければそれを採用
  • 設定がない/間違っている場合、最初に DHCP 接続を試みる
  • DHCP 接続に失敗した際、もし設定ファイルに固定IPプロファイルが記述してあればそちらを利用する

という挙動をとります。DHCP を介さない固定 IP 環境を利用している方にしてみれば、この挙動は固定 IP を上書きされてしまう可能性大ですし、DHCP鯖の応答を待つことも無駄です。そして wlan0 デバイスが確実に存在する 3B 以降の機種で、WiFi 環境を設定する方法が面倒なので、レスキュー環境ではダイレクトにIPを設定可能な systemd-networkd を採用することにしています1
(有線 LAN の DHCP環境のみが前提の方であれば、下の systemd-networkd を採用をする必要もありませんし、設定ファイルを弄る必要もありません。)

DHCP/固定IP環境の方共通作業

# デフォルトの設定ファイルはコメントが冗長すぎますので、整理して雛形ファイルとします。
[hoge@fuga tmp]$ cd ./raspbian_root/etc
[hoge@fuga etc]$ sudo mv -pf ./dhcpcd.conf ./dhcpcd.conf.bak
[hoge@fuga etc]$ sudo su
[root@fuga etc]# grep -ve '^#' ./dhcpcd.conf.bak | grep -ve '^$' > ./dhcpcd.conf

固定IP環境の方はこちらへスキップしてください。

DHCP 環境の方

DHCP鯖は、特定ホストにIPを貸し出した後、貸出先ホストがリンクダウンしたとしても、同一ホスト名+MACアドレスを持つクライアントから「もう1回同じ IP をくれ」と要求されると

  • かなり時間が経過していて他のクライアントに貸し出してしまった
  • 貸出用にストックしている IP が猛烈に逼迫している
  • セキュリティの都合で DHCP 鯖側で特殊な設定(再要求を受け付けない)を施している

といった特殊な事情がない限り同一IPアドレスを貸し出す、という挙動をとります。

今回構築中の環境へと再起動後も、基本的には同一IPを使いたいわけですから、 当然、DHCP 鯖に要求するべき現在のIPを調べます。

[root@fuga etc]# ip address show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether b8:27:eb:XX:YY:ZZ brd ff:ff:ff:ff:ff:ff
    inet x.y.z.w/24 brd x.y.z.255 scope global dynamic eth0
       valid_lft 23204sec preferred_lft 23204sec
# 3B 以降なら wlan0 も確認
[root@fuga etc]# ip address show dev wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:PP:QQ:RR brd ff:ff:ff:ff:ff:ff
    inet x.y.z.p/24 brd x.y.z.255 scope global dynamic wlan0
       valid_lft 43088sec preferred_lft 43088sec

# 3B 以降なら wlan0 が接続している ESSID 名も確認
[root@fuga etc]# iwconfig
wlan0     IEEE 802.11  ESSID:"HOGEHOGE"
          Mode:Managed  Frequency:2.462 GHz  Access Point: MM:NN:OO:PP:QQ:RR
          Bit Rate=54 Mb/s   Tx-Power=31 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on
          Link Quality=48/70  Signal level=-62 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

lo        no wireless extensions.

eth0      no wireless extensions.

[root@fuga ect]# 

上記コマンドにより、現在利用している IP は
eth0 が x.y.z.w/24 , wlan0 が x.y.z.p/24
WiFi の ESSID は "HOGEHOGE" と判明したので、以下の内容を追加します。

[root@fuga etc]# cat >> ./dhcpcd.conf
interface eth0
inform x.y.z.w/24

SSID HOGEHOGE
inform x.y.z.p/24
^D
[root@fuga ect]#

これで、多くの環境で再起動後も同一IPで接続できる確率が高まります。
レスキュー環境で systemd-networkd を使う予定がない人は dhcpcd の設定を完了すればネットワーク環境の設定は終了です。こちらにジャンプしていただいて構いません。

固定IPの方

出来上がった雛形ファイルに以下の内容を追加してください

[root@fuga etc]# cat >> ./dhcpcd.conf
# eth0 設定
interface eth0
# IPv6を使わないなら
noipv6
# 固定IP
static ip_address=x.y.z.w/24
# デフォルトゲートウェイ
static routers=x.y.z.p
# DNS サーバ群
static domain_name_servers=x.y.z.q 8.8.8.8 8.8.4.4

# WiFi 設定 (3B以降, SSID が HOGEHOGE の場合)
SSID HOGEHOGE
noipv6
static_ip_address=x.y.z.r/24
static_routers=x.y.z.p
static_domain_name_servers=x.y.z.q 8.8.8.8 8.8.4.4
^D
[root@fuga etc]#

レスキュー環境で systemd-networkd を使う予定がない人は dhcpcd の設定を完了すればネットワーク環境の設定は終了です。こちらにジャンプしていただいて構いません。

systemd-networkd 用設定ファイル (/etc/systemd/network/*.network)

ここからはデフォルトで起動される dhcpcd を使いたくない人向けの設定方法です。

既存環境でも systemd-networkd を利用している方

/etc/systemd/network/ 配下の設定ファイルをすべてコピーすれば終了です。

[hoge@fuga tmp]$ sudo cp -pf /etc/systed/network/*.network ./raspbian_root/etc/systemd/network/

既存環境では systemd-networkd を利用していない方

新しくファイルを作成します (3B/3B+の場合は eth0 用と wlan0 用の二つ)
詳細な説明はここから

eth0 用設定(DHCP 環境の人向け)
[hoge@fuga tmp]$ sudo vi ./raspbian_root/etc/systemd/network/20-eth0.network
(編集)
[hoge@fuga tmp]$ cat ./raspbian_root/etc/systemd/network/20-eth0.network

[Match]
# デバイス名 : WiFi 向け設定の場合は wlan0 に変える
Name=eth0

# IPv6 とIPv4 両方で DHCP する場合は 値を "yes" に変更
# IPv6 のみで DHCP する場合は "ipv6" に変更
[Network]
DHCP=ipv4

# 3B/3B+ で eth0 と wlan0 が同一ネットワークの IP を要求するときは以下の記述があると幸せになれる
# wlan0 向けファイルではこの値を大きくしておけば
# 両方 IP が割り振られているとき(=有線でつながっているとき)は eth0 経由での通信が優先され
# 切断されると即座に wlan0 へと切り替わる
[DHCP]
RouteMetric=10

[hoge@fuga tmp]$
eth0 用設定(IPv4 固定アドレス環境の人向け)
[hoge@fuga tmp]$ sudo vi ./raspbian_root/etc/systemd/network/20-eth0.network
(編集)
[hoge@fuga tmp]$ cat ./raspbian_root/etc/systemd/network/20-eth0.network

# デバイス名 : WiFi 向け設定の場合は wlan0 に変える
[Match]
Name=eth0

[Network]
# 固定IP
Address=x.y.z.w/24
# デフォルトゲートウェイ
Gateway=x.y.z.p
# DNS サーバ: systemd-resolved でも利用される
DNS=x.y.z.q
DNS=8.8.8.8
DNS=8.8.4.4
# NTP サーバ: systemd-timesyncd でも利用される
# 自前の GPS NTP 鯖を運用しているような環境ではここを変えること
NTP=ntp.nict.jp

[hoge@fuga tmp]$

(3B 以降向け) WiFi 環境設定ファイル

systemd-networkd 向け wlan0 設定

eth0 の設定を参考に編集して、同じディレクトリで別名のファイルとして保存してください

[hoge@fuga tmp]$ sudo vi ./raspbian_root/etc/systemd/network/21-wlan0.network
(編集)

ここまでが、改造必須のファイルたちとなります。ここから先は改変してもしなくても構わないファイルたちです

必須ではないものの、改造しておいたほうが良いその他のファイルを修正

/etc/locale.gen

[hoge@fuga tmp]$ sudo su
[root@fuga tmp]# cat > ./raspbian_root/etc/locale.gen
en_US.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
[root@fuga tmp]# 

/etc/timezone

[root@fuga tmp]# cat > ./raspbian_root/etc/timezone
JST
[root@fuga tmp]# 

/etc/locale.conf

[root@fuga tmp]# cat > ./raspbian_root/etc/locale.conf
LANG=ja_JP.UTF-8
[root@fuga tmp]#

/etc/localtime

あえてシンボリックにします

[root@fuga tmp]# cd ./raspbian_root/etc
[root@fuga etc]# ln -sf ../usr/share/zoneinfo/Asia/Tokyo ./localtime
[root@fuga etc]# cd /tmp
[root@fuga tmp]

/etc/systemd/timesyncd.conf

自組織内で NTP 鯖を立てている人はもちろん、そうでない人もデフォルトの NTP 鯖は国内のものにしておきましょう.具体的には、NTP= の行を自組織内 NTP鯖 IP か ISP が指定する NTP 鯖のIP
FallbackNTP= の行を、ntp.nict.jp 等信頼できる国内鯖にしましょう、ということですね。

[root@fuga tmp]# vi ./raspbian_root/etc/networkd/timesyncd.conf
(編集)
[root@fuga tmp]# cat ./raspbian_root/etc/networkd/timesyncd.conf
(抜粋)
[Time]
NTP=x.y.z.t
FallbackNTP=ntp.nict.jp
(以下略)
[root@fuga tmp]#

/etc/default/locale

デフォルトロケール設定。en_GB.UTF-8 が設定されているので ja_JP.UTF-8 に変更

[root@fuga tmp]# cat > ./raspbian_root/etc/default/locale
LANG=ja_JP.UTF-8
[root@fuga tmp]#

/etc/default/keyboard

キーボードレイアウトの設定ファイル

通常の日本語キーボードの人

[root@fuga tmp]# cat > ./raspbian_root/etc/default/keyboard
XKBMODEL="pc105"
XKBLAYOUT="jp"
XKBVARIANT=""
XKBOPTIONS=""

BACKSPACE="guess"
[root@fuga tmp]#

HHK(US) の人

[root@fuga tmp]# cat > ./raspbian_root/etc/default/keyboard
XKBMODEL="hhk"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""

BACKSPACE="guess"
[root@fuga tmp]#

~その他、ラズパイに USB キーボードを刺したときのためにキーボードレイアウトファイルなども設定しておいたほうがいいでしょうけれども、私の場合 SSH で全て済ませてしまいますので、設定してません。~

ここまでくれば、新しいSDで再起動しても、chroot しても問題ありません。そして その3 へと続きます。


[脚注]


  1. 私の場合、ここに挙げた理由の他に、「他ソフトへの依存性を減らすことで片方のソフトがバージョンアップした際に発生しうる齟齬を抑えるためにも、可能であれば systemd に含まれるもので全てを実行したい」、と考えていますのでネットワーク環境設定も systemd-networkd のみを採用することにしています(通常の環境においても)。