ZFS on Linuxで高信頼なストレージを作る（Ubuntu 14.04）

#ZFSとは何か？
非常に多くのメモリやCPUを消費してしまうが、それでも利用したいと思うメリットが沢山。
##ZFSのメリット
- 128bitファイルシステムであるので現行の64bitファイルシステムよりはるかに大きな容量のデータを扱うことが可能。最大16EiBのファイルサイズ、最大256ZiBのファイルシステム。
- ストレージプールの採用。複数のHDD の容量をまとめて大きなプールとして扱い、その中から必要な容量を切り出して利用する。
- コピーオンライト。ファイルへの書き込み時にデータを上書きしない仕組み。書き込み中に電源断が発生したとしても、元のファイルが保たれるのでエラーの発生が防げる。
- 64bitチェックサム（スクラブ）。一部の領域だけでなくファイルシステム全体に対してEnd-to-Endのチェックサムを行う仕組み。データの構造に関する誤りを訂正できる。
- RAID5/6の書き込みホール問題の解決。RAID5/6には書き込みが途中で中断された場合、検出不可能なパリティとデータの不整合が起きてしまう問題がある。通常はハードウェアRAIDボードに大容量のキャパシタを載せることで対処ができるがコストが高い。これを可変長ストライプとコピーオンライトによってソフトウェア上で解決した世界初の技術
- ゼロアドミニストレーション。基本的にzpoolやzfsの２つのコマンドしか使用しないので操作が簡単。LVMとは大違い。
等々。他にもホットスペアやスナップショットにも対応しているので便利。スナップショットはLVMと違いデータのレストアまでコマンドが用意されている。

***ZFSはいいぞ***

##ZFS on Linuxの登場
元々このZFSは2005年にOpenSolaris用に開発されたシステムなので、ライセンスの問題（CDDLライセンスとGPLライセンス）によってLinuxではネイティブに利用することはできなかった。
しかし、サードパーティのカーネルモジュールとしてZFS on Linuxが登場したことによって状況が変わりました。先のライセンス問題で色々と議論されているが、新しいUbuntu16.04LTSではZFS on Linuxがデフォルトでサポートされ、利用の幅が拡がりそうだ。
ただ、安定性を考えるとホントはできればBSDで利用したほうがいいかも。
#手順
##環境
Fujitu　TX100S3（RAM 6G）Ubuntu 14.04.04lts
システム用HDD　320GB
ZFS用HDD　３TB✕１本、２TB✕３本
##インストール
今回はZFSで３TBHDD 1台、２TBHDD 3台を使用するRAID-Zを構築した。
1台だけ３TBのHDDを使用していることにより１TBの無駄が発生するが気にしてはいけない。（RAIDディスクに不揃いがあると最小領域に合わせて無駄が生じる。今回では２TBに合わせられる。）RAIDZ1ではRAID５相当の環境となるので実効容量は約６TBになるね。
まずは２TB以上のHDDをZFSとして利用する場合パーティションテーブルがGPTである必要がある。
方法は色々とあるが今回は`parted`コマンドを利用した。実行結果を以下に示す。

```
kazuki@ubuntuserver:~$ sudo parted -l
[sudo] password for kazuki: 
Model: ATA ST250DM000-1BD14 (scsi)
Disk /dev/sda: 250GB
Sector size (logical/physical): 512B/4096B
Partition Table: msdos

Number  Start   End    Size   Type      File system  Flags
 1      1049kB  256MB  255MB  primary   ext2         boot
 2      257MB   250GB  250GB  extended
 5      257MB   250GB  250GB  logical                lvm


Model: ATA TOSHIBA DT01ACA2 (scsi)
Disk /dev/sdb: 2000GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start   End     Size    File system  Name  Flags
 1      1049kB  2000GB  2000GB  ext4


Model: ATA WDC WD30EZRX-00D (scsi)
Disk /dev/sdc: 3001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start   End     Size    File system  Name       Flags
 1      1049kB  3001GB  3001GB               Linux LVM  lvm


Model: ATA WDC WD20EADS-55R (scsi)
Disk /dev/sdd: 2000GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  2000GB  2000GB  primary  ext4


Model: ATA WDC WD20EZRX-00D (scsi)
Disk /dev/sde: 2000GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start   End     Size    File system  Name                  Flags
 1      20.5kB  210MB   210MB   fat32        EFI System Partition  boot
 2      210MB   2000GB  2000GB  hfs+         imac2TB
 3      2000GB  2000GB  650MB   hfs+         Recovery HD
　＜以下略＞
```

