This commit is contained in:
2026-06-11 21:49:04 +02:00
parent 8e760d3adf
commit 8ef7d1cfd1
15 changed files with 1621 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
# SeaweedFS na Unraidu — S3-kompatibilní úložiště
Vyladěný Docker stack proti původnímu příkladu. Hlavní rozdíly a proč:
| Změna | Proč |
|---|---|
| Pin verze image `:4.32` místo `:latest` | reprodukovatelnost, žádné překvapení po `pull` |
| Master má `-mdir=/data` + namapovaný volume | **metadata masteru** (kde co leží) jinak po restartu zmizí |
| Filer má namapovaný `/data` | leveldb s metadaty souborů musí persistovat |
| `-config=config_s3.json` u s3 | bez něj je S3 **bez autentizace, otevřené komukoliv** v síti |
| `healthcheck` + `depends_on: service_healthy` | služby nestartují dřív, než je master skutečně nahoře |
| `restart: unless-stopped` | přežije restart Unraidu |
| `-ip.bind=0.0.0.0` | dostupnost z LAN, ne jen z kontejneru |
| Data pod `/mnt/user/appdata/...` | zálohovatelné, ne v anonymním volume |
## Kam se ukládají data (DŮLEŽITÉ pro Unraid)
Klíčové pravidlo Unraidu: **cache není pod paritou** → patří tam jen to, co jde
snadno obnovit. Rozhoduje tedy ne velikost, ale obnovitelnost:
| Co | Obnovitelné? | Kam | Cesta |
|---|---|---|---|
| volume (vlastní obsah) | ne (to jsou ta data) | **POLE (parita)** | `/mnt/user/seaweedfs/volume` |
| **filer metadata** | **NE** — bez nich jsou bloby slepé | **externí DB** (Mongo/PG) | `filer.toml` |
| master metadata | ano — poskládá se z heartbeatů | cache / appdata | `/mnt/user/appdata/seaweedfs/master` |
| config_s3.json | trivální | vedle compose | `./config_s3.json` |
### Proč filer metadata nesmí na cache
filer drží mapu *název souboru → které chunky na kterém volume*. Volume servery ji
**neumí zrekonstruovat** — bloby na poli přežijí, ale ztratíš informaci, co je co.
Proto je dáváme do tvé existující DB na 192.168.1.76 (viz `filer.toml`):
- **MongoDB (doporučeno)** — kolekce v DB `seaweedfs` se vytvoří sama, žádné schéma.
- **PostgreSQL** — vytvoř DB a tabulku:
```sql
CREATE DATABASE seaweedfs;
-- v DB seaweedfs:
CREATE TABLE IF NOT EXISTS filemeta (
dirhash BIGINT,
name VARCHAR(65535),
directory VARCHAR(65535),
meta BYTEA,
PRIMARY KEY (dirhash, name)
);
```
Master metadata na cache nechávám schválně — po ztrátě cache si je master poskládá
z hlášení volume serverů, takže spadají do „snadno obnovitelné".
### Nejdřív založ share na poli
Settings → Shares → Add Share:
- Název: `seaweedfs`
- **Primary storage: Array** (NE cache), Secondary: none — jinak by data tekla zpět na cache a zaplnila ji
- Allocation/split dle libosti
Tím vznikne `/mnt/user/seaweedfs`, kam míří volume vrstva. (Alternativa: napřímo na
konkrétní ZFS disk, `/mnt/diskX/seaweedfs/volume`, když chceš obejít user share.)
> Pozn.: Disk 8 (sdd) má v poli **14 223 čtecích chyb** — než tam pustíš nová data,
> mrkni na SMART / zvaž jeho vyřazení. Na takový disk bych volume dir nesměroval.
## Spuštění
```bash
cd /boot/config/plugins/compose/... # nebo kamkoliv stack uložíš
docker compose -p seaweedfs up -d
docker compose -p seaweedfs ps
```
## Endpoints (nahraď `UNRAID-IP`)
- Master UI: `http://UNRAID-IP:9333`
- Filer/web: `http://UNRAID-IP:8888`
- **S3 API:** `http://UNRAID-IP:8333`
## Před produkcí
1. **Změň klíče** v `config_s3.json` (admin i readonly). Dlouhé náhodné secret keys.
2. Soubor `config_s3.json` drž s právy `600`.
3. Zvaž reverzní proxy (SWAG/NPM) s TLS, pokud má být S3 dostupné mimo LAN.
4. `defaultReplication=000` = bez replikace (1 kopie). Pro odolnost přes víc disků/serverů zvyš (např. `001`, `010`) a přidej volume servery.
## Test
```bash
# AWS CLI
S3=http://UNRAID-IP:8333 AK=admin SK=tajne ./test_s3.sh
```
Nebo přes `s3cmd`, `rclone`, MinIO client (`mc`) — vše funguje proti `:8333`.
## Škálování později
Tohle je single-node setup (test / menší nasazení). Pro distribuovaný cluster přidej
další `volume` servery (klidně na jiných strojích) mířící na stejný master a zvyš
replikaci. Master + filer mohou zůstat, volume vrstva se škáluje horizontálně.
+33
View File
@@ -0,0 +1,33 @@
{
"identities": [
{
"name": "admin",
"credentials": [
{
"accessKey": "ZMEN_ME_admin",
"secretKey": "ZMEN_ME_tajny_klic_dlouhy_nahodny"
}
],
"actions": [
"Admin",
"Read",
"Write",
"List",
"Tagging"
]
},
{
"name": "readonly",
"credentials": [
{
"accessKey": "ZMEN_ME_readonly",
"secretKey": "ZMEN_ME_tajny_klic_readonly"
}
],
"actions": [
"Read",
"List"
]
}
]
}
+89
View File
@@ -0,0 +1,89 @@
# =============================================================================
# SeaweedFS — S3-kompatibilní úložiště na Unraidu (Docker)
# Vyladěná verze: persistence VŠECH dat, S3 přihlášení, healthcheck, restart.
#
# Spuštění:
# docker compose -p seaweedfs up -d
# (na starším Unraidu: docker-compose -f docker-compose.yml -p seaweedfs up -d)
#
# Endpoints (nahraď UNRAID-IP IP adresou serveru):
# Master UI : http://UNRAID-IP:9333
# Filer/web : http://UNRAID-IP:8888
# S3 API : http://UNRAID-IP:8333
# Volume : http://UNRAID-IP:8080 (interní, kvůli debugu)
#
# DŮLEŽITÉ: před produkčním použitím změň klíče v config_s3.json!
# =============================================================================
x-image: &swimg chrislusf/seaweedfs:4.32 # pin verze (ne :latest) kvůli reprodukovatelnosti
services:
seaweed-master:
image: *swimg
container_name: seaweed-master
command: >
master -ip=seaweed-master -ip.bind=0.0.0.0
-mdir=/data -volumeSizeLimitMB=1024 -defaultReplication=000
ports:
- "9333:9333"
volumes:
# metadata masteru — cache OK: po ztrátě se poskládá z heartbeatů volume serverů
- /mnt/user/appdata/seaweedfs/master:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:9333/cluster/status"]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
seaweed-volume:
image: *swimg
container_name: seaweed-volume
command: >
volume -mserver=seaweed-master:9333 -ip=seaweed-volume -ip.bind=0.0.0.0
-dir=/data -max=0
ports:
- "8080:8080"
volumes:
# POZOR: vlastní obsah (roste do TB) -> na POLE, NE do appdata/cache!
# Vyžaduje share "seaweedfs" s primary storage = Array (cache=No).
- /mnt/user/seaweedfs/volume:/data
depends_on:
seaweed-master:
condition: service_healthy
restart: unless-stopped
seaweed-filer:
image: *swimg
container_name: seaweed-filer
command: >
filer -master=seaweed-master:9333 -ip=seaweed-filer -ip.bind=0.0.0.0
ports:
- "8888:8888"
volumes:
# filer metadata -> externí DB dle filer.toml (Mongo/Postgres) = chráněné.
- ./filer.toml:/etc/seaweedfs/filer.toml:ro
# Jen pokud ve filer.toml zvolíš variantu C (leveldb2): odkomentuj a dej na POLE
# - /mnt/user/seaweedfs/filermeta:/data
depends_on:
seaweed-master:
condition: service_healthy
seaweed-volume:
condition: service_started
restart: unless-stopped
seaweed-s3:
image: *swimg
container_name: seaweed-s3
command: >
s3 -filer=seaweed-filer:8888 -ip.bind=0.0.0.0
-config=/etc/seaweedfs/config_s3.json
ports:
- "8333:8333"
volumes:
- ./config_s3.json:/etc/seaweedfs/config_s3.json:ro # S3 přihlašovací údaje (read-only)
depends_on:
seaweed-filer:
condition: service_started
restart: unless-stopped
+38
View File
@@ -0,0 +1,38 @@
# =============================================================================
# SeaweedFS filer — kde se ukládají METADATA (název -> chunky, stromová struktura)
#
# POZOR: filer metadata NEJDOU rekonstruovat z volume serverů. Když se ztratí,
# data na poli sice přežijí, ale ztratíš mapu, co je co. Proto NESMÍ ležet na
# nechráněné cache. Tři varianty (zapni právě JEDNU sekci enabled=true):
#
# A) mongodb (DOPORUČENO u tebe) — metadata do tvého Monga (192.168.1.76),
# kolekce se vytvoří sama. Chrání je, co chrání Mongo (zálohy/replica).
# B) postgres — metadata do tvého Postgresu; vyžaduje ručně založit tabulku
# (CREATE TABLE viz README).
# C) leveldb2 — embedded soubor; pak ho MUSÍŠ mapovat na POLE (parita), ne cache.
# =============================================================================
# --- A) MongoDB (doporučeno) -------------------------------------------------
[mongodb]
enabled = true
uri = "mongodb://192.168.1.76:27017"
option_pool_size = 0
database = "seaweedfs"
# --- B) PostgreSQL -----------------------------------------------------------
[postgres]
enabled = false
hostname = "192.168.1.76"
port = 5432
username = "seaweedfs"
password = "ZMEN_ME"
database = "seaweedfs"
sslmode = "disable"
connection_max_idle = 5
connection_max_open = 30
# --- C) leveldb2 (embedded) — jen když chceš zůstat bez DB --------------------
# Pak v compose mapuj /data na POLE: /mnt/user/seaweedfs/filermeta:/data
[leveldb2]
enabled = false
dir = "/data/filerldb2"
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# =============================================================================
# Rychlý test SeaweedFS S3 API přes AWS CLI.
# Předpoklad: nainstalované awscli (pip install awscli / apt install awscli)
#
# Použití:
# ./test_s3.sh # použije defaulty níže
# S3=http://192.168.1.50:8333 AK=admin SK=tajne ./test_s3.sh
# =============================================================================
set -euo pipefail
S3="${S3:-http://UNRAID-IP:8333}"
AK="${AK:-ZMEN_ME_admin}"
SK="${SK:-ZMEN_ME_tajny_klic_dlouhy_nahodny}"
BUCKET="${BUCKET:-test-bucket}"
export AWS_ACCESS_KEY_ID="$AK"
export AWS_SECRET_ACCESS_KEY="$SK"
export AWS_DEFAULT_REGION="us-east-1"
AWS=(aws --endpoint-url "$S3")
echo "== 1) vytvoření bucketu =="
"${AWS[@]}" s3 mb "s3://$BUCKET" || true
echo "== 2) upload souboru =="
echo "ahoj ze SeaweedFS $(date)" > /tmp/sw_test.txt
"${AWS[@]}" s3 cp /tmp/sw_test.txt "s3://$BUCKET/hello.txt"
echo "== 3) výpis bucketu =="
"${AWS[@]}" s3 ls "s3://$BUCKET/"
echo "== 4) stažení zpět a kontrola =="
"${AWS[@]}" s3 cp "s3://$BUCKET/hello.txt" /tmp/sw_back.txt
diff /tmp/sw_test.txt /tmp/sw_back.txt && echo "OK: obsah sedí"
echo "== 5) úklid =="
"${AWS[@]}" s3 rm "s3://$BUCKET/hello.txt"
echo "Hotovo."