UbuntuにZFSを導入しSambaファイルサーバにする

スポンサーリンク

タイトル通りです。私が実際にやった作業をメモ代わりに記載しておきます。

スポンサーリンク

Ubuntuのインストール

インストール方法などは本記事スコープ外。Ubuntuの公式サイトからisoイメージをDLし、Rufusを使ってUSBメモリに焼き込んでブータブル化、それを用いてPCにUbuntuをインストールしました。
UbuntuのバージョンはUbuntu 22.04.2 LTS (GNU/Linux 5.15.0-69-generic x86_64)です。
追記:Ubuntu 24.02 LTSでも動作確認しました。

パッケージ最新化

とりあえず最新化を行うおまじないのような作業です。

sudo apt -y update
sudo apt -y upgrade

番外編 矢印キーで履歴サーチ設定

番外編作業ですが、ターミナル操作で、矢印キーを使って履歴のサーチができるようにしたいので、.bashrcにbindコマンドを追記します。

bind '"\e[A": history-search-backward'
bind '"\e[B": history-search-forward'

ZFSのインストール

ZFSはデフォルトで入っていないため、インストールします。

sudo apt install zfsutils-linux

ZFSプール用のディスクIDの確認

プールを作成するためのメンバーディスクを確認します。下記コマンドで確認できます。WWMというのが、HDDの固有情報らしいのでそれをメモ。

ls -lA /dev/disk/by-id/

私の場合、メンバディスクはHDD6本で、RAIDZ2を構成します。
一応固有番号なので一部マスクしてます。
wwn-0x50014XXXbef8d74f
wwn-0x50014XXXbeff8538
wwn-0x50014XXX69a999a6
wwn-0x50014XXXbeff7e90
wwn-0x50014XXXbeff84d2
wwn-0x50014XXX69a98c86

これらをメンバディスクに、RAIDZ2プールを作成します。プール名はtankとします。

sudo zpool create -f tank raidz2 /dev/disk/by-id/wwn-0x50014XXXbef8d74f /dev/disk/by-id/wwn-0x50014XXXbeff8538 /dev/disk/by-id/wwn-0x50014XXX69a999a6 /dev/disk/by-id/wwn-0x50014XXXbeff7e90 /dev/disk/by-id/wwn-0x50014XXXbeff84d2 /dev/disk/by-id/wwn-0x50014XXX69a98c86

作成されたプールは、/tankにマウントされます。ちなみにマウント場所は、オプションで変えられるらしいです。

補足:そもそもWWMとは何なのか

WWN (World Wide Name) とは?

WWN(World Wide Name)またはWWID(World Wide Identifier)は、HDDやSSDなどのストレージデバイスに製造時に割り当てられる、世界中で一意な識別子です 。ネットワークカードのMACアドレスのようなものと考えてください。  

一意性: 世界に同じものはありません 。  

永続性: デバイスが壊れるまで変わりません。OSを再インストールしたり、別のPCに接続したりしても同じままです 。  

/dev/sdX の問題点

Linuxでは伝統的に /dev/sda, /dev/sdb のような名前が使われますが、これらはカーネルがデバイスを認識した順番で動的に割り当てられます 。そのため、以下の要因で名前が変わってしまう可能性があります 。  

  • 起動のタイミング  
  • ハードウェアの追加・削除(ディスク、USBメモリ、拡張カードなど)  
  • ケーブルの接続ポート変更  
  • BIOS/UEFI設定の変更  

ZFSプールを /dev/sda のような名前で作ってしまうと、名前が変わったときにプールを認識できなくなったり(インポート失敗)、一部のディスクが見つからない状態(縮退)になったりするリスクがあります 。最悪の場合、ディスク交換時に間違ったデバイスを操作してデータを失う可能性すらあります 。  

LinuxでZFSプールを安定して運用するには、/dev/sda のような変わりやすい名前ではなく、/dev/disk/by-id/wwn-... のような永続的なデバイスパスを使うことがベストプラクティスです。

あとは、細かい設定をします。アクセス時のタイムスタンプの機能であるatimeを切ったり、圧縮方式をzstdにしたりします。このへんの情報はこのサイトを参考にしました。

ZFS RAID-ZをUbuntuで試してみる (暗号化、圧縮)
Ubuntu Server で RAID-Z を試してみたので、その...
sudo zfs set atime=off tank
sudo zfs set compression=zstd tank

次に、データセットを作成します。プールのサブフォルダ的なものです。スナップショットなどはデータセット単位で取れます。メインで使うstorageと、Nextcloud用のデータセットcloudを作ることにしました。

sudo zfs create tank/storage
sudo zfs create tank/cloud

