コンテンツにスキップ

Linux + KVM で仮想化ホストを構築してみた(Backing File編)

前回に続き、今回もDebianホスト上で仮想マシン環境を構築して、最終的にKubernetesのラボ構築を目指しています。本記事では、qemu-img resize を使ったディスク容量の拡張方法と、qcow2のBacking Fileを利用したLinked Cloneの仕組みを紹介します。


ディスク容量の拡張

bridge / cloud-init編では、クラウドイメージをインポートしてみました。

インストール要らずでとても楽でしたが、一つの問題点が残っています。ゲストOSにSSHで接続して、ディスク容量を見てみます。

1
2
3
4
5
6
7
8
$ lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
NAME     SIZE TYPE MOUNTPOINT
sr0      368K rom
vda      3.5G disk
├─vda1   2.4G part /
├─vda13 1023M part /boot
├─vda14    4M part
└─vda15  106M part /boot/efi

ディスクはvdaのみで、その容量は3.5GB程度のようです。

これは、ダウンロードしたクラウドイメージのディスク容量が3.5GBだからです。以下のコマンドで確認できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ qemu-img info questing-server-cloudimg-amd64.img
image: questing-server-cloudimg-amd64.img
file format: qcow2
virtual size: 3.5 GiB (3758096384 bytes)
disk size: 783 MiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false
Child node '/file':
    filename: questing-server-cloudimg-amd64.img
    protocol type: file
    file length: 783 MiB (821282816 bytes)
    disk size: 783 MiB

virt-install--diskパラメータでディスク容量を指定すれば良いでは?と思うかもしれませんが、容量指定ができるのは、仮想ディスクを新規作成時にのみで、クラウドディスクをインポートする場合は容量変更できません。指定しても無視されます。

そこで、qemu-img resizeを使用してサイズ変更します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ cp questing-server-cloudimg-amd64.img new.qcow2

$ qemu-img resize new.qcow2 +20G
Image resized.

$ qemu-img info new.qcow2
image: new.qcow2
file format: qcow2
virtual size: 23.5 GiB (25232932864 bytes)
disk size: 783 MiB
cluster_size: 65536
...

リサイズ後は、イメージファイルとしてほとんどサイズが変わらないものの、「バーチャルサイズ」が20GB増えて、23.5GBになっています。

このイメージを使って仮想マシンを作成してみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ sudo cp new.qcow2 /var/lib/libvirt/images/
$ virt-install \
    --name new \
    --memory 8192 \
    --vcpus 2 \
    --import \
    --disk path=/var/lib/libvirt/images/new.qcow2,format=qcow2,bus=virtio \
    --disk path=/var/lib/libvirt/images/seed.iso,device=cdrom \
    --network bridge=br0,model=virtio \
    --os-variant ubuntu25.10 \
    --graphics none \
    --noautoconsole

起動後、SSHで接続し、再度容量を確認します。

1
2
3
4
5
6
7
8
$ lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
NAME     SIZE TYPE MOUNTPOINT
sr0      368K rom
vda     23.5G disk
├─vda1  22.4G part /
├─vda13 1023M part /boot
├─vda14    4M part
└─vda15  106M part /boot/efi

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

ここでは、cloud-initが起動時に自動的にgrowpartモジュールを実行してくれるので、パーティションサイズが自動的にディスク容量に合わせて拡張されます。

cloud-initの使われていないイメージの場合は、手動でパーティションサイズの変更が必要です。

Backing Fileの利用

Backing File、いわゆるLinked Cloneを可能にする仕組みです。こちらの動作を確認してみたいと思います。

まずは、クラウドイメージをコピーし、ディスクを20GBにリサイズして、これをベースとします。

1
2
3
4
5
6
7
$ cp questing-server-cloudimg-amd64.img master.qcow2
$ qemu-img resize master.qcow2 20G
$ qemu-img info master.qcow2
image: master.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
...
次に、master.qcow2をBacking Fileとして、差分ディスクを作成します。

1
2
$ qemu-img create -f qcow2 -F qcow2 -b master.qcow2 vm1.qcow2
Formatting 'vm1.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=21474836480 backing_file=master.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16

この差分ディスクの情報を見ると、ホスト側のディスク上でのサイズは、わずか196KBです。そして、backing file: master.qcow2と、Backing Fileの所在を記載しています。

1
2
3
4
5
6
7
8
9
$ qemu-img info vm1.qcow2
image: vm1.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
disk size: 196 KiB
cluster_size: 65536
backing file: master.qcow2
backing file format: qcow2
...

