2015/05/05

ZFSルートなFreeBSDゲストのzpoolのディスクを拡張する

KVM 上の FreeBSD ゲストで freebsd-update 中にルートファイルシステムの zfs がディスクフルとなり、ファイルを削除することも出来なくなったので慌てて FreeBSD の zpool に割り当てているディスクの拡張方法を調べたときのメモです。

環境

環境は Debian/GNU Linux の KVM ゲストとして、ZFS をルートファイルシステムとした FreeBSD 10.0 です。

当時の手順は以下にまとめています。

前半でディスクを拡張するに至った経緯、実際の拡張作業は後半になります。お急ぎの方は「zpoolのディスクを拡張する」をご覧下さい。

Debianアップグレード(wheezy→jessie)によるディスクデバイス名の変更

FreeBSD とは関係ありませんが、KVM ホストの Debian を wheezy から jessie にアップグレードしたところ、RAIDZ 用に KVM ゲストに割り当てていたディスクの WWID ベースのデバイス名が変更されていて VM が起動できませんでした。

アップグレード前は /dev/disk/by-id/scsi-* として存在していましたが、
# ls -l /dev/disk/by-id/scsi* | grep -v -- -part | sort -k 9 | cut -d' ' -f 9,11
/dev/disk/by-id/scsi-SATA_INTEL_SSDSC2CT2CVKI2463039A240DGN ../../sda
/dev/disk/by-id/scsi-SATA_Hitachi_HDS7220_JK1171YAHW4JMS ../../sdb
/dev/disk/by-id/scsi-SATA_Hitachi_HDS7220_JK1171YAHVULVS ../../sdc
/dev/disk/by-id/scsi-SATA_Hitachi_HDS7220_JK1171YAHWGBAS ../../sdd
/dev/disk/by-id/scsi-SATA_Hitachi_HDS7220_JK1171YAHVV5UN ../../sde
アップグレード後は /dev/disk/by-id/ata-* と変わっていました。
# ls -l /dev/disk/by-id/ata* | grep -v -- -part | sort -k 9 | cut -d' ' -f 9,11
/dev/disk/by-id/ata-INTEL_SSDSC2CT240A4_CVKI2463039A240DGN ../../sda
/dev/disk/by-id/ata-Hitachi_HDS722020ALA330_JK1171YAHW4JMS ../../sdb
/dev/disk/by-id/ata-Hitachi_HDS722020ALA330_JK1171YAHVULVS ../../sdc
/dev/disk/by-id/ata-Hitachi_HDS722020ALA330_JK1171YAHWGBAS ../../sdd
/dev/disk/by-id/ata-Hitachi_HDS722020ALA330_JK1171YAHVV5UN ../../sde
見た目の分かりやすさを優先してデバイス名にしていましたが、WWN だと問題なかったのかも知れません。
# ls -l /dev/disk/by-id/wwn* | grep -v -- -part | sort -k 9 | cut -d' ' -f 9,11
/dev/disk/by-id/wwn-0x5001517387e9f5b3 ../../sda
/dev/disk/by-id/wwn-0x5000cca221da6e8d ../../sdb
/dev/disk/by-id/wwn-0x5000cca221da4948 ../../sdc
/dev/disk/by-id/wwn-0x5000cca221da9373 ../../sdd
/dev/disk/by-id/wwn-0x5000cca221da4b75 ../../sde

FreeBSDアップグレード中のディスクフル

さてデバイス名を変更することで無事に FreeBSD ゲストが起動できましたので、ハンドブックに従って 10.1 へアップグレードします。

# freebsd-update -r 10.1-RELEASE upgrade

Looking up update.FreeBSD.org mirrors... 5 mirrors found.
Fetching metadata signature for 10.0-RELEASE from update2.freebsd.org... done.
Fetching metadata index... done.
Fetching 1 metadata patches. done.
Applying metadata patches... done.
Inspecting system... done.

The following components of FreeBSD seem to be installed:
kernel/generic src/src world/base

The following components of FreeBSD do not seem to be installed:
world/doc world/games world/lib32

Does this look reasonable (y/n)? y

