2014年3月9日日曜日

CentOS 6 の root ファイルシステムに ZFS を使ってみた

ZFS on Linux 0.6.2 には zfs-dracut というパッケージが用意されており、root ファイルシステムに ZFS を利用するための仕組みが入っています。しかしながら、CentOS 6 の dracut は、バージョンが古いため、そのままでは動きませんでした。
dracut のデバッグが厄介だったのですが、どうにか動きましたので、まとめておきたいと思います。
2016-07-02追記、CentOS 7 の GRUB2 から ZFS 上の CentOS 6 を起動する方法も書きました。こちらのほうが運用し易いかと思います。

まず、前提ですが、カーネルと initramfs イメージは、GRUB が扱えるファイルシステム上に置く必要があるので、/boot だけは ext4 等にする必要があります。また、直接 ZFS 上にインストールはできないので、ext4 にインストール後に、引っ越すという手順をとる必要があります。また、将来 ZFS のバージョンアップを行う際、起動できなくならないように注意する必要がある(引越し前の ext4 の root イメージを保持しておく等の対策が必要)かと思います。また、たしか ZOL は SELinux には対応していなかったと思いますので、留意する必要があるかと思います。

以下、手順です。

(1) zfs-dracut に含まれる dracut 用のスクリプトをコピーする
# rpm -ql zfs-dracut
/lib/dracut/modules.d/90zfs
/lib/dracut/modules.d/90zfs/module-setup.sh
/lib/dracut/modules.d/90zfs/mount-zfs.sh
/lib/dracut/modules.d/90zfs/parse-zfs.sh  ※この3つをコピー
/usr/share/doc/zfs-dracut-0.6.2
/usr/share/doc/zfs-dracut-0.6.2/README.dracut.markdown
# cp -r /lib/dracut/modules.d/90zfs /usr/share/dracut/modules.d

(2) スクリプトに修正を加える
まず、関数モジュール化されたスクリプト(中を見ると関数定義だけになっており、最近の Fedora の dracut 向けの作法になってます)をコピーします。
# cd /usr/share/dracut/modules.d/90zfs
# cp module-setup.sh check
# cp module-setup.sh install
コピーしたスクリプトをちょっと加工します。差分は次の通りです。
# diff -u module-setup.sh check 
--- module-setup.sh 2013-08-23 06:39:05.000000000 +0900
+++ check 2014-02-22 21:29:28.000000000 +0900
@@ -54,3 +54,5 @@
  inst_simple "$TMP" /etc/hostid
  rm "$TMP"
 }
+
+check
# diff -u module-setup.sh install 
--- module-setup.sh 2013-08-23 06:39:05.000000000 +0900
+++ install 2014-02-22 21:30:14.000000000 +0900
@@ -31,6 +31,7 @@
  inst_rules /lib/udev/rules.d/90-zfs.rules
  inst_rules /lib/udev/rules.d/69-vdev.rules
  inst_rules /lib/udev/rules.d/60-zvol.rules
+ dracut_install /bin/awk
  dracut_install /sbin/zfs
  dracut_install /sbin/zpool
  dracut_install /lib/udev/vdev_id
@@ -54,3 +55,5 @@
  inst_simple "$TMP" /etc/hostid
  rm "$TMP"
 }
+
+install
さらに、mount-zfs.sh と parse-zfs.sh に修正を加えます。
# diff -u /lib/dracut/modules.d/90zfs /usr/share/dracut/modules.d/90zfs
Only in /usr/share/dracut/modules.d/90zfs: check
Only in /usr/share/dracut/modules.d/90zfs: install
diff -u /lib/dracut/modules.d/90zfs/mount-zfs.sh /usr/share/dracut/modules.d/90zfs/mount-zfs.sh
--- /lib/dracut/modules.d/90zfs/mount-zfs.sh 2013-08-23 06:39:05.000000000 +0900
+++ /usr/share/dracut/modules.d/90zfs/mount-zfs.sh 2014-03-08 20:43:21.086727408 +0900
@@ -2,6 +2,22 @@
 
 . /lib/dracut-lib.sh
 
+# copied from Fedora19's /usr/lib/dracut/modules.d/99base/dracut-lib.sh
+getargbool() {
+    local _b
+    unset _b
+    local _default
+    _default=$1; shift
+    _b=$(getarg "$@")
+    [ $? -ne 0 -a -z "$_b" ] && _b=$_default
+    if [ -n "$_b" ]; then
+        [ $_b = "0" ] && return 1
+        [ $_b = "no" ] && return 1
+        [ $_b = "off" ] && return 1
+    fi
+    return 0
+}
+
 ZPOOL_FORCE=""
 
 if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then