自動スナップショットの設定

ZFSの強みの一つはスナップショット機能です。これを定期的にとるためのツールが存在しています。

sudo apt install zfs-auto-snapshot

auto-snapshot機能はcronを使用して実行されます。そのため、設定ファイルは以下の場所にあります。

ラベルファイル名
frequent/etc/cron.d/zfs-auto-snapshot
hourly/etc/cron.hourly/zfs-auto-snapshot
daily/etc/cron.daily/zfs-auto-snapshot
weekly/etc/cron.weekly/zfs-auto-snapshot
monthly/etc/cron.monthly/zfs-auto-snapshot

cronの設定ファイルには、以下の頻度でスナップショットをとるように記載されています。

ラベル取得タイミング保持個数説明
frequent15分415分ごとに1時間確保
hourly1時間(60分)241時間ごとに1日分確保
daily1日(24時間)311日毎に1ヶ月(31日)分確保
weekly1週(7日)81週(7日)毎に8週(2ヶ月弱)分確保
monthly1ヶ月121ヶ月ごとに1年分確保

このデフォルト設定でも問題ありませんが、個人的には、monthlyで一年分スナップショットを保持する形になってるので、ここはもう少し短くてもいいのかなと思っています(保存するものにもよりますが…)その場合は直接設定ファイルを編集してください。(要root)

参考サイト

# UbuntuでZFSを使ってみよう ## 第10回 Ubuntu 20.04 LTSの auto-snapshot 機能 前回は、zsysdとそれを使用するzsysctl の機能について説明しました。今回は自動的にスナップショットを取得してくれる、auto-snapshot 機能について説明します。 | 株式会社デジタル・ヒュージ・テクノロジー
ZFSのスナップショット(snapshot)とはスナップショットは ZFSの有用な機能の1つで、スナップショット取得時点のディスクイメージを保持する機能です。

古いスナップショット削除コマンド

スナップショットを無限に保持しておくわけにもいかないので、古いものは消していかないといけません。雑にシェルスクリプトを書いたのでメモします。これをcron実行すればいいと思います。

zfs list -t snapshot -o name -S creationは、スナップショット一覧を新しいもの順に表示するコマンド、
tail -n +100は、上から100行目以外を表示するコマンド、
xargs -n 1 zfs destroy -vは、一つ一つを引数に、zfs destroyを実行するコマンドです。
つまり最新100件以外のスナップショットを削除するコマンドになっています。

この辺りをうまく改良して使うといいかと思います。ちなみにroot権限で動かす必要があります。あと最後の-vはverboseなのでcronjobにするには必要ないかも。

zfs list -t snapshot -o name -S creation | tail -n +100 | xargs -n 1 zfs destroy -v

参考サイト

Ubuntuのzfs supportを使って、アップグレード後などのrollbackを実現する - Qiita
Ubuntu 20.04 -> 20.10 にアップグレード後、カーネルパニックが起こるようになり、zfsの機能で20.04に戻すことができたという記事です。また、/home/であるpool/US…

定期Scrub

ZFSには、「Scrub(スクラブ)」という仕組みが備わっています。これは、ZFSプールに保存されている全データのチェックサムを確認し、データが正しいかどうか=壊れていないかを確認する機能です。基本的にZFSにおいてデータ不一致が発生するということは、ハードウェアの異常であるということを意味します(ZFSにバグがあるという可能性もあるが、一般的な使い方をしているうえではかなり低い確率)。よって、Scrubを定期実行しておくことで、ハードウェアすなわちHDDやSSD等の故障にいち早く気付けるというメリットがあります。ただし、Scrubは、全データをチェックするという性質上時間がかかり、やりすぎると逆にハードウェアの寿命を縮めることにもつながりかねないので、数週間~1か月に1回くらいのペースがいいと思います。

スクラブについては下記を参照

ZFS ファイルシステムの整合性をチェックする - Oracle Solaris ZFS 管理ガイド
このドキュメントは、Oracle ZFS ファイルシステムの設定と管理を担当するユーザーを対象としています。必要に応じて、SPARC システムと x86 システムに分けて説明しています。

定期的なScrubを実施する方法としては、systemdの機能を用いるのが簡単です。OpenZFSに最初から、systemdの設定ファイルが含まれており、上記の手順でZFSを導入していれば、すでに準備はできています。

一番バランスがいいと思われる、毎月実行の設定をします。プール名が「tank」の場合、

sudo systemctl enable zfs-scrub-monthly@tank.timer

を実行します。zfs-scrub-monthly@.timer.inとzfs-scrub-weekly@.timer.in、zfs-scrub@.service.inという設定ファイルがすでにあるので、上記のコマンドで設定ができます。ソースコードは下記参照。