Fetching metadata signature for 10.1-RELEASE from update2.freebsd.org... done.
Fetching metadata index... done.
Fetching 1 metadata patches. done.
Applying metadata patches... done.
Fetching 1 metadata files... done.
Inspecting system...
done.
Fetching files from 10.0-RELEASE for merging... done.
Preparing to download files...
done.
Fetching 40219 patches.

...

Applying patches...
done.
Fetching 2807 files... done.
Attempting to automatically merge changes in files... done.

The following file could not be merged automatically: /etc/ttys
Press Enter to edit this file in vim and resolve the conflicts
manually...

...

The following changes, which occurred between FreeBSD 10.0-RELEASE and
FreeBSD 10.1-RELEASE have been merged into /etc/motd:

...

Does this look reasonable (y/n)? y

...

To install the downloaded upgrades, run "/usr/sbin/freebsd-update install".
シリアルコンソール用に編集していた /etc/ttys とアップグレードによる /etc/motd の変更が表示されましたが、それ以外はとくに問題なくアップグレードの準備は済みましたので、それらをインストールしますが、、、
# freebsd-update install

Installing updates...

install: ///boot/kernel/snd_mss.ko.symbols: chmod: No space left on device
rm: 653fb8f6b8ab6b0838e8ca35b8f53b90a8d49183a5284e6ff8397dd013b3ef51: No space left on device
/usr/sbin/freebsd-update: cannot create 4892e33f0fea1cadb3759ba6d991e4cb38377182c1d88b719362ed9350f84e40: No space left on device
install: 4892e33f0fea1cadb3759ba6d991e4cb38377182c1d88b719362ed9350f84e40: No such file or directory
rm: 4892e33f0fea1cadb3759ba6d991e4cb38377182c1d88b719362ed9350f84e40: No such file or directory
/usr/sbin/freebsd-update: cannot create 17589e6235a801c9cc092948faf057de2b5ab04ef6c3fd4bcfe117bae3a7e4f3: No space left on device
install: 17589e6235a801c9cc092948faf057de2b5ab04ef6c3fd4bcfe117bae3a7e4f3: No such file or directory

...

/usr/sbin/freebsd-update: cannot create cd206a257b7de6b7d1c2560eea431ad0cd5e0a8e4f479c2db83ae61045f94cc1: No space left on device
install: cd206a257b7de6b7d1c2560eea431ad0cd5e0a8e4f479c2db83ae61045f94cc1: No such file or directory
rm: cd206a257b7de6b7d1c2560eea431ad0cd5e0a8e4f479c2db83ae61045f94cc1: No such file or directory
chflags: ///boot/kernel/snd_mss.ko.symbols: No such file or directory
/usr/sbin/freebsd-update: cannot create newfiles: No space left on device
join: newfiles: No such file or directory
/usr/sbin/freebsd-update: cannot create killfiles: No space left on device
/usr/sbin/freebsd-update: cannot open killfiles: No such file or directory
rm: newfiles: No such file or directory
rm: killfiles: No such file or directory
エラーに気づいて慌ててディスク使用量を見ると全て 100% でした。
# df -h
Filesystem                           Size    Used   Avail Capacity  Mounted on
rpool/ROOT/freebsd-10.1              938M    938M      0B   100%    /
devfs                                1.0K    1.0K      0B   100%    /dev
rpool/ROOT/freebsd-10.1/tmp          800K    800K      0B   100%    /tmp
rpool/ROOT/freebsd-10.1/usr          4.4G    4.4G      0B   100%    /usr
rpool/ROOT/freebsd-10.1/usr/local    1.0G    1.0G      0B   100%    /usr/local
rpool/ROOT/freebsd-10.1/var          2.2G    2.2G      0B   100%    /var
アップグレード用の Boot Environment(ZFSスナップショット)で作業していたので作業前に戻そうとしましたが、 /tmp もディスクフルなのでコマンドがエラー。/tmp 以下の小さなファイルだけでも削除できればと幾つか試みましたが、過去のスナップショットもあるだろうし zfs 特有の CoW の為か削除もディスクフルで出来ませんでした。
# beadm list
BE                 Active Mountpoint  Space Created
freebsd-9.1        -      -            2.1M 2013-05-03 18:10
freebsd-9.1p3      -      -            1.5M 2013-05-03 19:17
freebsd-9.1p6      -      -          977.5K 2013-09-07 20:58
freebsd-9.1p7      -      -           68.3M 2013-10-06 02:17
freebsd-9.2        -      -          991.0K 2013-10-06 03:09
freebsd-9.2p3      -      -            1.2M 2014-02-09 01:54
freebsd-9.2p5      -      -           97.1M 2014-05-06 17:42
freebsd-10.0       -      -          777.5K 2014-05-06 17:54
freebsd-10.0p6     -      -          928.0K 2014-06-17 09:26
freebsd-10.0p18    -      -            1.0M 2015-05-04 11:41
freebsd-10.0p18-02 -      -            1.0M 2015-05-04 11:57
freebsd-10.1       NR     /           19.3G 2015-05-04 12:49

