ラズパイのOSイメージをできるだけ小さくddでバックアップする手順

Raspberry Pi 3の初期インストール時に使用するイメージファイルをSDに焼き付けてセットアップし、できあがった16GBのSDカードをバックアップしようとすると、例え5GBしか使用していなくても16GBのイメージファイルができあがります。

また、SDカードの物理的なサイズは、同じ16GBと表記されていても実際のサイズはメーカーごとに異なり、あるメーカーのSDカードからバックアップイメージファイルを作っても、別のメーカーのSDカードにはサイズが大きくて書き込めないこともよくあります。

SDカードのバックアップ時点で未使用部分を切り捨てて、どのメーカーのSDカードにでも書き込める小さなバックアップファイルを作成できればメーカー間の差異を気にする必要もなく、イメージファイルのサイズも小さくなって可搬性がよくなるということで手順をまとめました。大まかには、

1) ファイルシステムの縮小
2) パーティションの縮小
3) 使用部分だけをddでバックアップ

という3ステップになります。

#ファイルシステムの縮小#
SDカードのサイズを縮小するには、イメージ化したいSDカードとRaspberry Piを起動するためのSDカードの2枚のカードが必要です。

1) SDカードを入れたUSBリーダーライターをRaspberry Piに接続
2)  Raspberry Piを起動してsshでログイン
3) ディスクの構成を確認

```shell
#以下のコマンドでディスク・デバイスの内容を表示します。
#sdaがUSB接続のリーダーライターになります。
sudo fdisk –l

Disk /dev/sda: 15 GiB, 16088301568 bytes, 31422464 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: 0xb47c752b

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        8192    93813    85622 41.8M  c W95 FAT32 (LBA)
/dev/sda2       94208 31225855 31131648 14.9G 83 Linux
```

5) ファイルシステムの検証
以下のコマンドで、Linuxパーティションに不整合や破断がないかどうかチェックします。

```shell
sudo e2fsck -p -f /dev/sda2
/dev/sda2: 155081/938672 files (0.1% non-contiguous), 970333/3891456 blocks
```

6) 縮小後のファイルシステムのサイズ見積もり
以下のコマンドで、パーティション上のファイルシステムをいくつに縮小できるか見積もります。単位はブロック（４KB）です。

```shell
sudo resize2fs -P /dev/sda2
resize2fs 1.43.4 (31-Jan-2017)
Estimated minimum size of the filesystem: 1190428
```

7) ファイルシステムの縮小
上記で見積もられたブロックサイズ＋1024にファイルシステムを縮小します。

```shell
sudo resize2fs -p /dev/sda2 1191452
resize2fs 1.43.4 (31-Jan-2017)
Resizing the filesystem on /dev/sda2 to 1191452 (4k) blocks.
Begin pass 2 (max = 244785)
Relocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 3 (max = 119)
Scanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 4 (max = 11806)
Updating inode references    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The filesystem on /dev/sda2 is now 1191452 (4k) blocks long.
```

#パーティションの縮小#

1) 以下のコマンドを実行し、対話型でパーティションを縮小します。

```shell
sudo fdisk /dev/sda
Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
```

2) まず以下の入力でパーティションの状態を表示します。

```shell
Command (m for help): p
Disk /dev/sda: 15 GiB, 16088301568 bytes, 31422464 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: 0xb47c752b

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        8192    93813    85622 41.8M  c W95 FAT32 (LBA)
/dev/sda2       94208 31225855 31131648 14.9G 83 Linux
```

3) 以下のコマンドで2番目のLinuxパーティションを削除します。

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

Partition 2 has been deleted.
```

4) パーティションが削除されたか確認する。（2番目のLinuxパーティションがなくなっていること）

```shell
Command (m for help): p
Disk /dev/sda: 15 GiB, 16088301568 bytes, 31422464 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: 0xb47c752b

Device     Boot Start   End Sectors  Size Id Type
/dev/sda1        8192 93813   85622 41.8M  c W95 FAT32 (LBA)
```

5) 以下のコマンドで新しいパーティションを作成します。

```shell
Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
```

6) 以下のようにプライマリーパーティションとします。

```shell
Select (default p): p
```

7) パーティション番号は削除したものと同じ2番とします。

```shell
Partition number (2-4, default 2): 2
```

8) セクターの開始位置は、削除したLinuxパーティションの開始位置に合わせます。

```shell
First sector (2048-31422463, default 2048): 94208
```

9) 上記スタート位置からどれだけの領域を確保するか入力します。
ここでは、縮小したファイルシステムのサイズに若干余裕を持たせたサイズにします。例えば、1191452ブロック×4KB≒4.5GBなので余裕をみて5GBとします。

```shell
Last sector, +sectors or +size{K,M,G,T,P} (94208-31422463, default 31422463): +5G

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

10) 以下のプロンプトにNを入力します。該当のパーティションは、元々ext4のフォーマットでsignatureを削除する必要はありません。

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

11) 以下のコマンドで変更したパーティションを書き込みます。

```shell
Command (m for help): w

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```

12) ディスクの構成を再確認
下記コマンドで、再度ディスク構成を表示しパーティションが縮小されていることを確認します。

```shell
sudo fdisk –l
Disk /dev/sda: 15 GiB, 16088301568 bytes, 31422464 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: 0xb47c752b

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        8192    93813    85622 41.8M  c W95 FAT32 (LBA)
/dev/sda2       94208 10579967 10485760    5G 83 Linux
```

#使用領域のみに縮小されたイメージの作成#
パーティションが縮小されたSDカードを、ddでそのままバックアップしても物理的なSDカードのサイズでイメージデータが作成されます。そこで、どの位置までをイメージデータとしてバックアップするべきか指定する必要があります。具体的には以下のコマンドを用いて必要な部分だけをイメージ化します。

```shell
sudo dd if=/dev/rdisk2 of=Downloads/YOUR_IMAGEFILE_NAME.img count=5166 bs=1m
```

countはddが読み書きするレコード数です。12）で再確認した/dev/sda2の「End」に記載されているセクター数÷2048を小数点以下切り上げでセットします。例えば、/dev/sda2のEndが10579967であれば、10579967÷2048＝5165.99……なので切り上げて5166をセットします。

レコードサイズは、bsで指定されたブロックサイズであり、/dev/sda2の1セクターは512バイトです。このことから、1レコードは1MBで2048セクターを意味するので、/dev/sda2のセクター数を2048で割り、小数点以下を切り上げすることで、読み書きすべきレコード数を算出します。

以上で、使用領域部分だけがバックアップされたイメージファイルを作成できました。