zfs/etc/systemd/system/zfs-scrub-monthly@.timer.in at master · openzfs/zfs
OpenZFS on Linux and FreeBSD. Contribute to openzfs/zfs development by creating an account on GitHub.

Samba共有の準備

次に、Samba共有用の準備をします。今回作ったのは、ほぼ自分用のプライベートなローカルNASとしての目的なので、セキュリティはあまり考慮しない作り方になっております。セキュリティを気にする方はその店ご注意ください。

sudo apt install -y samba

Sambaによる共有用のユーザとして、「storage」というユーザを作ることにします。まず、Linux側にユーザを作成します。パスワードは設定必要ですが、Full Name, Room Number, Work Phone, Home Phone, Otherという項目は全部空白でエンターしてしまいます。

sudo adduser storage

次に、pdbeditコマンドでSamba用のユーザを追加します。

sudo pdbedit -a storage

ユーザ名やパスワードは同じにしましょう。

次に、/tank/storageの所有権とパーミッションを変更します。先述の通り、自分しか使わないのでザル設定です。

cd /tank/
sudo chmod -R 777 storage/
sudo chown -R storage:storage storage/

次に、/etc/samba/smb.confの修正です。

[global]
dos charset = CP932
unix charset = UTF-8

  dns proxy = No
  aio max threads = 2
  max log size = 5120
  load printers = No
  printing = bsd
  disable spoolss = Yes
  kernel change notify = No
  unix extensions = No
  directory name cache size = 0
  unix charset = UTF-8
  obey pam restrictions = False
  logging = file
  server min protocol = SMB2_02
  map to guest = Bad User
  bind interfaces only = Yes
  netbios name = neon
  netbios aliases =
  server role = standalone
  workgroup = WORKGROUP
  registry shares = yes
  include = registry

  dos filemode = no
  store dos attributes = no
  map archive = no
  map hidden = no
  map readonly = no
  map system = no

   log file = /var/log/samba/log.%m
   max log size = 1000
   logging = file
   panic action = /usr/share/samba/panic-action %d
   server role = standalone server
   obey pam restrictions = yes
   unix password sync = yes
   passwd program = /usr/bin/passwd %u
   passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
   pam password change = yes
   map to guest = bad user
   usershare allow guests = yes

[storage]
  path = /tank/storage
  read only = no
  browsable = yes
  writable = yes
  #guest ok = yes
  #guest only = yes
  create mode = 0777
  directory mode = 0777

自分でもなんでこのコンフィグになったのか、正直覚えてません!とりあえずこれで動いてます

最後にsmbdを再起動します。

sudo systemctl restart smbd.service

別マシンで作成したzpoolのインポート

ZFSのいいところは、別マシンで作成したzpoolでも簡単にインポートできてしまえるところです。

sudo zpool import tank -f

基本的にこれで完了です。-fオプションをつけるのは、移行前のマシンでzpool exportをしていない場合でも強制的にインポートするためです。

sudo zpool status

で確認できます。こんな感じになりました。

$ sudo zpool status
  pool: tank
 state: ONLINE
status: Some supported and requested features are not enabled on the pool.
        The pool can still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
        the pool may no longer be accessible by software that does not support
        the features. See zpool-features(7) for details.
  scan: scrub repaired 0B in 2 days 03:48:47 with 0 errors on Mon Mar 24 18:48:55 2025
config:

        NAME                                      STATE     READ WRITE CKSUM
        tank                                      ONLINE       0     0     0
          raidz2-0                                ONLINE       0     0     0
            6058c47c-21f6-11e9-84aa-e03f496ebea1  ONLINE       0     0     0
            fd51c3ee-1899-11e7-a309-e03f496ebea1  ONLINE       0     0     0
            a5379724-9eb4-11eb-8709-e03f496ebea1  ONLINE       0     0     0
            dff677ad-b032-11ed-9d8e-e03f496ebea1  ONLINE       0     0     0
            16e8330e-f8ee-11eb-a44a-244bfe3d7a5a  ONLINE       0     0     0
            ffe73a48-1899-11e7-a309-e03f496ebea1  ONLINE       0     0     0

errors: No known data errors

ZFS プール上のディスクパスを UUID (中身は /dev/disk/by-partuuid/ のようなもの) ではなく wwn (たとえば /dev/disk/by-id/wwn-xxxxx のような) で管理したいので、下記の手順で再インポートしてみます。

プールをエクスポート

sudo zpool export tank

WWN ベースでプールをインポート

sudo zpool import -d /dev/disk/by-id/ tank

