ちょっと話題の記事

Raspberry Piで最小サイズのバックアップを作成する

2018.08.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

Raspberry PiのSDカードを複製(バックアップ・リストア)するとき、下記の問題を感じることがあります。

  • 16Gとかのカードに入っていると、バックアップイメージ自体が大きいのでコピーに時間がかかる
  • バックアップイメージが大きくて場所を取る
  • 同一メーカーの同サイズのSDにリストアしようとしてもブロック数の僅かな違いで失敗することがある

今回は、この問題を避けるために、SDカードのイメージを小さくバックアップする方法をまとめてみました。

便利なツールもあると思うのですが、私自身の勉強の兼ねて、すべての操作をコマンドラインで行っています。ddコマンドなど指定を誤るとシステムを壊わしてしまう恐れがありますので、もし、この記事を参考に作業される場合は、充分にご注意下さい。

2 パーティションの自動拡張

ダウンロードしたRASPBIANのイメージをSDカードにコピーして使用すると、初回起動時に、SDカードで利用可能な最大サイズまで自動的にパーティションが拡張されます。

下記は、ダウンロードしたイメージをSDカード(16G)にddでコピーした直後の状態です。 最後のセクタは、9322496であり、9322496 * 512 = 4773117952(4.44G)となっています。

$ sudo fdisk /dev/disk1
Disk: /dev/disk1	geometry: 1923/255/63 [30898176 sectors]
 #: id  cyl  hd sec -  cyl  hd sec [     start -       size]
------------------------------------------------------------------------
 1: 0C    0 130   3 -    6   4  22 [      8192 -      88472] Win95 FAT32L
 2: 83    6  30  25 -  586 106  32 [     98304 -    9322496] Linux files*

そして、このSDカードでRaspberry Piで起動すると、パーティションの状態は下記のように変化します。最後のセクタが30799872となっており、30799872 * 512 = 4773117952(14.68G)まで広がっていることが分かります。

$ sudo fdisk /dev/disk1
Disk: /dev/disk1	geometry: 1923/255/63 [30898176 sectors]
 #: id  cyl  hd sec -  cyl  hd sec [     start -       size]
------------------------------------------------------------------------
 1: 0C    0 130   3 -    6   4  22 [      8192 -      88472] Win95 FAT32L
 2: 83    6  30  25 - 1023 254  63 [     98304 -   30799872] Linux files*

RASPBIANのイメージを確認すると、起動時にパーティションを拡大しているS01resize2fs_onceが確認できます。そして、初回実行されると、このシェルは削除されているので、起動後はこれを見ることができません。

$ hdiutil mount 2018-06-27-raspbian-stretch.img 【RASPBIANのイメージをマウント(/dev/disk2にマウントされた)】
$ mkdir /tmp/Linux
$ ext4fuse /dev/disk2s2 /tmp/Linux【ファイルシステムにマウント】
$ cat /tmp/Linux/etc/rc3.d/S01resize2fs_once【S01resize2fs_onceの内容を確認する】
#!/bin/sh
### BEGIN INIT INFO
# Provides:          resize2fs_once
# Required-Start:
# Required-Stop:
# Default-Start: 3
# Default-Stop:
# Short-Description: Resize the root filesystem to fill partition
# Description:
### END INIT INFO
. /lib/lsb/init-functions
case "$1" in
  start)
    log_daemon_msg "Starting resize2fs_once"
    ROOT_DEV=$(findmnt / -o source -n) &&
    resize2fs $ROOT_DEV &&
    update-rc.d resize2fs_once remove &&
    rm /etc/init.d/resize2fs_once &&
    log_end_msg $?
    ;;
  *)
    echo "Usage: $0 start" >&2
    exit 3
    ;;
esac

3 システムの縮小

サイズの小さなバックアップを作成するためには、以下の手順が必要です。

  • ファイルシステムの縮小
  • パーティションの縮小

なお、この作業は、別のRasbianが起動していところに、対象のSDカードをUSB接続して、Macからsshで接続して行いました。

(1) ファイルシステムの縮小

USBに接続されたSDカードは、 /dev/sda(4.3/15G使用中)として認識されています。 bootパーティションと(/dev/sda1)とrootパティション(/dev/sda2)の2つがありますが、縮小の対象は、/dev/sda2です。

pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        15G  4.3G  9.3G  32% /
・・・略・・・
/dev/sda1        43M   22M   21M  51% /media/pi/boot
/dev/sda2        15G  4.0G  9.8G  29% /media/pi/rootfs

resize2fs-P オプションをつけると、必要サイズの確認ができます。

pi@raspberrypi:~ $ sudo resize2fs -P /dev/sda2
resize2fs 1.43.4 (31-Jan-2017)
Estimated minimum size of the filesystem: 1595822

ここで表示されている1595822の単位はブロック(4Kbyte)なので、1595822 * 4 * 1024 = 6536486912 (6.08Gbyte)となります。

縮小後のサイズは、必要サイズより25400(100Mbyte)ほど多い目にとって、1595822 + 25400 = 1621222 を指定することにしました。

pi@raspberrypi:~ $ umount /dev/sda2
pi@raspberrypi:~ $ sudo e2fsck -f /dev/sda2
pi@raspberrypi:~ $ sudo resize2fs -p /dev/sda2 1621222

(2) パーティションの縮小

現在の状態は、以下のようになっています。2つ目のパーティションは、Startが98304でEndが30898175で14.7G確保されています。

$ sudo fdisk /dev/sda
Command (m for help): p
・・・略・・・
Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        8192    96663    88472 43.2M  c W95 FAT32 (LBA)
/dev/sda2       98304 30898175 30799872 14.7G 83 Linux

