NAS用にどのディストリビューション入れようかなと思っていた。RHEL, Ubuntuでもいいけど、ちょっと飽きてきた。NAS用ならTrueNAS COREから始めれば良いのにと思いつつも、Arch Linuxに興味を持った。
- wikiでよく見かけるし、さほど間違ったことは書かれていない印象がある
- 原則にあった"最新であること"というのがよさそう
NASに求めるべき内容ではないとは思うけど、自分が面倒みるからええねん!という感じで始めてみたが、一番最初のセットアップも今までのディストリビューションになかったやり方だったので大変だった。でもわかれば裏でこんなことやってるのかなって思いを馳せながらできるので良かった。
以降はその作業メモ。rootfsの暗号化をするなどちょっと変わった点はある。
Arch Linuxのインストール
インストールメディアを作る
イメージのダウンロード https://ftp.jaist.ac.jp/pub/Linux/ArchLinux/iso/latest/
ダウンロードしたらWindowsならrufusか何かでUSBメモリにISOイメージを焼いておく。
Secure Bootを無効にする
Secure Boot状態だとうまくBootできず手順もよくわからなかったので、Secure Bootは無効にしている。設定の仕方はマザーボードによるので省略。
昨今はブートローダから侵略してくるという事例もあり有効にしたかったが、私にはうまくできなかったので、今まで通り悪いことが起きないよう祈る運用とする。
インストールを始める
ネットワークにつないだ状態で起動する。
USBでブートできると、必要なパッケージをダウンロードし始め、プロンプトが出てきて作業できるようになる。(USBメモリを使ってローカルインストールもできそうな気がするけど、今回は試していない)
作業することが多いので、このままコンソールは辛い。コピペしたい。 USBでブートした直後はSSHサーバが立ち上がった状態になっているので、SSH経由で操作する。
以降はSSH経由でやっていく
# インストールするドライブを選ぶ lsblk # インストールするドライブを変数にいれておく SYSTEM_DEVICE=/dev/sda # パーティション作成 # fdisk, parted, cfdisk, sfdisk, gdisk, sgdisk あたりが使える。 # - 1: 1GiB (/boot用) # - 2: 16GiB (swap ※暗号化対象) # - 3: 16GiB (ZFSのZIL用に予約。ZILはZFSが暗号化するはずなので普通に作る) # - 4: 残り (システム用 ※暗号化対象) sfdisk $SYSTEM_DEVICE << "__EOF__" label: gpt ,1G,U ,16G,S ,16G,L ,,L __EOF__ # rootパーティションを暗号化(パスフレーズ入力) cryptsetup luksFormat "${SYSTEM_DEVICE}3" # 暗号化されたrootパーティションを開く(パスフレーズ入力) cryptsetup open --type luks "${SYSTEM_DEVICE}3" cryptroot # /dev/mapper/cryptroot が存在すること ls -l /dev/mapper/cryptroot # bootのパーティションにFAT32ファイルシステムを作成 mkfs.fat -F 32 "${SYSTEM_DEVICE}1" # システム領域のbtrfsファイルシステムを作成 mkfs.btrfs /dev/mapper/cryptroot # マウント mount /dev/mapper/cryptroot -o noatime,compress=zstd:1 /mnt mount --mkdir "${SYSTEM_DEVICE}1" -o noatime /mnt/boot # マウントの確認 df # ... # /dev/mapper/cryptroot 451007488 5920 448892928 1% /mnt # /dev/sda1 1046508 4 1046504 1% /mnt/boot # 一旦Linuxのインストールを進める(/etcディレクトリの生成などが必要なため) # linux-ltsを使っているがこの辺はお好みで。 pacstrap -K /mnt base linux-lts linux-firmware # 自動マウント用にfstabの生成の確認 # ※UUID=で始まる指定になっていること(/dev/sda1 等はデバイスの認識の具合で変動することがあったのでお勧めしない) genfstab -U /mnt # fstab作成 genfstab -U /mnt >> /mnt/etc/fstab # SWAP領域をマウントするよう設定(/dev/mapper/swapは次のcrypttabの設定により用意される) echo "/dev/mapper/swap none swap defaults 0 0" >> /mnt/etc/fstab # SWAP領域をcrypttabで定義する(起動毎に使い捨てのパスフレーズを使い作成する) echo "swap PARTUUID=$(blkid "${SYSTEM_DEVICE}2" -o value -s PARTUUID) /dev/urandom swap,cipher=aes-xts-plain64,size=256" >> /mnt/etc/crypttab # crypttabの生成 # cryptsetup open したブロックデバイスを復号化する作業を **マウント前に** 行うために必要 output_file="/tmp/crypttab" # 現在マップされている /dev/mapper 配下のデバイスについて処理 for mapper in /dev/mapper/*; do name=$(basename "$mapper") # cryptsetup status で元デバイスが取得できるか確認(control等関係ないものがいるのでチェックする) device=$(cryptsetup status "$name" 2>/dev/null | grep 'device:' | awk '{print $2}') if [ -n "$device" ] && [ -b "$device" ]; then uuid=$(blkid -s UUID -o value "$device") if [ -n "$uuid" ]; then echo "$name UUID=$uuid none luks" else echo "警告: $device のUUIDが取得できませんでした。" >&2 fi fi done | tee "$output_file" # teeの結果で問題なければ、 /etc/crypttab に追記 cat "$output_file" >> /mnt/etc/crypttab
chrootして作業していく。
# chroot arch-chroot /mnt # ホスト名設定 echo testserver > /etc/hostname # rootユーザのパスワード変更 passwd # 管理ユーザの追加。ユーザ名は自由 USERNAME=ryozi useradd -m $USERNAME -s /bin/bash usermod -aG wheel $USERNAME # パスワード設定 passwd $USERNAME # 日本時間に設定 ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime # /etc/adjtimeの生成 hwclock --systohc # ロケール設定(英語しかつかわないけど日本語も使えるようにしておく) cat << '__EOF__' >> /etc/locale.gen en_US.UTF-8 UTF-8 ja_JP.UTF-8 UTF-8 __EOF__ locale-gen echo "LANG=en_US.UTF-8" > /etc/locale.conf echo "KEYMAP=jp106" > /etc/vconsole.conf # 使うパッケージを入れる pacman -S \ grub efibootmgr \ btrfs-progs \ openssh sudo less bash-completion # マイクロコード # https://wiki.archlinux.org/title/Microcode # Intel系は intel-ucode # AMD系は amd-ucode pacman -S amd-ucode # 好きなエディタを導入 pacman -S vim # viのシンボリックリンク作成 ln -s /usr/bin/vim /usr/bin/vi # vimのマウス動作を設定なしにする sudo mkdir /usr/share/vim/vimfiles/plugin sudo tee /usr/share/vim/vimfiles/plugin/no-mouse.vim << "__EOF__" :set mouse= __EOF__ # 自動起動設定 # (chroot中なのでsystemctl statusなどは使えない) systemctl enable sshd # 固定IPを設定するインタフェース名 or MACアドレスを控える ip addr # 固定プライベートIPの設定 # インタフェース名やIPなどは変える。MACアドレスも可能 cat << "__EOF__" > /etc/systemd/network/20-wired.network [Match] # デバイス名で一致させる # Name=enp5s0 # MACアドレスで一致させる MACAddress=XX:XX:XX:XX:XX:XX [Network] # 固定IP Address=192.168.XX.XXX/XX Gateway=192.168.XX.XXX DNS=192.168.XX.XXX # DHCPを使う # DHCP=yes __EOF__ # chroot中なので反映の確認はここではできない # systemctl restart systemd-networkd # ネットワークの自動起動設定 systemctl enable systemd-networkd # 名前解決のために systemd-resolved.service を自動起動設定 # https://wiki.archlinux.org/title/Systemd-resolved systemctl enable systemd-resolved.service # wheelグループのユーザにsudoが行えるようにする echo "%wheel ALL=(ALL) ALL" > /etc/sudoers.d/10-wheel # sudoのパスワード再入力させるタイムアウトを延ばす echo "Defaults timestamp_timeout=30" > /etc/sudoers.d/90-config # /etc/resolv.conf があることを期待するアプリのためにスタブを配置 # 参考: https://ryozi.hatenadiary.jp/entry/2025/03/26/080118 ln -nfs /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf # rootパーティションをinitramfsの時点で復号化する必要があるので移動(後述のsd-encryptで機能) mv /etc/crypttab{,.initramfs} # ---------------------- # ブートローダのインストール grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub --recheck grub-mkconfig -o /boot/grub/grub.cfg vim /etc/mkinitcpio.conf # HOOKS を書き換える # HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck) # /boot におくkernelのイメージを作り直す mkinitcpio -P # 作り直すと etc/crypttab が見えるはず lsinitcpio /boot/initramfs-linux-lts.img | grep crypttab
ここまでで一旦完了。
# chrootから抜ける exit # 再起動 reboot
再起動すると、GRUBでブートが始まる。 USBブート時とは状況が違うのでパスフレーズを求められる。
その後、ちゃんとbootし、IPでSSH接続できればOK
TPMを使ってrootパーティションの暗号化を自動的に解除する
# 対象デバイス確認 lsblk # 登録しなおす(/dev/sda3は適宜書き換え。) systemd-cryptenroll --wipe-slot tpm2 --tpm2-device=auto --tpm2-pcrs=0+4+7 "/dev/sda3"
PCRの値は同じデバイス&ファームウェアなら復号化してよい、というぐらいの内容。物理的な盗難には耐性がないが、ストレージ処分時の機密保護が達成できればいいので、ここは許容する。(Securebootしていない時点で意味ないとは思うし。じゃあなぜPCR7を入れてるんだって話ではあるが。)
自動時刻同期の有効化
何もしないと時刻同期は無効になっている
$ timedatectl
Local time: Wed 2025-04-09 01:57:30 JST
Universal time: Tue 2025-04-08 16:57:30 UTC
RTC time: Tue 2025-04-08 16:57:33
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
NTP service: inactive
RTC in local TZ: no
chronyとかを使っていたら、これもsystemdが面倒見てくれるっぽいので試す。
# systemd-timesyncd を使って自動時刻同期を有効化 sudo systemctl enable --now systemd-timesyncd.service
起動するとしばらくして同期される(3秒ほど進んでいたが補正された)
また、timedatectlで NTP service: active となっていれば定期的に時刻同期が行われる状態になっている。
$ timedatectl
Local time: Wed 2025-04-09 01:59:40 JST
Universal time: Tue 2025-04-08 16:59:40 UTC
RTC time: Tue 2025-04-08 16:59:40
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
時刻同期元は timedatectl show-timesync を見るとわかる。
ちなみに、NTPサーバは以下の方法で選ばれる
- systemd-networkd による
- systemd-timesyncd の設定による
/etc/systemd/timesyncd.confなど(主にfallback)
IPv6は全く詳しくないのでRA(ルーターアドバタイズメント)でこんなことができるなんて知らなかった。
Firewallの導入
- https://wiki.archlinux.jp/index.php/Nftables
- https://wiki.nftables.org/wiki-nftables/index.php/Main_Page
インストール
sudo pacman -Syu nftables # システムを再起動(インストールしただけでは使えないっぽいので。多分kernel moduleを読み込めば動く気はする) sudo reboot
再起動後、設定ファイルを書く。nft コマンドを使って定義もできるが、試行錯誤するわけでもない場合は設定ファイルに書いて読み直すのが良いと思われる。
# 既存のルールのバックアップ sudo nft list ruleset > /tmp/nftables.bak # バックアップから復元する場合 # sudo nft -f /tmp/nftables.bak sudo tee /etc/nftables.conf << "__EOF__" #!/usr/sbin/nft -f # 古いルールを破棄(これがないと読み直すたびに定義されてしまい二重になってしまったので) destroy table inet filter # 新しいルールを追加 table inet filter { chain input { type filter hook input priority 0 policy drop # 関連および確立済みの接続は許可 ct state invalid drop comment "early drop of invalid connections" ct state {established, related} accept comment "allow tracked connections" # ループバックインターフェースの通信は許可 iif lo accept comment "allow from loopback" # SSH(TCPポート22)へのアクセスを許可 tcp dport 22 accept ### このあたりはお好み # ICMPパケットの一部を受け入れる ip protocol icmp accept ip6 nexthdr icmpv6 accept # mDNS(UDPポート5353)へのアクセスを許可 udp dport 5353 accept # Samba(TCPポート139,445)へのアクセスを許可 tcp dport 139 accept tcp dport 445 accept # iSCSIへのアクセス(TCPポート3260)を許可 tcp dport 3260 accept # 秒間5回を超えるICMPは不応答 pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited counter ### ここまではお好み } chain forward { type filter hook forward priority 0 policy drop } chain output { type filter hook output priority 0 policy accept } } __EOF__
設定ファイルが構文的に正しいか確認
sudo nft -c -f /etc/nftables.conf
反映
sudo nft -f /etc/nftables.conf
自動起動設定 & 起動
# nftablesサービスを有効化(システム起動時に自動実行) sudo systemctl enable --now nftables.service
現在のルールを確認するには sudo nft list rulesetで確認できる。また、これはそのまま /etc/nftables.conf へ書き出してもよいが、destroy table inet filterの行がないので、再読み込みするたびにルールが連なってしまうし、コメント行も消える。お好みで。
nftコマンド実行時にnetlink: Error: cache initialization failed: Invalid argumentなどと出る場合は、nftables関連のモジュール(nf_tables)が読み込まれていないとかの理由だと思うので、素直に再起動するとよい。
TODO: dockerを動かす際にiptablesをいじるはずなので、コンテナで動かすアプリを別ネットワークからアクセスする場合は何かする必要があるはず
ZFS (OpenZFS) のインストール
ここで初めてAURのお世話になる。
AURを使うために必要なパッケージを入れる。ビルドが必要なのでビルドツールなど。kernelモジュールならheadersも必要でlinuxかlinux-ltsのどちらでインストールしたかどうかで合わせること。あとはパッケージごとに必要な物を入れておく必要がある。
sudo pacman -S base-devel git linux-lts-headers
yayを入れる。これはAURのパッケージの導入をちょっと簡単にしてくれるツール。
https://github.com/Jguer/yay?tab=readme-ov-file#binary
mkdir ~/src cd ~/src git clone https://aur.archlinux.org/yay-bin.git cd yay-bin makepkg -si
yayを使ってZFSをインストールする。今回はKernelのアップデートを気軽に行えるようにするためDKMS版を使う。
yay zfs-dkms
どのパッケージを入れるか聞かれる。今回は1がお目当てのパッケージ。
$ yay zfs-dkms
4 aur/zfs-dkms-staging-compat-git 2.2.6.r0.gbaa5031456-2 (+4 0.20) (Out-of-date: 2025-01-14)
Kernel modules for the Zettabyte File System (release staging branch) with compatibility patches for latest stable kernel.
3 aur/zfs-dkms-staging-git 2.3.1.r0.gf3e4043a36-1 (+10 0.29)
Kernel modules for the Zettabyte File System (release staging branch) with compatibility patches for latest stable kernel.
2 aur/zfs-dkms-git 2:2.3.99.r162.g788e69ca5d-1 (+27 0.43)
Kernel modules for the Zettabyte File System.
1 aur/zfs-dkms 2.3.1-2 (+186 1.97)
Kernel modules for the Zettabyte File System.
==> Packages to install (eg: 1 2 3, 1-3 or ^4)
==> 1
依存があると、それも聞かれるので答える。
:: There are 2 providers available for zfs-utils=2.3.1:
:: Repository AUR
1) zfs-utils 2) zfs-utils-staging-git
Enter a number (default=1):
==> 1
クリーンビルドするか聞かれている?よくわからないが All で答える。
AUR Explicit (1): zfs-dkms-2.3.1-2 AUR Dependency (1): zfs-utils-2.3.1-1 Sync Dependency (1): dkms-3.1.6-1 :: (1/2) Downloaded PKGBUILD: zfs-utils :: (2/2) Downloaded PKGBUILD: zfs-dkms 2 zfs-dkms (Build Files Exist) 1 zfs-utils (Build Files Exist) ==> Packages to cleanBuild? ==> [N]one [A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4) ==> A
差分を見るか聞かれている?何の差分かよくわからんので、NoneのつもりでEnterを押したら次に進んだ。
:: Deleting (1/2): /home/ryozi/.cache/yay/zfs-dkms HEAD is now at 560cadc ZFS 2.3.1 upstream release :: Deleting (2/2): /home/ryozi/.cache/yay/zfs-utils HEAD is now at 48a1037 ZFS 2.3.1 upstream release 2 zfs-dkms (Build Files Exist) 1 zfs-utils (Build Files Exist) ==> Diffs to show? ==> [N]one [A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4) ==>
色々ログが出た後、PGP keyをインポートするか確認された。Yesを応答。
:: PGP keys need importing: -> C33DF142657ED1F7C328A2960AB9E991C6AF658B, required by: zfs-dkms zfs-utils :: Import? [Y/n] Y
Keyがインポートされると、dkmsのインストールの確認が出てきたのでインストールする。
:: Importing keys with gpg... gpg: key 0AB9E991C6AF658B: public key "Brian Behlendorf <behlendorf1@llnl.gov>" imported gpg: Total number processed: 1 gpg: imported: 1 resolving dependencies... looking for conflicting packages... Packages (1) dkms-3.1.6-1 Total Download Size: 0.04 MiB Total Installed Size: 0.14 MiB :: Proceed with installation? [Y/n] Y
以降、zfs-dkmsに関するパッケージの取得やビルドが始まる。しばらく待つ。
しばらく待つと、それぞれのパッケージをインストールするか聞かれるのでインストールする。
loading packages... resolving dependencies... looking for conflicting packages... `` Packages (2) zfs-utils-2.3.1-1 zfs-utils-debug-2.3.1-1 Total Installed Size: 42.81 MiB :: Proceed with installation? [Y/n] Y ... loading packages... resolving dependencies... looking for conflicting packages... Packages (1) zfs-dkms-2.3.1-2 Total Installed Size: 18.24 MiB :: Proceed with installation? [Y/n] Y
インストールが進むとkernel モジュールの再構成が行われる。
... (3/3) Install DKMS modules ==> dkms install --no-depmod zfs/2.3.1 -k 6.12.20-1-lts ==> depmod 6.12.20-1-lts
ここまででうまくいけばインストール完了。
dkmsのステータスはよさそう
$ dkms status zfs/2.3.1, 6.12.20-1-lts, x86_64: installed
コマンドはまだ使えなさそう。モジュールがロードされていないのが理由。
$ zfs list The ZFS modules cannot be auto-loaded. Try running 'modprobe zfs' as root to manually load them.
従って modprobe zfs やってみる
sudo modprobe zfs
lsmod | grep zfs
zfs list
こんな感じになればzfsが使える状態。
$ lsmod | grep zfs zfs 6635520 0 spl 159744 1 zfs $ zfs list no datasets available
ZFSのZpoolを作る
ここは環境依存なのでお好みで。
# 対象のデバイスを確認する lsblk # zpoolを作る # zpoolはマウントさせない。名前はzpool0とする。 # 今回は8つのデバイスを使い、mirror vdevを4つ作りストライピングさせる。(mirrorの行) # ZIL 用 (log)にSSDのZIL用のパーティションを指定する sudo zpool create -f \ -O mountpoint=none zpool0 \ mirror /dev/disk/by-id/ata-WDC_*{4Y2,1C0} \ mirror /dev/disk/by-id/ata-WDC_*{4DD,HVK} \ mirror /dev/disk/by-id/ata-WDC_*{5JA,UXL} \ mirror /dev/disk/by-id/ata-WDC_*{A38,33T} \ log /dev/disk/by-id/ata-KIOXIA-EXCERIA_SATA_SSD_*0L5-part4
ZFSファイルシステムを作る
# 暗号化用のキーファイルを作る sudo dd if=/dev/random of=/etc/zfs/pool.key bs=32 count=1 sudo chmod 400 /etc/zfs/pool.key # チェックサムファイルを作っておく(コピー時の破損確認など) sudo cat /etc/zfs/pool.key | sha256sum | sudo tee /etc/zfs/pool.key.sha256sum # チェック sudo cat /etc/zfs/pool.key | sha256sum -c /etc/zfs/pool.key.sha256sum # => -: OK # ※これをなくすと復号化できなくなるのでUSBメモリなどにバックアップとるなどしておく # ファイルシステム作成。 samba用の領域を作る。 # mountpointは /zpool0/sambashare とする。ファイルシステム名も `zpool0/sambashare`と合わせる # ZFSによる透過的な暗号化を有効化する。(-o encryptionの行) # ZFSによる透過的な圧縮を有効化する。アルゴリズムはlz4(圧縮率はイマイチだが、圧縮も解凍もとにかく早い)(-o compressionの行) # そのほかのオプションはSamba共有するのに指定するとよさそうらしい値を指定している。(本当かどうかは知らない) sudo zfs create \ -o mountpoint=/zpool0/sambashare \ -o encryption=aes-256-gcm -o keylocation=file:///etc/zfs/pool.key -o keyformat=raw \ -o compression=lz4 \ -o atime=off -o acltype=posixacl -o xattr=sa -o dnodesize=auto -o normalization=formD -o casesensitivity=insensitive \ zpool0/sambashare
自動起動設定
https://wiki.archlinux.jp/index.php/ZFS
インストール直後は自動起動する設定になっていない。
今回はzfs-mount.serviceの手順にする。zfs-mount-generator の手順は複雑そうなので避ける。(/varなどをマウントしたい場合には必要らしい)
# zpoolを作ったら、cachefileプロパティを設定する(/etc/zfs/zpool.cacheに書き出される) # zpool0 というzpoolを作った場合 sudo zpool set cachefile=/etc/zfs/zpool.cache zpool0 # サービスの有効化 # zfs-import-cache: /etc/zfs/zpool.cache に記載があるデバイスからzpoolを読み込む # zfs-load-key: 暗号化に使っているキーをロードする # zfs-mount: zpoolからdatasetマウントする # zfs-volume-wait: /dev/zvolが出てくるまで待つ(iscsiのtarget等で後続の処理に使う場合) sudo systemctl enable zfs.target sudo systemctl enable zfs-import.target sudo systemctl enable zfs-volumes.target sudo systemctl --now enable zfs-import-cache.service sudo systemctl --now enable zfs-mount.service # datasetを暗号化している場合はこれも必要。 zfs load-key に相当 # しかし Arch Linuxでは /usr/lib/systemd/system/zfs-load-key.service はなぜか /dev/null にリンクされている。 # 調べると「作ればいいじゃん」という感じの回答が多かったのでとりあえず作る # 参考: https://forum.proxmox.com/threads/zfs-load-key-service-is-masked.155274/ sudo rm /usr/lib/systemd/system/zfs-load-key.service sudo tee /usr/lib/systemd/system/zfs-load-key.service << '__EOF__' [Unit] Description=Load ZFS encryption keys DefaultDependencies=no Before=zfs-mount.service After=zfs-import.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/zfs load-key -a [Install] WantedBy=zfs-mount.service __EOF__ # 自動起動設定 sudo systemctl daemon-reload sudo systemctl --now enable zfs-load-key.service
再起動し、マウントされていることを確認する。
# 再起動 sudo reboot # 認識していること zfs list # マウントできていること df
自動スクラブ設定
1か月に1度のzfs-scrub-monthly@.timer と1週間に1度のzfs-scrub-weekly@.timerがあるのでこれを利用してサービスを有効化すると楽。
@の後ろはプール名を指定する。
# zpool0 というzpoolを週1でスクラブする場合
sudo systemctl enable zfs-scrub-weekly@zpool0.timer
1か月にすべきか、1週間にすべきかについては、基本1週間がよい。不備は早く気が付けたほうが良いため。
一方でスクラブは全ファイルをチェックするのでHDDにその分の負担がかかる。古(いにしえ)より伝わる祈りの力をもって運用する場合は1か月でもいいだろう。要はバランス。
SambaとiSCSIターゲットの導入
Sambaのインストール
インストール
sudo pacman -Sy samba
下準備と設定ファイルの作成
# 作ったZFSのファイルシステムに # root以外も読み書きできるよう権限を与える sudo chown -R nobody:nobody /zpool0/sambashare sudo chmod 0777 /zpool0/sambashare # samba共有の設定ファイルの作成 # - guestはNG。(必ずログインさせる) # - 作成したファイルはログインした誰でも読み取り可能。書き込みはownerのみ # - グループは考えてない。otherと同じで読み取りのみにする sudo tee /etc/samba/smb.conf <<__EOF__ [global] workgroup = WORKGROUP server string = Ore no Samba Server security = user map to guest = Bad User load printers = no disable spoolss = yes obey pam restrictions = yes # /home/$USER へ \\address\homes でアクセスできるようにする(なくてもいい) [homes] comment = Home browseable = yes writable = yes guest ok = no valid users = %S # その他 [sambashare] comment = Share path = /zpool0/sambashare browseable = yes writable = yes guest ok = no create mask = 0755 directory mask = 0755 __EOF__
自動起動設定。samba共有ができればよく、NetBIOSを使った名前解決はしなくてよいためnmbは不要。
sudo systemctl --now enable smb.service
ログインユーザを作り、パスワードを設定する。(OS上に存在しないユーザならuseraddも必要なはず)
sudo smbpasswd -a "ryozi"
後は同一ネットワーク内のWindowsなどから接続できるか試す。ファイアウォールの設定も忘れずに。
iSCSiターゲットの導入
iSCSIはもう古い技術ぽいけど、代替もないので。targetcli経由で設定を仕込んでいく。
# AURよりtargetcli-fb をインストール yay -S targetcli-fb # ※途中で python-rtslib-fb をインストール後に削除するか確認されるが、`N`を応答すること # ==> WARNING: Skipping verification of source file PGP signatures. # ==> Validating source files with sha512sums... # rtslib-fb ... Passed # :: Remove make dependencies after install? [y/N] # ディレクトリがないと targetcli が次のエラーが出て失敗したので作る # "Cannot set dbroot to /etc/target. Please check if this directory exists." sudo mkdir /etc/target # バージョン確認。 sudo targetcli -v # => /usr/bin/targetcli version 2.1.58 # もしバージョン番号が出ず、以下のようなエラーが出る場合は以下の2行のコマンドを実行してみる(Pythonのパッケージの参照の仕方が変なのでそれを動きそうな形にいじっているだけ) # $ sudo targetcli -v # Traceback (most recent call last): # File "/usr/bin/targetcli", line 24, in <module> # from targetcli import UIRoot # File "/usr/lib/python3.13/site-packages/targetcli/__init__.py", line 18, in <module> # from .ui_root import UIRoot # File "/usr/lib/python3.13/site-packages/targetcli/ui_root.py", line 31, in <module> # from rtslib_fb.utils import ignored # ModuleNotFoundError: No module named 'rtslib_fb.utils'; 'rtslib_fb' is not a package sudo cp /usr/lib/python3.13/site-packages/rtslib_fb.py{,.bak} sudo ln -nfs /usr/lib/python3.13/site-packages/rtslib /usr/lib/python3.13/site-packages/rtslib_fb
ZFSにボリュームを作成する。
# ZFS volumeを作成 # sambaの時に使ったキーを使って透過暗号化(使いまわしていいのか?という話もあるが、鍵ファイルさえ漏れなければ復号化できないという前提ならホームユースならまぁいいでしょうということで。) # sudo zfs create -V 1TB \ -o encryption=aes-256-gcm -o keylocation=file:///etc/zfs/pool.key -o keyformat=raw \ zpool0/windows-iscsi # ZFSボリュームを作ると、/dev/zvol 配下からブロックデバイスとして参照できるようになる ls -l /dev/zvol/zpool0/windows-iscsi
iSCSIの設定をしていく
# バックストアを作成 # /dev/zvol/zpool0/windows-iscsi はあらかじめ zfs create -V でWindows機用にボリュームを作っている sudo targetcli /backstores/block create name=windows-iscsi dev=/dev/zvol/zpool0/windows-iscsi # ターゲットの生成。ターゲット名が自動生成されるので控えておく(末尾のドットは不要) # ターゲット名は自分で指定することもできるはず sudo targetcli /iscsi create # => Created target iqn.2003-01.org.linux-iscsi.testserver.x8664:sn.ad96bd5d6fc9. # LUNの設定。ターゲットとバックストアを紐づける sudo targetcli /iscsi/iqn.2003-01.org.linux-iscsi.testserver.x8664:sn.ad96bd5d6fc9/tpg1/luns create /backstores/block/windows-iscsi # ACLの設定。特定のイニシエーター名のみ接続できるようにする(イニシエータ名を詐称されたらダメなので脆弱ではある) # イニシエーター名はイニシエータ各自で持っている。Windowsならイニシエーターのプロパティ→構成から確認できる sudo targetcli /iscsi/iqn.2003-01.org.linux-iscsi.testserver.x8664:sn.ad96bd5d6fc9/tpg1/acls create iqn.1991-05.com.microsoft:desktop-XXXXXXXX # CHAP認証をつける sudo targetcli /iscsi/ set discovery_auth enable=1 # ユーザIDはおこのみで。イニシエータ名でもいいでしょう。 sudo targetcli /iscsi/ set discovery_auth userid=ryozi sudo targetcli /iscsi/ set discovery_auth password=PA$$w0rd! # 設定を保存 sudo targetcli saveconfig
自動起動設定。なぜかsystemdのユニットファイルがインストールされないので書く。
参考: https://github.com/open-iscsi/targetcli-fb/issues/152
以下のユニットファイルは参考程度に。ZFS volumeをiSCSIで提供したいのでAfterに zfs-volume-wait.service を入れたりしている。
sudo tee /etc/systemd/system/target.service << '__EOF__' [Unit] Description="Load/Clear targetcli config" DefaultDependencies=No After=zfs-volume-wait.service [Service] Type=oneshot Environment=CONFIG_FILE=/etc/target/saveconfig.json EnvironmentFile=-/etc/sysconfig/targetcli ExecStart=-/usr/bin/targetcli restoreconfig $CONFIG_FILE RemainAfterExit=true ExecStop=/usr/bin/targetcli clearconfig confirm=True ExecReload=/usr/bin/targetcli restoreconfig $CONFIG_FILE clearexisting [Install] WantedBy=remote-fs.target __EOF__ # 配置したユニットファイル反映 sudo systemctl daemon-reload # 自動起動有効化 sudo systemctl --now enable target.service
後は再起動して自動起動するか試す。
targetclidというプログラムも用意されているが、これはtargetcliの動作を高速化するためのもので、iSCSI ターゲットのためのものではないので特に起動する必要はない。(targetcliをたくさんいじるなら必要かもしれないが。)
データの引っ越し
時間はかかるが、rsyncのチェックサム確認を有効化にしながらおこなった。Sambaで管理していたファイル自体は4TB弱あった。rsyncのCPU使用率が常に100%でここがネックになってたと思われる。
# 両方の環境にrsyncを入れて実行 # - rootログインできない都合で-p,-g,-oは使わない(パーミッションはumask, group, ownerは実行ユーザに依存) # - 進捗はみたいので -P を使う rsync -crltvP /oldnas/share/ ryozi@remote-ip:/zpool0/sambashare/
iSCSIで管理していたファイルはメイン機のバックアップと古い仮想HDDファイルだったが、ほとんど使ってなかったのでこれを機に捨てた。(コピー作業が面倒くさかった)
ちなみに、tarとsshでもできる。rsyncのチェックサム無しより少し早いぐらい。gzip圧縮はしないほうがよい。チェックサムの仕組みはないし、レジュームもできない(rsyncも更新不要なら送らないだけでレジュームというわけではないが)
# 進捗が見たければ pv を入れて挟むなどする tar -C /oldnas/share/ -c ./ | ssh ryozi@remote-ip tar xv -C /zpool0/sambashare
関係ないが、ZFSを採用した理由は今後こういうコピーがzfs send/recvで速くできるようになるのではないか、という期待があったりする。
おまけ
mDNS を導入 (systemd)
DNSサーバはもちたくないけど、名前解決を楽にしたかったので。
https://wiki.archlinux.jp/index.php/Systemd-resolved#mDNS
sudo vi /etc/systemd/resolved.conf # [Resolve] セクションで設定(コメントアウトされているので解除) MulticastDNS=yes
その後、 反映させるためサービス再起動
sudo systemctl restart systemd-resolved.service
反映確認。Global: yesになっていること。
$ resolvectl mdns Global: yes Link 2 (eth0): no
Link 2 (eth0) の方も対応する必要がある。
# ネットワーク用の設定を書いているはずなので、編集する sudo vi "/etc/systemd/network/20-wired.conf" # [Network] セクションに追記 MulticastDNS=yes
その後、 反映させるために サービス再起動
sudo systemctl restart systemd-networkd.service
Windowsからベンチマーク(Samba, iSCSI)
10Gbps環境下でのベンチマーク。
どっちも結構早い。iSCSIなんていらないのでは、という気もしてくる。
ランダム読み書きが速すぎると思ったら、Zpoolのキャッシュ設定(primarycache, secondarycache)の存在を知ったので、無効にしてみたところ結構落ちた。でもやっぱりiSCSIいらないのでは


