概要:なぜ今、自宅SREインフラなのか?
クラウドサービスの利用料高騰やアカウント突然死リスクを背景に、オンプレミス・自前インフラへの回帰(Repatriation)が注目されています。
本稿では、一般家庭のリビングルームにおいて、 常時消費電力わずか30W を維持しながら、エンタープライズ金融システムと同等の可用性(RPO<1秒, RTO<10分)を実現する 「HomeLab SREアーキテクチャ」 の設計と運用基準をまとめます。
1. 物理アーキテクチャとハードウェア仕様
【前提:推奨購入構成ではなく、手元の遊休機材の利活用です】
ここに示すマシン型番(N100、TH50、Pi4B等)は、 購入を推奨する構成ではありません 。筆者の手元に余っていた旧機材を廃棄せず活用した結果であり、読者の皆様がお持ちの余剰PCや旧型ノートパソコンでも本設計(主系・従系・独立監視の役割分担)をそのまま再現可能です。
安定性と静音性、極限の省電力を両立するため、以下の3ノード構成(Golden Trio)を採用しています(実測パラメータはコードベースの inventory.ini に準拠)。
| ノード名 | 搭載ハードウェア | 常態消費電力 | SRE責務と主要ミドルウェア |
|---|---|---|---|
| Primary Master (n100) | NiPoGi N100 / 8GB RAM / 256GB NVMe + 1TB WD SSD (192.168.3.8) | ~8.5W-10.5W | Keepalived Master, PostgreSQL 18 (RW: 5432), Gitea, Redmine, MinIO, n8n |
| Secondary Compute (th50) | Minisforum TH50 i5-11320H / 16GB RAM / 512GB NVMe (192.168.3.9) | ~14W-16W | Keepalived Standby, PostgreSQL 18 (RO Standby: 5432), Dify AI, CI Runner |
| Monitoring Sentinel (pi4b) | Raspberry Pi 4B (ARM) / 4GB RAM / 64GB SD / 外付USB 3.0 RAID1 (東芝 2TB×2) (192.168.3.2) | ~3W | 独立監視(Uptime Kuma 3001&Slack通知), Kopia引取型バックアップ (/mnt/backup-hdd), WoL起動 |
| 合計常時電力 | N100(~10W) + i5(~15W) + Pi4B(~3W) + 外付RAID(~2W) | ~30W (実測27~31W) | ※手元の遊休機材を徹底活用、月額電気代 670円前後に完全抑制 |
【SRE設計思想:家庭・小規模環境における現実的判断】
万能のアーキテクチャは存在しません。エンタープライズの完全自動フェイルオーバーは二重系統電源とハードウェアSTONITH電源遮断が前提です。これらを持たない家庭内環境で完全自動クラスタを盲信すると、ネットワークの瞬断でスプリットブレインやフラッピングを誘発します。「独立監視ノードからの即時Slackアラート+確定的な迅速スクリプト復旧」こそが最も堅牢です。※UPSやスマートPDU導入後のQuorum Witness自動仲裁化へのアップグレードパスは第2方向にて詳述します。
2. ネットワーク設計と非対称ルーティング対策
Keepalivedによる仮想IP(VIP: 192.168.3.200)運用時、複数のNICを持つ物理マシンでは 「非対称ルーティングによるサイレントパケットドロップ」 が頻発します。
カーネルパラメータの必須設定 (/etc/sysctl.d/99-sre-ha.conf)
# 非ローカルIPバインドの許可 (Keepalived VIPが未割り当ての状態でもHAProxyを安全に起動するため)
net.ipv4.ip_nonlocal_bind = 1
# リバースパスフィルタリングの緩和 (非対称ルーティングによるパケット破棄を防止)
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
# TCP SYN Cookie の有効化 (SYN Flood防御)
net.ipv4.tcp_syncookies = 1
上記を適用後、sudo sysctl -p /etc/sysctl.d/99-sre-ha.conf を実行して反映します。
3. PostgreSQL 18 物理ストリーミングレプリケーション構成
論理レプリケーションではなく、バイナリWALをそのまま同期する非同期物理ストリーミングを採用。
従系側(i5)では primary_conninfo を設定し、standby.signal を配置。主系ダウン時は pg_ctl promote または Keepalived のフェイルオーバースクリプトにより自動昇格します。
4. オンデマンド異種GPUノードのWoL自動起動
大容量LLM(Ollama)や画像処理など高負荷タスクが発生した場合のみ、 Xeon D-1581 または i7-9700F + RTX 4060 搭載の拡張ノードをWake-on-LANでオンデマンド起動します。
# Raspberry Pi 4B監視ノードからGPUノードを起動するコマンド
wakeonlan 00:11:22:33:44:55
# HAProxy ランタイムソケットによる重み付け更新 (GPUノード活性化)
echo "set server backend_ai/gpu_node weight 100" | sudo socat stdio /var/run/haproxy.sock
タスク完了後は自律監視スクリプトがCPU/GPU負荷を監視し、15分間アイドルが続いた場合にS3ステート(2〜3W待機)へ降下させます。
まとめ
本設計により、月額数百ドル〜千ドル以上のクラウド請求を発生させることなく、堅牢かつ自律的なSRE運用を家庭内で完結させることが可能です。
全125章にわたる連載の次章では、 Intel N100とRaspberry Pi 4Bの物理インターフェース選定と電源ノイズ対策 を深掘りします。
付録:ノード基盤ヘルスチェック完全ソースコード(コピー&ペーストで即実行)
付録 A:ノード健全性&SRE不変条件検証スクリプト (cluster-health-check.sh)
実行手順 :以下のコードをコピーして
cluster-health-check.shとして保存し、chmod +x cluster-health-check.sh && ./cluster-health-check.sh --verboseを実行します。
#!/usr/bin/env bash
# ==============================================================================
# HomeLab SRE Cookbook - Node Baseline SRE Health Check (Read-Only)
# Target: Golden Trio Hardware Nodes (NiPoGi N100, Minisforum TH50, Raspberry Pi 4B)
# Usage: ./cluster-health-check.sh [--verbose] [--strict]
# Principle: Zero Silent Failures — Non-zero exit code on critical invariant breaches.
# ==============================================================================
set -euo pipefail
VERBOSE=0
STRICT=0
for arg in "$@"; do
case "${arg}" in
--verbose) VERBOSE=1 ;;
--strict) STRICT=1 ;;
esac
done
ERRORS_COUNT=0
WARNINGS_COUNT=0
echo "========================================================================"
echo " [HomeLab SRE] Golden Trio Node Baseline Health Check"
echo " Time: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo "========================================================================"
# 1. Check Local CPU, Memory, and Disk Pressure
printf "%s" "[1/4] Checking Local Host Resources... "
LOAD_1M=$(cat /proc/loadavg 2>/dev/null | awk '{print $1}' || true)
[[ -z "${LOAD_1M}" ]] && LOAD_1M="N/A"
MEM_FREE_MB=$(free -m 2>/dev/null | awk '/^Mem:/{print $7}' || true)
[[ -z "${MEM_FREE_MB}" ]] && MEM_FREE_MB="N/A"
# Portable POSIX df parsing robust against spaces in mount points or LVM line wrapping
DISK_USAGE_PCT=$(df -Pk / 2>/dev/null | awk 'NR>1 {for(i=1;i<=NF;i++) if($i ~ /^[0-9]+%$/) {sub(/%/,"",$i); print $i; exit}}' || true)
if [[ -z "${DISK_USAGE_PCT}" || ! "${DISK_USAGE_PCT}" =~ ^[0-9]+$ ]]; then
DISK_USAGE_PCT=0
fi
if [[ "${DISK_USAGE_PCT}" -ge 95 ]]; then
echo "CRITICAL (Root disk usage ${DISK_USAGE_PCT}% >= 95% - Outage Imminent)"
ERRORS_COUNT=$((ERRORS_COUNT + 1))
elif [[ "${DISK_USAGE_PCT}" -ge 90 ]]; then
echo "WARNING (Root disk usage ${DISK_USAGE_PCT}% >= 90%)"
WARNINGS_COUNT=$((WARNINGS_COUNT + 1))
else
echo "OK (Load: ${LOAD_1M}, Free Mem: ${MEM_FREE_MB}MB, Root Disk: ${DISK_USAGE_PCT}%)"
fi
# 2. Check Key Network & Kernel Tunables (rp_filter, ip_nonlocal_bind)
printf "%s" "[2/4] Checking Essential SRE Kernel Parameters... "
RP_FILTER_ALL=$(sysctl -n net.ipv4.conf.all.rp_filter 2>/dev/null || true)
[[ -z "${RP_FILTER_ALL}" ]] && RP_FILTER_ALL="N/A"
RP_FILTER_DEF=$(sysctl -n net.ipv4.conf.default.rp_filter 2>/dev/null || true)
[[ -z "${RP_FILTER_DEF}" ]] && RP_FILTER_DEF="N/A"
NONLOCAL_BIND=$(sysctl -n net.ipv4.ip_nonlocal_bind 2>/dev/null || true)
[[ -z "${NONLOCAL_BIND}" ]] && NONLOCAL_BIND="N/A"
RP_STATUS="COMPLIANT"
if [[ "${RP_FILTER_ALL}" != "2" || "${RP_FILTER_DEF}" != "2" ]]; then
RP_STATUS="WARNING (all=${RP_FILTER_ALL}, default=${RP_FILTER_DEF}; recommend 2 for dual-NIC asymmetric routing)"
WARNINGS_COUNT=$((WARNINGS_COUNT + 1))
fi
BIND_STATUS="COMPLIANT"
if [[ "${NONLOCAL_BIND}" != "1" ]]; then
BIND_STATUS="WARNING (ip_nonlocal_bind=${NONLOCAL_BIND}; required 1 for Keepalived VIP dynamic socket binding)"
WARNINGS_COUNT=$((WARNINGS_COUNT + 1))
fi
echo "DONE"
echo " -> Reverse Path Filtering: ${RP_STATUS}"
echo " -> Non-local Socket Binding: ${BIND_STATUS}"
# 3. Check Core High Availability Port Availability
printf "%s" "[3/4] Checking Core Ingress & Database Listening Sockets... "
SS_OUTPUT=$(ss -tuln 2>/dev/null || netstat -tuln 2>/dev/null || true)
# Monitored ports: PG(5432), Web(80,443), Grafana(3000), UptimeKuma(3001), ChromaDB(8000), Dify(8080), Traefik(8443), MinIO(9000), Ollama(11434)
PORTS_TO_CHECK=(5432 80 443 3000 3001 8000 8080 8443 9000 11434)
ACTIVE_PORTS=()
for port in "${PORTS_TO_CHECK[@]}"; do
# Avoid pipeline pipefail / SIGPIPE with pre-captured SS_OUTPUT
if echo "${SS_OUTPUT}" | grep -E -q "[:.]${port}\b"; then
ACTIVE_PORTS+=("${port}")
if [[ ${VERBOSE} -eq 1 ]]; then
echo " -> Socket [:${port}]: ACTIVE"
fi
fi
done
LISTENING_COUNT=${#ACTIVE_PORTS[@]}
echo "DONE (${LISTENING_COUNT}/${#PORTS_TO_CHECK[@]} monitored sockets active: ${ACTIVE_PORTS[*]:-none})"
# In production, at least one core SRE socket (DB, Web, or Container) must be listening
if [[ ${LISTENING_COUNT} -eq 0 ]]; then
echo " [NOTICE] No core service sockets currently listening on this local host."
WARNINGS_COUNT=$((WARNINGS_COUNT + 1))
fi
# In strict mode, promote any parameter warnings to critical errors (Zero Silent Failures)
if [[ ${STRICT} -eq 1 && ${WARNINGS_COUNT} -gt 0 ]]; then
echo " [STRICT MODE] Promoting ${WARNINGS_COUNT} warnings to critical failures."
ERRORS_COUNT=$((ERRORS_COUNT + WARNINGS_COUNT))
fi
# 4. Overall Node Readiness Verdict (Anti-Silent-Failure Enforcement)
echo "========================================================================"
if [[ ${ERRORS_COUNT} -gt 0 ]]; then
echo " [VERDICT: FAILED] ${ERRORS_COUNT} critical errors detected. Node NOT ready for production."
echo "========================================================================"
exit 1
elif [[ ${WARNINGS_COUNT} -gt 0 ]]; then
echo " [VERDICT: PASSED WITH WARNINGS] ${WARNINGS_COUNT} warnings detected. Review kernel/socket tunables."
echo "========================================================================"
exit 0
else
echo " [VERDICT: PASSED] All node baseline invariants satisfied. Ready for SRE state machine."
echo "========================================================================"
exit 0
fi
付録 B:最小限の検証用 Docker Compose 構成 (docker-compose.infra.yml)
実行手順 :以下のコードをコピーして
docker-compose.infra.ymlとして保存し、docker compose -f docker-compose.infra.yml up -dで起動します。
services:
# HomeLab SRE Baseline Verification Stack
# Lightweight node exporter for baseline CPU/Mem/Disk telemetry (approx 15MB RAM)
node-exporter:
image: prom/node-exporter:v1.8.2
container_name: homelab-node-exporter
restart: unless-stopped
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
network_mode: host
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
# Ingress verification dummy service (mapped to non-conflicting port 8088 to avoid Dify 8080)
ingress-probe:
image: nginx:1.27-alpine
container_name: homelab-ingress-probe
restart: unless-stopped
ports:
- "127.0.0.1:8088:80"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1/ || exit 1"]
interval: 10s
timeout: 3s
retries: 3