先程の縮小作業でサイズを1621222 としましたが、こちらは単位がブロック(4Kバイト)で、今度は、セクタ(512バイト)で指定するので 1621222 * 8 = 12969776 セクタ以上確保すれば良いことになります。(ここでは、12970000としておきます)

Startは変えることが出来ないので98304、そしてEndは、98304 + 12970000 で 13068304に変更します。

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): 【プライマリーを選択】

Using default response p.
Partition number (2-4, default 2):2【パーティション番号は2を指定】
First sector (2048-30898175, default 2048): 98304【Startセクタの指定】
Last sector, +sectors or +size{K,M,G,T,P} (98304-30898175, default 30898175): 13068304 【Endセクタの指定】

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

Do you want to remove the signature? [Y]es/[N]o: N 【ext4は変化せずsignatureを削除する必要は無いのでNを選択】

Command (m for help): p 【変化後の状態確認】

Disk /dev/sda: 14.8 GiB, 15819866112 bytes, 30898176 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: 0xb973c9fe

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        8192    96663    88472 43.2M  c W95 FAT32 (LBA)
/dev/sda2       98304 13068304 12970001  6.2G 83 Linux  【6.2Gに変化している】

Command (m for help): w 【変更を書き込む】
The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Device or resource busy

これで、縮小作業は終わりです。念のため、作業したSDカードで起動してみましたが、無事、6.1Gに変化していることが確認できました。

$ ssh pi@raspberrypi.local

・・・略・・・

pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       6.1G  4.0G  1.8G  69% / 

・・・略・・・

4 ブロック数を指定したイメージのコピー

ここからの作業は、Macで行っています。

SDカードからイメージを作成するには、ddコマンドを使用しますが、最後まで全部コピーしてしまうと結局サイズが縮まらないので、ブロック数の指定をします。

書き込みスピードを上げるためにブロック数を1Mバイトとすることにして、セクタ(単位は512バイト)の最後が12970001でしたので、12970001 / 2048 = 6333.0083... ということで6334ブロックまで書くことにします。

Macに接続すると、SDカードは、/dev/disk3で認識されています。

$ df -h
Filesystem      Size   Used  Avail Capacity iused      ifree %iused  Mounted on
・・・略・・・
/dev/disk3s1    43Mi   22Mi   21Mi    51%       0          0  100%   /Volumes/boot

ブロックサイズを指定したコピーは、以下のとおりです。(途中経過を確認したい場合は、CTRL+T)

$ sudo dd bs=1m if=/dev/rdisk3 of=./RPI.img count=6334
6334+0 records in
6334+0 records out
6641680384 bytes transferred in 79.723395 secs (83309051 bytes/sec)

出来上がったイメージファイルのサイズは、当然、約6G、zipで圧縮すると約2Gになってました。

$ ls -la RPI*
-rw-r--r--  1 root  staff  6641680384  8 16 03:41 RPI.img
-rw-r--r--  1 sin   staff  2060124736  8 16 03:53 RPI.img.zip

5 リストア

リストアは、8GのSDカードで試してみることにします。イメージが6Gちょいなので、書き込めるはずです。

Macに接続して、下記のとおりイメージを書き出します。(/dev/disk3で認識している前提です)

$ diskutil umountDisk /dev/disk3 【アンマウントしないとddで書き込めない】
$ sudo dd bs=1m if=./RPI.img of=/dev/rdisk3 【イメージのコピー】
$ touch /Volumes/boot/ssh 【SSHを許可】
$ diskutil eject /dev/disk3 【イジェクト】

なお、この状態で起動すると、SDカードの最大容量まで使用した状態とはなっていません。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       6.1G  4.0G  1.8G  69% /
・・・略・・・

広げる場合は、以下のようになります。(コマンド出力は省略されています)

$ sudo fdisk /dev/mmcblk0

【現在の状態を確認】
Command (m for help): p

Device         Boot Start      End  Sectors  Size Id Type
/dev/mmcblk0p1       8192    96663    88472 43.2M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      98304 13068304 12970001  6.2G 83 Linux

【パーティション2を削除】
Command (m for help): d
Partition number (1,2, default 2):2

Partition 2 has been deleted.

【パーティション2を作成】
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

Using default response p.
Partition number (2-4, default 2):
First sector (2048-15546367, default 2048): 98304
Last sector, +sectors or +size{K,M,G,T,P} (98304-15546367, default 15546367): 15546367

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

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

【状態確認】
Command (m for help): p

Device         Boot Start      End  Sectors  Size Id Type
/dev/mmcblk0p1       8192    96663    88472 43.2M  c W95 FAT32 (LBA)
/dev/mmcblk0p2      98304 15546367 15448064  7.4G 83 Linux

Command (m for help): w

パーティション変更後は、反映のために再起動が必要です。

ファイルシステムは以下のコマンドで拡張できます。resize2fsは、サイズを指定しないと、パーティションサイズのいっぱいまでディスクサイズを拡張します。

$ sudo resize2fs /dev/mmcblk0p2
resize2fs 1.43.4 (31-Jan-2017)
Filesystem at /dev/mmcblk0p2 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/mmcblk0p2 is now 1931008 (4k) blocks long.

これで、SDカードいっぱいまで利用可能になています。

pi@raspberrypi:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root       7.2G  4.0G  3.0G  58% /
・・・略・・・

6 最後に

今回作成したイメージは6G程度でSDへの読み書きは4分程度でした。恐らく16Gでの作業と比べると半分以下の時間でコピーなどが可能になっているでしょう。リストア後にパーティション等を広げる作業をしても、時間節約は大きいと思います。また、リストアも6G以上のSDカードであれば、サイズ不足で書き込み失敗となる心配も無いはずです。

すこし、ややこしいですが、一通り作業すると、ファイルシステムとパーティションの理解も少し深まるかも知れません。