動作確認

sudo zpool status

ZFSタイプについて

Ubuntu などの Linux 環境で新規に zpool を作成すると、各ディスクに「Solaris /usr & Apple ZFS (part1)」や「Solaris reserved 1 (part9)」といった GPT パーティションが作成されます。一方、TrueNAS(FreeBSD ベース)で ZFS を作成すると、「FreeBSD swap (part1) + FreeBSD ZFS (part2)」という形が一般的です。

fdisk や parted などのツールでディスクを確認すると、下記のように分かれています。

  • Ubuntu 作成時:
    • part1 → Solaris /usr & Apple ZFS
    • part9 → Solaris reserved 1(余白や予約領域)
  • TrueNAS 作成時:
    • part1 → FreeBSD swap
    • part2 → FreeBSD ZFS
=== /dev/disk/by-id/wwn-0x50014XXXXXX46ce4 ===
Disk /dev/disk/by-id/wwn-0x50014XXXXXX46ce4: 5.46 TiB, 6001175126016 bytes, 11721045168 sectors
Disk model: WDC WD60EFZX-68B
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 16C91E45-F8EE-11EB-A44A-244BFE3D7A5A

Device                                         Start         End     Sectors  Size Type
/dev/disk/by-id/wwn-0x50014XXXXXX46ce4-part1     128     4194431     4194304    2G FreeBSD swap
/dev/disk/by-id/wwn-0x50014XXXXXX46ce4-part2 4194432 11721045127 11716850696  5.5T FreeBSD ZFS
=== /dev/disk/by-id/wwn-0x50014XXXXXX98c86 ===
Disk /dev/disk/by-id/wwn-0x50014XXXXXX98c86: 5.46 TiB, 6001175126016 bytes, 11721045168 sectors
Disk model: WDC WD60EFZX-68B
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: DC3FE6FE-0575-704E-A846-CDB5A7A57E8F

Device                                             Start         End     Sectors  Size Type
/dev/disk/by-id/wwn-0x50014XXXXXX98c86-part1        2048 11721027583 11721025536  5.5T Solaris /usr & Apple ZFS
/dev/disk/by-id/wwn-0x50014XXXXXX98c86-part9 11721027584 11721043967       16384    8M Solaris reserved 1

これはあくまで「どんなパーティションコードを使うか」の違いであって、ZFS そのものの機能・性能に大きな差はありません。ZFS はディスク末尾や先頭など複数か所にメタデータ(ラベル)を持ち、GPT パーティションの種類が異なっていても同じように動作します。

たとえば TrueNAS が「ZFS + Swap」のレイアウトを作るのは、障害対応時のダンプ領域やスワップスペースを FreeBSD 側で確保するためです。一方で Ubuntu (OpenZFS on Linux) は、スワップを別途確保しない代わりに小さな予約領域(part9)を GPT に配置して、ZFS 用の領域 (part1) を広く確保する設計になっています。

混在運用しても問題ありませんが、ディスク故障などで新規ディスクを zpool replace すると、Ubuntu 環境では自動的に「Solaris /usr & Apple ZFS」のパーティションコードが作成され、徐々に Solaris 形式のディスクが増えていくことがあります。
もちろん、パーティションを削除してディスク全体を「WWN 形式」で扱うこと(whole disk)も可能ですが、その際はディスクごとに zpool offlinefdisk/partedzpool replace(リシルバ待ち)といった手間が必要になります。

要するに、ZFS の「タイプ」は同じ ZFS でも OS やツールごとにパーティションのラベルや構成が変わりますが、性能や信頼性に違いはほぼありません。気になる方はディスク交換やメンテナンス時に揃えても良いですが、運用上はそのままでもまったく問題ないということを覚えておくと便利です。

番外編 Dockerインストール

全然関係ないですが、合わせてDockerのインストールもしたのでメモです。

sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
cat /etc/apt/sources.list.d/docker.list
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

ちなみに、合わせてDocker composeと、Docker buildxをインストールしてます。

Dockerクライアントがデーモンを操作するためには、sudoコマンドを使って管理者権限を取得するか、dockerグループに所属する必要があります。dockerグループに所属しておけば、sudoなしにコンテナの生成や操作ができますので何かと便利です。このdockerグループはdocker-engineインストール時に自動的に作成されていますので、あとはユーザーをグループに追加してログインしなおすだけです。

今操作しているユーザをdockerグループに加えることで、dockerコマンドをsudoなしで実行できるように権限付与しておきます。

sudo usermod -aG docker $USER

次回ログインから有効になるので、適宜再ログインしましょう。

コメント

タイトルとURLをコピーしました