それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

qcow2 をqemu-img で スナップショットを取り扱う

qemu-img で スナップショットを取り扱う

Snapshot を使って仮想マシンを管理したいなと。

snapshot / qcow2

仮想マシンの状態保存する機能。

kvm + qemu / qcow2 で使える。qcow2 を使う場合に使える。

qcow2 のストレージでサポートされていて、qcow-img で管理する。

今回は、libvirtqemu 自体のスナップショット関連機能は言及しない。

qcow2 / qcow-img に絞り仮想マシンのスナップショットを管理する方法を記載する。

qcow2 機能 cow とスナップショット

qcow の cow は copy on write の略称である。copy on write は、書き込み時にコピーし新領域に書き込む。つまり、古いデータを残せるってことよ。だからスナップショットを作れる。btrfs はFS自体に同じ機能を持ってるので、qcow2 をbtrfs 上につくる、qcow2 内部をbtrfs にすると無駄処理が増えてパフォーマンスは劣化する。(といっても現代はnvme ssd 数Gbps とかだし気にならない・・・はず)

qcow2 スナップショットの使い方

スナップショットは、qcow2 のファイル内部に保存される。

スナップショット一覧 -l

qemu-img snapshot -l name.qcow2

スナップショット作成 -c

名前を指定して作成

qemu-img snapshot -c 1.0.0 name.qcow2
qemu-img snapshot -c base name.qcow2

スナップショット選択 -a

apply / 名前を指定してそのバージョンのスナップショットを使う。

qemu-img snapshot -a testing name.qcow2

name.qcow2は スナップショット取得時に巻き戻される。

スナップショット削除 -d

名前を指定して削除

qemu-img snapshot -d 1.0.1 name.qcow

スナップショットからスナップショットを作成

スナップショットからスナップショットを起動するとは

  1. スナップショットの状態に戻す
  2. 戻した状態で起動する
  3. 別のスナップショットとして保存する。

ただし、スナップショットは単体でスナップショットであり、qcow2ファイルに親子関係は存在しない。単にスナップショットが増えるだけである。 スナップショットが複数ある状態になる。親子関係は名前を使い、自分で管理する。

スナップショットからスナップショットを作る(流れ)

わりやすさのため名前を番号にした。

スナップショットからスナップショットを作成する場合

qcow2 -> 1.0.0 -> 1.0.1 -> 1.0.2
               └─ 2.0.0 -> 2.0.1

いったん、スナップショットを適用して作るといい

1.0.0 -> 1.0.1 -> 1.0.2 と順番に保存する時

qemu-img -c 1.0.0 name.qcow2
do something
qemu-img -c 1.0.1 name.qcow2
do something
qemu-img -c 1.0.2 name.qcow2

現在状態を捨てて 1.0.0 -> 2.0.1 と一旦戻して作る時

qemu-img -a 1.0.0 name.qcow2
do something
qemu-img -c 2.0.0 name.qcow2

一旦スナップショットの状態に戻して起動、なんか作業をして、新しいスナップショットとして保存する。これが一連の流れになる。

スナップショットを単一ファイルにする

convert を使う

qemu-img -a 1.0.0 name.qcow2
qemu-img convert name.qcow2 -O qcow2 name-1.0.0.qcow2

スナップショットを単一のqcow2 ファイルとして取り出すことができる。コピーして取り出すことができる。

qcow2 スナップショットの制限

qcow2 のスナップショットは、 qemu-img で管理する。

qemu-img が qcow2 のストレージを直接扱うため、qcow2 に安全に書き込める必要がある。

つまり、qcow2 snapshotにはシャットダウンが必要である。

実験してみる

使い方がわかったので、ちょっと実験してみよう

仮想マシンの準備

virt-install とpreseedでサクッとインストールしておく

virt-install \
 --connect=qemu:///system \
 --graphics none \
 --location http://ftp.kddilabs.jp/pub/Linux/distributions/Debian/debian/dists/buster/main/installer-amd64/ \
 --extra-args="console=ttyS0"
 --ram 4096 \
 --vcpus 8 \
 --virt-type kvm \
 --os-type linux \
 --os-variant debian10 \
 --name d01-manual \
 --disk path=/var/lib/libvirt/images/d01.qcow2 \

インストールの自動化の細かいやり方は、別記事に書いた

vm の開始と接続

vm を開始し接続する

$ sudo virsh start d02
$ sudo virsh console d02

Debian GNU/Linux 10 d02 ttyS0

d02 login: takuya

takuya@d02:~$ ls -lt
total 0

そして、なにか作業(アップデートなど)をする

vm の強制終了

sudo virsh destroy d02

作業終了したら、シャットダウンする。

スナップショットを作る

必ず、停止してから行う。

$ sudo qemu-img snapshot -c 1.0.0 /var/lib/libvirt/images/d02.qcow2
$ sudo qemu-img snapshot -c 1.1.0 /var/lib/libvirt/images/d02.qcow2

スナップショットを作ったのを確認

$ sudo qemu-img snapshot -l /var/lib/libvirt/images/d02.qcow2
Snapshot list:
ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
1         1.0.0                 0 B 2022-04-21 14:50:34 00:00:00.000          0
2         1.1.0                 0 B 2022-04-21 14:51:00 00:00:00.000          0

スナップショットに入る。

スナップショットの状態で起動する

sudo qemu-img snapshot -a 1.1.0 /var/lib/libvirt/images/d02.qcow2
sudo virsh start d02

起動したら、スナップショット状態がわかるようにファイルを書いておく。

$ sudo virsh consle d02
Debian GNU/Linux 10 d02 ttyS0

d02 login: takuya
Password:
Linux d02 4.19.0-20-amd64 #1 SMP Debian 4.19.235-1 (2022-03-17) x86_64