diff -u /lib/dracut/modules.d/90zfs/parse-zfs.sh /usr/share/dracut/modules.d/90zfs/parse-zfs.sh
--- /lib/dracut/modules.d/90zfs/parse-zfs.sh 2013-08-23 06:39:05.000000000 +0900
+++ /usr/share/dracut/modules.d/90zfs/parse-zfs.sh 2014-02-22 21:30:39.000000000 +0900
@@ -54,5 +54,6 @@
 # modules to settle before mounting.
 if [ "${wait_for_zfs}" = "1" ]; then
  ln -s /dev/null /dev/root 2>/dev/null
- echo '[ -e /dev/zfs ]' > $hookdir/initqueue/finished/zfs.sh
+# echo '[ -e /dev/zfs ]' > $hookdir/initqueue/finished/zfs.sh
+ echo '[ -e /dev/zfs ]' > /initqueue-finished/zfs.sh
 fi

(3) 引越し先の ZFS root ファイルシステムを用意する
FreeBSD や OpenIndiana を眺めてみて、rpool/ROOT/cent6 のようなネーミングが良いだろうかとも思いましたが、やっぱり長すぎるかなとも思い、rpool/ROOT のようにしました。また、mountpoint プロパティを legacy 設定にする必要があります。
# zfs set mountpoint=legacy tank4/ROOT
# zfs get all -s local tank4/ROOT
NAME        PROPERTY              VALUE                  SOURCE
tank4/ROOT  mountpoint            legacy                 local
今回は実験ということで、既存のプール tank4 から切り出しました。もっと細かく、/var や /home を別に切り出してもいいのでしょうが、わたしの用途では、そこまでする必要を感じませんので、ROOT のみです。

(4) ルート(/)イメージのコピー
マウントしたままコピーは気が引けるので、LiveDVD 等で起動して dump コマンドを用いて、ext4 上のルート(/)イメージをバックアップします。
# dump -y -0uf /mnt_backup_disk/sdXX.dump /dev/sdXX
ext4 から起動して、ZFS 上へ展開します。
# mkdir /mnt_tank4_ROOT
# mount -t zfs tank4/ROOT /mnt_tank4_ROOT
# cd /mnt_tank4_ROOT
# restore -rf /mnt_backup_disk/sdXX.dump

(5) grub.conf に ZFS から起動するためのエントリを作成する
/boot/grub.conf に次のようにエントリーを追加します。initrd は、ext4 root 用のものとは別名(.zfsを付加)にしておきます。
title CentOS on ZFS (2.6.32-431.5.1.el6.x86_64)
        root (hd0,5)
        kernel /boot/vmlinuz-2.6.32-431.5.1.el6.x86_64 ro root=ZFS=tank4/ROOT rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=128M  KEYBOARDTYPE=pc KEYTABLE=jp106 rd_NO_LVM rd_NO_DM elevator=deadline
        initrd /boot/initramfs-2.6.32-431.5.1.el6.x86_64.img.zfs

(6) fstab を書き換える
ZFS root 上の fstab の / エントリーを次のように書き換えます。
#UUID=xxxxxxxx-yyyy-zzzz-uuuu-vvvvvvvvvvvv /  ext4  defaults  1 1
tank4/ROOT                                 /  zfs   defaults  1 0

(7) ZFS root 用の initramfs を作成する
# mount -t zfs tank4/ROOT /mnt_tank4_ROOT
# mount -t devtmpfs devtmpfs /mnt_tank4_ROOT/dev
# mount -t devpts devpts /mnt_tank4_ROOT/dev/pts
# mount -t sysfs sysfs /mnt_tank4_ROOT/sys
# mount -t proc proc /mnt_tank4_ROOT/proc
# mount --bind /boot /mnt_tank4_ROOT/boot  ※ここ注意、ZFS root 上の /boot に作っておいてコピーでもOKですが
# chroot /mnt_tank4_ROOT /bin/bash
# dracut -f /boot/initramfs-2.6.32-431.5.1.el6.x86_64.img.zfs 2.6.32-431.5.1.el6.x86_64

以上です。

