# Auto-Stock NAS 배포 가이드 (Synology DS1517) ## 환경 정보 - NAS: Synology DS1517+ (16GB RAM) - OS: DSM 7.x (Linux 3.10.108, x86_64) - Docker: 24.0.2 - Docker Compose: v2.20.1 (호스트) / v2.20.3 (Jenkins 내부) - Cloudflare Tunnel 사용 중 --- ## 1. 디렉토리 구조 ``` /volume1/docker/ ├── autostock/ # 앱 배포 디렉토리 │ ├── .env # 환경변수 (Git에 없음, 수동 관리) │ ├── docker-compose.yml │ ├── docker/ │ ├── backend/ │ ├── mcp-server/ │ ├── frontend/ │ ├── logs/ │ └── backups/ ├── gitea/ # Gitea 데이터 ├── jenkins/ # Jenkins 데이터 └── cicd/ # CI/CD 인프라 설정 ``` --- ## 2. 초기 설정 ### 2.1 디렉토리 생성 ```bash sudo mkdir -p /volume1/docker/autostock sudo mkdir -p /volume1/docker/gitea sudo mkdir -p /volume1/docker/jenkins sudo chown -R shuim:users /volume1/docker/autostock /volume1/docker/gitea sudo chown -R 1000:1000 /volume1/docker/jenkins ``` ### 2.2 Gitea 설치 ```bash docker run -d --name gitea --restart unless-stopped -p 23000:3000 -v /volume1/docker/gitea:/data -e TZ=Asia/Seoul -e "GITEA__server__ROOT_URL=https://gitea.shium.net" gitea/gitea:latest ``` - Cloudflare Tunnel: `gitea.shium.net:443 → localhost:23000` - 초기 설정: https://gitea.shium.net 접속 → SQLite3 선택 → 관리자 생성 - 저장소 생성: `auto-stock` (Private) ### 2.3 Jenkins 설치 ```bash docker run -d --name jenkins --restart unless-stopped -p 21080:8080 -p 21000:50000 -v /volume1/docker/jenkins:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v /volume1/docker/autostock:/volume1/docker/autostock -e TZ=Asia/Seoul -e JAVA_OPTS="-Xmx512m -Xms256m" --user root jenkins/jenkins:lts-jdk17 ``` **중요**: `-v /volume1/docker/autostock:/volume1/docker/autostock` 마운트 필수 (Jenkins에서 배포 디렉토리 접근) 초기 비밀번호 확인: ```bash docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword ``` ### 2.4 Jenkins 컨테이너 내부 도구 설치 **Python3 + rsync + curl:** ```bash docker exec -u root jenkins bash -c "apt-get update && apt-get install -y python3 rsync curl" ``` - `systemd` 관련 에러 발생하지만 무시 가능 (Python3는 정상 설치됨) **Docker CLI (바이너리 직접 설치):** ```bash docker exec -u root jenkins bash -c "curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz -o /tmp/docker.tgz && tar xz -C /tmp -f /tmp/docker.tgz && cp /tmp/docker/docker /usr/local/bin/docker && chmod +x /usr/local/bin/docker && rm -rf /tmp/docker /tmp/docker.tgz && docker --version" ``` - `docker.io` apt 패키지는 Synology 커널과 호환되지 않음 (systemd 의존성 충돌) - 바이너리 직접 설치로 해결 **Docker Compose (독립 바이너리):** ```bash docker exec -u root jenkins bash -c "curl -fsSL -o /tmp/dc https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-linux-x86_64 && mv /tmp/dc /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose && docker-compose version" ``` - NAS 호스트의 `docker-compose`를 `docker cp`로 복사하면 GLIBC 버전 불일치 발생 - GitHub에서 독립 바이너리 다운로드로 해결 - `curl -o /usr/local/bin/docker-compose` 직접 쓰면 `client returned ERROR on write` 발생 → `/tmp/dc`에 먼저 받고 `mv`로 해결 **Docker 소켓 권한:** ```bash docker exec -u root jenkins bash -c "chmod 666 /var/run/docker.sock" ``` ### 2.5 설치 검증 ```bash docker exec jenkins bash -c "python3 --version && docker --version && docker-compose version" ``` 예상 출력: ``` Python 3.13.x Docker version 24.0.7, build afdd53b Docker Compose version v2.20.3 ``` --- ## 3. Jenkins 파이프라인 설정 ### 3.1 Pipeline 프로젝트 생성 1. Jenkins 대시보드 → **+ 새로운 Item** 2. 이름: `auto-stock`, 타입: **Pipeline** → OK ### 3.2 Pipeline 설정 (구성 페이지) 1. Pipeline 섹션 → Definition: **Pipeline script from SCM** 2. SCM: **Git** 3. Repository URL: `https://gitea.shium.net/shuim/auto-stock.git` 4. Credentials: **Add** → Username/Password (Gitea 계정) 5. Branch: `*/main` 6. Script Path: `Jenkinsfile` 7. **Lightweight checkout: 반드시 체크 해제** (체크 시 `fatal: not in a git directory` 에러) 8. 저장 ### 3.3 Gitea Webhook (자동 빌드) Gitea 저장소 → Settings → Webhooks → Add Webhook: - URL: `http://localhost:21080/gitea-webhook/post` - Content Type: `application/json` - Trigger: Push Events --- ## 4. 로컬 Git 설정 ```bash cd /Users/commylife/myproject/java/workspace/auto-stock git remote add nas https://gitea.shium.net/shuim/auto-stock.git git push nas main ``` 배포 흐름: ``` 로컬 코드 수정 → git push nas main → Jenkins 자동 빌드 → NAS 배포 ``` --- ## 5. .env 설정 `/volume1/docker/autostock/.env` 파일을 수동 생성하고 비밀번호를 설정: ```bash # NAS SSH 접속 후 nano /volume1/docker/autostock/.env ``` 필수 변경 항목: - `POSTGRES_PASSWORD`: 강력한 비밀번호 - `REDIS_PASSWORD`: 강력한 비밀번호 - `SECRET_KEY`: 64자 이상 랜덤 문자열 - `API_KEY`, `MCP_API_KEY`: API 인증키 - `ANTHROPIC_API_KEY`: Claude API 키 - `KIS_*`: 한국투자증권 API 키 - `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`: 텔레그램 알림 --- ## 6. 수동 첫 배포 Jenkins 파이프라인이 .env 부재로 실패할 경우: ```bash cd /volume1/docker/autostock # .env 파일이 준비된 상태에서 docker-compose up -d ``` --- ## 7. 트러블슈팅 ### 에러: `python3: not found` **원인**: Jenkins 컨테이너에 Python 미설치 **해결**: ```bash docker exec -u root jenkins bash -c "apt-get update && apt-get install -y python3" ``` ### 에러: `docker.io` 설치 시 systemd dpkg 에러 **원인**: Synology 커널(3.10.108)이 최신 systemd와 호환되지 않음 **해결**: `docker.io` 패키지 대신 Docker CLI 바이너리 직접 설치 ```bash docker exec -u root jenkins bash -c "curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz -o /tmp/docker.tgz && tar xz -C /tmp -f /tmp/docker.tgz && cp /tmp/docker/docker /usr/local/bin/docker && chmod +x /usr/local/bin/docker && rm -rf /tmp/docker /tmp/docker.tgz" ``` ### 에러: `unknown shorthand flag: 'f' in -f` (docker compose) **원인**: Jenkins 내부 Docker CLI에 `compose` 플러그인이 없음. `docker compose`(v2 플러그인)가 아닌 `docker-compose`(독립 바이너리) 사용 필요 **해결**: docker-compose 독립 바이너리 설치 (섹션 2.4 참조) ### 에러: `docker-compose: not found` **원인**: NAS 호스트의 docker-compose를 `docker cp`로 복사하면 GLIBC 버전 불일치 **해결**: GitHub에서 독립 바이너리 직접 다운로드 ```bash docker exec -u root jenkins bash -c "curl -fsSL -o /tmp/dc https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-linux-x86_64 && mv /tmp/dc /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose" ``` ### 에러: `curl: (23) client returned ERROR on write of 1369 bytes` **원인**: `/usr/local/bin/`에 직접 쓸 때 권한/공간 문제 **해결**: `/tmp`에 먼저 다운로드 후 `mv`로 이동 ### 에러: `fatal: not in a git directory` **원인**: Pipeline 설정에서 **Lightweight checkout**이 활성화되어 있으면 git workspace 없이 Jenkinsfile을 읽으려 함 **해결**: Pipeline 구성 → **Lightweight checkout 체크 해제** → 저장 ### 에러: `mkdir: cannot create directory '/volume1': Permission denied` **원인**: Jenkins 컨테이너에 NAS 볼륨이 마운트되지 않음 **해결**: Jenkins 컨테이너 재생성 시 `-v /volume1/docker/autostock:/volume1/docker/autostock` 볼륨 마운트 추가 ### 에러: Gitea 500 Internal Server Error **원인**: 이전 설정 데이터가 꼬진 상태 **해결**: ```bash docker rm -f gitea sudo rm -rf /volume1/docker/gitea/* # 다시 docker run으로 재생성 ``` ### 에러: `git push nas main` → `Failed to connect to port 3001` **원인**: Cloudflare Tunnel 사용 시 직접 포트 접근 불가 **해결**: HTTPS URL 사용 ```bash git remote remove nas git remote add nas https://gitea.shium.net/shuim/auto-stock.git git push nas main ``` --- ## 8. Jenkins 컨테이너 재시작 후 복구 Jenkins 컨테이너가 재시작되면 바이너리 설치된 Docker CLI와 docker-compose가 유지됩니다 (볼륨 아님, 컨테이너 레이어에 저장). 단, 컨테이너를 **삭제 후 재생성**하면 재설치 필요: ```bash # 전체 재설치 (컨테이너 삭제 후 재생성 시) docker exec -u root jenkins bash -c "apt-get update && apt-get install -y python3 rsync curl && curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz -o /tmp/docker.tgz && tar xz -C /tmp -f /tmp/docker.tgz && cp /tmp/docker/docker /usr/local/bin/docker && chmod +x /usr/local/bin/docker && rm -rf /tmp/docker /tmp/docker.tgz && curl -fsSL -o /tmp/dc https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-linux-x86_64 && mv /tmp/dc /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose && chmod 666 /var/run/docker.sock" ``` --- ## 9. 메모리 배분 (docker-compose.yml) | 서비스 | 메모리 제한 | |--------|-----------| | PostgreSQL | 1GB | | Backend | 768MB | | RabbitMQ | 512MB | | Redis | 256MB (maxmemory 200MB) | | MCP Server | 256MB | | Frontend (Nginx) | 64MB | | Gitea | ~200MB | | Jenkins | ~1GB (빌드 시) | | **합계** | ~4.1GB / 16GB | --- ## 10. Cloudflare Tunnel 라우팅 | 도메인 | 포트 | 용도 | |--------|------|------| | gitea.shium.net:443 | localhost:23000 | Gitea (Git 웹 UI) | | jenkins.shium.net:443 | localhost:21080 | Jenkins (CI/CD) | | stock.shium.net:443 | localhost:3000 | Frontend | | stock.shium.net/api | localhost:8000 | Backend API | --- *마지막 업데이트: 2026-03-27*