# beadm activate freebsd-10.0p18-02
mktemp: mkdtemp failed on /tmp/BE-freebsd-10.0p18-02.hlYlxIG2: No space left on device

# rm /tmp/groff*
remove /tmp/groff1CjJgB? y
rm: /tmp/groff1CjJgB: No space left on device
remove /tmp/groffJUhS7X? y
rm: /tmp/groffJUhS7X: No space left on device

...

# dd if=/dev/null of=/tmp/groffw7BNbC
dd: /tmp/groffw7BNbC: No space left on device

# cat /dev/null /tmp/groffw7BNbC
zsh: no space left on device: /tmp/groffw7BNbC
この FreeBSD ゲストは NAS のディスク入れ替えで余った HDD を使って RAIDZ を試そうとしたもので、ルートファイルシステムの ZFS スナップショットによる BE 構成は後付けだったため 20GB の割り当てでは少なすぎたのでした。
# zpool list
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
rpool  19.8G  19.4G   314M    98%  1.00x  ONLINE  -
tank   7.25T  14.1G  7.24T     0%  1.00x  ONLINE  -
「ZFS ではプールの空きに注意して使用率が 80% を超えないようにする」というのをどこかで見聞きしたことがありますが、たまにコマンドを試す程度でしか起動しないサーバでしたのでまったくチェックしていませんでした。 幸い作業前に FreeBSD ゲストのバックアップは取得していましたので、それをリストアして zpool のディスクを拡張してからやり直すことにしました。ここで頑張って ZFS のディスクフルを解決できたとしてもアップグレード中に起きたディスクフルから正常に復旧することは私には出来ませんので。
# poweroff
Shutdown NOW!
poweroff: [pid 35906]

wall: can't open temporary file: No space left on device

zpoolのディスクを拡張する

前置きが長くなりましたがここからが本題です。zpool で使用可能な容量を増やすにはディスクを追加するだけだと思いますが、VM イメージファイルを増やしたくなかったのと、FreeBSD での拡張方法を知りたかったので以下の記事を参考に zpool に割り当てているディスクのサイズを拡張する方法をとります。

VMイメージファイルのサイズ拡張

まずは KVM ホスト側での作業。raw フォーマットのイメージファイルですので単純に qemu-img コマンドで 10GB 増やします。

# qemu-img info /var/lib/libvirt/images/FreeBSD.img
image: /var/lib/libvirt/images/FreeBSD.img
file format: raw
virtual size: 20G (21474836480 bytes)
disk size: 20G

# qemu-img resize /var/lib/libvirt/images/FreeBSD.img +10G
Image resized.

# qemu-img info /var/lib/libvirt/images/FreeBSD.img
image: /var/lib/libvirt/images/FreeBSD.img
file format: raw
virtual size: 30G (32212254720 bytes)
disk size: 20G

GPTパーティションの拡張

ここからは FreeBSD ゲストでの作業です。OS を起動して現状を確認します。イメージファイルの拡張によってディスク末尾にあったセカンダリ GPT パーティションテーブルが不明となってしまったようで status が CORRUPT となっています。

# gpart show vtbd0

=>      34  41942973  vtbd0  GPT  (30G) [CORRUPT]
        34       122      1  freebsd-boot  (61K)
       156    262144      2  freebsd-swap  (128M)
    262300  41680707      3  freebsd-zfs  (20G)
