2013/03/26

FreeBSDでBoot Environments

ZFS の機能を活用すべく、Oracle Solaris の Live アップグレードで使われるブート環境と同じようなものを FreeBSD 9.1-RELEASE に構築したときのメモです。

Boot Environments とは?

ルートファイルシステムが ZFS となっている Oracle Solaris 11 では、システムの Live アップグレードを容易に行うためにブート環境(Boot Environments、以下 BE)と呼ばれる ZFS のクローンとプロモーションを利用する仕組みがあります。

ZFS ブートが可能な FreeBSD でもこの BE の仕組みを利用する方法があるようで、Oracle Solaris で BE を管理する beadm(1M) コマンド(python2.6 スクリプト)のオープンソース実装(シェルスクリプト)も FreeBSD の Ports Collection に存在します。 Oracle Solaris は管理したことがなく個人で自由に使えそうなイメージが持てないので、ZFS の機能を少しでも理解すべく FreeBSD 9.1-RELEASE で BE 環境を構築してみました。

Boot Environments への移行手順

基本的に BSDCan 2012 の資料にある手順通りです。

ここでは最初に作成する BE(以下、基礎 BE)となる既存のルートファイルシステムは rpool ではなく rpool/root から作成します。
# zpool get bootfs rpool
NAME   PROPERTY  VALUE       SOURCE
rpool  bootfs    rpool/root  local

# zfs list -o name,mountpoint
NAME                  MOUNTPOINT
rpool                 none
rpool/root            legacy
rpool/root/tmp        /tmp
rpool/root/usr        /usr
rpool/root/usr/local  /usr/local
rpool/root/var        /var

# zfs list -t snapshot
no datasets available
事前に beadm コマンドをインストールします。
# cd /usr/ports
# make quicksearch name=beadm
Port: beadm-0.8.5
Path: /usr/ports/sysutils/beadm
Info: Solaris-like utility to manage Boot Environments on ZFS

Port: beadm-devel-0.8.99.20121205
Path: /usr/ports/sysutils/beadm-devel
Info: Solaris-like utility to manage Boot Environments on ZFS

# cd /usr/ports/sysutils/beadm
# make install clean

基礎 BE の作成

制御構造を使用するため作業はボーンシェルで行います。

# /bin/sh
BE を配置する ROOT データセットを作成します。必要に応じて重複排除を有効にします。
# zfs create -o dedup=on rpool/ROOT
基礎 BE とするルートファイルシステムとその子孫のスナップショットを作成します。
# zfs snapshot -r rpool/root@snap0
ルートファイルシステムのスナップショットから基礎 BE を作成します。
# zfs send rpool/root@snap0 | zfs recv rpool/ROOT/base-be
基礎 BE を作成したので不要となったルートファイルシステムのスナップショットを削除します。
# zfs destroy rpool/root@snap0
基礎 BE に付随するスナップショットは不要なので削除します。
# zfs destroy rpool/ROOT/base-be@snap0
ルートファイルシステムの子孫のスナップショットから基礎 BE の子孫ファイルシステムを作成します。
# zfs list -t snapshot -H -o name | grep '^rpool/root/.*@snap0$' | while read s; do zfs send $s | zfs recv -v `echo $s | sed 's/rpool\/root\/\(.*\)@snap0$/rpool\/ROOT\/base-be\/\1/'`; done
基礎 BE の作成に使用したすべてのスナップショットを削除します。
# zfs list -t snapshot -H -o name | grep snap0 | xargs -n 1 zfs destroy -v
ここまでの作業でデータセットは次のようになっています。
# beadm list
BE      Active Mountpoint  Space Created
base-be -      -            4.5G 2013-03-25 23:09