わたしの実験用マシン(ThinkPad T510)の様子を、参考に示します。
[root@hoge ~]# uname -a
Linux hoge 2.6.32-431.5.1.el6.x86_64 #1 SMP Wed Feb 12 00:41:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[root@hoge ~]# cat /proc/cmdline 
ro root=ZFS=tank4/ROOT rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=128M  KEYBOARDTYPE=pc KEYTABLE=jp106 rd_NO_LVM rd_NO_DM elevator=deadline
[root@hoge ~]# df
Filesystem     1K-blocks      Used Available Use% Mounted on
tank4/ROOT     121070464  15237632 105832832  13% /
tmpfs            3959608        80   3959528   1% /dev/shm
tank4          119538944  13706112 105832832  12% /tank4
tank4/backup   148460288  42627456 105832832  29% /tank4/backup
tank4/backup2  108885632   3052800 105832832   3% /tank4/backup2
tank4/backup3  291054080 185221248 105832832  64% /tank4/backup3
[root@hoge ~]# zfs list
NAME            USED  AVAIL  REFER  MOUNTPOINT
tank4           261G   101G  13.1G  /tank4
tank4/ROOT     14.5G   101G  14.5G  legacy
tank4/backup   40.7G   101G  40.7G  /tank4/backup
tank4/backup2  2.91G   101G  2.91G  /tank4/backup2
tank4/backup3   177G   101G   177G  /tank4/backup3
tank4/swap     1.03G   102G    80K  -
tank4/test      136K   101G   136K  legacy
tank4/zvol32   12.5G   101G  12.5G  -
[root@hoge ~]# zpool status
  pool: tank4
 state: ONLINE
  scan: scrub repaired 0 in 1h21m with 0 errors on Sun Mar  2 18:24:46 2014
config:

 NAME                                                        STATE     READ WRITE CKSUM
 tank4                                                       ONLINE       0     0     0
   mirror-0                                                  ONLINE       0     0     0
     ata-HITACHI_HTS725050A9A364_xxxxxxxxxxxxxxxxxxxx-part1  ONLINE       0     0     0
     ata-HGST_HTS721010A9E630_yyyyyyyyyyyyyy-part1           ONLINE       0     0     0

errors: No known data errors
[root@hoge ~]# zfs get all tank4/ROOT
NAME        PROPERTY              VALUE                  SOURCE
tank4/ROOT  type                  filesystem             -
tank4/ROOT  creation              Sat Feb 22 21:58 2014  -
tank4/ROOT  used                  14.5G                  -
tank4/ROOT  available             101G                   -
tank4/ROOT  referenced            14.5G                  -
tank4/ROOT  compressratio         1.00x                  -
tank4/ROOT  mounted               yes                    -
tank4/ROOT  quota                 none                   default
tank4/ROOT  reservation           none                   default
tank4/ROOT  recordsize            128K                   default
tank4/ROOT  mountpoint            legacy                 local
tank4/ROOT  sharenfs              off                    default
tank4/ROOT  checksum              on                     default
tank4/ROOT  compression           off                    default
tank4/ROOT  atime                 off                    inherited from tank4
tank4/ROOT  devices               on                     default
tank4/ROOT  exec                  on                     default
tank4/ROOT  setuid                on                     default
tank4/ROOT  readonly              off                    default
tank4/ROOT  zoned                 off                    default
tank4/ROOT  snapdir               hidden                 default
tank4/ROOT  aclinherit            restricted             default
tank4/ROOT  canmount              on                     default
tank4/ROOT  xattr                 on                     default
tank4/ROOT  copies                1                      default
tank4/ROOT  version               5                      -
tank4/ROOT  utf8only              off                    -
tank4/ROOT  normalization         none                   -
tank4/ROOT  casesensitivity       sensitive              -
tank4/ROOT  vscan                 off                    default
tank4/ROOT  nbmand                off                    default
tank4/ROOT  sharesmb              off                    default
tank4/ROOT  refquota              none                   default
tank4/ROOT  refreservation        none                   default
tank4/ROOT  primarycache          all                    default
tank4/ROOT  secondarycache        all                    default
tank4/ROOT  usedbysnapshots       0                      -
tank4/ROOT  usedbydataset         14.5G                  -
tank4/ROOT  usedbychildren        0                      -
tank4/ROOT  usedbyrefreservation  0                      -
tank4/ROOT  logbias               latency                default
tank4/ROOT  dedup                 off                    default
tank4/ROOT  mlslabel              none                   default
tank4/ROOT  sync                  standard               default
tank4/ROOT  refcompressratio      1.00x                  -
tank4/ROOT  written               14.5G                  -
tank4/ROOT  snapdev               hidden                 default
ここまで、実験的に約2週間ほど動かしましたが、安定しています。scrub をかけるとちょっと重いですが、実サーバで使えないこともないかなと思いました。ただ、ZFS 自体のアップデートだけが難点です。0.6.3 が出るのも間近みたいですし、そのあとも着々と開発が計画されているようです。

0 件のコメント:

コメントを投稿

人気ブログランキングへ にほんブログ村 IT技術ブログへ