ラズパイのバックアップイメージをオンライン・リモート操作のみで作る

RaspberryPi・マイコン

遠隔地に常時稼働のRaspberryPi(ラズパイ)を設置したものの、バックアップイメージを作成していなかったが、なんとかリモート操作のみで作った話。

遠隔地(実家)に常時稼働ラズパイを設置

自宅サーバの稼働状態を別拠点から常時監視したくて、実家のネット環境にRaspberry pi zeroを設置した。
実家は、おいそれとは帰れないほど物理的に遙か遠く離れた地だったが、Nagios等を簡易に設定しただけだったのでバックアップなどは考えておらず、壊れれば郵送してもらって再構築する程度のことを考えていた。
ところが、帰省時の設置を終えて自宅からラズパイを見て見ると、通信不安定となることがあるためにSoftEtherなどで通信環境を補強したり、実家側のPCの電源を入れて自由に操作できるようにしてみたり(割と便利)等々、常時起動マシンならではの便利さを追求した結果、いろいろと作り込んでしまい、壊れればもったいないと思い始めていた。
ラズパイは突然microsdが故障することもあるし(経験済み)、各アプリの設定ファイルなどはバックアップしているが、再構築はやはり手間だし、イメージファイルとして残しておけば復旧時も簡単だ。

とはいえ、バックアップイメージを取るためにsdカードを抜き差しするなど、実家の家人には不可能なので、オンラインのリモート操作のみ(物理操作なし)でやる方法をなんとか試してみた、そんな経緯。

実現方法

結論から言うと、手元のPC(Linux)にRaspberryPiのイメージファイル(.img)を少々加工してマウントし、rsyncで同期すれば実現できた。後述するが加工の際には”ディスク識別子(PARTUUID)”を一致させる必要がある。

環境

遠隔地に設置したバックアップ対象のラズパイ(以下、ラズパイ)と手元で操作するPC(以下、PC)は直接通信できる状態にあること。基本的にはssh等でアクセスする環境を整えていると思われるのでここが問題になることはないだろう。今回はrootによる公開鍵暗号方式でのログイン環境を利用している。
ちなみに、SoftEtherを利用するとルータに手を入れることなく直接通信環境を整えることができるので便利だ。RaspberryPi ZeroでもSoftEther Serverが問題なく動作している。

バックアップの対象となるラズパイは、公式推奨のRaspberryPi OS(旧Raspbian)で構築したものを想定している。バックアップにrsync利用を前提としているので基本的にはPCはLinuxマシンを想定している。また、イメージファイルのファイルシステムext4はWindowsは非対応でもある。
ただしWindowsマシンであってもWSLなどで仮想のLinuxマシンを起動すれば、同じことは実現できる。実際にやってみたができた。詳細は割愛。

バックアップ用イメージファイルの用意

ブート領域を含めMBRレコード等ゼロから作ると面倒なので、sdカードに書き込めば必ず起動するイメージを調達する。RaspberryPi OSの公式サイトが配布しているインストールイメージを選んだ。

ここで、”Manually install an operating system image”セクションの”See all download option”のリンクを辿り、”Raspberry Pi OS Lite”をクリックしてイメージをダウンロードする。どうせ上書きして消すので何でもいいのだが、小さい方が早いと言うことで。

ダウンロードした”.xz”のファイルは、unxzコマンドで解凍でき、”.img”ファイルが現れる。

バックアップ対象のラズパイのOSとバージョンが近い方がよければ、古いバージョンのものを選ぶなど、そこら辺は適宜。

イメージファイルのディスク情報を整える

イメージファイルの容量拡張

ダウンロードしたイメージは2GB程度のサイズなので、イメージファイルをバックアップに耐えられるように必要であれば拡張する。
イメージファイルの中はMBR形式、パーティション2つで構成されている。第1パーティションはboot(FAT32)、第2パーティションはroot(ext4)だ。バックアップ対象の容量に合わせて第2パーティションを拡張する。

容量は大きめに作っておいて後で縮小することも可能。後に説明する”pishrink.sh”を使うと、最小限まで自動で縮小してくれ、しかもリストア後には自動でSDカード一杯に拡張するスクリプトまで仕込んでくれる。これを使えば手間も削減できる。

手順は、イメージファイルの拡張→パーティションの拡張→ファイルシステムの拡張だ。
以下のlinuxコマンドはroot権限を前提とする。

ダウンロードした.imgファイルは直接いじらず、コピーを残しておくことをお勧めする。失敗してやり直しなどが多く、いちいちダウンロードするのが面倒だった。

イメージファイルの拡張

以下、特記なき場合は”/tmp”での作業。

[root@]# truncate -s 4G /tmp/xxx.img

truncateを使用。xxx.imgはイメージファイル、-s 4Gでサイズ4GBを指定した。ファイルサイズが大きくなっていることを確認する。

パーティションの拡張

