Files

9.0 KiB

UGREEN NAS 운영 배포 안내

운영 원칙

  • 기능 테스트는 개발 Mac에서 수행한다.
  • NAS에는 운영 컨테이너만 실행한다.
  • 로컬 빌드와 Docker 검증을 통과한 커밋만 NAS에 배포한다.
  • NAS에서 소스 코드를 직접 수정하지 않는다.
  • 운영 주소는 현재 http://playuniare.sori.studio다.
  • HTTPS는 인증서와 리버스 프록시 구성이 완료된 뒤 전환한다.

현재 프로젝트는 Vue 정적 프런트엔드와 Node.js Socket.IO 서버를 같은 Compose 프로젝트로 배포한다.

배포 구조

사용자 브라우저
    ↓
http://playuniare.sori.studio
    ↓
NAS 리버스 프록시
    ↓
127.0.0.1:41809
    ↓
Play Uniare Nginx 컨테이너
    ├── /              → Vue 빌드 결과
    ├── /card-assets/  → 기존 Uniare 카드 이미지
    └── /socket.io/    → Docker 내부 playuniare-server:31873

31873은 Docker 내부 통신에만 사용하며 NAS 호스트에는 공개하지 않는다. 외부에서는 웹 주소와 같은 http://playuniare.sori.studio/socket.io 경로로 접속한다.

카드 이미지는 복사하지 않고 다음 폴더를 읽기 전용으로 연결한다.

/volume1/docker/projects/apps/uniare/config/www/images

로컬 배포 전 검증

개발 Mac의 프로젝트 폴더에서 실행한다.

npm install
npm run build
docker compose build

필요하면 로컬 Docker 컨테이너도 실행한다.

docker compose up -d

브라우저에서 다음 주소를 확인한다.

http://localhost:41809

로컬 Mac에는 NAS 카드 폴더가 없으므로 /card-assets 확인은 NAS 배포 후 수행한다.

검증이 끝나면 로컬 컨테이너를 종료한다.

docker compose down

NAS 최초 설치

1. SSH로 NAS 접속

개발 Mac 터미널에서 실행한다.

ssh NAS사용자명@192.168.50.146

실제 SSH 사용자명은 NAS 설정에 맞게 사용한다.

2. 저장소 복제

NAS 터미널에서 실행한다.

cd /volume1/docker/projects/apps
git clone https://git.sori.studio/zenn/playuniare.sori.studio.git playuniare
cd playuniare

비공개 저장소가 인증을 요구하면 Git 서버의 접근 토큰을 사용한다. 토큰을 문서나 .env에 저장하지 않는다.

3. NAS 환경변수 파일 생성

cp .env.example .env

기본 내용:

PLAYUNIARE_PRODUCTION_HTTP_PORT=41809
VITE_CARD_ASSET_BASE_URL=/card-assets

운영 Socket.IO 컨테이너는 내부 포트 31873을 사용한다. 브라우저는 현재 도메인의 /socket.io를 사용하므로 별도 공개 Socket.IO 주소가 필요하지 않다.

4. 포트 사용 여부 확인

docker ps --format "table {{.Names}}\t{{.Ports}}"

41809가 이미 사용 중이면 .env의 값을 다른 포트로 바꾼다.

PLAYUNIARE_PRODUCTION_HTTP_PORT=41819

이 경우 리버스 프록시 대상 포트도 같은 값으로 변경해야 한다.

5. 운영 컨테이너 실행

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  up -d --build

상태 확인:

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  ps

playuniare-web과 playuniare-server가 모두 healthy 또는 running이면 정상이다.

6. 리버스 프록시 연결

현재 연결 기준:

외부 주소: http://playuniare.sori.studio
내부 대상: http://127.0.0.1:41809

.env에서 포트를 변경했다면 내부 대상 포트도 변경한다.

7. 배포 확인

메인 화면:

http://playuniare.sori.studio

카드 이미지:

http://playuniare.sori.studio/card-assets/ua01/EX02BT_CGH-2-007.png

두 주소가 모두 열리면 정적 배포와 카드 자산 연결은 정상이다. 추가로 서로 다른 브라우저 또는 시크릿 창 두 개를 열어 한쪽에서 방을 만들고 다른 쪽에서 코드로 참가해 실시간 연결을 확인한다.

새 버전 업데이트

개발 Mac

  1. 기능을 구현한다.
  2. 관련 문서를 수정한다.
  3. npm run build를 실행한다.
  4. 필요한 경우 로컬 Docker로 검증한다.
  5. Git에 커밋하고 푸시한다.

NAS

cd /volume1/docker/projects/apps/playuniare
git pull

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  up -d --build

배포 후 반드시 확인한다.

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  ps

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  logs --tail=100