Backing Fileと差分ディスクを移動します。qemu-img createで差分ディスクを作成した際に、相対パスで記述したため、差分ディスクだけでなくBacking Fileも一緒に移動しないと、起動時にBacking Fileが見つからずエラーになります。

1
$ sudo mv master.qcow2 vm1.qcow2 /var/lib/libvirt/images/

差分ディスクを使用して仮想マシンを作成します(seedは作成済みとします)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ virt-install \
    --name vm1 \
    --memory 8192 \
    --vcpus 2 \
    --import \
    --disk path=/var/lib/libvirt/images/vm1.qcow2,format=qcow2,bus=virtio \
    --disk path=/var/lib/libvirt/images/seed.iso,device=cdrom \
    --network bridge=br0,model=virtio \
    --os-variant ubuntu25.10 \
    --graphics none \
    --noautoconsole

また、seed を変更すれば、この1つのBacking Fileから複数の差分ディスクを作成し、複数の仮想マシンを瞬時に起動することができます。

応用:自動化スクリプト

色々書きましたが、実際に複数の仮想マシンを作成する場合、やはり1個1個コマンドを打つのが大変なので、シンプルなシェルスクリプトにまとめました。

このスクリプトは、/var/lib/libvirt/images/master.qcow2というBacking Fileが存在することを前提としています。コマンドラインでVM名とIPアドレスを指定するだけで、VMをクラウドイメージから作成してくれて、設定してくれます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/env bash
set -euo pipefail

if [ "$EUID" -ne 0 ]; then
    echo "This script must be run as root"
    exit 1
fi

VM="${1:?usage: $0 <vm-name> <ip-address>}"
IP="${2:?usage: $0 <vm-name> <ip-address>}"

BASE="/var/lib/libvirt/images/master.qcow2"
DIR="/var/lib/libvirt/images/${VM}"
DISK="${DIR}/${VM}.qcow2"
SEED="${DIR}/${VM}-seed.iso"

RAM=8192
VCPUS=2
CIDR="/24"
GW="192.168.0.1"
DNS1="192.168.0.1"
BRIDGE="br0"
USER_NAME="nogawa"
SSH_KEY="$(cat /home/user/.ssh/id_ed25519.pub)"

mkdir -p "$DIR"

qemu-img create -f qcow2 -F qcow2 -b "$BASE" "$DISK" 20G

cat > "${DIR}/user-data" <<EOF
#cloud-config
users:
  - name: ${USER_NAME}
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    shell: /bin/bash
    lock_passwd: true
    ssh_authorized_keys:
      - ${SSH_KEY}
packages:
  - qemu-guest-agent
runcmd:
  - systemctl enable --now qemu-guest-agent
EOF

cat > "${DIR}/meta-data" <<EOF
instance-id: ${VM}
local-hostname: ${VM}
EOF

cat > "${DIR}/network-config" <<EOF
network:
  version: 2
  ethernets:
    server-main-nic:
      match:
        driver: virtio_net
      addresses:
        - ${IP}${CIDR}
      routes:
        - to: default
          via: ${GW}
      nameservers:
        addresses: [${DNS1}]
EOF

cloud-localds "$SEED" "${DIR}/user-data" "${DIR}/meta-data" \
  --network-config "${DIR}/network-config"

virt-install \
  --name "$VM" \
  --memory "$RAM" \
  --vcpus "$VCPUS" \
  --import \
  --disk path="$DISK",format=qcow2,bus=virtio \
  --disk path="$SEED",device=cdrom \
  --network bridge="$BRIDGE",model=virtio \
  --os-variant ubuntu25.10 \
  --graphics none \
  --noautoconsole

echo "VM created:"
echo "  name: $VM"
echo "  ip:   $IP"
echo "  ssh:  ssh ${USER_NAME}@${IP}"

使い方はこんな感じです:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ sudo ./tool.sh vm3 192.168.0.123
Formatting '/var/lib/libvirt/images/vm3/vm3.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=21474836480 backing_file=/var/lib/libvirt/images/master.qcow2 backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16

Starting install...
Creating domain...                                                                                                                                                                             |         00:00:00
Domain creation completed.
VM created:
  name: vm3
  ip:   192.168.0.123
  ssh:  ssh nogawa@192.168.0.123

これを使えば、1つのVMの作成に必要な時間は5秒未満でした。