RaspberryPi で RaspberryPi をバックアップ

RaspberryPiのmicroSDカードをバックアップ／復元する方法にはいくつか方法があります。
しかしながら Windows や Mac で行う場合、ツールをインストールしたり、イメージの中身が読み書きできなかったりで敷居が高いです。

また、Linuxで行ったとしてもLinuxデスクトップではオートマウントが悪さをしてうっかりするとイメージ書き込みが思うようにできなかったりします。

また、例えば32GBytesのSDカードについて、実際には4GBytesぐらいしか使って無かった場合、
32GBytesをバックアップするのもかさばるし書き込み時間がかかって仕方がないですね。
また、32GBytesを32GBytesにコピーしようとしても、微妙にサイズが違って収まらなかったりします。その場合でも実害が出るとは必ずしも限りませんが、やっぱり気持ち悪いですね。

ここでは、RaspberryPiを使ってコンパクトに確実にバックアップや復元をする方法を紹介します。

# 今回の方法

## 特徴
- バックアップ、復元は ZIP 圧縮／展開しながら行う
- 速い！ 2分でコピー(Raspbian buster ベースの1.6G使用時を復元の場合)。
- その代わりバックアップには手間がかかる
- ディスクイメージもZIP圧縮でコンパクト

## 概要
ここでは、RaspberryPiを使ってRaspberryPiのバックアップや復元を行う方法を紹介します。
残念ながら動作途中の自分自身のバックアップではなく、別のSDカードを使って起動し、ターゲットのSDカードをバックアップします。
また、完全にヘッドレスで行います。sshとかでログインして作業する方法。GUIを使う方法は、またの機会に。

# 必要なもの

- RaspberrtPi
- 操作用SDカード
- USB SDカードリーダライタ
- バックアップ元SDカード
- 保管用のUSBメモリなど
- 復元先SDカード

# 手順


## シュリンク
- RaspberryPiを操作用SDカードで起動します
- バックアップ元SDカードをUSBリーダで接続、サイズをシュリンク

## バックアップ
- RaspberryPiを操作用SDカードで起動します
- バックアップします
- シュリンクしたファイルシステムを拡張

## 復元
- RaspberryPiを操作用SDカードで起動します
- 復元
- シュリンクしたファイルシステムを拡張

# シュリンク
まず、RaspberryPiを操作用SDカードで起動します

## 分析

```

 dmesg -w
```
としてから、バックアップ元のmicroSDカードをUSBカードリーダを使ってUSBポートに刺します。

```

[sda] Attached SCSI removable disk
```
と出るので、 sdaデバイスであることがわかります。

Ctrl+Cで止めて、

```

 sudo fdisk -l /dev/sda
```

として分析します

```

Disk /dev/sda: 29.5 GiB, 31652315136 bytes, 61820928 sectors
Disk model: SD Card Reader  
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: 0x6c586e13

Device     Boot  Start      End  Sectors  Size Id Type
/dev/sda1         8192   532479   524288  256M  c W95 FAT32 (LBA)
/dev/sda2       532480 61820927 61288448 29.2G 83 Linux

```

と出ています。/dev/sda2 の Start の 532480、End の 61820927 の値が重要です。後で使うことを覚えておきましょう。

## ファイルシステム使用量を確認

```

 $ sudo mount /dev/sda2 /mnt
```
一旦マウントして、

```

pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       6.9G  1.3G  5.4G  19% /
devtmpfs        459M     0  459M   0% /dev
tmpfs           464M     0  464M   0% /dev/shm
tmpfs           464M   12M  452M   3% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           464M     0  464M   0% /sys/fs/cgroup
tmpfs            93M     0   93M   0% /run/user/1000
/dev/sda2        29G  1.6G   26G   6% /mnt

```

として、使用量を見ます。/dev/sda2 は 1.6GBtres 使用しています。

```

pi@raspberrypi:~ $ sudo umount /dev/sda2
```
としてアンマウントしておきます。


# resize2fs

resize2fs をそのまま起動したら

```

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2
resize2fs 1.44.5 (15-Dec-2018)
Please run 'e2fsck -f /dev/sda2' first.
```
と出ました。先にe2fsckをかけておきます。


```

pi@raspberrypi:~ $ e2fsck -f /dev/sda2
e2fsck 1.44.5 (15-Dec-2018)
e2fsck: Permission denied while trying to open /dev/sda2
You must have r/w access to the filesystem or be root
pi@raspberrypi:~ $ sudo e2fsck -f /dev/sda2
e2fsck 1.44.5 (15-Dec-2018)
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: 51665/1883232 files (0.2% non-contiguous), 538568/7661056 blocks
```
では、もう一度。

