更新日誌
2021/08/12
在年初整理了一次,現在已經換成 hardware RAID 了
OMV 後來覺得不是特別好用,現在直接寫 NFS 還有 samba 的 config file 了

使用 Raspberry Pi 4 建置小型 NAS

因為覺得筆電裡面的 HDD 運作時在轉的聲音很吵,剛好之前訂的 RPi 4 也到了,所以就決定把 HDD 拆下來,搭配之前買的富士通 1TB 的硬碟組一個 RAID 1 掛在 RPi 上當作一個簡單的小 NAS。

以下將筆電裡面那顆叫做 sda,富士通的叫做 sdb

RAID

因為資料其實 sda 和 sdb 上都有,而且 file system 在兩顆上都是 NTFS,所以要先想辦法把資料整理到一顆硬碟上,之後再用軟體 RAID 起來。

首先把兩個硬碟的資料整理到一顆裡面 (假設是複製到 sdb),sda 這時候就變成一顆空的硬碟。

把 sda 的 partition 做清理,並建立 RAID 的 partition,在這邊叫 sda1:

使用 gdisk,RAID 的 partition code 是 FD00

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ gdisk /dev/sda
GPT fdisk (gdisk) version 1.0.5

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): p
Disk /dev/sda: 1953525168 sectors, 931.5 GiB
Model: 035-1RK172
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): A915C599-9CBF-4742-A45A-6A0860993853
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 1953525134
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048      1953525134   931.5 GiB   FD00  Linux RAID

透過 mdadm 建立 RAID Array,因為 sdb 還沒準備好,所以先使用 missing 建立:

1
$ mdadm --create /dev/md0 --level 1 --raid-devices=2 missing /dev/sda1

可以透過 cat /proc/mdstat 或是 mdadm --detail /dev/md0 查看目前的 RAID 狀態。

接著就可以把 /dev/md0 format 成 ext4 然後 mount 到一個目錄,把 sdb 的東西搬過去。

1
2
3
4
5
6
$ rsync -aAXHv [src] [dst]
# --archive, -a     archive mode; equals -rlptgoD (no -H,-A,-X)
# --acls, -A        preserve ACLs (implies --perms)
# --xattrs, -X      preserve extended attributes
# --hard-links, -H  preserve hard links
# --verbose, -v     increase verbosity

複製完,因為是從 NTFS 搬過來的,很多目錄都還是 777,所以調整一下資料夾與檔案權限

1
2
$ find -type d -exec chmod 755 {} +
$ find -type f -exec chmod 644 {} +

準備要複製的時候,碰到 read-only filesystem 的問題,重開機後莫名就好了,後來查了一下 mdadm --readwrite /dev/md1 好像可以解決這個問題

重開機後原本 md0 名字就跑掉了,變成 md127

mdadm --detail --scan 可以拿到:ARRAY /dev/md/XXX metadata=1.2 name=XXX UUID=XXX 把 ARRAY 後面的 /dev/md/XXX 改成 /dev/md/0,加到 /etc/mdadm/mdadm.conf

重新生成 initramfs:sudo update-initramfs -u

把硬碟 umount 後,複製 sda 的 partition table 到 sdb

1
$ sfdisk -d /dev/sda | sfdisk /dev/sdb

把 sdb 加到 RAID 中

1
$ mdadm --manage /dev/md0 --add /dev/sdb1

等待 RAID 同步

1
2
3
4
5
6
7
8
$ cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 sdb1[2] sda1[1]
      976629440 blocks super 1.2 [2/1] [_U]
      [==>..................]  recovery = 13.9% (135758336/976629440) finish=335.3min speed=41789K/sec
      bitmap: 7/8 pages [28KB], 65536KB chunk

unused devices: <none>

跑玩 RAID 就建完了

1
2
3
4
5
6
7
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 sdb1[2] sda1[1]
      976629440 blocks super 1.2 [2/2] [UU]
      bitmap: 0/8 pages [0KB], 65536KB chunk

unused devices: <none>

OpenMediaVault (OMV)

雖然說 OMV 提供的東西用 CLI 也都能做到,但想到要搞權限什麼的就好麻煩… 還是直接用現成的好了 XD