# zfs list -o name,canmount,mountpoint
NAME                          CANMOUNT  MOUNTPOINT
rpool                               on  none
rpool/ROOT                          on  none
rpool/ROOT/base-be                  on  none
rpool/ROOT/base-be/tmp              on  none
rpool/ROOT/base-be/usr              on  none
rpool/ROOT/base-be/usr/local        on  none
rpool/ROOT/base-be/var              on  none
rpool/root                          on  legacy
rpool/root/tmp                      on  /tmp
rpool/root/usr                      on  /usr
rpool/root/usr/local                on  /usr/local
rpool/root/var                      on  /var

# zfs list -t snapshot
no datasets available

基礎 BE でのブート設定

基礎 BE を /mnt にマウントして、ルートファイルシステムとしてマウントするように loader.conf を書き換えます。
→ストレージプールの bootfs プロパティで指定すればよいのでこの設定は不要です。loader.conf でも指定している場合は該当行を削除します。

# zfs set mountpoint=/mnt rpool/ROOT/base-be
# sed -i -e 's/^\(vfs.root.mountfrom="zfs:\).*/\1rpool\/ROOT\/base-be"/' /mnt/boot/loader.conf
基礎 BE のデータセットにユーザプロパティを設定します。
# zfs set freebsd:boot-environment=1 rpool/ROOT/base-be
継承可能な通常の mountpoint プロパティを保持するように基礎 BE 配下のファイルシステムを設定します。
# zfs list -H -o name | grep ROOT/base-be | xargs -n 1 zfs set canmount=off
基礎 BE のマウントポイントを設定します。
# zfs set mountpoint=/ rpool/ROOT/base-be
基礎 BE の子孫ファイルシステムのマウントポイントをデータセット名の階層に合わせて設定します。
# zfs list -H -o name | grep ROOT/base-be/ | while read f; do zfs set mountpoint=`echo $f | sed 's/.*base-be//'` $f; done
基礎 BE 配下のファイルシステムをマウントできるように設定します。
# zfs list -H -o name | grep ROOT/base-be | xargs -n 1 zfs set canmount=on
基礎 BE からブートするようにストレージプールのプロパティを設定します。
# zpool set bootfs=rpool/ROOT/base-be rpool
現在のルートファイルシステムを自動マウントしないように設定します。
# zfs list -H -o name | grep ^rpool/root | xargs -n 1 zfs set canmount=noauto
ここまでの作業でデータセットは次のようになっています。
# beadm list
BE      Active Mountpoint  Space Created
base-be R      -            4.5G 2013-03-25 23:09

# zfs list -o name,canmount,mountpoint
NAME                          CANMOUNT  MOUNTPOINT
rpool                               on  none
rpool/ROOT                          on  none
rpool/ROOT/base-be                  on  /
rpool/ROOT/base-be/tmp              on  /tmp
rpool/ROOT/base-be/usr              on  /usr
rpool/ROOT/base-be/usr/local        on  /usr/local
rpool/ROOT/base-be/var              on  /var
rpool/root                      noauto  legacy
rpool/root/tmp                  noauto  /tmp
rpool/root/usr                  noauto  /usr
rpool/root/usr/local            noauto  /usr/local
rpool/root/var                  noauto  /var
成功を祈って OS を再起動します。
# reboot

旧ルートファイルシステムの削除

基礎 BE からの起動が確認できたら不要となった旧ルートファイルシステムのデータセットを削除します。

# beadm list
BE      Active Mountpoint  Space Created
base-be NR     /            4.5G 2013-03-25 23:09

# df -t zfs
Filesystem                   1K-blocks    Used    Avail Capacity  Mounted on
rpool/ROOT/base-be            12015618  382379 11633238     3%    /
rpool/ROOT/base-be/tmp        11633289      51 11633238     0%    /tmp
rpool/ROOT/base-be/usr        15413918 3780679 11633238    25%    /usr
rpool/ROOT/base-be/usr/local  12117408  484169 11633238     4%    /usr/local
rpool/ROOT/base-be/var        11733357  100118 11633238     1%    /var