# gpart list
Geom name: vtbd0
modified: false
state: CORRUPT
fwheads: 16
fwsectors: 63
last: 41943006
first: 34
entries: 128
scheme: GPT
Providers:
1. Name: vtbd0p1
   Mediasize: 62464 (61K)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 17408
   Mode: r0w0e0
   rawuuid: 646ac321-54d4-11e2-8e58-525400c151da
   rawtype: 83bd6b9d-7f41-11dc-be0b-001560b84f0f
   label: boot0
   length: 62464
   offset: 17408
   type: freebsd-boot
   index: 1
   end: 155
   start: 34
2. Name: vtbd0p2
   Mediasize: 134217728 (128M)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 79872
   Mode: r1w1e1
   rawuuid: 8ae1a9a7-54d4-11e2-8e58-525400c151da
   rawtype: 516e7cb5-6ecf-11d6-8ff8-00022d09712b
   label: swap0
   length: 134217728
   offset: 79872
   type: freebsd-swap
   index: 2
   end: 262299
   start: 156
3. Name: vtbd0p3
   Mediasize: 21340521984 (20G)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 134297600
   Mode: r1w1e2
   rawuuid: b4378490-54d4-11e2-8e58-525400c151da
   rawtype: 516e7cba-6ecf-11d6-8ff8-00022d09712b
   label: disk0
   length: 21340521984
   offset: 134297600
   type: freebsd-zfs
   index: 3
   end: 41943006
   start: 262300
Consumers:
1. Name: vtbd0
   Mediasize: 32212254720 (30G)
   Sectorsize: 512
   Mode: r2w2e5
# dmesg | grep GEOM
GEOM: vtbd0: the secondary GPT header is not in the last LBA.
GEOM: vtbd1: the primary GPT table is corrupt or invalid.
GEOM: vtbd1: using the secondary instead -- recovery strongly advised.
GEOM: vtbd2: the primary GPT table is corrupt or invalid.
GEOM: vtbd2: using the secondary instead -- recovery strongly advised.
GEOM: vtbd3: the primary GPT table is corrupt or invalid.
GEOM: vtbd3: using the secondary instead -- recovery strongly advised.
GEOM: vtbd4: the primary GPT table is corrupt or invalid.
GEOM: vtbd4: using the secondary instead -- recovery strongly advised.
gpart recover コマンドで GPT パーティションテーブルの復旧を行います。
# gpart recover vtbd0
vtbd0 recovered
すると拡張した 10GB が空き領域として認識されています。
# gpart show vtbd0
=>      34  62914493  vtbd0  GPT  (30G)
        34       122      1  freebsd-boot  (61K)
       156    262144      2  freebsd-swap  (128M)
    262300  41680707      3  freebsd-zfs  (20G)
  41943007  20971520         - free -  (10G)
つぎに zpool に割り当てているパーティションを拡張します。単純な拡張ですのでサイズ指定無しの gpart resize を実行します。
# gpart resize -i 3 vtbd0
vtbd0p3 resized
これで vtbd0p3 が 20GB から 30GB となりました。
# gpart show vtbd0
=>      34  62914493  vtbd0  GPT  (30G)
        34       122      1  freebsd-boot  (61K)
       156    262144      2  freebsd-swap  (128M)
    262300  62652227      3  freebsd-zfs  (30G)
# gpart list vtbd0
Geom name: vtbd0
modified: false
state: OK
fwheads: 16
fwsectors: 63
last: 62914526
first: 34
entries: 128
scheme: GPT
Providers:
1. Name: vtbd0p1
   Mediasize: 62464 (61K)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 17408
   Mode: r0w0e0
   rawuuid: 646ac321-54d4-11e2-8e58-525400c151da
   rawtype: 83bd6b9d-7f41-11dc-be0b-001560b84f0f
   label: boot0
   length: 62464
   offset: 17408
   type: freebsd-boot
   index: 1
   end: 155
   start: 34
2. Name: vtbd0p2
   Mediasize: 134217728 (128M)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 79872
   Mode: r1w1e1
   rawuuid: 8ae1a9a7-54d4-11e2-8e58-525400c151da
   rawtype: 516e7cb5-6ecf-11d6-8ff8-00022d09712b
   label: swap0
   length: 134217728
   offset: 79872
   type: freebsd-swap
   index: 2
   end: 262299
   start: 156