마지막으로 실제 도메인에서 메인 화면과 주요 기능을 확인한다.

기존 NAS 테스트 컨테이너 제거

이전에 playuniare-test-web을 실행했다면 한 번만 정리한다.

docker rm -f playuniare-test-web

컨테이너가 없다는 메시지가 나오면 이미 제거된 것이므로 무시해도 된다.

테스트용 Docker 네트워크가 남아 있다면 확인 후 제거한다.

docker network ls
docker network rm playuniare-test_default

네트워크가 사용 중이거나 존재하지 않으면 무리하게 삭제하지 않는다.

이전 버전으로 되돌리기

최근 커밋 확인:

git log --oneline -10

정상 동작했던 커밋으로 전환:

git checkout 정상커밋식별자

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  up -d --build

복구 후 개발 Mac에서 문제를 수정해 새로운 커밋을 만든다. 다시 최신 main으로 돌아갈 때:

git checkout main
git pull

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  up -d --build

운영 점검 명령

상태:

docker compose -f compose.yaml -f compose.nas.yaml ps

최근 로그:

docker compose -f compose.yaml -f compose.nas.yaml logs --tail=100

재시작:

docker compose -f compose.yaml -f compose.nas.yaml restart

중지 및 제거:

docker compose -f compose.yaml -f compose.nas.yaml down

포트 충돌

다음 오류는 NAS 호스트 포트가 다른 서비스에 사용 중이라는 뜻이다.

Bind for 0.0.0.0:<포트> failed: port is already allocated

사용 중인 포트 확인:

docker ps --format "table {{.Names}}\t{{.Ports}}"

.env의 PLAYUNIARE_PRODUCTION_HTTP_PORT를 사용하지 않는 숫자로 변경하고 다시 실행한다. 컨테이너 내부의 80 포트는 다른 컨테이너와 같아도 괜찮다.

카드 이미지가 403인 경우

로그에 다음 내용이 있으면 NAS ACL에 의한 읽기 권한 문제다.

open() "/srv/uniare-card-images/..." failed (13: Permission denied)

현재 이미지는 카드 파일 소유자 UID 1000과 맞춘 cardreader 사용자를 사용한다. 최신 소스를 받고 반드시 이미지를 다시 빌드한다.

git pull
docker compose -f compose.yaml -f compose.nas.yaml up -d --build

Nginx 워커 확인:

docker exec playuniare-web ps aux

nginx: worker process가 cardreader로 표시되어야 한다.

카드 읽기 확인:

docker exec playuniare-web \
  su -s /bin/sh cardreader -c \
  'head -c 10 /srv/uniare-card-images/ua01/EX02BT_CGH-2-007.png >/dev/null && echo READ_OK'

데이터 마이그레이션

현재는 데이터베이스가 없으므로 마이그레이션할 데이터도 없다. 방 상태 저장, 사용자 계정 또는 덱 저장 데이터베이스가 추가되면 docs/migrations.md의 원칙을 따른다.

NAS에서 SQL이나 임시 명령을 직접 입력하는 방식은 초기에는 빠르지만, 같은 변경을 다시 재현하거나 복구하기 어렵다. 운영 데이터가 생긴 뒤에는 반드시 Git에 포함된 버전 관리 마이그레이션 코드를 실행하는 방식으로 전환한다.

배포 체크리스트

  • 로컬 npm run build 성공
  • 필요한 로컬 Docker 검증 성공
  • 관련 문서 업데이트
  • Git 커밋과 푸시 완료
  • NAS git pull 완료
  • 운영 컨테이너 재빌드
  • 컨테이너 상태와 로그 확인
  • http://playuniare.sori.studio 확인
  • /card-assets/<series>/<fileName> 확인
  • 두 브라우저의 방 생성·참가와 준비 상태 동기화 확인
  • .env, 토큰, 비밀번호가 Git에 없는지 확인

실시간 서버 구조

브라우저에 Socket.IO 서버 포트를 직접 공개하지 않는다.

브라우저
  → http://playuniare.sori.studio/socket.io
  → Play Uniare Nginx
  → Docker 내부 Socket.IO 서버:31873

Docker 내부에서는 다른 컨테이너와 같은 포트를 사용해도 충돌하지 않는다. Socket.IO 서비스는 ports 대신 내부 통신용 expose를 사용한다.

실시간 서버 로그만 확인하려면 다음 명령을 사용한다.

docker compose \
  -f compose.yaml \
  -f compose.nas.yaml \
  logs --tail=100 playuniare-server

현재 방 상태는 서버 메모리에만 저장된다. playuniare-server를 재시작하거나 재배포하면 진행 중인 방은 종료되므로, 이용자가 없는 시간에 업데이트한다.