# zfs list -o name,mountpoint
NAME                          MOUNTPOINT
rpool                         none
rpool/ROOT                    none
rpool/ROOT/base-be            /
rpool/ROOT/base-be/tmp        /tmp
rpool/ROOT/base-be/usr        /usr
rpool/ROOT/base-be/usr/local  /usr/local
rpool/ROOT/base-be/var        /var
rpool/root                    legacy
rpool/root/tmp                /tmp
rpool/root/usr                /usr
rpool/root/usr/local          /usr/local
rpool/root/var                /var
# zfs list -H -o name | grep rpool/root | sort -r | xargs -n 1 zfs destroy -v

Jail と組み合わせたシステムのアップデート

以下ページに倣って、FreeBSD のコンテナ型仮想化機構 Jail と BE を組み合わせて FreeBSD 9.1-RELEASE-p1 にアップデートしてみます。

Jail の設定

ここでの設定は、普段 Jail は使用せず今回のアップデートだけで使用する前提です。

  • 普段は使用しないので jail_enable は "NO"
  • 名前は updatejail
  • マウントポイントは /usr/jails/freebsd-update
  • IP アドレスはホストと同じセグメントのもの(例では VirtualBox の NAT)
Jail 用のディレクトリを作成します。
# mkdir /usr/jails
Jail の設定を rc.conf に記述します。
# cat << EOF >> /etc/rc.conf
jail_enable="NO"
jail_set_hostname_allow="NO"
jail_list="updatejail"
jail_updatejail_rootdir="/usr/jails/freebsd-update"
jail_updatejail_hostname="freebsd-update"
jail_updatejail_interface="em0"
jail_updatejail_ip="10.0.2.100"
jail_updatejail_devfs_enable="YES"
EOF
Jail 内で freebsd-update が正常に動作するように chflags を利用できるようにします。
# sysctl security.jail.chflags_allowed=1
security.jail.chflags_allowed: 0 -> 1

# echo !$ >> /etc/sysctl.conf
echo security.jail.chflags_allowed=1 >> /etc/sysctl.conf

アップデート用 BE の作成

アップデート用の BE を作成します。(基礎 BE のクローン)

# beadm create freebsd-9.1p1
Created successfully
アップデート用の BE をマウントします。
# beadm mount freebsd-9.1p1 /usr/jails/freebsd-update
Mounted successfully on '/usr/jails/freebsd-update'
ここまでの作業でデータセットとマウント状態は次のようになっています。
# beadm list
BE            Active Mountpoint                 Space Created
base-be       NR     /                           4.5G 2013-03-25 23:09
freebsd-9.1p1 -      /usr/jails/freebsd-update 221.0K 2013-03-25 23:34

# zfs list -o name,mountpoint,origin
NAME                                MOUNTPOINT  ORIGIN
rpool                               none        -
rpool/ROOT                          none        -
rpool/ROOT/base-be                  /           -
rpool/ROOT/base-be/tmp              /tmp        -
rpool/ROOT/base-be/usr              /usr        -
rpool/ROOT/base-be/usr/local        /usr/local  -
rpool/ROOT/base-be/var              /var        -
rpool/ROOT/freebsd-9.1p1            /           rpool/ROOT/base-be@2013-03-25-23:34:12
rpool/ROOT/freebsd-9.1p1/tmp        /tmp        rpool/ROOT/base-be/tmp@2013-03-25-23:34:12
rpool/ROOT/freebsd-9.1p1/usr        /usr        rpool/ROOT/base-be/usr@2013-03-25-23:34:12
rpool/ROOT/freebsd-9.1p1/usr/local  /usr/local  rpool/ROOT/base-be/usr/local@2013-03-25-23:34:12
rpool/ROOT/freebsd-9.1p1/var        /var        rpool/ROOT/base-be/var@2013-03-25-23:34:12