```

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2
resize2fs 1.44.5 (15-Dec-2018)
The filesystem is already 7661056 (4k) blocks long.  Nothing to do!
```
何も起こりませんでした。今度は縮小後のファイルシステムサイズを指定していきます。先程使用量は1.6Gでした。小さめから1G,2G,3G・・・と順に試してしていきます。

```

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2 1G
resize2fs 1.44.5 (15-Dec-2018)
resize2fs: New size smaller than minimum (642567)

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2 2G
resize2fs 1.44.5 (15-Dec-2018)
resize2fs: New size smaller than minimum (642567)

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2 3G
resize2fs 1.44.5 (15-Dec-2018)
Resizing the filesystem on /dev/sda2 to 786432 (4k) blocks.
The filesystem on /dev/sda2 is now 786432 (4k) blocks long.
```
3GBytesになりました。もうちょっと詰めたいな〜と思い、2.9Gとすると・・・

```

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2 2.9G
resize2fs 1.44.5 (15-Dec-2018)
resize2fs: Invalid new size: 2.9G
```
小数指定はダメでした。今度は2100M,2200M,2400M,2500M と増やしていきます。

```


pi@raspberrypi:~ $ sudo resize2fs /dev/sda2 2400M
resize2fs 1.44.5 (15-Dec-2018)
resize2fs: New size smaller than minimum (628817)

pi@raspberrypi:~ $ sudo resize2fs /dev/sda2 2500M
resize2fs 1.44.5 (15-Dec-2018)
Resizing the filesystem on /dev/sda2 to 640000 (4k) blocks.
The filesystem on /dev/sda2 is now 640000 (4k) blocks long.
```
2500Mで通りました。このサイズでOKとしました。4kブロックが640000とありますね。この数字も覚えておきます。
なお、元々1.6Gしか使っていないのにそれまで詰めることができないのは恐らくディスクのフラグメント的な何かかな〜と思います。もしこれが著しくひどいようならフラグメント解消をする必要が出てきますが、今回はこのまま進めます。

## fdisk


次に、fdisk コマンドを使います。

```

pi@raspberrypi:~ $ sudo fdisk /dev/sda

Welcome to fdisk (util-linux 2.33.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sda: 29.5 GiB, 31652315136 bytes, 61820928 sectors
Disk model: SD Card Reader  
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: 0x6c586e13

Device     Boot  Start      End  Sectors  Size Id Type
/dev/sda1         8192   532479   524288  256M  c W95 FAT32 (LBA)
/dev/sda2       532480 61820927 61288448 29.2G 83 Linux
```
/dev/sda2 パーティションを削除し、新たなパーティーションを e2fsck で設定したファイスリステムサイズに合わせて作成します


```

Command (m for help): d
Partition number (1,2, default 2): 2

Partition 2 has been deleted.
```
削除できました

```

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 
First sector (2048-61820927, default 2048): 532480
```
ここの値は先程確認した値を入力します

```

Last sector, +/-sectors or +/-size{K,M,G,T,P} (532480-61820927, default 61820927): +`expr 640000 '*' 8`
```

:::note

数字の前に`+`をつけて、セクタ数でパーティションを指定するようにします。

:::

次に、e2fsck で作成したファイルシステムサイズ 640000 にあわせてパラメータを指定します。
セクタサイズが512Bytesでした。4096ブロックの640000を512Bytesセクタに換算すると8を掛けることになります。

計算にexprとしようとしましたが、ここではexprは使えないのでした。とりあえず別に計算した値を入力します。

```

Last sector, +/-sectors or +/-size{K,M,G,T,P} (532480-61820927, default 61820927): +5120000

Created a new partition 2 of type 'Linux' and of size 2.5 GiB.
Partition #2 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: y

The signature will be removed by a write command.

```
うまくいったかな・・・確認してみましょう

```

Command (m for help): p
Disk /dev/sda: 29.5 GiB, 31652315136 bytes, 61820928 sectors
Disk model: SD Card Reader  
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: 0x6c586e13

Device     Boot  Start     End Sectors  Size Id Type
/dev/sda1         8192  532479  524288  256M  c W95 FAT32 (LBA)
/dev/sda2       532480 5652480 5120001  2.5G 83 Linux

Filesystem/RAID signature on partition 2 will be wiped.

```

:::note

ここの、`Sectors`の値が意図したものかどうか照合して下さい
:::
うーん？ 1つずれてしまいました。そうですね、終了セクタは1つ引き算をしないといけません。
今作ったパーティションは消してしまいましょう。

```

Command (m for help): d
Partition number (1,2, default 2): 2

Partition 2 has been deleted.
```
これでさっきのは消えました。では、やり直し。

