ディスクイメージを手元でマウントしてリサイズ(シュリンク)する
概要
RaspberryPiなどのディスクイメージを,実際の環境に書き込むことなく手元で仮想的にマウントしてリサイズ(シュリンク)し保存する方法
背景
RasPiの実際に動かしているSDカードのイメージをバックアップや移植などの都合でddで(なにも考えず)コピーした場合,いらない空間までもれなくコピーされる.これが8GBや16GBならまあなんとかなるが,32GBとかになると流石に邪魔くさい
また,複製して焼くとなると,書き込み先のサイズが元のサイズ以上でないと問題が起こる.同一サイズでも微妙に内部的に使用可能なサイズが異なるせいで,書き込めたり書き込めないとうことが起こる
解決するために,わざわざ別のディスクに書き出して,リサイズして取り込むというのはかなり面倒なので,全部手元でやろうという話
前提
OS: Ubuntu20.04
対象ディスクイメージ: 稼働中のRasPiイメージ
以下RasPiのイメージを扱っている体でコマンドは表現する
その他諸元情報はこのとおり
- SDカードは /dev/sdc に接続
- ループバックデバイスはloop10へ接続
- 内部のパーティションはloop10p1とloop10p2(RasPiのbootパーティションとrootパーティション)
手順
sudo
権限については適宜実行する際に付けてください
-
イメージをまず手元に取り込む
dd if=/dev/sdc of=./image.img status=progress
-
if
: Input File ここでは/dev/sdcに接続されたSDカード.sdcのcは適宜変わる -
of
: Output File ここではカレントディレクトリのimage.imgファイルとして書き出す -
status=progress
: 進行状況を表示してくれる.無いと,どんだけかかるかわからんくて辛い
-
-
取り込んだイメージのループバックデバイスを作成する
losetup -f -P --show ./image.img
-
-f
: 空いているループバックの番号を選択する -
-P
: パーティションを持つイメージの場合は自動的にそれらをloop10p2
のように接続してくれる -
--show
:-f
によって自動選択されたループバックデバイスの名前を表示する.今後の操作でどこに繋がれたのかわからんと困る
-
-
ファイルシステムのシュリンク
まずパーティションを削る前に,念の為ファイルシステムを目的のサイズまで小さくする
resize2fs -p /dev/loop10p2 9G
-
-p
: 進捗表示 - ファイルシステムを選択する必要があるので,パーティション番号まで選択すること
- ここでは仮に9GBへリサイズすることにする
- 表記は,K,M,G,Tが使える
- ここで失敗する場合は
-f
のファイルチェックをせず強制実行するオプションをつける必要がある.(対象がループバックデバイスで,実デバイスではないせいか高確率(僕の環境では100%)で失敗するので,実質必須オプション)
-
-
パーティションの編集
パーティション自体を操作する.
fdisk /dev/loop10
ここからは対話システムがたちがる.入力する手順は-
p
: ディスクの状態を表示(サイズやパーティションのサイズが表示される)- 今回は2つ目のパーティションをシュリンクしたいので,2つ目のパーティションの開始セクタの番号をメモっておく
-
d
: パーティションを削除する- 削除と言っても,中身が消えるわけではなく,ただの管理テーブルが消去されるだけなので,実行して問題ない.また処理は最後に書き込みが実行さるまでは実行されない
- どのパーティションを削除するか聞かれるので数字を入力 (今回は
2
を選択) -
n
: パーティションを作成 - パーティションの形式をプライマリ(
p
)か拡張(e
)か聞かれるので選ぶ(今回はもとがプライマリなのでp
を選択) - パーティションの番号を選択(元が2なので2を選択)
- パーティションの署名を削除するか聞かれるが
N
で削除しない(削除するとどうなるのかは未検証…よくわかってない) - 開始セクタ位置を入力する.ここで先にメモったセクタ位置を使う
- つまり,一度削除したパーティションの区切りを,同じ場所に作れば実質リサイズされたことになる…という手順である
- 終了セクタ位置を入力する.
+
記号を使うことで,実際に使いたい容量を入力することで設定してくれる(+10G
とすると10GBの容量を持つ終了セクタを自動計算して使ってくれる.表記は,K,M,G,Tが使える) -
w
: 実際に書き込まれる
-
-
ファイルシステムの再調整
先にシュリンクしたファイルシステムを,シュリンクしたパーティションサイズに合わせる
resize2fs /dev/loop10p2
サイズ指定をしないと自動的に合わせてくれる. -
ループバックデバイスの削除
パーティションの編集が終わったので,イメージをループバックデバイスから外す
losetup -d /dev/loop10
-
イメージファイル自体をシュリンク
ここまでの作業でパーティションはシュリンクしたが,実際のイメージファイルは縮小していない.あくまで内部データが変化しただけなので,使ってない部分は切り落とす
truncate --size=$[(終了セクタ+1)*セクタサイズ] ./image.img
- 終了セクタ位置に念の為1を加えたものに,セクタ1つのサイズをかけることで,実際に利用されているサイズを計算する
- セクタ1サイズは512(たいていのシステムは)
- truncateコマンドで使われているサイズだけを切り取って,残りを切り落とす
- ここをトチるとパーになる
-
これにて縮小したイメージファイルの完成
あとは煮るなり焼くなりすきにしてください.
おまけ
ループバックデバイスを作成後,ファイルシステムとパーティションの操作は,Gpartedが利用できればもっと楽にできるかもしれない
gparted /dev/loop10
とすることでGpartedで編集ができる.ただし,高確率でresize2fsでエラーするので,Gpartedでの操作はできないと思われる.(というかできなくて,この七面倒臭い方法を行なったので備忘録として残している)
まとめ
めんどくさいが,ループバックデバイスを駆使して,仮想でもファイルシステムやパーティションを操作できる
(気が向いたら,コマンドのログや画像を追加したい…が,Ubuntuを起動するのがめんどくさいのである)