# zfs list -t snapshot
NAME                                               USED  AVAIL  REFER  MOUNTPOINT
rpool/ROOT/base-be@2013-03-25-23:34:12              43K      -   373M  -
rpool/ROOT/base-be/tmp@2013-03-25-23:34:12            0      -    51K  -
rpool/ROOT/base-be/usr@2013-03-25-23:34:12          47K      -  3.61G  -
rpool/ROOT/base-be/usr/local@2013-03-25-23:34:12    34K      -   473M  -
rpool/ROOT/base-be/var@2013-03-25-23:34:12          43K      -  97.8M  -

# df -t zfs
Filesystem                         1K-blocks    Used    Avail Capacity  Mounted on
rpool/ROOT/base-be                  16764769  382379 16382389     2%    /
rpool/ROOT/base-be/tmp              16382440      51 16382389     0%    /tmp
rpool/ROOT/base-be/usr              20163076 3780686 16382389    19%    /usr
rpool/ROOT/base-be/usr/local        16866559  484169 16382389     3%    /usr/local
rpool/ROOT/base-be/var              16482507  100118 16382389     1%    /var
rpool/ROOT/freebsd-9.1p1            16764769  382379 16382389     2%    /usr/jails/freebsd-update
rpool/ROOT/freebsd-9.1p1/tmp        16382425      36 16382389     0%    /usr/jails/freebsd-update/tmp
rpool/ROOT/freebsd-9.1p1/usr        20163075 3780685 16382389    19%    /usr/jails/freebsd-update/usr
rpool/ROOT/freebsd-9.1p1/usr/local  16866559  484169 16382389     3%    /usr/jails/freebsd-update/usr/local
rpool/ROOT/freebsd-9.1p1/var        16482507  100118 16382389     1%    /usr/jails/freebsd-update/var

Jail 環境で freebsd-update を実行

Jail 環境を実行します。

# service jail onestart
Configuring jails:. set_hostname_allow=NO.
Starting jails: freebsd-update.
実行した Jail 環境を確認します。
# jls
   JID  IP Address      Hostname                      Path
     1  10.0.2.100      freebsd-update                /usr/jails/freebsd-update
Jail 環境で freebsd-update を実行します。
# jexec 1 freebsd-update fetch install
Jail 環境を停止します。
# service jail onestop
Stopping jails: freebsd-update.
アップデート用の BE をアンマウントします。
# beadm unmount freebsd-9.1p1
Unmounted successfully

アップデートした BE での起動

次回リブート時にアップデートした BE がアクティブになるように切り替えます。(アップデート BE のプロモーション)

# beadm activate freebsd-9.1p1
Activated successfully
ここまでの作業で BE とデータセットは次のようになっています。
# beadm list
BE            Active Mountpoint  Space Created
base-be       N      /           31.8M 2013-03-25 23:09
freebsd-9.1p1 R      -            4.6G 2013-03-25 23:34

# zfs list -o name,mountpoint,origin
NAME                                MOUNTPOINT  ORIGIN
rpool                               none        -
rpool/ROOT                          none        -
rpool/ROOT/base-be                  /           rpool/ROOT/freebsd-9.1p1@2013-03-25-23:34:12
rpool/ROOT/base-be/tmp              /tmp        rpool/ROOT/freebsd-9.1p1/tmp@2013-03-25-23:34:12
rpool/ROOT/base-be/usr              /usr        rpool/ROOT/freebsd-9.1p1/usr@2013-03-25-23:34:12
rpool/ROOT/base-be/usr/local        /usr/local  rpool/ROOT/freebsd-9.1p1/usr/local@2013-03-25-23:34:12
rpool/ROOT/base-be/var              /var        rpool/ROOT/freebsd-9.1p1/var@2013-03-25-23:34:12
rpool/ROOT/freebsd-9.1p1            legacy      -
rpool/ROOT/freebsd-9.1p1/tmp        /tmp        -
rpool/ROOT/freebsd-9.1p1/usr        /usr        -
rpool/ROOT/freebsd-9.1p1/usr/local  /usr/local  -
rpool/ROOT/freebsd-9.1p1/var        /var        -