takuya@d02:~$ ls -alt
takuya@d02:~$ touch snapshot-1.1.0
takuya@d02:~$ sudo shutdown -h now 

再起動してもデータが残ることを確認

$ sudo virsh start d02
$ sudo virsh consle d02

d02 login: takuya
Password:
Last login: Fri Apr 22 15:18:41 JST 2022 on ttyS0

takuya@d02:~$ ls -l
total 0
-rw-r--r-- 1 takuya takuya 0 Apr 22 15:19 snapshot-1.1.0

スナップショットを切り替える

スナップショットを切り替えると、データが消えることを確認

sudo qemu-img snapshot -a 1.1.0 /var/lib/libvirt/images/d02.qcow2
sudo virsh start d02
d02 login: takuya
Password:
Last login: Fri Apr 22 15:18:41 JST 2022 on ttyS0

takuya@d02:~$ ls -l
total 0
takuya@d02:~$ ls -l

snapshotは特定の状態に戻す機能

次のように、Aから Aダッシュまで、複数個のスナップショットを作っていたとして

A → A'→ A''→  A'''

A' を消したら A'' が辿れなくなるというわけでない

Aから派生したA'で、A' から派生したA''だとしても、スナップショットは仮想マシンのその時の状態を保存するものである。

したがってA''は単体スナップショットである。

A→A'の差分を保存しているわけではない。A'の状態を保存しているのである。なのでqcow2スナップショットに親子関係はなく、親子関係は利用者が覚えている限りである。

と考えるのが正しかろう

SnapShot で取り出し

スナップショットを適用する次のコマンド は 1.1.0 の状態に「復元」している

sudo qemu-img snapshot -a 1.1.0 /var/lib/libvirt/images/d02.qcow2

ファイルシステム状態は、その時の状態にきれいに戻る。

snapshots [ A,  A'',  C, B, A'] 
                ↑
                qcow2

スナップショット同士には、相互に順番がない。スナップショットは、順不同でグチャッとqcow2保存されていると考えたらイメージしやすいと思う。あの時のあの状態で保存、名前をつけた時の状態へ戻す。っていう感じです。

スナップショットを取り出したあと、起動したら、起動時の状態はスナップショットより進んだ状態になる。

A → A'→ A''→ A''' のように順番にならんだ差分を取りたいときはSnapShotではなく、backing-file-chainとうqcow-imgの別の機能を使うことになる。backing-file機能がDocker仮想マシンのレイヤにt近い。snapshotはbacking-fileとは全く違う。スナップショットはwindowsMacの「復元」と同じ機能ですよね。

snapshot の名前の付け方

takuya@:~$ sudo sudo qemu-img snapshot -l /var/lib/libvirt/images/d02.qcow2
Snapshot list:
ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
1         1.0.0                 0 B 2022-04-21 14:50:34 00:00:00.000          0
2         1.1.0                 0 B 2022-04-21 14:51:00 00:00:00.000          0
3         1.1.0                 0 B 2022-04-22 16:01:42 00:00:00.000          0

スナップショットに指定するのは、名前ではなくタグです。

一見すると名前のように見えるし、名前のように使えます。ですが実際はタグです。

同じ名前で複数個作ることできます。同名のものはIDで識別されます。

同じ名前(タグ)で複数個作ることができるので、ある意味便利ですがある意味で不便です。

スナップショットIDを指定した、取り出し

特定のスナップショット状態を、一つのqcow2 ファイルとして取り出すことができる。

sudo qemu-img convert -l snapshot.id=3 name.qcow2 -f qcow2 -O qcow2 id-3.qcow2

snapshot.id を指定すれば、特定のスナップショットを確実に取り出すことができる

raw でほしいときは、raw を指定する(またはフォーマット指定省略)

sudo qemu-img convert -l snapshot.id=3 name.qcow2 -O raw id-3.qcow2
sudo qemu-img convert -l snapshot.id=3 name.qcow2 id-3.qcow2 # 省略時はraw

convertでタグだけを指定したときは、一番若いIDが採用されるようです。

次の状態のスナップショットがある時

takuya@:~$ sudo sudo qemu-img snapshot -l name.qcow2
Snapshot list:
ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
1         1.0.0                 0 B 2022-04-21 14:50:34 00:00:00.000          0
2         1.1.0                 0 B 2022-04-21 14:51:00 00:00:00.000          0
3         1.1.0                 0 B 2022-04-22 16:01:42 00:00:00.000          0

convert で取り出してみると、id=3 , id=2 が候補になるが

### ID=2 が採用される
sudo qemu-img convert -l 1.1.0 name.qcow2 id-3.qcow2

取り出されたのは、 id=2 でした。

convert でスナップショットを指定するとき、次の形式のようです。

man の記載より抜粋。

SNAPSHOT_PARAM is param used for internal snapshot, format is 'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]'.

manを見た感じだと、'[ID_OR_NAME]' と記載されているので、最初にヒットしたものが取り出されるって感じですね。

まとめ

qemu-img コマンドでスナップショットを取り扱える。

スナップショットは qcow2 で扱える

qemu-img でqcow2を任意の状態に保存できるし、巻き戻しできる

保存した状態を、別のファイルにすることができる。

差分だけを保存するわけではない。

docker のように差分差分を作るのは backing file という別の機能

libvirt など仮想マシン管理ソフトは、kvm/qemu ゲストに対しqemu-img の機能を呼び出している

スナップショットはIDが自動採番されている。

スナップショットには名前をつける(被ってもいい)

被った名前は、IDで識別される(同名の旧バージョンみたいな感じ)

ただし、スナップショットを扱うときは、仮想マシンを停止する必要がある。

参考資料

man qemu-img