docs(plan): Plan-B-Base — NAS Redis + Windows WSL2/Docker/Tailscale/SMB
분산 아키텍처 base 인프라 셋업. 8 task: - Task 1-2: NAS docker-compose redis 서비스 추가 + 검증 - Task 3-5: Windows AI WSL2 + Docker Engine + Tailscale 설치 - Task 6-7: NAS SMB 자격증명·마운트 (/etc/fstab 자동화) - Task 8: 통합 검증 (redis PING, /mnt/nas 양방향 R/W, docker hello-world) SP-2 작업은 박재오 Windows AI 머신 192.168.45.59에서 직접 실행 필요. Claude는 SP-1만 직접 처리, SP-2는 명령어·검증 가이드 제공. 후속 Plan-B-Insta/Music/Video/Infra의 prerequisite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
635
docs/superpowers/plans/2026-05-18-plan-b-base-redis-wsl2.md
Normal file
635
docs/superpowers/plans/2026-05-18-plan-b-base-redis-wsl2.md
Normal file
@@ -0,0 +1,635 @@
|
|||||||
|
# Plan-B-Base — NAS Redis 컨테이너 + Windows WSL2/Docker/Tailscale/SMB Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 분산 아키텍처 base 인프라 셋업 — NAS에 24/7 Redis 컨테이너 신설 + Windows AI 머신에 WSL2 + Docker Engine + Tailscale + NAS SMB 마운트 구성. 후속 Plan-B-Insta/Music/Video/Infra 트랙의 prerequisite.
|
||||||
|
|
||||||
|
**Architecture:** SP-1 (NAS Redis) = docker-compose service 추가 + deployer auto-rebuild. SP-2 (Windows) = 박재오 머신 192.168.45.59에서 직접 셋업 (WSL2 Ubuntu 22.04 + Docker Engine + Tailscale + cifs-utils로 NAS SMB 마운트). 두 SP가 모두 끝나야 후속 트랙의 worker가 NAS ↔ Windows 양방향 통신 가능.
|
||||||
|
|
||||||
|
**Tech Stack:** Redis 7-alpine, WSL2, Ubuntu 22.04, Docker Engine 24+, Tailscale, cifs-utils (SMB 3.0). PowerShell (관리자) + bash (WSL2 내부).
|
||||||
|
|
||||||
|
**Spec:** `web-backend/docs/superpowers/specs/2026-05-18-nas-windows-distributed-architecture-design.md` §4 SP-1·SP-2, §10 SP-1·SP-2 상세
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 사전 확인 사항
|
||||||
|
|
||||||
|
- **박재오 자격증명 필요**: NAS SMB 마운트용 user/password (Synology DSM 사용자, SMB 권한 보유)
|
||||||
|
- **Windows AI 머신 직접 접근 필요**: WSL2 설치는 관리자 PowerShell + 재부팅 1회. Claude는 별도 머신이라 명령 직접 실행 불가 — **Task 4~7은 박재오가 콘솔에서 직접 수행**. 명령어와 검증 방법 명시.
|
||||||
|
- **NAS deployer 사용자**: Gitea webhook으로 docker compose up -d 자동 실행. 새 redis 서비스도 추가 시 자동 startup.
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
### SP-1 — NAS 측 (Modify)
|
||||||
|
|
||||||
|
| 파일 | 변경 | 책임 |
|
||||||
|
|------|------|------|
|
||||||
|
| `web-backend/docker-compose.yml` | `redis:` 서비스 블록 추가 | 컨테이너 정의 (image, volume, healthcheck) |
|
||||||
|
|
||||||
|
### SP-2 — Windows 측 (Create, 박재오 머신 로컬)
|
||||||
|
|
||||||
|
| 파일/위치 | 변경 | 책임 |
|
||||||
|
|----------|------|------|
|
||||||
|
| (Windows AI) WSL2 Ubuntu-22.04 | install | Linux 런타임 |
|
||||||
|
| WSL2 `/etc/apt/keyrings/docker.gpg` | install | Docker Engine apt key |
|
||||||
|
| WSL2 `/etc/apt/sources.list.d/docker.list` | install | Docker Engine apt source |
|
||||||
|
| (Windows AI) Tailscale | install + auth | 사설망 100.x.x.x |
|
||||||
|
| WSL2 `/etc/nas-smb-credentials` (신규) | NAS user/password | SMB 자격증명 (chmod 600) |
|
||||||
|
| WSL2 `/etc/fstab` (수정) | SMB 마운트 항목 추가 | 부팅 시 자동 마운트 |
|
||||||
|
| WSL2 `/mnt/nas` | mkdir | 마운트 포인트 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: NAS docker-compose.yml에 redis 서비스 추가
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `C:/Users/jaeoh/Desktop/workspace/web-backend/docker-compose.yml`
|
||||||
|
|
||||||
|
- [ ] **Step 1: 현재 docker-compose.yml 끝부분 확인 (deployer 위치)**
|
||||||
|
|
||||||
|
Run: `tail -20 C:/Users/jaeoh/Desktop/workspace/web-backend/docker-compose.yml`
|
||||||
|
Expected: `deployer` 서비스가 마지막. line ~277-293 영역.
|
||||||
|
|
||||||
|
- [ ] **Step 2: redis 서비스 블록 추가**
|
||||||
|
|
||||||
|
`C:/Users/jaeoh/Desktop/workspace/web-backend/docker-compose.yml` 파일 **끝**에 (deployer 서비스 다음, volumes 블록 있다면 그 전에) 다음 블록 추가. 들여쓰기는 다른 서비스(`lotto:`, `stock:` 등)와 동일하게 services 아래 2칸 들여쓰기:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: redis
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- ${RUNTIME_PATH}/redis-data:/data
|
||||||
|
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 60s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
```
|
||||||
|
|
||||||
|
**주의:**
|
||||||
|
- 파일 끝에 추가하되, 만약 `networks:` / `volumes:` top-level 블록이 services 다음에 있다면 그 블록들 **앞에** 삽입
|
||||||
|
- 첫 줄에 빈 줄 1개 두기 (deployer와 분리)
|
||||||
|
- `${RUNTIME_PATH}` 환경변수는 다른 서비스에서도 사용 중. 자동 적용됨
|
||||||
|
|
||||||
|
- [ ] **Step 3: yaml 문법 검증**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
python -c "import yaml; yaml.safe_load(open('C:/Users/jaeoh/Desktop/workspace/web-backend/docker-compose.yml'))" && echo "yaml OK"
|
||||||
|
```
|
||||||
|
Expected: `yaml OK`
|
||||||
|
|
||||||
|
만약 실패하면 indent 또는 trailing space 확인.
|
||||||
|
|
||||||
|
- [ ] **Step 4: redis 서비스가 services dict에 들어갔는지 확인**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
```bash
|
||||||
|
python -c "import yaml; d=yaml.safe_load(open('C:/Users/jaeoh/Desktop/workspace/web-backend/docker-compose.yml')); print(sorted(d['services'].keys()))"
|
||||||
|
```
|
||||||
|
Expected: 리스트에 `'redis'` 포함. 다른 서비스(`lotto`, `stock`, `music-lab`, `insta-lab`, `realestate-lab`, `agent-office`, `personal`, `packs-lab`, `travel-proxy`, `frontend`, `deployer`)도 모두 그대로.
|
||||||
|
|
||||||
|
- [ ] **Step 5: 커밋**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd C:/Users/jaeoh/Desktop/workspace/web-backend
|
||||||
|
git add docker-compose.yml
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
feat(infra): add redis container as 24/7 queue + cache base (SP-1)
|
||||||
|
|
||||||
|
redis:7-alpine, 256MB maxmemory, AOF appendonly ON, allkeys-lru.
|
||||||
|
docker volume ${RUNTIME_PATH}/redis-data로 영속화.
|
||||||
|
Plan-B 후속 트랙(insta-render/music-render/video-render Windows
|
||||||
|
워커)의 BLPOP 큐 + NAS↔Windows pub/sub의 base.
|
||||||
|
|
||||||
|
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: push (Gitea webhook → NAS deployer 자동 적용)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd C:/Users/jaeoh/Desktop/workspace/web-backend
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
자격증명 prompt 시 입력. 1회 실패 시 1회 재시도 패턴.
|
||||||
|
|
||||||
|
Expected: push 성공. NAS deployer가 webhook 수신 → `git pull` → `docker compose up -d redis` 자동 실행.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: NAS Redis 컨테이너 헬스 확인
|
||||||
|
|
||||||
|
**Files:** 없음 (NAS 검증)
|
||||||
|
|
||||||
|
- [ ] **Step 1: deployer 완료까지 대기 (통상 30초~2분)**
|
||||||
|
|
||||||
|
Run (Windows 로컬에서):
|
||||||
|
```bash
|
||||||
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
code=$(curl -s -o /dev/null -w "%{http_code}" https://gahusb.synology.me/api/stock/news -m 5)
|
||||||
|
echo "[try $i] HTTP $code"
|
||||||
|
if [ "$code" = "200" ]; then break; fi
|
||||||
|
sleep 15
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: HTTP 200 응답 — NAS 컨테이너 안정 상태. redis 컨테이너는 별도 endpoint 없으나 deployer가 build 완료했음을 시사.
|
||||||
|
|
||||||
|
- [ ] **Step 2: NAS에서 redis 컨테이너 확인 (박재오 SSH)**
|
||||||
|
|
||||||
|
NAS bash:
|
||||||
|
```bash
|
||||||
|
ssh -p 22 박재오@gahusb.synology.me
|
||||||
|
cd /volume1/docker/webpage
|
||||||
|
docker compose ps redis
|
||||||
|
```
|
||||||
|
|
||||||
|
또는 한 번에:
|
||||||
|
```bash
|
||||||
|
ssh -p 22 박재오@gahusb.synology.me "cd /volume1/docker/webpage && docker compose ps redis && docker exec redis redis-cli PING"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- `docker compose ps redis` → `redis ... healthy` 또는 `Up X seconds (health: starting)` 후 곧 healthy
|
||||||
|
- `redis-cli PING` → `PONG`
|
||||||
|
|
||||||
|
만약 `docker compose ps`에 redis가 안 보이면:
|
||||||
|
```bash
|
||||||
|
cd /volume1/docker/webpage && docker compose up -d redis
|
||||||
|
```
|
||||||
|
|
||||||
|
수동 실행해서 startup 확인.
|
||||||
|
|
||||||
|
- [ ] **Step 3: redis-data 볼륨 생성 확인 (Z: drive로)**
|
||||||
|
|
||||||
|
Run (Windows):
|
||||||
|
```powershell
|
||||||
|
Test-Path "Z:\webpage\redis-data"
|
||||||
|
```
|
||||||
|
|
||||||
|
또는 NAS bash:
|
||||||
|
```bash
|
||||||
|
ls -la /volume1/docker/webpage/redis-data/
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 디렉토리 존재. 그 안에 `appendonlydir/` 또는 `dump.rdb` 등의 redis 데이터 파일.
|
||||||
|
|
||||||
|
- [ ] **Step 4: AOF append-only 작동 확인 (선택, 데이터 영속성 검증)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -p 22 박재오@gahusb.synology.me 'docker exec redis redis-cli SET test_key "hello"'
|
||||||
|
ssh -p 22 박재오@gahusb.synology.me 'docker exec redis redis-cli RESTART' # 또는 docker restart
|
||||||
|
# 잠시 대기
|
||||||
|
ssh -p 22 박재오@gahusb.synology.me 'docker exec redis redis-cli GET test_key'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `"hello"` — 재시작 후에도 값 유지 (AOF 영속화 작동).
|
||||||
|
|
||||||
|
테스트 후 정리: `docker exec redis redis-cli DEL test_key`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: Windows AI에 WSL2 + Ubuntu 22.04 설치
|
||||||
|
|
||||||
|
**Files:** 없음 (Windows AI 머신 192.168.45.59에서 박재오 직접 실행)
|
||||||
|
|
||||||
|
**전제:** Windows 10 build 19041+ 또는 Windows 11. 박재오 9800X3D 머신 충족.
|
||||||
|
|
||||||
|
- [ ] **Step 1: 관리자 PowerShell 실행**
|
||||||
|
|
||||||
|
박재오 Windows AI 머신에서 시작 메뉴 → "PowerShell" 우클릭 → "관리자 권한으로 실행".
|
||||||
|
|
||||||
|
- [ ] **Step 2: WSL2 + Ubuntu 22.04 설치**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl --install -d Ubuntu-22.04
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 다운로드 progress + "Ubuntu-22.04 has been installed". **재부팅 필요할 수 있음.**
|
||||||
|
|
||||||
|
- [ ] **Step 3: 재부팅 (필요 시)**
|
||||||
|
|
||||||
|
설치 완료 메시지에 "재시작이 필요합니다"가 보이면 재부팅. 자동 재부팅 안 됨.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Ubuntu 초기 설정 (재부팅 후 자동 실행 또는 시작 메뉴에서 "Ubuntu" 클릭)**
|
||||||
|
|
||||||
|
새 콘솔이 열리고 다음 입력 요청됨:
|
||||||
|
- 새 UNIX username: `jaeoh` 또는 박재오 선호 username (이후 모든 sudo에 사용)
|
||||||
|
- 비밀번호: 박재오가 정하는 값. 잘 기억할 것.
|
||||||
|
|
||||||
|
Expected: `jaeoh@<hostname>:~$` 프롬프트 표시 → WSL2 진입 성공.
|
||||||
|
|
||||||
|
- [ ] **Step 5: WSL 버전 확인**
|
||||||
|
|
||||||
|
WSL2 내부에서 PowerShell로 잠시 돌아와서:
|
||||||
|
```powershell
|
||||||
|
wsl -l -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
```
|
||||||
|
NAME STATE VERSION
|
||||||
|
* Ubuntu-22.04 Running 2
|
||||||
|
```
|
||||||
|
|
||||||
|
VERSION=2 확인. 만약 1이면:
|
||||||
|
```powershell
|
||||||
|
wsl --set-version Ubuntu-22.04 2
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: WSL2 안 진입 (이후 작업)**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl -d Ubuntu-22.04
|
||||||
|
```
|
||||||
|
|
||||||
|
이후 Task 4~7은 모두 WSL2 안 bash에서 실행.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: WSL2 안 Docker Engine 설치 (Docker Desktop 사용 X)
|
||||||
|
|
||||||
|
**Files:** (WSL2 내부) `/etc/apt/keyrings/docker.gpg`, `/etc/apt/sources.list.d/docker.list`
|
||||||
|
|
||||||
|
**위치:** WSL2 Ubuntu-22.04 bash 프롬프트.
|
||||||
|
|
||||||
|
- [ ] **Step 1: 패키지 인덱스 + 기본 의존성 설치**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y ca-certificates curl gnupg lsb-release
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 에러 없이 완료.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Docker apt key 등록**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
|
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 에러 없이 완료. `/etc/apt/keyrings/docker.gpg` 파일 생성.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Docker repository 추가**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
|
sudo apt update
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `Hit:N https://download.docker.com/linux/ubuntu jammy InRelease` 라인 보임.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Docker Engine + Compose 설치**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 설치 완료. 용량 ~400MB.
|
||||||
|
|
||||||
|
- [ ] **Step 5: 현재 사용자를 docker 그룹에 추가**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 출력 없음 (정상). **새 셸 열어야 적용됨.**
|
||||||
|
|
||||||
|
- [ ] **Step 6: Docker 서비스 시작 + 자동 시작 설정**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable docker
|
||||||
|
sudo systemctl start docker
|
||||||
|
sudo systemctl status docker | head -5
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `Active: active (running)`.
|
||||||
|
|
||||||
|
만약 `systemctl: command not found` 또는 systemd 미지원 시:
|
||||||
|
```bash
|
||||||
|
sudo service docker start
|
||||||
|
```
|
||||||
|
|
||||||
|
WSL2 systemd 활성화는 `/etc/wsl.conf`에 `[boot]\nsystemd=true` 추가 후 PowerShell에서 `wsl --shutdown` 후 재진입. (Ubuntu-22.04는 보통 기본 활성)
|
||||||
|
|
||||||
|
- [ ] **Step 7: docker 명령 동작 확인**
|
||||||
|
|
||||||
|
새 셸로 (PowerShell에서 다시 `wsl -d Ubuntu-22.04` 또는 현재 셸 종료 후 재진입):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker version
|
||||||
|
docker run --rm hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- `docker version`: Client + Server 둘 다 표시 (Server에 Engine version)
|
||||||
|
- `hello-world`: "Hello from Docker!" 출력
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 5: WSL2 안 Tailscale 설치 + 가입
|
||||||
|
|
||||||
|
**Files:** Tailscale은 systemd service 등록 (별도 path 신경 안 써도 됨)
|
||||||
|
|
||||||
|
- [ ] **Step 1: Tailscale 설치**
|
||||||
|
|
||||||
|
WSL2 bash:
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://tailscale.com/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 패키지 install 후 "Installation complete!" 출력.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Tailscale 가입 (브라우저 OAuth)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo tailscale up
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `To authenticate, visit: https://login.tailscale.com/a/...` URL 표시.
|
||||||
|
|
||||||
|
브라우저에서 그 URL 열기 → Google/Microsoft/GitHub 등으로 로그인 → 박재오 Tailscale 네트워크에 가입 (기존 계정 없으면 생성).
|
||||||
|
|
||||||
|
- [ ] **Step 3: 가입 완료 확인**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tailscale status
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- 첫 줄에 Windows AI 머신의 100.x.x.x IP 표시
|
||||||
|
- (이미 가입된) NAS도 같은 네트워크에 있다면 NAS의 100.x.x.x IP도 표시
|
||||||
|
|
||||||
|
- [ ] **Step 4: NAS와 Tailscale ping (양방향 사설망 확인)**
|
||||||
|
|
||||||
|
NAS의 Tailscale IP를 `tailscale status` 출력에서 찾아 (예: `100.64.0.10`):
|
||||||
|
```bash
|
||||||
|
tailscale ping 100.64.0.10
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `pong from <NAS hostname>` (직접 LAN 또는 DERP 중계). 만약 NAS가 Tailscale 미가입이면 별도로 NAS DSM Tailscale 패키지 셋업 필요 — 이는 박재오 결정 사항이라 plan 외.
|
||||||
|
|
||||||
|
> **참고:** Tailscale은 spec §3 sense의 사설망 layer 보조. LAN(192.168.45.0/24) 안에서만 작업한다면 Tailscale 없이도 작동. 외부 출장 등에서 NAS↔Windows 통신을 위해 권장.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 6: WSL2 안 NAS SMB 자격증명 파일 + 마운트 포인트 준비
|
||||||
|
|
||||||
|
**Files:** `/etc/nas-smb-credentials`, `/mnt/nas`
|
||||||
|
|
||||||
|
- [ ] **Step 1: cifs-utils 설치 (SMB 마운트 패키지)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install -y cifs-utils
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 설치 완료.
|
||||||
|
|
||||||
|
- [ ] **Step 2: SMB 자격증명 파일 생성**
|
||||||
|
|
||||||
|
박재오 NAS 계정의 username과 password를 사용. 파일 위치는 system-wide `/etc/`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash -c 'cat > /etc/nas-smb-credentials <<EOF
|
||||||
|
username=박재오NAS사용자명
|
||||||
|
password=박재오NAS비밀번호
|
||||||
|
domain=
|
||||||
|
EOF'
|
||||||
|
```
|
||||||
|
|
||||||
|
**위 명령 실행 전 `박재오NAS사용자명` / `박재오NAS비밀번호`를 실제 값으로 교체.** Synology DSM Control Panel → User & Group 에서 SMB 접근 권한 있는 계정 사용. 비밀번호에 특수문자 있을 시 escape 필요 (특히 `!`, `$`, `\`).
|
||||||
|
|
||||||
|
- [ ] **Step 3: 자격증명 파일 권한 보호**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo chmod 600 /etc/nas-smb-credentials
|
||||||
|
sudo chown root:root /etc/nas-smb-credentials
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 출력 없음.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la /etc/nas-smb-credentials
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `-rw------- 1 root root ... /etc/nas-smb-credentials`
|
||||||
|
|
||||||
|
- [ ] **Step 4: 마운트 포인트 생성**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /mnt/nas
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 7: NAS SMB 마운트 (수동 마운트 + fstab 자동화)
|
||||||
|
|
||||||
|
**Files:** `/etc/fstab` (수정)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 수동 마운트 시도 (자격증명·경로 검증)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mount -t cifs //gahusb.synology.me/docker /mnt/nas \
|
||||||
|
-o credentials=/etc/nas-smb-credentials,vers=3.0,uid=1000,gid=1000,_netdev
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 출력 없음 (성공). 만약 `mount error(13)` (permission) → 자격증명 오류. `mount error(2)` (no such file) → share name `docker` 확인.
|
||||||
|
|
||||||
|
> **share name 변형:** 박재오 NAS는 메모리(`feedback_nas_deploy_paths.md`)에 따르면 SMB 매핑이 `/volume1/docker/`를 share `docker`로 노출. 만약 다른 share name(예: `webpage`)이라면 그것으로 교체.
|
||||||
|
|
||||||
|
- [ ] **Step 2: 마운트 결과 확인**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls /mnt/nas/
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `webpage/` 디렉토리 + 다른 share 내 디렉토리 보임.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls /mnt/nas/webpage/data/
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `insta/`, `music/` 등 후속 트랙에서 사용할 디렉토리. 없으면 후속 트랙에서 생성됨.
|
||||||
|
|
||||||
|
- [ ] **Step 3: 마운트 해제 후 fstab으로 자동화**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo umount /mnt/nas
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 출력 없음.
|
||||||
|
|
||||||
|
`/etc/fstab` 끝에 다음 라인 추가:
|
||||||
|
```bash
|
||||||
|
sudo bash -c 'cat >> /etc/fstab <<EOF
|
||||||
|
|
||||||
|
# NAS Synology SMB mount for web-ai-services workers (2026-05-18)
|
||||||
|
//gahusb.synology.me/docker /mnt/nas cifs credentials=/etc/nas-smb-credentials,vers=3.0,uid=1000,gid=1000,_netdev,nofail 0 0
|
||||||
|
EOF'
|
||||||
|
```
|
||||||
|
|
||||||
|
`nofail` 옵션은 부팅 시 NAS 미접속이어도 boot 진행 (production 안전).
|
||||||
|
|
||||||
|
- [ ] **Step 4: fstab 적용 + 검증**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mount -a
|
||||||
|
ls /mnt/nas/webpage/data/ 2>&1 | head -5
|
||||||
|
mount | grep cifs
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- `mount -a` 출력 없음 (성공)
|
||||||
|
- `ls /mnt/nas/webpage/data/` 디렉토리 내용 표시
|
||||||
|
- `mount | grep cifs` 라인에 마운트 정보 보임
|
||||||
|
|
||||||
|
- [ ] **Step 5: WSL2 재시작 시 자동 마운트 확인**
|
||||||
|
|
||||||
|
PowerShell에서 (관리자 권한 불필요):
|
||||||
|
```powershell
|
||||||
|
wsl --shutdown
|
||||||
|
wsl -d Ubuntu-22.04
|
||||||
|
```
|
||||||
|
|
||||||
|
WSL2 다시 진입 후:
|
||||||
|
```bash
|
||||||
|
ls /mnt/nas/webpage/data/
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 정상 디렉토리 목록. 자동 마운트 성공.
|
||||||
|
|
||||||
|
만약 마운트 안 됨:
|
||||||
|
- `dmesg | grep cifs` 확인
|
||||||
|
- `nofail` 때문에 boot은 통과했으나 마운트 실패 가능. 수동 `sudo mount -a` 후 동작 확인 → fstab syntax 재검토
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 8: 통합 검증 — base 인프라 동작 확인
|
||||||
|
|
||||||
|
**Files:** 없음 (검증)
|
||||||
|
|
||||||
|
- [ ] **Step 1: NAS Redis 외부 ping (Windows 로컬에서)**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Windows AI 또는 박재오 PC에서
|
||||||
|
Test-NetConnection -ComputerName 192.168.45.54 -Port 6379
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `TcpTestSucceeded : True`
|
||||||
|
|
||||||
|
> 외부 6379 노출은 LAN 한정. 가능하면 NAS firewall (DSM Control Panel)에서 6379 LAN-only allowed로 한정 권장. (이번 plan에 포함 안 됨, 별도 사용자 작업)
|
||||||
|
|
||||||
|
- [ ] **Step 2: WSL2에서 NAS Redis 접속**
|
||||||
|
|
||||||
|
WSL2 bash:
|
||||||
|
```bash
|
||||||
|
docker run --rm redis:7-alpine redis-cli -h 192.168.45.54 PING
|
||||||
|
```
|
||||||
|
|
||||||
|
또는 Tailscale 사용 시:
|
||||||
|
```bash
|
||||||
|
docker run --rm redis:7-alpine redis-cli -h <NAS_TAILSCALE_IP> PING
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: `PONG`
|
||||||
|
|
||||||
|
- [ ] **Step 3: NAS volume 쓰기 테스트 (Windows→NAS 양방향)**
|
||||||
|
|
||||||
|
WSL2 bash:
|
||||||
|
```bash
|
||||||
|
echo "Plan-B-Base test $(date)" | sudo tee /mnt/nas/webpage/data/.plan-b-test.txt
|
||||||
|
cat /mnt/nas/webpage/data/.plan-b-test.txt
|
||||||
|
sudo rm /mnt/nas/webpage/data/.plan-b-test.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- `tee` 출력에 같은 내용 + 파일 생성됨
|
||||||
|
- `cat` 으로 확인 성공
|
||||||
|
- 파일 삭제 성공
|
||||||
|
|
||||||
|
`sudo` 필요 시 chmod로 uid 1000 쓰기 권한 확인. 또는 mount option `uid=1000,gid=1000` 적용 후 일반 사용자도 쓰기 가능. 만약 안 되면 NAS DSM에서 SMB user의 write 권한 확인.
|
||||||
|
|
||||||
|
- [ ] **Step 4: WSL2 Docker로 hello-world 한 번 더 (재진입 후 상태 확인)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: "Hello from Docker!"
|
||||||
|
|
||||||
|
- [ ] **Step 5: 모든 검증 완료 후 보고 — 후속 트랙으로 진입 가능 상태**
|
||||||
|
|
||||||
|
다음 plan(Plan-B-Insta 등)이 가정하는 상태:
|
||||||
|
- ✅ NAS `redis:6379` PING/PONG 성공
|
||||||
|
- ✅ Windows WSL2 Ubuntu-22.04 작동 + Docker Engine 실행
|
||||||
|
- ✅ `/mnt/nas/webpage/data/` 양방향 read·write 성공
|
||||||
|
- ✅ Tailscale 가입 (선택, 외부 출장 시 필요)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Review
|
||||||
|
|
||||||
|
### Spec 커버리지
|
||||||
|
|
||||||
|
| Spec 요구사항 | 구현 Task |
|
||||||
|
|---------------|-----------|
|
||||||
|
| §4 SP-1: NAS Redis 컨테이너 | Task 1 (compose 추가) + Task 2 (헬스 검증) |
|
||||||
|
| §10 SP-1: redis:7-alpine + 256MB + AOF + healthcheck | Task 1 Step 2 |
|
||||||
|
| §4 SP-2: Windows WSL2 + Docker Engine | Task 3 (WSL2) + Task 4 (Docker) |
|
||||||
|
| §10 SP-2: Tailscale | Task 5 |
|
||||||
|
| §10 SP-2: NAS SMB mount `/mnt/nas` | Task 6 (자격증명·포인트) + Task 7 (마운트+fstab) |
|
||||||
|
| §10 SP-2: 검증 (docker ps, tailscale status, ls /mnt/nas) | Task 8 |
|
||||||
|
| §6 Redis 키 컨벤션 사용 가능 | Task 2 Step 2 (PING) — 컨벤션 자체는 후속 트랙에서 RPUSH로 시작 |
|
||||||
|
|
||||||
|
### Placeholder 스캔
|
||||||
|
|
||||||
|
- TBD/TODO 없음 ✓
|
||||||
|
- 모든 명령어가 그대로 실행 가능한 형태 ✓
|
||||||
|
- 한 가지 예외: Task 6 Step 2 — `박재오NAS사용자명/박재오NAS비밀번호`는 사용자 자격증명이라 placeholder가 의도된 것. 실행 전 교체 명시 ✓
|
||||||
|
- Task 5 Step 4 — `<NAS 의 Tailscale IP>`는 `tailscale status` 출력에서 박재오가 보고 입력. 사용자 환경에서만 결정 가능, plan에 명시 ✓
|
||||||
|
|
||||||
|
### Type/이름 consistency
|
||||||
|
|
||||||
|
- `redis` 서비스명 (Task 1, 2, 8 모두 동일) ✓
|
||||||
|
- `/mnt/nas` 마운트 포인트 (Task 6, 7, 8 모두 동일) ✓
|
||||||
|
- `/etc/nas-smb-credentials` 자격증명 파일 (Task 6, 7 동일) ✓
|
||||||
|
- share name `docker` (Task 7 Step 1, fstab 동일) ✓
|
||||||
|
- Ubuntu-22.04 (Task 3, 4 동일) ✓
|
||||||
|
|
||||||
|
### 위험·주의
|
||||||
|
|
||||||
|
| 위험 | 완화 |
|
||||||
|
|------|------|
|
||||||
|
| Windows 재부팅 시 WSL2 자동 시작 안 함 | 향후 Plan-B-Infra(SP-9)에서 NSSM으로 자동 시작 |
|
||||||
|
| WSL2 systemd 미지원 시 docker service 자동 시작 안 함 | Task 4 Step 6의 fallback `sudo service docker start` 또는 `/etc/wsl.conf` 수정 |
|
||||||
|
| SMB 마운트 자격증명 노출 | `/etc/nas-smb-credentials` chmod 600 + root:root |
|
||||||
|
| NAS firewall에서 6379 외부 노출 | 권장: LAN(192.168.45.0/24) only allow. 본 plan 외 (DSM 수동) |
|
||||||
|
| Tailscale 미가입 시 NAS↔Windows 외부 통신 불가 | LAN 내에선 작동. 외부 출장 시 필요할 때만 가입 |
|
||||||
|
| /mnt/nas 쓰기 권한 부족 | uid=1000 mount option + NAS DSM에서 SMB user의 share write 권한 확인 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 완료 후 다음 단계
|
||||||
|
|
||||||
|
Plan-B-Base 완료 후 spec §14 권장 순서대로:
|
||||||
|
|
||||||
|
1. **Plan-B-Insta** — SP-3 (insta-render Windows worker) + SP-4 (NAS insta-lab 분할)
|
||||||
|
2. **Plan-B-Music** — SP-5 + SP-6
|
||||||
|
3. **Plan-B-Video** — SP-7 + SP-8
|
||||||
|
4. **Plan-B-Infra** — SP-9 (NSSM 자동 시작) + SP-10 (task-watcher)
|
||||||
|
|
||||||
|
각 후속 plan은 본 plan이 제공한 base 인프라(Redis + WSL2/Docker + /mnt/nas)에 의존.
|
||||||
Reference in New Issue
Block a user