====== Raspberry Pi 5 - domácí server ======
Dokumentovaná sestava se skládá z těchto komponent:
* [[https://rpishop.cz/563516/raspberry-pi-5-16gb-ram/|Raspberry Pi 5 - 16GB RAM]]
* [[https://rpishop.cz/chladice-pro-raspberry-pi-5/6496-raspberry-pi-5-active-cooler.html|Raspberry Pi 5 Active Cooler]]
* [[https://rpishop.cz/560366/suptronics-x1005-2280-m-2-nvme-dual-shield/|Suptronics - X1005 2280 M.2 NVMe dual Shield pro Raspberry Pi 5]]
* [[https://rpishop.cz/sprava-napajeni-a-ups/3102-suptronics-x728-ups-deska-pro-inteligentni-napajeni.html|Suptronics X728 v2.5 UPS deska pro inteligentní napájení]]
* [[https://rpishop.cz/zdroje-s-25x55mm-kabelem/5048-cellevia-25x55-mm-5v4a-napajeci-zdroj-eu-cerny.html|Cellevia 2,5x5,5 mm 5V⎓4A napájecí zdroj, EU]]
Napájecí zdroj je kvůli UPS desce, protože UPS deska dokáže přes jack konektor 2,5×5,5 mm dodat až 20W. To je maximum, které půjde do UPS desky dodat a zároveň pokud nebudu připojovat další náročné periferie, tak tento výkon utáhne NVMe disky.
===== Bootování z NVMe disku ======
Standardně Raspberry Pi 5 bootuje z microSD karty, ale je možné nakonfigurovat systém tak, aby bootoval přímo z NVMe SSD připojeného přes PCIe. Návod vychází z článku [[https://wiki.geekworm.com/NVMe_SSD_boot_with_the_Raspberry_Pi_5|https://wiki.geekworm.com/NVMe_SSD_boot_with_the_Raspberry_Pi_5]]. Tento postup zahrnuje několik kroků:
=== 1. Flashování NVMe SSD pomocí Raspberry Pi Imager ===
Pro instalaci operačního systému na NVMe SSD můžete použít nástroj **Raspberry Pi Imager** na Windows nebo macOS. K tomu budete potřebovat **USB → NVMe adaptér**.
**Postup:**
* Nainstalujte a spusťte **Raspberry Pi Imager**.
* Připojte NVMe SSD k počítači pomocí **USB → NVMe adaptéru**.
* Vyberte operační systém pro instalaci (např. Raspberry Pi OS).
* Zvolte disk (NVMe SSD připojené přes adaptér).
* Klikněte na **Write** a potvrďte zápis.
* Po dokončení **NEODPOJUJTE NVMe SSD**, dokud neprovedete aktivaci PCIe. Tedy bod níže a jednoduchá editace config.txt na NVMe disku. Pak je možné z disku nabootovat a řešit už další kroky.
=== 2. Aktivace PCIe konektoru ===
Ve výchozím nastavení je PCIe port deaktivovaný a je nutné jej povolit.
Otevřete konfigurační soubor:
sudo nano /boot/firmware/config.txt
Přidejte následující řádky na konec souboru:
# Povolení PCIe externího konektoru
dtparam=pciex1
# Alternativní zápis pro povolení NVMe portu
dtparam=nvme
Uložte změny a restartujte Raspberry Pi:
sudo reboot
=== 3. Nastavení NVMe disku jako primárního bootovacího zařízení ===
Po povolení PCIe portu je třeba upravit pořadí bootování v bootloaderu.
**Možnost 1: Použití raspi-config**
Spusťte konfigurátor:
sudo raspi-config
Zvolte:
* **6 Advanced Options → A4 Boot Order → B2 NVMe/USB Boot**
* Potvrďte volbu **Yes** a restartujte:
sudo reboot
**Možnost 2: Ruční úprava bootovacího řetězce**
Otevřete EEPROM konfiguraci:
sudo rpi-eeprom-config --edit
Najděte řádek `BOOT_ORDER` a upravte ho na:
BOOT_ORDER=0xf416
Uložte změny a restartujte Raspberry Pi.
===== UPS X728 ======
UPS desku jsem kupoval ve verzi 2.5. Je důležité si uvědomit, že **UPS X728 není určena k automatickému spuštění Raspberry Pi po obnovení napájení**. Její hlavní funkcí je zajistit nepřerušený provoz **během výpadku**, dokud je baterie dostatečně nabitá.
Jakmile baterie klesne na **kritickou úroveň**, Raspberry Pi by mělo být **řízeně vypnuto**, aby se zabránilo náhlé ztrátě dat nebo poškození systému. **UPS však Raspberry Pi znovu automaticky nenastartuje**, i když je baterie plně nabitá.
Pokud po zapnutí tlačítka na UPS svítí **červená LED dioda** na Raspberry Pi, znamená to, že deska je pod napětím, ale Raspberry Pi se samo nespustilo. Skutečné spuštění a běh systému indikují **jiné LED diody** na Raspberry Pi.
==== Specifikace ====
* Napájení:
* přes USB-C: 5Vdc, 3A
* přes DC jack: 5Vdc ±5%, ≥4A
* UPS výstup : 5.1V ±5% Max 8A
* UPS nabíjecí proud: 2,3-3,2A
* Terminální napětí baterie : 4,24V
* Limit nabití : 4,1V
==== Dokumentace: ====
* https://wiki.geekworm.com/X728-script
* https://github.com/geekworm-com/x728-script/tree/main
{{:it:jednodeskove-pocitace:pasted:20250214-225625.jpeg}}
==== Zprovoznění software ====
Tento návod popisuje postup pro zprovoznění softwaru UPS X728 a jeho správné nastavení.
=== Aktivace I2C podpory ===
Nejprve zapněte podporu I2C pomocí `raspi-config`:
sudo raspi-config
Poté nainstalujte potřebné balíčky:
apt-get install i2c-tools
apt install python3-smbus
Ověření připojení přes I2C:
root@propasiv-server:~# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- 36 -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
#36 - adresa chipu pro měření úrovně nabití baterie
#68 - adresa RTC chipu
=== Instalace X728 ovladačů a skriptů ===
Nainstalujte potřebné nástroje:
sudo apt install -y gpiod
Stáhněte ovladače:
git clone https://github.com/geekworm-com/x728-script
Nastavte práva pro skripty:
cd x728-script
chmod +x *.sh
=== Konfigurace tlačítka pro fyzické vypnutí ===
Přesuňte potřebné soubory na správná místa:
sudo cp -f ./xPWR.sh /usr/local/bin/
sudo cp -f x728-pwr.service /lib/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable x728-pwr
sudo systemctl start x728-pwr
Tento postup umožní, aby fyzické tlačítko na UPS desce X728 fungovalo takto:
* Stisknutí po dobu **1-2 sekund** – **restart** zařízení.
* Stisknutí po dobu **3 sekund** – **bezpečné vypnutí** (safe shutdown).
* Stisknutí po dobu **7-8 sekund** – **nucené vypnutí** (force shutdown).
Tento postup **nedělá nic jiného** – pouze definuje chování tlačítka.
=== Softwarové vypnutí UPS (bez použití Linuxového `shutdown`) ===
Pro správné softwarové vypnutí je nutné nastavit vlastní alias:
1. Připravte skript `xSoft.sh`:
sudo cp -f ./xSoft.sh /usr/local/bin/
2. Vytvořte alias `x728off`, který bude bezpečně vypínat UPS:
echo "alias x728off='sudo /usr/local/bin/xSoft.sh 0 '''26''' '" >> ~/.bashrc
3. Aktivujte změny v `.bashrc`:
source ~/.bashrc
4. Nyní můžete bezpečně vypnout UPS příkazem:
x728off
**Pozor:** Nepoužívejte klasický Linuxový příkaz `shutdown`, jinak se UPS nevypne správně a může zůstat zapnutá.
=== Test bezpečného vypnutí ===
Softwarové bezpečné vypnutí:
x728off
**Nepoužívejte příkaz `shutdown` v Linuxu**, jinak se X728 nevypne správně.
=== Hardwarové bezpečné vypnutí ===
Pomocí fyzického tlačítka na UPS lze ověřit bezpečné vypnutí:
* **1-2 sekundy** – restart zařízení.
* **3 sekundy** – bezpečné vypnutí, LED diody pomalu zhasnou.
* **7-8 sekund** – vynucené vypnutí, okamžité zhasnutí.
Tímto postupem zajistíte, že UPS X728 bude správně fungovat a umožní bezpečné vypnutí jak softwarově, tak fyzickým tlačítkem.
=== Přehled dostupných skriptů pro další práci s UPS ===
Každý skript demonstruje jinou funkcionalitu UPS X728:
* **x728-v2.x-bat.py** – Čtení napětí baterie a jejího nabití.
* **x728-v2.x-pld.py** – Detekce výpadku napájení z AC adaptéru.
* **x728-v2.x-asd.py** – Automatické vypnutí při poklesu napětí baterie pod nastavenou hodnotu.
== Problém s knihovnou RPi.GPIO a řešení pomocí libgpiod ==
Starší ukázkové skripty používají knihovnu **RPi.GPIO**, která **není podporována v jádru Linuxu 6.6.x**. Pokud spustíte skript jako:
sudo python3 sample/x728-v2.x-plsd.py
může se objevit chyba kvůli nesprávnému **gpiochip** číslu.
Doporučuje se přejít na knihovnu **libgpiod**, která je oficiálně doporučena a lépe podporována. UPS X728 poskytuje **jediný oficiální skript** využívající libgpiod:
sudo python3 sample/x728-v2.x-plsd-gpiod.py
U ostatních skriptů, které stále používají RPi.GPIO, je doporučeno přepsání na libgpiod nebo jejich převedení na shell skripty.
Skript jsem si tedy přizpůsobil pro libgpiod:
#!/usr/bin/env python
import struct
import smbus
import time
import gpiod
import logging
# Log interval
LOG_INTERVAL = 300 # seconds
last_power_state = None # Stores last power state
last_log_time = 0 # Stores last log timestamp
# Logging configuration
logging.basicConfig(filename='/var/log/x728-battery.log', level=logging.INFO, format='%(asctime)s - %(message)s')
# GPIO chip and line definitions
#chipname = "gpiochip0" # Use "gpiochip4" for Raspberry Pi 4/3
chipname = "gpiochip4" # Use "gpiochip4" for Raspberry Pi 5
out_line_offset = 26 # Corresponds to GPIO26
pld_line_offset = 6 # Power loss detection pin
buzzer_line_offset = 20 # Buzzer control pin
# I2C address for battery monitoring
I2C_ADDR = 0x36
# Initialize I2C bus
bus = smbus.SMBus(1)
# Open GPIO chip
chip = gpiod.Chip(chipname)
# Get the output lines
out_line = chip.get_line(out_line_offset)
out_line.request(consumer="battery_monitor", type=gpiod.LINE_REQ_DIR_OUT)
buzzer_line = chip.get_line(buzzer_line_offset)
buzzer_line.request(consumer="power_monitor", type=gpiod.LINE_REQ_DIR_OUT)
# Get the input line for power loss detection
pld_line = chip.get_line(pld_line_offset)
pld_line.request(consumer="power_monitor", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
def readVoltage(bus):
"""Reads battery voltage from I2C bus."""
address = I2C_ADDR
read = bus.read_word_data(address, 2)
swapped = struct.unpack("H", read))[0]
voltage = swapped * 1.25 / 1000 / 16
return voltage
def readCapacity(bus):
"""Reads battery capacity from I2C bus."""
address = I2C_ADDR
read = bus.read_word_data(address, 4)
swapped = struct.unpack("H", read))[0]
capacity = swapped / 256
if capacity > 100:
capacity = 100
return capacity
def print_power_status():
"""Monitors power status and logs changes."""
global last_power_state, last_log_time
state = pld_line.get_value()
current_time = time.time()
if state == 1:
print("Power Supply A/C Lost") # First detection of power loss
if last_power_state != 1:
logging.warning("Power Supply A/C Lost")
elif current_time - last_log_time > LOG_INTERVAL: # Subsequent logging at intervals
logging.warning("Power Supply A/C Lost")
last_log_time = current_time
# Activate buzzer to indicate power loss
for _ in range(3): # Buzzer alarm cycle
buzzer_line.set_value(1)
time.sleep(0.1)
buzzer_line.set_value(0)
time.sleep(0.1)
else:
print("AC Power OK")
if last_power_state != 0: # First detection of power restoration
logging.info("AC Power OK")
elif current_time - last_log_time > LOG_INTERVAL: # Subsequent logging at intervals
logging.info("AC Power OK")
last_log_time = current_time
buzzer_line.set_value(0)
last_power_state = state
return state
try:
while True:
print("******************")
voltage = readVoltage(bus)
capacity = readCapacity(bus)
print(f"Voltage: {voltage:.2f}V")
print(f"Battery: {capacity:.0f}%")
# Log battery voltage and capacity at intervals
if time.time() - last_log_time > LOG_INTERVAL:
logging.info(f"Voltage: {voltage:.2f}V, Battery: {capacity:.0f}%")
last_log_time = time.time()
# Monitor power loss detection
power_status = print_power_status()
if capacity == 100:
print("Battery FULL")
if capacity < 20:
print("Battery Low")
# This condition ensures shutdown only if the battery is below 99% and the power is disconnected.
# This means that if the power is connected, the server will not shut down.
# Everyone should evaluate whether this is safe and adjust the condition if necessary.
if voltage < 3.00 and power_status == 1:
print("Battery LOW!!!")
logging.critical("Battery LOW! Shutdown in 10 seconds")
print("Shutdown in 10 seconds")
time.sleep(10)
out_line.set_value(1)
time.sleep(3)
out_line.set_value(0)
time.sleep(2)
except KeyboardInterrupt:
print("Exiting...")
finally:
chip.close()
=== Automatické spuštění po restartu ===
Pro zajištění automatického spuštění skriptu po restartu použijeme **systemd service**, což je spolehlivý způsob, jak zajistit, že skript poběží na pozadí.
== Vytvoření systemd služby ==
Otevřete terminál a vytvořte soubor pro službu:
sudo nano /etc/systemd/system/x728-battery.service
Do souboru vložte následující obsah a uložte:
[Unit]
Description=X728 Battery Monitor
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /etc/local-scripts/x728-script/sample/x728-v2.x-asd-gpiod.py
Restart=always
User=root
StandardOutput=append:/var/log/x728-battery.log
StandardError=append:/var/log/x728-battery.log
[Install]
WantedBy=multi-user.target
== Aktivace služby při startu ==
Načtěte systemd a povolte službu při startu:
sudo systemctl daemon-reload
sudo systemctl enable x728-battery.service
== Okamžité spuštění služby ==
Pro okamžité spuštění služby spusťte:
sudo systemctl start x728-battery.service
== Kontrola stavu služby ==
Pro ověření, zda služba běží správně, použijte:
sudo systemctl status x728-battery.service
=== Použití logrotate pro rotaci logů na Raspberry Pi ===
Na Raspberry Pi mi aplikace vytvořila nový logový soubor `/var/log/x728-battery.log`. Abych zajistil jeho pravidelnou rotaci a zabránil nadměrnému růstu, rozhodl jsem se použít **logrotate**. Tento nástroj už byl v systému nainstalován.
== Jak přidat pravidlo do logrotate ==
Nejprve jsem vytvořil nový konfigurační soubor v `/etc/logrotate.d/`:
sudo nano /etc/logrotate.d/x728-battery
Do souboru jsem přidal následující konfiguraci:
/var/log/x728-battery.log {
weekly
rotate 4
compress
missingok
notifempty
create 644 root root
postrotate
systemctl restart x728-battery.service
endscript
}
Bylo nutné přidat `postrotate` sekci, která restartuje službu `x728-battery.service`, protože jinak aplikace nepokračovala v logování do nového souboru.
== Otestování konfigurace ==
Pro kontrolu, zda logrotate soubor správně rozpoznává, jsem spustil:
sudo logrotate -d /etc/logrotate.d/x728-battery
(Debug mód `-d` pouze zobrazí, co by se stalo, ale skutečně rotaci neprovede.)
Pokud konfigurace neobsahovala chyby, provedl jsem ruční rotaci:
sudo logrotate -f /etc/logrotate.d/x728-battery
Po této úpravě se logy správně rotují a starší soubory jsou automaticky komprimovány a spravovány.
=== Nastavení a čtení RTC času ===
Tento návod popisuje kompletní nastavení a použití RTC (Real Time Clock) na UPS X728. UPS využívá RTC modul pro udržení přesného času i po odpojení napájení. Tento postup byl testován na **Raspberry Pi OS**.
== Povolení RTC modulu ==
1. Otevřete konfigurační soubor `/boot/config.txt` a přidejte na konec nebo pod sekci `[all]` tento řádek:
sudo nano /boot/config.txt
Přidejte:
dtoverlay=i2c-rtc,ds1307
Uložte změny stisknutím **Ctrl+O**, potvrďte **Enter**, a ukončete editor **Ctrl+X**.
2. Restartujte Raspberry Pi:
sudo reboot
== Zakázání falešného hwclocku ==
Raspberry Pi OS obsahuje **fake-hwclock**, který simuluje RTC a může způsobovat problémy s reálným RTC modulem. Proto je nutné ho odstranit:
sudo apt-get -y remove fake-hwclock
sudo update-rc.d -f fake-hwclock remove
sudo systemctl disable fake-hwclock
== Úprava udev pravidel ==
Pro správné fungování RTC je třeba upravit soubor `/lib/udev/hwclock-set` a zakomentovat řádky 7-12:
sudo nano /lib/udev/hwclock-set
Najděte následující část kódu:
#!/bin/sh
# Reset the System Clock to UTC if the hardware clock from which it
# was copied by the kernel was in localtime.
dev=$1
#if [ -e /run/systemd/system ] ; then
# exit 0
#fi
#
#/sbin/hwclock --rtc=$dev --systz
#/sbin/hwclock --rtc=$dev --hctosys
Každý řádek označený `#` je zakomentován a nebude se vykonávat.
Uložte změny a ukončete editor.
== Ověření a nastavení času ==
Po dokončení výše uvedených kroků restartujte Raspberry Pi:
sudo reboot
Po restartu můžete ověřit aktuální systémový čas:
date
Pokud je čas nesprávný, nastavte ho ručně:
date -s "5 MAR 2019 13:00:00"
Uložte nastavený čas do RTC:
sudo hwclock -w
Pro ověření času uloženého v RTC modulu použijte:
sudo hwclock -r
**Poznámka:** Ujistěte se, že jsou v UPS X728 vloženy baterie, aby se uložený čas zachoval i po vypnutí zařízení.
Po dokončení tohoto postupu bude při každém startu Raspberry Pi čas automaticky synchronizován z RTC modulu.
=== Možné problémy a jejich řešení ===
Tato sekce popisuje možné problémy při používání UPS X728 a jejich řešení. Informace čerpám z oficiální dokumentace výrobce:
[Zdroj: Geekworm Wiki - X728 FAQ](https://wiki.geekworm.com/X728#FAQ)
__Problém: Zobrazuje se hláška „This power supply is not capable of supplying 5A“ na Raspberry Pi 5__
UPS X728/X729 má dostatečnou kapacitu pro napájení **5A**, nicméně je potřeba provést následující nastavení:
**Krok 1: Úprava konfigurace napájení (povinné)**
Otevřete terminál v Raspberry Pi OS a spusťte příkaz:
sudo rpi-eeprom-config -e
Na konec souboru přidejte následující řádek:
PSU_MAX_CURRENT=5000
Uložte změny stisknutím **Ctrl+O**, potvrďte klávesou **Enter**, a ukončete editor stisknutím **Ctrl+X**.
**Krok 2: Zvýšení proudového limitu USB (volitelné, pokud používáte USB zařízení s vyšší spotřebou)**
Otevřete konfigurační soubor:
sudo nano /boot/firmware/config.txt
Přidejte tento řádek:
usb_max_current_enable=1
Uložte změny a zavřete editor stejným způsobem jako v předchozím kroku.
**Restartujte Raspberry Pi, aby se změny projevily:**
sudo reboot
**Poznámka:** Pokud používáte jiný operační systém (například Ubuntu), je nutné nejprve nahrát Raspberry Pi OS, provést výše uvedené úpravy a teprve poté znovu nahrát požadovaný operační systém.
=== Softwarové řízení nabíjení pomocí GPIO16 ===
Od verze **X728 v2.5** je možné **softwarově řídit nabíjení baterie** pomocí **GPIO16**. Tato funkce je určena pouze pro **pokročilé uživatele**, kteří mají zkušenosti s Linuxem. Pokud si nejste jisti, doporučuje se ponechat jumper "CHG Ctrl" zkratovaný, což umožní **automatické nabíjení** při připojení napájecího adaptéru.
**Možnosti nastavení "CHG Ctrl" jumperu:**
- **Jumper zkratovaný** → Baterie se **automaticky nabíjí**, pokud je připojen napájecí adaptér.
- **Jumper otevřený** → Nabíjení lze **ovládat přes GPIO16**:
- **GPIO16 = HIGH** → Nabíjení povoleno.
- **GPIO16 = LOW** → Nabíjení zakázáno.
== Ovládání nabíjení pomocí GPIO16 ==
Pro ruční ovládání nabíjení je nutné nejprve zjistit odpovídající GPIO pin:
GPIO=16
# Zjištění skutečného čísla GPIO pinu
GPIO=$(cat /sys/kernel/debug/gpio | grep "GPIO$GPIO" | awk -F'gpio-' '{print $2}' | awk -F' ' '{print $1}')
echo "$GPIO" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio$GPIO/direction
**Povolení nabíjení:**
echo "1" > /sys/class/gpio/gpio$GPIO/value
**Zakázání nabíjení:**
echo "0" > /sys/class/gpio/gpio$GPIO/value
**Poznámka:** Nakonec jsem tuto funkci **nevyužil**, ale uvádím ji pro **kompletní dokumentaci**, pokud by bylo v budoucnu potřeba řídit nabíjení softwarově.
===== Konfigurace softwarového RAIDu – zrcadlení =====
Při konfiguraci jsem vycházel z těchto návodů, přičemž ani jeden není dokonalý pro moji situaci a musel jsem si návody přízpůsobit. Uvádím je pro úplnost jako zdroj:
* https://github.com/robertalexa/rpi-raid1-root-partition/blob/main/README.md
* https://www.jeffgeerling.com/blog/2020/building-fastest-raspberry-pi-nas-sata-raid
* https://gist.github.com/leandrofilipe/f9636be272f97d414652ce1f21e6b1f4
==== Adresace disků ====
Používám **Suptronics X1005 2280 M.2 NVMe Dual Shield** pro **Raspberry Pi 5**, který umožňuje připojení dvou disků.
Na desce jsou viditelně označeny dva sloty:
* **SSD1**
* **SSD2**
Při připojení jednoho disku do **SSD1**, systém jej rozpozná jako **nvme0n1**:
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 1,8T 0 disk
├─nvme0n1p1 259:1 0 512M 0 part /boot/firmware
└─nvme0n1p2 259:2 0 1,8T 0 part /
Po připojení druhého disku do **SSD2** došlo k nečekanému přeskupení číslování disků. Systém nyní rozpoznává:
* Disk připojený v **SSD2** jako **nvme0n1**
* Disk připojený v **SSD1** jako **nvme1n1**
Výstup příkazu `lsblk` po připojení druhého disku:
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 1,8T 0 disk
nvme1n1 259:1 0 1,8T 0 disk
├─nvme1n1p1 259:2 0 512M 0 part /boot/firmware
└─nvme1n1p2 259:3 0 1,8T 0 part /
Toto chování jsem nečekal, ale beru ho jako fakt a budu s ním dále pracovat obezřetně.
Abych si ušetřil problémy a následné zmatky, tak jsem raději disky prohodil. Tedy disk s operačním systémem jsem dal do slotu SSD2 a nový disk do slotu SSD1. Po změně zapojení vypadá výpis takto:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 1,8T 0 disk
├─nvme0n1p1 259:1 0 512M 0 part /boot/firmware
└─nvme0n1p2 259:2 0 1,8T 0 part /
nvme1n1 259:3 0 1,8T 0 disk
==== Vytvoření partition na novém disku před RAIDem ====
Před vytvořením softwarového RAIDu je doporučeno **ručně vytvořit odpovídající partitiony na novém disku** (**nvme0n1**), aby odpovídaly rozdělení stávajícího disku (**nvme1n1**).
RAID se obvykle vytváří nad existujícími partitionami, nikoliv nad celým diskem (i když je to možné, ale méně běžné).
=== Jak vytvořit partitiony přesně podle původního disku? ===
K tomu použijeme příkaz **sfdisk**, který umožňuje zkopírovat tabulku oddílů ze **nvme1n1** na **nvme0n1**.
=== Krok 1: Záloha stávající partition tabulky ===
Než cokoliv změníme, je vhodné **uložit stávající partition tabulku**, pokud by bylo potřeba ji obnovit:
sudo sfdisk -d /dev/nvme0n1 > partition_backup.txt
Tím se uloží rozložení oddílů do souboru **partition_backup.txt**, což umožní jejich případnou obnovu.
=== Krok 2: Zkopírování partition schématu na nový disk ===
Zkopíruj stejnou partition tabulku ze **nvme1n1** na **nvme0n1**:
sudo sfdisk /dev/nvme1n1 < partition_backup.txt
Tento příkaz vytvoří na **nvme1n1** stejnou strukturu jako na **nvme0n1**.
=== Krok 3: Ověření správnosti nového rozdělení disku ===
Po provedení předchozího příkazu je vhodné **ověřit, zda jsou partitiony nyní identické**:
lsblk
fdisk -l /dev/nvme1n1
Pokud se vše shoduje, můžeme pokračovat v nastavování RAIDu.
==== Konfigurace RAID 1 pomocí mdadm ====
Pro konfiguraci softwarového RAIDu pro zrcadlení (RAID 1) použijeme **mdadm**.
Nejprve nainstalujeme potřebný balíček:
sudo apt install mdadm
Vzhledem k tomu, že RAID nastavujeme na běžícím systému, vytvoříme RAID **v degradovaném režimu**, tedy pouze s jedním diskem. Druhý disk přidáme později.
=== Vytvoření RAID 1 v degradovaném režimu ===
Místo dvou disků v RAIDu vytvoříme pole pouze s novým diskem (**nvme1n1p1** a **nvme1n1p2**).
Druhý disk zatím nebude připojen (`missing`), což RAID umožňuje:
sudo mdadm --create --verbose /dev/md0 --level=1 --raid-devices=2 /dev/nvme1n1p1 missing --metadata=0.90
sudo mdadm --create --verbose /dev/md1 --level=1 --raid-devices=2 /dev/nvme1n1p2 missing
✅ **Vysvětlení:**
* `missing` znamená, že druhý disk zatím není připojen, RAID poběží pouze s jedním diskem.
* `--metadata=0.90` je doporučeno pro zaváděcí oddíly.
Následujícím krokem je vytvoření souborového systému na nově vytvořeném RAIDu.
=== Vytvoření souborových systémů ===
Na nových RAID oddílech vytvoříme souborový systém:
sudo mkfs.vfat /dev/md0
sudo mkfs.ext4 /dev/md1
Nyní připojíme RAID a přeneseme systémové soubory.
=== Přenos systémových souborů na RAID ===
Nejprve připojíme bootovací oddíl RAID:
mkdir /mnt/raid_boot
mount /dev/md0 /mnt/raid_boot
rsync -axv /boot/firmware/ /mnt/raid_boot/
Poté připojíme hlavní oddíl a přeneseme systém:
mkdir /mnt/raid_root
mount /dev/md1 /mnt/raid_root
rsync -axv / /mnt/raid_root --exclude=/mnt --exclude=/proc --exclude=/sys --exclude=/dev --exclude=/run --exclude=/tmp
=== Úprava fstab pro použití RAIDu ===
Otevřeme soubor **fstab** na novém RAIDu:
nano /mnt/raid_root/etc/fstab
Najdeme řádky obsahující `/dev/nvme0n1p1` a `/dev/nvme0n1p2` a upravíme je:
/dev/md0 /boot/firmware vfat defaults 0 2
/dev/md1 / ext4 defaults,noatime,errors=remount-ro 0 1
Tím zajistíme, že systém při bootu použije RAID.
=== Aktualizace konfigurace mdadm ===
Zjistíme UUID RAID polí:
mdadm --detail --scan
Výstup bude podobný tomuto:
ARRAY /dev/md0 metadata=0.90 UUID=e11e72e6:cfe13794:c15f4f5c:b4c7de4f
ARRAY /dev/md1 metadata=1.2 name=server:1 UUID=6af6a5bd:b7fd9bcc:2cd91b19:bf09e0c3
Tento výstup zapíšeme na konec souboru:
nano /mnt/raid_root/etc/mdadm/mdadm.conf
=== Úprava cmdline.txt pro bootování z RAIDu ===
Otevřeme soubor bootovací konfigurace:
nano /mnt/raid_boot/cmdline.txt
Najdeme řádek obsahující:
root=PARTUUID=aa235387-02
A nahradíme jej:
root=/dev/md1 rootfstype=ext4 fsck.repair=yes rootwait rootdelay=10 cfg80211.ieee80211_regdom=CZ
✅ **Vysvětlení:**
* `root=/dev/md1` – říká jádru, že root filesystem je na RAIDu.
* `rootwait rootdelay=10` – umožňuje systému počkat na sestavení RAIDu.
* `fsck.repair=yes` – umožní automatickou opravu souborového systému při bootu.
=== Přidání RAID modulů do initramfs ===
Aby jádro vědělo, že používáme RAID již při bootu, přidáme moduly do **initramfs**:
nano /mnt/raid_root/etc/initramfs-tools/modules
Přidáme tyto řádky:
raid1
md_mod
ext4
Aktualizujeme initramfs:
umount /mnt/raid_boot
mount /dev/md0 /mnt/raid_root/boot/firmware/
mkdir -p /mnt/raid_root/dev /mnt/raid_root/proc /mnt/raid_root/sys /mnt/raid_root/run
mount --bind /dev /mnt/raid_root/dev
mount --bind /proc /mnt/raid_root/proc
mount --bind /sys /mnt/raid_root/sys
mount --bind /run /mnt/raid_root/run
chroot /mnt/raid_root
update-initramfs -u
Tím jsme zajistili, že RAID bude dostupný již při startu systému.
**Nyní jsem mohl Raspberry restartovat. Důležitá věc, musel jsem primární disk - tedy disk s RAID přesunout do slotu SSD2 na desce. Dokud jsem to neudělal, boot se nepodařil, systém byl zmatený. Tento krok je klíčový - prohodit disky ve slotech.**
==== Přidání disku do RAID ====
Po prohození disků ve slotech (disk s nastaveným RAIDem musí být ve slotu **SSD2**) a nabootování systému je možné přidat druhý disk zpět do RAID pole.
Stejný postup se použije i v případě, že se nějaký disk odpojí a pole je **degradované**, tedy běží pouze s jedním diskem.
✅ **Klíčové pravidlo:**
**Primární disk musí být ve slotu SSD2, aby systém správně nabootoval.**
=== Stav RAID pole po nabootování ===
Z výpisu je vidět, že v RAID poli je zatím pouze jeden disk:
cat /proc/mdstat
**Výstup:**
Personalities : [raid1] [linear] [raid0] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 nvme0n1p1[0]
524224 blocks [2/1] [U_]
md1 : active raid1 nvme0n1p2[0]
1952854080 blocks super 1.2 [2/1] [U_]
bitmap: 4/4 pages [64KB], 65536KB chunk
Nově připojený disk **nvme1n1** zatím není součástí RAID pole.
=== Výpis připojených disků ===
Podíváme se na aktuální stav připojených disků:
lsblk
**Výstup:**
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 1,8T 0 disk
├─nvme0n1p1 259:1 0 512M 0 part
│ └─md0 9:0 0 511,9M 0 raid1 /boot/firmware
└─nvme0n1p2 259:2 0 1,8T 0 part
└─md1 9:1 0 1,8T 0 raid1 /
nvme1n1 259:3 0 1,8T 0 disk
├─nvme1n1p1 259:4 0 512M 0 part
└─nvme1n1p2 259:5 0 1,8T 0 part
=== Detaily RAID pole ===
Zkontrolujeme aktuální stav RAID pole:
mdadm --detail /dev/md0
/dev/md0:
Version : 0.90
Creation Time : Sat Feb 15 16:52:29 2025
Raid Level : raid1
Array Size : 524224 (511.94 MiB 536.81 MB)
Used Dev Size : 524224 (511.94 MiB 536.81 MB)
Raid Devices : 2
Total Devices : 1
Persistence : Superblock is persistent
Update Time : Sat Feb 15 19:15:46 2025
State : clean, degraded
Active Devices : 1
Working Devices : 1
Failed Devices : 0
Spare Devices : 0
Consistency Policy : resync
Number Major Minor RaidDevice State
0 259 1 0 active sync /dev/nvme0n1p1
- 0 0 1 removed
Stejným způsobem můžeme zkontrolovat i hlavní RAID oddíl:
mdadm --detail /dev/md1
**Výstup ukazuje, že RAID pole je degradované – chybí druhý disk.**
=== Přidání nového disku do RAID pole ===
Nyní přidáme nový disk **nvme1n1** do RAID pole:
mdadm --add /dev/md0 /dev/nvme1n1p1
mdadm --add /dev/md1 /dev/nvme1n1p2
Po přidání zkontrolujeme stav RAIDu:
cat /proc/mdstat
**Výstup ukazuje, že RAID začíná synchronizaci:**
Personalities : [raid1] [linear] [raid0] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 nvme1n1p1[1] nvme0n1p1[0]
524224 blocks [2/2] [UU]
md1 : active raid1 nvme1n1p2[2] nvme0n1p2[0]
1952854080 blocks super 1.2 [2/1] [U_]
[=>...................] recovery = 5.3% (104572928/1952854080) finish=149.1min speed=206517K/sec
bitmap: 4/4 pages [64KB], 65536KB chunk
=== Sledování průběhu synchronizace ===
Pro sledování průběhu synchronizace RAID pole můžeme použít:
watch -n 1 cat /proc/mdstat
✅ **RAID nyní probíhá synchronizace a disk bude plně zrcadlen po dokončení procesu.**
=== Priorita disků po odpojení a opětovném připojení ===
Pokud dojde k **odpojení jednoho disku** a následně jej znovu připojíme, systém rozhodne, **který disk bude v RAIDu upřednostněn**, a to na základě několika faktorů.
Nezáleží na tom, **že je disk ve slotu SSD2**, protože po připojení obou disků systém automaticky **vybere ten, který běžel jako poslední aktivní po rozpojení RAIDu**.
=== Jak systém určuje, který disk bude upřednostněn? ===
Systém rozhoduje na základě **poslední aktualizace metadat RAIDu**. Každý disk v RAIDu obsahuje **metadata (superblock)**, která uchovávají informace o změnách v poli.
**Klíčový parametr je tzv. Event Count**, což je čítač změn.
✅ **RAID vybere disk s nejvyšším Event Count jako platný.**
Pokud má jeden disk vyšší Event Count než druhý, systém považuje tento disk za aktuální a použije jej jako primární.
=== Jak zjistit, který disk má vyšší Event Count? ===
Můžeš si ověřit, který disk má aktuálnější metadata pomocí příkazu:
mdadm --examine /dev/nvme0n1p2 /dev/nvme1n1p2
**Výstup bude obsahovat řádky podobné tomuto:**
/dev/nvme0n1p2:
Events : 405
/dev/nvme1n1p2:
Events : 392
✅ **Disk s vyšším číslem „Events“ je považován za aktuální.**
Pokud se **Event Count neshoduje**, mdadm automaticky označí **starší disk jako neaktuální** a vyřadí ho z RAID pole.
=== Co se stane při neaktuálním disku? ===
Pokud má jeden z disků nižší Event Count, systém jej při dalším spuštění považuje za **zastaralý** a označí jej jako neaktivní.
RAID pak při připojení tohoto disku provede **resynchronizaci** dat.
Proto je důležité po výpadku disku **zkontrolovat stav RAID