GPTに揃えてからZFSのフォーマットを行う。
因みに、sdaはルートファイルシステムとして使用しているLVM領域である。これをZFSにすることは今回はしない。あまりおすすめもしない。ここは正直普通に運用したほうが障害発生時の対応が楽（LVMには悩まされたことが…）
`parted`コマンドでGPTに揃えた。

```
kazuki@ubuntuserver:~$ sudo parted /dev/sdd
[sudo] password for kazuki: 
GNU Parted 2.3
Using /dev/sdd
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
Warning: The existing disk label on /dev/sdd will be destroyed and all data on this disk will be lost. Do you want to continue?
Yes/No? Yes                                                               
(parted) quit                                                             
Information: You may need to update /etc/fstab.                           

kazuki@ubuntuserver:~$ sudo parted -l
＜中略＞
Model: ATA WDC WD20EADS-55R (scsi)
Disk /dev/sdd: 2000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start  End  Size  File system  Name  Flags
＜以下略＞
```
早速ZFS on Linuxのインストールにかかる。
先のライセンス問題もありデフォルトで提供されていないのでPPAを追加する。

```
kazuki@ubuntuserver:~$ sudo apt-add-repository --yes ppa:zfs-native/stable
gpg: keyring `/tmp/tmp1u6dk_fo/secring.gpg' created
gpg: keyring `/tmp/tmp1u6dk_fo/pubring.gpg' created
gpg: requesting key F6B0FC61 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmp1u6dk_fo/trustdb.gpg: trustdb created
gpg: key F6B0FC61: public key "Launchpad PPA for Native ZFS for Linux" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK
```
レポジトリの更新を行い必要なパッケージをインストールする。DKMS対応版があるようなのでもちろんこれを利用する。ZFSはカーネルモジュールなので毎回コンパイルが必要だがこれを自動化してくれる。

```
kazuki@ubuntuserver:~$ sudo apt update
＜略＞
kazuki@ubuntuserver:~$ sudo apt install debootstrap spl-dkms zfs-dkms ubuntu-zfs
＜略＞
kazuki@ubuntuserver:~$ sudo modprobe zfs
kazuki@ubuntuserver:~$ dmesg | egrep "SPL|ZFS"
[113146.602200] SPL: Loaded module v0.6.5.6-1~trusty
[113146.614929] ZFS: Loaded module v0.6.5.6-1~trusty, ZFS pool version 5000, ZFS filesystem version 5
```
by-idを使用してZFSでフォーマットを行いRAID-Z1も同時に作成する。このような複雑な操作をワンラインで実行できるというのがとても嬉しい。めったに操作しないコマンドであるからこそ、障害時に慌てて操作してオペミス…という最悪の事態を起こしにくくなる。