3. Name: vtbd0p3
   Mediasize: 32077940224 (30G)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 134297600
   Mode: r1w1e2
   rawuuid: b4378490-54d4-11e2-8e58-525400c151da
   rawtype: 516e7cba-6ecf-11d6-8ff8-00022d09712b
   label: disk0
   length: 32077940224
   offset: 134297600
   type: freebsd-zfs
   index: 3
   end: 62914526
   start: 262300
Consumers:
1. Name: vtbd0
   Mediasize: 32212254720 (30G)
   Sectorsize: 512
   Mode: r2w2e5

zpoolの拡張

zpool を構成するディスクのサイズを変更しただけではまだ zpool の容量は変わっていません。

# zpool list
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
rpool  19.8G  17.1G  2.65G    86%  1.00x  ONLINE  -
tank   7.25T  14.1G  7.24T     0%  1.00x  ONLINE  -
zpool online -e コマンドを使用して拡張します。 その前に、zpool status コマンドを実行すると幾つかの機能が使えないと表示されます。
# zpool status
  pool: rpool
 state: ONLINE
status: The pool is formatted using a legacy on-disk format.  The pool can
        still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the
        pool will no longer be accessible on software that does not support feature
        flags.
  scan: scrub repaired 0 in 0h3m with 0 errors on Sun Dec 22 04:34:34 2013
config:

        NAME         STATE     READ WRITE CKSUM
        rpool        ONLINE       0     0     0
          gpt/disk0  ONLINE       0     0     0

errors: No known data errors
今回の作業に直接関係のある機能フラグでは無さそうですが、何度か試したところ upgrade しないとダメでしたので zpool のバージョンを最新化します。
# zfs get all | grep disabled
rpool  feature@async_destroy          disabled                       local
rpool  feature@empty_bpobj            disabled                       local
rpool  feature@lz4_compress           disabled                       local
rpool  feature@multi_vdev_crash_dump  disabled                       local
# zpool upgrade rpool

This system supports ZFS pool feature flags.

Successfully upgraded 'rpool' from version 28 to feature flags.
Enabled the following features on 'rpool':
  async_destroy
  empty_bpobj
  lz4_compress
  multi_vdev_crash_dump

If you boot from pool 'rpool', don't forget to update boot code.
Assuming you use GPT partitioning and da0 is your boot disk
the following command will do it:

        gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0
ブートに使用しているプールの変更なので忘れずにセカンダリローダを更新します。
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 vtbd0
bootcode written to vtbd0
zpool online -e による拡張を行うためプールのプロパティ autoexpand を有効化します。
# zpool get autoexpand rpool
NAME   PROPERTY    VALUE   SOURCE
rpool  autoexpand  off     default
# zpool set autoexpand=on rpool
# zpool get autoexpand rpool
NAME   PROPERTY    VALUE   SOURCE
rpool  autoexpand  on      local
そして zpool online -e でプールを拡張します。
# zpool list rpool
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
rpool  19.8G  17.1G  2.63G    86%  1.00x  ONLINE  -
# zpool online -e rpool gpt/disk0
# zpool list rpool
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
rpool  29.8G  17.1G  12.6G    57%  1.00x  ONLINE  -
これで空き領域に余裕が出来ましたので、安心して freebsd-update 出来そうです。
# df -h
Filesystem                             Size    Used   Avail Capacity  Mounted on
rpool/ROOT/freebsd-10.0p6               13G    861M     12G     6%    /
devfs                                  1.0K    1.0K      0B   100%    /dev
rpool/ROOT/freebsd-10.0p6/tmp           12G    807K     12G     0%    /tmp
rpool/ROOT/freebsd-10.0p6/usr           17G    4.4G     12G    26%    /usr
rpool/ROOT/freebsd-10.0p6/usr/local     13G    920M     12G     7%    /usr/local
rpool/ROOT/freebsd-10.0p6/var           14G    1.8G     12G    13%    /var

おわりに

ディスクフルでアップグレードに失敗というサーバ管理の基本的なところでつまずいてしまいましたが、ZFS ではとくに空き領域に注意することを身をもって学びました。

あとで FAQ ページ見て知りましたが、truncate(1) コマンド ならばディスクフルでも使えたみたいです。

あまりそういうシチュエーションに陥りたくありませんが覚えておくとよいかも知れません。

0 件のコメント:

コメントを投稿