# Run NFS Server with Podman Pod
## 1. 先決條件
1. Podman host kernel 必須載入以下 kernel modules
```
printf "%s\n" nfs nfsd rpcsec_gss_krb5 | sudo tee /etc/modules-load.d/nfs.conf
```
2. 手動觸發載入服務
```
sudo systemctl restart systemd-modules-load.service
```
3. 檢查模組是否已載入
```
sudo lsmod | grep -E "nfs|nfsd|rpcsec_gss_krb5"
```
執行結果:
```
rpcsec_gss_krb5 40960 0
nfs 598016 0
fscache 393216 1 nfs
netfs 65536 2 fscache,nfs
nfsd 897024 5
auth_rpcgss 188416 2 nfsd,rpcsec_gss_krb5
nfs_acl 12288 1 nfsd
lockd 184320 2 nfsd,nfs
grace 12288 2 nfsd,lockd
sunrpc 839680 18 nfsd,auth_rpcgss,lockd,rpcsec_gss_krb5,nfs_acl,nfs
```
## 2. 注意事項
1. 此 container 需要以 `privileged` 來執行。這是必要的,因為 NFS 伺服器需要在 container **內部**掛載數個檔案系統以支援其運作,而若無這些權限,在 container 內部執行掛載(mount)是不可能的。
2. 此外,此 container 需要能存取到您想透過 NFS 分享的本機檔案。您可以使用 Podman volumes、綁定掛載(bind mounts)、將檔案直接建置在自訂的映像檔(custom image)中,或幾乎任何其他能將檔案提供給 Podman Container 的方式。
## 3. 規劃一顆硬碟給 NFS Server 用
```
# 1. 在 VM 新增一顆硬碟專門給 NFS Server 使用
# 2. 檢查新的硬碟名稱
$ lsblk
...
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:16 0 100G 0 disk
# 3. 將硬碟名稱設為變數
$ D="/dev/sdb"
# 4. 使用 parted 建立 GPT 分割區,從 1 MiB 到磁碟尾,並標記為 LVM 用途
$ sudo parted -s ${D} mklabel gpt
$ sudo parted -s ${D} unit MiB mkpart primary 1 100%
# 5. 將剛建立的分割區初始化為 LVM PV
$ sudo pvcreate ${D}1
# 6. 建立名為 vg-nfs 的 VG
$ sudo vgcreate vg-nfs ${D}1
# 7. 從 VG 中建立一 LV,利用全部剩餘空間並命名為 lv-nfs
$ sudo lvcreate -l +100%FREE -n lv-nfs /dev/vg-nfs
# 8. 格式化 LV 為 XFS 檔案系統,以提供穩健且高效的儲存
$ sudo mkfs.xfs /dev/vg-nfs/lv-nfs
# 9. 建立 NFS Server 要共享給 Client 的目錄
$ sudo mkdir -p /data/nfs
# 10. 修改目錄權限
$ sudo chown -R 65534:65534 /data/nfs
# 11. 將目錄設為開機自動掛載 lv 裝置上
$ echo '/dev/vg-nfs/lv-nfs /data/nfs xfs defaults 0 0' | sudo tee -a /etc/fstab
# 12. 將目錄掛載到 lv 裝置上
$ sudo mount -a && sudo systemctl daemon-reload
# 13. 設定共享目錄
$ echo '/data/nfs 192.168.11.0/24(rw,sync,no_subtree_check,no_root_squash,fsid=0)' | sudo tee /etc/exports
```
## 4. 設定與部署 NFS Server Podman Pod
1. 建立工作目錄
```
mkdir "$HOME"/nfs-server; cd "$HOME"/nfs-server
```
2. 設定 NFS Server Podman Pod YAML
```
nano nfs-pod.yaml
```
檔案內容如下
```
apiVersion: v1
kind: Pod
metadata:
name: nfs-server-pod
spec:
containers:
- name: nfs-server-container
image: docker.io/erichough/nfs-server
securityContext:
privileged: true
ports:
- name: nfs-tcp
containerPort: 2049
hostPort: 2049
protocol: TCP
# volume 掛載設定
volumeMounts:
- name: nfs-data-volume
mountPath: /data/nfs
- name: nfs-exports-config
mountPath: /etc/exports
# 定義 Pod 層級的 Volume
volumes:
- name: nfs-data-volume
hostPath:
path: /data/nfs # <-- 請替換成主機上的實際路徑
type: Directory
- name: nfs-exports-config
hostPath:
path: /etc/exports # <-- 請替換成主機上的實際路徑
type: File
```
3. 部署 NFS Server
```
sudo podman kube play ./nfs-pod.yaml
```
4. 檢查運作狀態
```
sudo podman ps -a --pod --filter pod=nfs-server-pod
```
正確執行結果如下:
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
3b17c7f41587 localhost/podman-pause:4.9.5-1729598400 4 minutes ago Up 4 minutes 0.0.0.0:2049->2049/tcp 3cf2e7b352a4-infra 3cf2e7b352a4 nfs-server-pod
87740e79d0e1 docker.io/erichough/nfs-server:latest 4 minutes ago Up 4 minutes 0.0.0.0:2049->2049/tcp nfs-server-pod-nfs-server-container 3cf2e7b352a4 nfs-server-pod
```
5. 在其他主機驗測是否可以掛載
```
$ mkdir test
$ sudo mount -t nfs 192.168.11.11:/ test
$ sudo touch test/qqq
# run command on nfs server host
$ ls -l /data/nfs
total 0
-rw-r--r-- 1 root root 0 Aug 13 17:57 qqq
$ sudo umount test
```
6. 停止 NFS Server
```
sudo podman kube down ./nfs-pod.yaml
```
7. 設定開機自動重啟
```
# 1. 建立一個目錄,用來存放 Podman Quadlet 要使用的 Kubernetes YAML 設定檔
sudo mkdir -p /etc/containers/kube
# 2. 將預先定義好的 NFS Pod YAML 檔複製到上述目錄中
sudo cp nfs-pod.yaml /etc/containers/kube/nfs-server.yaml
# 3. 使用 "here document" 的方式,建立一個 systemd 的 Quadlet unit 檔案。
# 這個 .kube 檔案會告訴 systemd 如何使用指定的 YAML 檔來管理一個 Pod。
sudo tee /etc/containers/systemd/nfs-server-pod.kube >/dev/null <<'EOF'
[Unit]
Description=Podman Quadlet: NFS Server Pod (nfs-server-pod)
# 指定此服務依賴於網路連線
Wants=network-online.target
After=network-online.target
[Kube]
# 指定要使用的 Kubernetes YAML 設定檔路徑
Yaml=/etc/containers/kube/nfs-server.yaml
# StopTimeout=120
[Service]
# 設定服務失敗時自動重啟
Restart=always
# 設定重啟間隔為 5 秒
RestartSec=5s
# 設定停止服務的等待時間為 120 秒
TimeoutStopSec=120s
[Install]
# 設定此服務在系統開機後,進入多使用者模式時啟動
WantedBy=multi-user.target
EOF
# 4. 重新載入 systemd 設定,讓系統讀取到剛剛建立的新服務檔案
sudo systemctl daemon-reload
# 5. 設定 nfs-server-pod 服務開機自動啟動,並立即啟動它
sudo systemctl start nfs-server-pod.service
# 6. 檢查 nfs-server-pod 服務目前的運行狀態
sudo systemctl status nfs-server-pod.service
```
8. 確認運作狀態
```
sudo podman ps -a --pod --filter pod=nfs-server-pod
```
正確執行結果如下:
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
3b17c7f41587 localhost/podman-pause:4.9.5-1729598400 4 minutes ago Up 4 minutes 0.0.0.0:2049->2049/tcp 3cf2e7b352a4-infra 3cf2e7b352a4 nfs-server-pod
87740e79d0e1 docker.io/erichough/nfs-server:latest 4 minutes ago Up 4 minutes 0.0.0.0:2049->2049/tcp nfs-server-pod-nfs-server-container 3cf2e7b352a4 nfs-server-pod
```
## 參考資料
- [erichough/nfs-server](https://hub.docker.com/r/erichough/nfs-server/)