```
kazuki@ubuntuserver:~$ ls -l /dev/disk/by-id | grep sd
lrwxrwxrwx 1 root root  9 May  3 01:09 ata-ST250DM000-1BD141_Z6E048GZ -> ../../sda
lrwxrwxrwx 1 root root 10 May  1 18:21 ata-ST250DM000-1BD141_Z6E048GZ-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 May  1 18:21 ata-ST250DM000-1BD141_Z6E048GZ-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 May  1 18:21 ata-ST250DM000-1BD141_Z6E048GZ-part5 -> ../../sda5
lrwxrwxrwx 1 root root  9 May  3 01:09 ata-TOSHIBA_DT01ACA200_349KWKBKS -> ../../sdb
lrwxrwxrwx 1 root root  9 May  3 01:09 ata-WDC_WD20EADS-55R6B0_WD-WCAVY1097330 -> ../../sdd
lrwxrwxrwx 1 root root  9 May  3 01:09 ata-WDC_WD20EZRX-00DC0B0_WD-WMC1T1988512 -> ../../sde
lrwxrwxrwx 1 root root  9 May  3 01:09 ata-WDC_WD30EZRX-00D8PB0_WD-WCC4NJPSFKE2 -> ../../sdc
lrwxrwxrwx 1 root root 10 May  1 18:21 ata-WDC_WD30EZRX-00D8PB0_WD-WCC4NJPSFKE2-part1 -> ../../sdc1
lrwxrwxrwx 1 root root  9 May  3 01:09 wwn-0x5000039ff3f26847 -> ../../sdb
lrwxrwxrwx 1 root root  9 May  3 01:09 wwn-0x5000c50066322d44 -> ../../sda
lrwxrwxrwx 1 root root 10 May  1 18:21 wwn-0x5000c50066322d44-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 May  1 18:21 wwn-0x5000c50066322d44-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 May  1 18:21 wwn-0x5000c50066322d44-part5 -> ../../sda5
lrwxrwxrwx 1 root root  9 May  3 01:09 wwn-0x50014ee258dd8f76 -> ../../sdd
lrwxrwxrwx 1 root root  9 May  3 01:09 wwn-0x50014ee25ff398cf -> ../../sdc
lrwxrwxrwx 1 root root 10 May  1 18:21 wwn-0x50014ee25ff398cf-part1 -> ../../sdc1
lrwxrwxrwx 1 root root  9 May  3 01:09 wwn-0x50014ee6586f0074 -> ../../sde
kazuki@ubuntuserver:~$ zpool create tank raidz ata-TOSHIBA_DT01ACA200_349KWKBKS ata-WDC_WD30EZRX-00D8PB0_WD-WCC4NJPSFKE2 ata-WDC_WD20EADS-55R6B0_WD-WCAVY1097330 ata-WDC_WD20EZRX-00DC0B0_WD-WMC1T1988512
```
永続的なマウントを有効にするためにby-id名を利用して作成する。HDDをまるごと利用するのでデバイス自体のidを参照した。
**が、しかしここでエラーが発生**
色々と試行錯誤をした結果、Multipath関連の相性がZFSと宜しくないということがわかった。そういえばISCSIのテストをした時に入れてたなあ。そこでMultipathの無効化を以下で行った。

```
root@ubuntuserver:~# multipath -ll 
350014ee6586f0074 dm-5 ATA     ,WDC WD20EZRX-00D
size=1.8T features='0' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=1 status=active
  `- 3:0:0:0 sde 8:64 active ready running
35000039ff3f26847 dm-3 ATA     ,TOSHIBA DT01ACA2
size=1.8T features='0' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=1 status=active
  `- 0:0:1:0 sdb 8:16 active ready running
350014ee258dd8f76 dm-4 ATA     ,WDC WD20EADS-55R
size=1.8T features='0' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=1 status=active
  `- 1:0:1:0 sdd 8:48 active ready running