```

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 
First sector (2048-61820927, default 2048): 532480
Last sector, +/-sectors or +/-size{K,M,G,T,P} (532480-61820927, default 61820927): +5119999

Created a new partition 2 of type 'Linux' and of size 2.5 GiB.
Partition #2 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: y

The signature will be removed by a write command.

Command (m for help): p
Disk /dev/sda: 29.5 GiB, 31652315136 bytes, 61820928 sectors
Disk model: SD Card Reader  
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: 0x6c586e13

Device     Boot  Start     End Sectors  Size Id Type
/dev/sda1         8192  532479  524288  256M  c W95 FAT32 (LBA)
/dev/sda2       532480 5652479 5120000  2.5G 83 Linux

Filesystem/RAID signature on partition 2 will be wiped.
```
OKです。書き込みます。

```

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```
さて、このままマウントしようとしたら


```

pi@raspberrypi:~ $ sudo mount /dev/sda2 /mnt
mount: /mnt: wrong fs type, bad option, bad superblock on /dev/sda2, missing codepage or helper program, or other error.

```
エラーになりました。
もう一度e2fsck

```

pi@raspberrypi:~ $ sudo e2fsck -f /dev/sda2
e2fsck 1.44.5 (15-Dec-2018)
ext2fs_open2: Bad magic number in super-block
e2fsck: Superblock invalid, trying backup blocks...
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: ***** FILE SYSTEM WAS MODIFIED *****
rootfs: 51665/160960 files (0.2% non-contiguous), 429904/640000 blocks
```
したらうまくいきました。

マウントして使用容量を確認します。

```

pi@raspberrypi:~ $ sudo mount /dev/sda2 /mnt
pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       6.9G  1.3G  5.4G  19% /
devtmpfs        459M     0  459M   0% /dev
tmpfs           464M     0  464M   0% /dev/shm
tmpfs           464M   12M  452M   3% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           464M     0  464M   0% /sys/fs/cgroup
tmpfs            93M     0   93M   0% /run/user/1000
/dev/sda2       2.4G  1.6G  704M  70% /mnt
pi@raspberrypi:~ $ sudo umount /dev/sda2
```
使用は1.6Gですが、2.4Gのパーティションになりました。



# バックアップ

## 準備

あらかじめ、zip コマンドをインストールしておきます。

```

pi@raspberrypi:~ $ sudo apt install zip
```

## バックアップ元を接続

dmesg -w としてUSBカードリーダに入れたSDカードを差し込みます。

```

 [sda] Attached SCSI removable disk
```
と出るので、 sdaデバイスであることがわかります。


## バックアップ先を接続


dmesg -w としてUSBメモリを入れます。
```

[ 7037.585895] sd 1:0:0:0: [sdb] Attached SCSI removable disk
```

と出るので /dev/sdb であることがわかります。
dmesg を Ctrl+Cで止めておきます。


```

pi@raspberrypi:~ $ sudo fdisk -l /dev/sdb
Disk /dev/sdb: 57.3 GiB, 61505273856 bytes, 120127488 sectors
Disk model: Ultra Fit       
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: 0xe4af68c6

Device     Boot Start      End  Sectors  Size Id Type
/dev/sdb1  *     2048 65538047 65536000 31.3G  7 HPFS/NTFS/exFAT
```

として、USBメモリであることを確認してから

```

pi@raspberrypi:~ $ sudo mount /dev/sdb1 /mnt
```

とマウントします。中身を確認するには

```

pi@raspberrypi:~ $  ls /mnt
'System Volume Information'   bootmgr       hunsn                  lenovoL540.png     sources       upgrade
 autorun.inf                  bootmgr.efi   j4d214ww.exe           produkey-x64.zip   support
 boot                         efi           j4r205ww_764_864.exe   setup.exe          tb_free.exe
```
とします。


## ソース、ディスティネーション指定

書き込み時の、指定の間違いで事故が起こことを防止するために、

```
pi@raspberrypi:~ $ export SOURCE=/dev/sda
pi@raspberrypi:~ $ export DIST=/mnt/raspbian-FABLIB-20191221.img.zip

```
とします。DISTのファイル名は適当に。

## バックアップ実行

```

$ sudo dd if=$SOURCE bs=512 count=5652480 | zip > $DIST.zip
```

:::note
数字は先程 fdisk で確認した End のあたいをしていしまs

:::
とすると書き込み終了まで何も出てこず、最後に

```
  adding: -5652480+0 records in
5652480+0 records out
2894069760 bytes (2.9 GB, 2.7 GiB) copied, 671.977 s, 4.3 MB/s
 (deflated 67%)

```
と出てきます。10分強かかっていますね。