# zfs list -t snapshot
NAME                                                     USED  AVAIL  REFER  MOUNTPOINT
rpool/ROOT/freebsd-9.1p1@2013-03-25-23:34:12            6.92M      -   373M  -
rpool/ROOT/freebsd-9.1p1/tmp@2013-03-25-23:34:12          40K      -    51K  -
rpool/ROOT/freebsd-9.1p1/usr@2013-03-25-23:34:12        23.4M      -  3.61G  -
rpool/ROOT/freebsd-9.1p1/usr/local@2013-03-25-23:34:12   143K      -   473M  -
rpool/ROOT/freebsd-9.1p1/var@2013-03-25-23:34:12         212K      -  97.8M  -
再起動します。
# reboot
アップデート BE で起動したことを確認します。
# beadm list
BE            Active Mountpoint  Space Created
base-be       -      -           32.1M 2013-03-25 23:09
freebsd-9.1p1 NR     /            4.6G 2013-03-25 23:34

# df -t zfs
Filesystem                         1K-blocks    Used    Avail Capacity  Mounted on
rpool/ROOT/freebsd-9.1p1            16713492  382425 16331066     2%    /
rpool/ROOT/freebsd-9.1p1/tmp        16331101      35 16331066     0%    /tmp
rpool/ROOT/freebsd-9.1p1/usr        20111756 3780690 16331066    19%    /usr
rpool/ROOT/freebsd-9.1p1/usr/local  16815235  484168 16331066     3%    /usr/local
rpool/ROOT/freebsd-9.1p1/var        16451536  120469 16331066     1%    /var
FreeBSD 初級者なので freebsd-update しても uname の値が変わっていないのが気になりますが、変更ファイルである libc.so.7 が新しくなっているから大丈夫でしょう。
# uname -v
FreeBSD 9.1-RELEASE #0 r243825: Tue Dec  4 09:23:10 UTC 2012     root@farrell.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC

# ll -T /lib/libc.so.7
-r--r--r--  1 root  wheel  1369840 Mar 25 23:50 2013 /lib/libc.so.7
(追記)9.1-RELEASE-p1 ではカーネルの変更は無いのでバイナリパッチの freebsd-update で uname の値が変わるはずありませんね。カーネルビルド時に参照されるファイルで確認するのでしょうかね。
# grep -A1 ^REV /usr/src/sys/conf/newvers.sh
REVISION="9.1"
BRANCH="RELEASE-p1"

おわりに

Oracle Solaris 11 の Boot Environments ではルートファイルシステムのある ZFS データセットの管理のみならず、ブートローダ GNU GRUB のメニューもあわせて編集され、システム起動時に任意の BE を選択できるようになっています。果たして FreeBSD のブートマネージャで同じようなことができるのか分かりませんが、BE を利用することでシステムアップデートに対する敷居は少しは下がったかなと思います。

また BE 前提であれば /home や /var を別階層のデータセットにしておくなどレイアウトも検討すべきですね。やはり Solaris からは学べることが多そうです。

# uname -rsp
SunOS 5.11 i386

# zpool get bootfs rpool
NAME   PROPERTY  VALUE               SOURCE
rpool  bootfs    rpool/ROOT/solaris  local

# beadm list
BE      Active Mountpoint Space Policy Created
--      ------ ---------- ----- ------ -------
solaris NR     /          2.96G static 2013-03-24 18:06

# zfs list -o name,canmount,mountpoint
NAME                        CANMOUNT  MOUNTPOINT
rpool                             on  /rpool
rpool/ROOT                       off  legacy
rpool/ROOT/solaris            noauto  /
rpool/ROOT/solaris/var        noauto  /var
rpool/VARSHARE                noauto  /var/share
rpool/dump                         -  -
rpool/export                      on  /export
rpool/export/home                 on  /export/home
rpool/export/home/yoshikaw        on  /export/home/yoshikaw
rpool/swap                         -  -

0 件のコメント:

コメントを投稿