```
次に、
`/etc/multipath.conf`を作成し内容は

```
kazuki@ubuntuserver:~$ cat /etc/multipath.conf 
blacklist { 
  wwid 35000039ff3f26847
  wwid 350014ee6586f0074
  wwid 350014ee258dd8f76  
} 
```
これでOK
以下で作成。

```
kazuki@ubuntuserver:~$ sudo zpool create tank raidz /dev/disk/by-id/ata-TOSHIBA_DT01ACA200_349KWKBKS /dev/disk/by-id/ata-WDC_WD30EZRX-00D8PB0_WD-WCC4NJPSFKE2 /dev/disk/by-id/ata-WDC_WD20EADS-55R6B0_WD-WCAVY1097330 /dev/disk/by-id/ata-WDC_WD20EZRX-00DC0B0_WD-WMC1T1988512 -f
```
そんなこんなで作成できたZpoolを確認する。

```
kazuki@ubuntuserver:~$ sudo zpool list
NAME   SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  7.25T   552K  7.25T         -     0%     0%  1.00x  ONLINE  -
```
tankと言うのはZFSのストレージプールによく使われる名称で自分もそれを使った。
マウントポイントは`/tank`として自動でマウントされる。ストレージプールから別のプールを切り出すこともできる。幾つか切り出しを行った。

```
kazuki@ubuntuserver:~$ sudo zfs create tank/video5
kazuki@ubuntuserver:~$ sudo zfs create tank/samba
kazuki@ubuntuserver:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            2.9G  4.0K  2.9G   1% /dev
tmpfs           594M  964K  593M   1% /run
/dev/dm-1       227G   69G  147G  32% /
none            4.0K     0  4.0K   0% /sys/fs/cgroup
none            5.0M     0  5.0M   0% /run/lock
none            2.9G  4.0K  2.9G   1% /run/shm
none            100M     0  100M   0% /run/user
/dev/sda1       236M   39M  185M  18% /boot
tank            5.2T  128K  5.2T   1% /tank
tank/video5     5.2T  128K  5.2T   1% /tank/video5
tank/samba      5.2T  128K  5.2T   1% /tank/samba
```
起動時に自動マウントを行うために以下を`/etc/default/zfs`に追加。
また、`/etc/init/zpool-import.conf`の`zfs_autoimport_disable`を0に

```
# When OS startup, automount ALL ZFSfilesystem.
ZFS_MOUNT='yes'
```
追加で幾つかチューニングを行う。
評判の良い新圧縮アルゴリズムであるlz4圧縮を全Poolにおいて有効にし、
ついでに大抵の人には関係のないatimeを全Poolにおいて無効にした。

```
kazuki@ubuntuserver:~$ sudo zfs set compression=lz4 tank
kazuki@ubuntuserver:~$ sudo zfs get compress
NAME         PROPERTY     VALUE     SOURCE
tank         compression  lz4       local
tank/samba   compression  lz4       inherited from tank
tank/video5  compression  lz4       inherited from tank
kazuki@ubuntuserver:~$ sudo zfs set atime=off tank
```
他にも沢山のオプションが有るので調べてみるといいかも。
後はSambaの設定ファイルを編集して以前の設定を書き換えた。
`/etc/samba/smb.conf`に追加

```
[video5]
path = /tank/video5/video5
writable = yes
force create mode = 0777
force directory mode = 0777
guest ok = yes
guest only = yes

[ZFSshare]
path = /tank/samba/samba
writable = yes
force create mode = 0777
force directory mode = 0777
guest ok = yes
guest only = yes
```
smbdを再起動して変更を適用する。

```
kazuki@ubuntuserver:/tank/samba$ sudo service smbd restart
smbd stop/waiting
smbd start/running, process 13637
```
おしまいです
samba周りについてだけどWindows10から接続する場合は
ユーザ認証が必須となっているので注意が必要。
##その他
ZFSにはfsckがないが代わりに週に一回スクラブをすることでファイルシステムの整合性を保つことにする。

```
# crontab -e
... 
30 19 * * 5 zpool scrub tank
...
```
##補足
今回マルチパス関連のエラーが出たが、Googleフォーラムの力を借りてなんとか対処できた。しかし、話によると本来の挙動とは異なる動作をしているとのことで、いつかまた別の問題が起きるかもしれない。きっとどこかで設定ミスがあるのでしょう。



#参考文献
https://wiki.archlinuxjp.org/index.php/ZFS
http://lazy-dog.hatenablog.com/entry/2014/08/17/033038
http://l-w-i.net/t/ubuntu/zfs_001.txt
https://github.com/zfsonlinux/pkg-zfs/wiki/HOWTO-install-Ubuntu-14.04---15.04-to-a-Native-ZFS-Root-Filesystem
https://groups.google.com/a/zfsonlinux.org/forum/#!topic/zfs-discuss/V9OyIbb_6tc
http://www.atmarkit.co.jp/ait/articles/0903/13/news125.html