partedでイメージファイルを直接開き、resizepartで第2パーティションをファイルサイズ一杯に拡張する。

[root@]# parted /tmp/xxx.img
GNU Parted 3.1
/tmp/xxx.img を使用
GNU Parted へようこそ! コマンド一覧を見るには 'help' と入力してください。
(parted) p
モデル:  (file)
ディスク /tmp/xxx.img: 4295MB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ:

番号  開始    終了    サイズ  タイプ   ファイルシステム  フラグ
 1    4194kB  273MB   268MB   primary  fat32             lba
 2    273MB   1875MB  1602MB  primary  ext4

(parted) resizepart 2 100%
(parted) p
モデル:  (file)
ディスク /tmp/xxx.img: 4295MB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ:

番号  開始    終了    サイズ  タイプ   ファイルシステム  フラグ
 1    4194kB  273MB   268MB   primary  fat32             lba
 2    273MB   4295MB  4022MB  primary  ext4

(parted) q
[root@]#
ファイルシステムの拡張

ファイルシステムの拡張のためには、イメージファイルをループバックにマッピングする必要がある。

[root@]# kpartx -av xxx.img
add map loop0p1 (253:3): 0 524288 linear /dev/loop0 8192
add map loop0p2 (253:4): 0 7856128 linear /dev/loop0 532480

kpartxを利用しloop0にマッピングされた。第2パーティションは”/dev/mapper/loop0p2″でアクセスできる。

次に”resize2fs”でファイルシステムを拡張。その前に”e2fsck”で整合性チェックしてから。

[root@tmp]# e2fsck -f /dev/mapper/loop0p2
e2fsck 1.43.1 (08-Jun-2016)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
rootfs: 47607/244800 files (0.1% non-contiguous), 305632/982016 blocks

[root@tmp]# resize2fs /dev/mapper/loop0p2
resize2fs 1.43.1 (08-Jun-2016)
Resizing the filesystem on /dev/mapper/loop0p2 to 982016 (4k) blocks.
The filesystem on /dev/mapper/loop0p2 is now 982016 (4k) blocks long.

[root@tmp]# 

これでファイルシステムがパーティション一杯に拡大した。

ちょっと脱線。

ここは”おま環”で多少ハマったところ。
当方の作業PCはCentos7を使用していたが、e2fsck,resize2fs等のツールが古く、最新のRaspiOSのファイルシステムに対応していなかった。後のpishrink.sh利用時やイメージをフラッシュ後の起動時にエラーとなる。
新しいlinuxでは”Metadata_Checksum”とよばれる信頼性を高めるオプションが採用されているらしいが、これに対応していないツールを使用するとファイルシステムが破壊されたと認識されるらしい。
仕方がないので、新版のツールをDLしてコンパイルして差し替えた。ささっとヒントを書いておく。

wget http://downloads.sourceforge.net/project/e2fsprogs/e2fsprogs/v1.43.1/e2fsprogs-1.43.1.tar.gz
tar xzf e2fsprogs-1.43.1.tar.gz
cd e2fsprogs-1.43.1
./configure
make


参考サイト:https://askubuntu.com/questions/747656/after-a-power-failure-unable-to-mount-the-drive-get-a-newer-version-of-e2fsck

“ディスク識別子”の書き換え

ラズパイのブートシーケンスでは、まずROMのプログラムから起動し、途中でSDカードをマウントして中身を読み取りブートを継続するが、その際に”ディスク識別子”を使用する。
対象ラズパイと配布イメージファイルでは、このディスク識別子が違っており、書き換えておかなければリストア後のラズパイはブートが途中で止まってしまう。ディスク識別子はlsblkなどでは”PARTUUID”として表示される。

まず、運用中ラズパイでディスク識別子を確認する。RaspberryPi OSのSDカードのディスクはMBR管理のため、fdiskを利用する(ようです多分)。

user@raspi:~ $ sudo fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 57.75 GiB, 62008590336 bytes, 121110528 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x40fa665a

Device         Boot  Start       End   Sectors  Size Id Type
/dev/mmcblk0p1        8192    532479    524288  256M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      532480 121110527 120578048 57.5G 83 Linux

この例では”Disk identifier: 0x40fa665a”がそれ。これはディスクによって違う値なので。
“/dev/mmcblk0″はラズパイでのSDカード(ディスク)の認識名。誤ってパーティションを読まないように。

次にPCのイメージファイルのディスク識別子を書き換え。

[root@]# fdisk /tmp/xxx.img
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


コマンド (m でヘルプ): p

Disk /tmp/xxx.img: 4294 MB, 4294967296 bytes, 8388608 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
Disk label type: dos
ディスク識別子: 0xb1214a26

 デバイス ブート      始点        終点     ブロック   Id  システム
/tmp/xxx.img1            8192      532479      262144    c  W95 FAT32 (LBA)
/tmp/xxx.img2          532480     8388607     3928064   83  Linux

コマンド (m でヘルプ): x

