Mac上でPiShrinkがインストールされたDockerコンテナを使用してRaspberry PiのSDカードのバックアップを作成する方法
(The English version of this article is here)
Mac上でラズベリーパイのSDカード全体のバックアップを行う際にdd
コマンドを使用できます。dd
コマンドで単純にSDカード全体を読み出すと、未使用領域分も含めてSDカード全容量分の巨大なイメージファイルが作成されてしまうため、ストレージの容量を圧迫し、SDカードに復元する際に長時間を要してしまいます。そこで、
PiShrinkというツールがインストールされたDockerコンテナを使用してイメージファイルのサイズを小さくしてみました。本記事ではその手順を説明します。
環境
- Mac: 10.14.6
- ラズベリーパイ3 Model B+
- Docker for Mac(docker desktop): 2.1.0.4
- PiShrinkがインストールされたDockerコンテナ
- tureeさんのpishrink-dockerを使用、Docker Hubには他にもいくつか公開されていましたが、今回は未検証
不要なアプリ・ソフトウェアパッケージ等の削除
イメージを作成する前に、不要なアプリ・ソフトウェアパッケージ等の削除をしておきます。ラズベリーパイに圧縮したいSDカードを挿入して起動します。
不要なアプリの削除
sudo apt-get purge libreoffice wolfram-engine sonic-pi scratch
使っているアプリを間違って削除しないように注意しましょう!
不要なソフトウェアパッケージの削除
sudo apt-get clean sudo apt-get autoremove
SDカードイメージファイルの作成
ラズベリーパイをシャットダウンしてSDカードを取り出します。SDカードをMacに接続し、dd
コマンドでイメージファイルとして読み出します。まずはコマンドラインでdiskutil list
コマンドを実行し、SDカードのデバイスファイルの場所を見つけます。
$ diskutil list /dev/disk0 (internal): #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme 251.0 GB disk0 1: EFI EFI 314.6 MB disk0s1 2: Apple_APFS Container disk1 250.7 GB disk0s2 ~ ~ ~ snip ~ ~ ~ /dev/disk3 (external, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *32.0 GB disk3 1: Windows_FAT_32 boot 46.0 MB disk3s1 2: Linux 32.0 GB disk3s2
/dev/disk3
にSDカードがマウントされているので、このパスをdd
コマンドに指定すればOKですが、Macでは/dev/diskX
の他に、読み書きがバッファされないr
つきのデバイスファイル(/dev/rdiskX
)も作成されており、こちらを使用する方が高速に読み出すことができます。
$ ls /dev/rdisk* /dev/rdisk0 /dev/rdisk0s2 /dev/rdisk1s1 /dev/rdisk1s3 /dev/rdisk2 /dev/rdisk2s2 /dev/rdisk3s1 /dev/rdisk0s1 /dev/rdisk1 /dev/rdisk1s2 /dev/rdisk1s4 /dev/rdisk2s1 /dev/rdisk3 /dev/rdisk3s2 $ sudo dd if=/dev/rdisk3 of=./XXXX.img bs=1m
Macにインストールされているdd
コマンドは実行中に何も進捗の状態を表示してくれませんが、ターミナル上でCtrl+T
を入力すると、その時点での処理済みバイト数を表示してくれます。
SDカードイメージファイルの圧縮
イメージファイルの圧縮にはPiShrinkというツールを使用します。 Docker Hubを検索するとPiShrinkをインストール済みのDockerコンテナがいくつか公開されています。今回はtureeさんのpishrink-dockerを使用させてもらいます。Docker Desktop for Macはインストールして起動を済ませておきます。
$ docker pull turee/pishrink-docker Using default tag: latest latest: Pulling from turee/pishrink-docker Digest: sha256:31e16c7d382b7a96e28cd92458a0cc1bf1e9b88bad116b68fd7dd4ca95fbf6b8 Status: Image is up to date for turee/pishrink-docker:latest docker.io/turee/pishrink-docker:latest
docker run
実行時にホストマシンのボリュームをDockerコンテナにマウントすることができますが、バックアップしたSDカードイメージファイルのディレクトリをマウントしてPiShrinkの実行したところエラーになってしまいました。
$ docker run --rm --privileged=true -v (pwd):/workdir turee/pishrink-docker pishrink XXXX.img Warning: Unable to open /workdir/XXXX.img read-write (Permission denied). /workdir/XXXX.img has been opened read-only. Warning: Unable to open /workdir/XXXX.img read-write (Permission denied). /workdir/XXXX.img has been opened read-only. mount: /tmp/tmp.nDyP6lWYv6: WARNING: device write-protected, mounted read-only. Creating new /etc/rc.local ~ ~ ~ snip ~ ~ ~ Couldn't find valid filesystem superblock. resize2fs: Operation not permitted while trying to open /dev/loop0 ERROR: resize2fs failed... mount: /tmp/tmp.nDyP6lWYv6: can't read superblock on /dev/loop0. mv: cannot stat '/tmp/tmp.nDyP6lWYv6/etc/rc.local.bak': No such file or directory umount: /tmp/tmp.nDyP6lWYv6: not mounted. losetup: /dev/loop0: detach failed: No such device or address
若干手間が増えてしまいますが、コンテナ側にイメージファイルをコピーして圧縮、圧縮されたイメージファイルをホスト側にあらためてコピー、という手順を踏むことにします。pishrink
コマンドに引数一つ(圧縮元イメージファイルのパス)しか指定しないと、圧縮元ファイルが圧縮後のファイルで上書きされます。
$ docker cp XXXX.dmg 32f4176aa68a:/root/XXXX.img $ docker exec -it 32f4176aa68a bash root@32f4176aa68a:/workdir# cd /root/ root@32f4176aa68a:~# pishrink XXXX.img Creating new /etc/rc.local rootfs: 114911/950272 files (0.5% non-contiguous), 938002/3793920 blocks resize2fs 1.44.1 (24-Mar-2018) ~ ~ ~ snip ~ ~ ~ Begin pass 4 (max = 12048) Updating inode references XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX The filesystem on /dev/loop0 is now 937412 (4k) blocks long. Shrunk XXXX.img from 30G to 3.7G root@32f4176aa68a:~# exit exit $ docker cp 32f4176aa68a:/root/XXXX.img XXXX-shrink.img
最後のダメ押しで、pishrink
で圧縮したイメージファイルをxz
コマンドでも圧縮してみます。イメージファイルの内容次第にはなりますが、執筆時、pishrink
で圧縮した時点で3.7GBあったファイルが1.1GB程度まで圧縮できました。
$ xz XXXX.img load: 2.88 cmd: xz 30200 running 58.35u 0.42s
dd
コマンドと同様に、xz
コマンド実行中にCtrl+T
を入力すると進捗が表示されます。xz
コマンドに圧縮元ファイル名のみを指定すると、元ファイル名に.xz
の拡張子がついた圧縮後のファイルで上書きされます。
圧縮したSDカードイメージファイルの書き込み
圧縮されたSDカードイメージの.xz
ファイルは、Etcherを使うとそのままSDカードに書き込むことができます。
圧縮したSDカードイメージでラズベリーパイを起動
初回起動時に、SDカードの空きスペースいっぱいまでパーティションが拡張されます。
まとめ
DockerコンテナにインストールされたPiShrinkというツールを使用して、ラズベリーパイのSDカードイメージファイルのサイズを小さくする手順を説明しました。イメージファイルのサイズは小さい方がストレージ容量の節約になり書き込み時間も少なくて済むため、容量の大きいSDカードからバックアップを作成した後には圧縮を行うことをおすすめします。
参考
- How do you clean up unused files in memory sd card? - Raspberry Pi Stack Exchange
- sd card - Why is “/dev/rdisk” about 20 times faster than “/dev/disk” in Mac OS X - Super User
- Docker Desktop for Mac
- PiShrink
- Docker containers with PiShrink installed on Docker Hub
- turee/pishrink-docker
- SDカードの作成 - FaBo DonkeyCar Docs
- balenaEtcher