シーケンシャルリードでもネットワーク帯域をきっちり叩けなかったのは残念。ただ200MB/s弱の時と比べたら十分かな。これ以上の速度を求めたければSSDを積みなさいということで。
しばらくはメインマシンのバックアップディスクとLLMのモデル置き場として活躍してもらうこととなるでしょう。
メモ
Arch Linuxのパッケージ管理
dnfやaptとは別のpacmanを使う。
リポジトリは公式のcore,extraがあるが、これとは別にArch User Repository (AUR)とよばれるリポジトリがあり、こちらは自分でビルドを行う必要がある。AURで実績があがるとextraに移管される仕組みらしい。
Arch Linuxはサービスも自分で起動設定しないといけなさそう
パッケージをインストールしても自動的にサービス起動することはない模様。全部自分でやれ、という感じでよい。
お仕事で「そのパッケージはインストールすると勝手に有効化されるから有効化の手順はいらないよ」という指摘をもらったが「2重に実行しても影響なくて冪等ならやっておけばええじゃろがい」って口答えをして論争になったので、そういう無駄がなく機械的に「最後に有効化の設定しないと」となるのがよい(?)
mkinitcpio -P 時の警告
# mkinitcpio -P ==> Building image from preset: /etc/mkinitcpio.d/linux-lts.preset: 'default' ==> Using default configuration file: '/etc/mkinitcpio.conf' -> -k /boot/vmlinuz-linux-lts -g /boot/initramfs-linux-lts.img ==> Starting build: '6.12.19-1-lts' -> Running build hook: [base] -> Running build hook: [systemd] -> Running build hook: [autodetect] -> Running build hook: [microcode] -> Running build hook: [modconf] -> Running build hook: [kms] -> Running build hook: [keyboard] -> Running build hook: [sd-vconsole] -> Running build hook: [block] -> Running build hook: [sd-encrypt] -> Running build hook: [filesystems] -> Running build hook: [fsck] ==> WARNING: No fsck helpers found. fsck will not be run on boot. ==> Generating module dependencies ==> Creating zstd-compressed initcpio image: '/boot/initramfs-linux-lts.img' ==> WARNING: errors were encountered during the build. The image may not be complete. ==> Running post hooks -> Running post hook: [sbctl] Signing /boot/vmlinuz-linux-lts File has already been signed /boot/vmlinuz-linux-lts ==> Post processing done ==> Building image from preset: /etc/mkinitcpio.d/linux-lts.preset: 'fallback' ==> Using default configuration file: '/etc/mkinitcpio.conf' -> -k /boot/vmlinuz-linux-lts -g /boot/initramfs-linux-lts-fallback.img -S autodetect ==> Starting build: '6.12.19-1-lts' -> Running build hook: [base] -> Running build hook: [systemd] -> Running build hook: [microcode] -> Running build hook: [modconf] -> Running build hook: [kms] ==> WARNING: Possibly missing firmware for module: 'ast' -> Running build hook: [keyboard] ==> WARNING: Possibly missing firmware for module: 'xhci_pci_renesas' -> Running build hook: [sd-vconsole] -> Running build hook: [block] ==> WARNING: Possibly missing firmware for module: 'aic94xx' ==> WARNING: Possibly missing firmware for module: 'bfa' ==> WARNING: Possibly missing firmware for module: 'qed' ==> WARNING: Possibly missing firmware for module: 'qla1280' ==> WARNING: Possibly missing firmware for module: 'qla2xxx' ==> WARNING: Possibly missing firmware for module: 'wd719x' -> Running build hook: [sd-encrypt] -> Running build hook: [filesystems] -> Running build hook: [fsck] ==> Generating module dependencies ==> Creating zstd-compressed initcpio image: '/boot/initramfs-linux-lts-fallback.img' -> Early uncompressed CPIO image generation successful ==> Initcpio image generation successful ==> Running post hooks -> Running post hook: [sbctl] Signing /boot/vmlinuz-linux-lts File has already been signed /boot/vmlinuz-linux-lts ==> Post processing done
WARNING: No fsck helpers found. fsck will not be run on boot.はHOOKSにfsckがあるのに、ヘルパが見つからないので、ブート時にfsckを行わない(だからHOOKSに指定しても機能してないぞ)、という警告。
Linuxのfsckといえば、ファイルシステムが正しい状態かチェックしたり必要なら修復したりするツール。実装はファイルシステムごとにあり、btrfsならfsck.btrfsが相当する。packageはbtrfs-progsとして配布されている。
# pacman -F fsck.btrfs
core/btrfs-progs 6.13-1
usr/bin/fsck.btrfs
なので、ブート時にfsck実施したいならこのbtrfs-progsパッケージを入れておけばやってくれるようになるし、警告に出なくなる。
WARNING: errors were encountered during the build. The image may not be complete. は他の警告があると出るらしい。上記のbtrfs-progsをインストールしたら出なくなった。
WARNING: Possibly missing firmware for module: はそのハードウェアを使っていないなら無視して大丈夫らしい。
https://wiki.archlinux.jp/index.php/Mkinitcpio#Possibly_missing_firmware_for_module_XXXX
よくあるのは上記リンクにある。対応するファームウェアのパッケージのdescriptionを見るとわかる。
また、見ての通り、プリセットがdefaultとfallbackのうちのfallbackでの警告であり、fallbackは基本的に使わないはずなので今回は無視する。