上級者コマンド (m でヘルプ): i
新しいディスク識別子 (現在 0xb1214a26): 0x40fa665a
ディスク識別子: 0x40fa665a

上級者コマンド (m でヘルプ): r

コマンド (m でヘルプ): p

Disk /tmp/xxx.img: 4294 MB, 4294967296 bytes, 8388608 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
Disk label type: dos
ディスク識別子: 0x40fa665a

 デバイス ブート      始点        終点     ブロック   Id  システム
/tmp/xxx.img1            8192      532479      262144    c  W95 FAT32 (LBA)
/tmp/xxx.img2          532480     8388607     3928064   83  Linux

コマンド (m でヘルプ): w
パーティションテーブルは変更されました!

ディスクを同期しています。
[root@]#

fdiskを起動した後、上級者コマンドx→識別子設定i→新識別子を入力。これでディスク識別子の変更は完了。

マウントしてバックアップコマンド(rsync)実行

マウントポイント作成とマウント。

[root@]# mkdir /mnt/pi
[root@]# mkdir /mnt/pi/boot
[root@]# mount /dev/mapper/loop0p2 /mnt/pi
[root@]# mount /dev/mapper/loop0p1 /mnt/pi/boot

[root@]# df -h
ファイルシス                     サイズ  使用  残り 使用% マウント位置
<中略>
/dev/mapper/loop0p2                3.7G  1.1G  2.4G   32% /mnt/pi
/dev/mapper/loop0p1                255M   50M  206M   20% /mnt/pi/boot

rsyncコマンド発行。
試行錯誤は出てくる可能性があるので、イメージは予めバックアップしておくことと、rsyncコマンドには”–dry-run”オプションでシミュレーション動作をさせて動作確認するといいかもしれない。

[root@]# rsync -e "ssh" -azcv --delete --exclude="/dev/" --exclude="/mnt/" --exclude="/proc/" --exclude="/sys/" --exclude="/tmp/" --exclude="/run/" --exclude="/var/tmp/" root@xxxxxx.com:/ /mnt/pi

“root@xxxxxx.com:/”のxxxxxx.comは接続先のFQDNかIPアドレスを。接続先(バックアップするラズパイ)には、rootのアカウントで接続できるようにしておく必要がある。
“exclude=”xxx”は、同期対象外のディレクトリ。

rsyncが無事に完了したら、後始末。アンマウント、マッピング解除。

[root@]# umount /mnt/pi/boot
[root@]# umount /mnt/pi
[root@]# kpartx -d /tmp/xxx.img
loop deleted : /dev/loop0
[root@]# rmdir /mnt/pi/boot
[root@]# rmdir /mnt/pi

pishrink.shでイメージ縮小(任意)

前項rsyncが完了したら、バックアップは完了。xxx.imgを”Win32DiskImager”などを使って、microsdにフラッシュすればよい。ファイルの保管サイズなどを極力小さくしたければ、ディスクイメージを縮小することは可能。前述の拡張の手順の逆順で行けばいい。resize2fs→parted→truncate。

ただ、サイズをぴったりに調整するなどは多少面倒なので、便利なスクリプトを使う手もある。

ここにある”pishrink.sh”がそれ。テキストエディタを開いてコピペでもOK。

このツールは優れもので、イメージファイルのサイズを可能な限り自動で縮小してくれる。しかもSDカードにリストアしてラズパイを起動すると、初回起動時にカード一杯に自動で領域拡張してくれる。

pishrink.shをパスの通ったところにおいて(以下の例では/usr/local/bin)実行権をつけて以下の通り。

[root@]# /usr/local/bin/pishrink.sh /tmp/xxx.img
pishrink.sh v0.1.2
pishrink.sh: Gathering data ...
Creating new /etc/rc.local
pishrink.sh: Checking filesystem ...
rootfs: 47608/244800 files (0.1% non-contiguous), 305633/982016 blocks
resize2fs 1.43.1 (08-Jun-2016)
pishrink.sh: Shrinking filesystem ...
resize2fs 1.43.1 (08-Jun-2016)
Resizing the filesystem on /dev/loop0 to 406198 (4k) blocks.
Begin pass 3 (max = 30)
Scanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The filesystem on /dev/loop0 is now 406198 (4k) blocks long.

pishrink.sh: Shrinking image ...
pishrink.sh: Shrunk /tmp/xxx.img from 4.0G to 1.9G ...
[root@]# 

win32DiskImagerで新たなmicrosdカードにxxx.imgをフラッシュし、手元にある予備機のラズパイに差して起動したところ、正常起動することを確認した。最初の起動時には領域拡張後に一旦自動でリブートする。

まとめ

物理的に手の出せない遠隔地に設置してしまったラズパイ。
バックアップイメージを後から作りたくなっても、RaspberryPi OSの公式イメージファイルとrsyncを利用できるPCがあれば、なんとかやる方法はあるよ、ということで。

コメント

タイトルとURLをコピーしました