一開始用 Ubuntu 18.04 裝,但遇到 ubuntu 提供的套件版本過低 dependency 問題,搞到最後放棄了… 還是用 Raspberryp Pi OS,不要想不開…

Raspberry Pi OS ARM64 版本在 beta 測試了:http://downloads.raspberrypi.org/raspios_arm64/images

裝完 OS 後,直接執行官方的腳本

1
$ wget -O - https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bash

預設帳號:admin,密碼:openmediavault

進到檔案系統後,就可以將之前建立的 md0 掛載

Docker

因為想要把 docker 的資料存在 RAID 上,所以先去 RAID 的根目錄建一個目錄叫 docker,並拿到絕對路徑:/srv/dev-disk-by-label-md0/docker,之後到 OMV-Extras > Docker 做設定

點擊上面的安裝 docker

portainer 也可以順便裝一下,OMV 會建立一個 portainer 的 docker container 並跑在 9000 port 上

SAMBA

把一些磁碟上的目錄建立成共享資料夾,docker 資料夾就是前面建立的,appdata 用來放 volume 的資料

之後可以到 SAMBA > 共享 那邊設定要分享出去的資料夾

設定 pi 群組的共享檔案夾權限 (在共享檔案夾那邊也可以設定,在群組的設定也是面對共享檔案夾的)

共享檔案夾的 ACL 依 官方文件 的說法是不建議在小型家用環境做設定

啟用 SAMBA

在 Gnome 的 nautilus 就可以看到了,如果不行下面也可以自行輸入地址,舉例來說:smb://192.168.1.1

測試了一下接 1Gbps 的網路,寫入速度大概在 65MB/s ~ 85MB/s 上下,應該還要再 tune 一下

Portainer

預設服務會開在 9000 port

選 docker

主頁面

接下來就可以開始拉 image 建 container 了,我自己是喜歡用 docker-compose 建,方便版控,而且建完後 portainer 會把一組 compose 當作一個 stack,看起來比較整齊一點,目錄的規劃大概會像是:

1
2
3
4
5
6
7
8
9
.
├── Aria2
│   └── docker-compose.yml
├── Blog
│   └── docker-compose.yml
└── Photoprism
    └── docker-compose.yml

3 directories, 3 files

建完的效果大概像這樣,在 Stacks 裡面可以點開來,然後就只有個別檔案的 Container

Photoprism

裝了 Nextcloud 試用了一下,發現我好像用不到這麼多功能,我需要的只是管理本地的照片而已,所以又找了一下發現已經有 Photoprism 現成的工具。

注意 RPi 要拉 ARM64 版本的 (photoprism/photoprism-arm64,載成 amd64 的還在想怎麼跑不起來…

照著教學給的範例 docker-compose.yml 設定一下建起來就弄好可以開始使用了

Appendix. 自動風扇開關服務

因為網路買的風扇沒有自動開關功能,一直開著很大聲,上網找才發現大家都 DIY 用三極管用 GPIO 控制風扇開關… 於是也自己弄了杜邦線和三極管,用 Python 透過讀取 sysfs 提供的溫度資訊來控制 GPIO 腳位的開關

/usr/local/bin/fan.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/python3

import sys
import time
import RPi.GPIO as GPIO

def cpu_temp():
    with open("/sys/class/thermal/thermal_zone0/temp", 'r') as f:
        return float(f.read()) / 1000

def main():
    channel = 14
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)

    GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)
    is_close = False
    while True:
        temp = cpu_temp()
        if is_close == True:
            if temp > 60.0:
                GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)
                is_close = False
        else:
            if temp < 50.0:
                GPIO.setup(channel, GPIO.OUT, initial=GPIO.LOW)
                is_close = True

        time.sleep(5)

if __name__ == '__main__':
    main()

順手寫了一個簡單的 systemd service,可以直接用 systemctl enable fan 讓開機自動啟動腳本

/etc/systemd/system/fan.service

1
2
3
4
5
6
7
8
9
[Unit]
Description=fan

[Service]
ExecStart=/usr/local/bin/fan.py
Restart=always

[Install]
WantedBy=default.target

後來發現 RPI OS 內建好像就有這個服務了 XD

參考資料

ArchWiki - RAID

openmediavault.org

openmediavault - Access Rights Management

photoprism/photoprism

docs.photoprism.org

comments powered by Disqus