## バックアップイメージ名を設定する

このままだと内部に書き込んだものはファイル名が - となるので、名前を付け直します。
```

printf "@ -\n@=raspbian-FABLIB-20191221.img\n" | zipnote -w $DIST.zip
```

## 完成したバックアップファイル

```
-rwxrwxrwx 1 root root 907M Dec 21 05:40 /mnt/raspbian-FABLIB-20191221.img.zip

```

となりました。かなり小さくなってお得。

## 取り出し

syncしてumountして取り出します

```

pi@raspberrypi:~ $ sync;sync;sync
pi@raspberrypi:~ $ sudo umount /mnt
```


# 復元


## スーパーユーザになる

sudo ごしの操作はちょっと煩雑になるので以下のようにしてスーパーユーザになってしまいます。

```

pi@raspberrypi:~ $ sudo bash
```

## バックアップイメージの入っているUSBリーダメモリを接続

dmesg -w として バックアップイメージの入っているUSBリーダメモリを接続します。


```

[ 9463.830093] sd 0:0:0:0: [sda] Attached SCSI removable disk
```
と出るので、 /dev/sdaデバイスであることがわかります。
fdiskで確認してみます。

```
root@raspberrypi:/home/pi# fdisk -l /dev/sda
Disk /dev/sda: 57.3 GiB, 61505273856 bytes, 120127488 sectors
Disk model: Ultra Fit       
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: 0xe4af68c6

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1  *     2048 65538047 65536000 31.3G  7 HPFS/NTFS/exFAT

```

間違いないですね。

## USBメモリをマウント

```

root@raspberrypi:/home/pi# mount /dev/sda1 /mnt
```
バックアップイメージを確認します。

```

root@raspberrypi:/home/pi# ls /mnt
'System Volume Information'   bootmgr.efi    j4r205ww_764_864.exe               setup.exe     upgrade
 autorun.inf                  efi            lenovoL540.png                     sources
 boot                         hunsn          produkey-x64.zip                   support
 bootmgr                      j4d214ww.exe   raspbian-FABLIB-20191221.img.zip   tb_free.exe


```
raspbian-FABLIB-20191221.img.zip があるのがわかりますね。

## コピー先を接続

sdカードをUSBカードリーダーに入れてUSBインターフェースに刺します。
```
[ 9641.771349] sd 1:0:0:0: [sdb] Attached SCSI removable disk

```
と出るので、 /dev/sdbデバイスであることがわかります。




## コピー元、コピー先指定

```


root@raspberrypi:/home/pi# export SOURCE=/mnt/raspbian-FABLIB-20191221.img.zip 
root@raspberrypi:/home/pi# export DIST=/dev/sdb
```

## 復元

以下のコマンドで展開しながら書き込みます

```

root@raspberrypi:/home/pi# unzip -p  $SOURCE | dd bs=4k of=$DIST status=progress

```
以下のようになりました。

```

706560+0 records in
706560+0 records out
2894069760 bytes (2.9 GB, 2.7 GiB) copied, 134.109 s, 21.6 MB/s
```

速い！ SandiskのClass10を使いましたが2分ちょっとで終わりましたね。

## syncして取り外し

```

root@raspberrypi:/home/pi# sync;sync;sync
root@raspberrypi:/home/pi# umount /mnt

```


# シュリンクしたファイルシステムを拡張
シュリンクした状態では以下のようになっています。

```

pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       2.4G  1.6G  704M  70% /
devtmpfs        433M     0  433M   0% /dev
tmpfs           438M     0  438M   0% /dev/shm
tmpfs           438M  5.9M  432M   2% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           438M     0  438M   0% /sys/fs/cgroup
/dev/mmcblk0p1  253M   52M  201M  21% /boot
tmpfs            88M     0   88M   0% /run/user/1000
```


sudo raspi-configで、Advancedを選び、最大容量までパーティションを増やすことができます。
32GのSDカードを使って拡張した後の状態：

```

pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        29G  1.6G   27G   6% /
devtmpfs        433M     0  433M   0% /dev
tmpfs           438M     0  438M   0% /dev/shm
tmpfs           438M  5.9M  432M   2% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           438M     0  438M   0% /sys/fs/cgroup
/dev/mmcblk0p1  253M   52M  201M  21% /boot
tmpfs            88M     0   88M   0% /run/user/1000
pi@raspberrypi:~ $ 

```

# 最後に

今回は、動作途中の自分自身のバックアップではなく、別のSDカードを使って起動し、ターゲットのSDカードをバックアップしました。
動作途中の自分自身のバックアップはライブバックアップとかホットバックアップと呼ばれる方法になります。
これらについてはいくつかツールがあるようですが、また今度・・・