Skip to content

Commit ea62d22

Browse files
committed
feat: 프로덕션 배포 자동화 시스템 구축
octodocs.site 도메인으로 최소한의 커맨드로 배포 가능하도록 구성 주요 변경사항: - compose.deploy.yml 추가: 자체 완결형 프로덕션 배포 설정 - SSL 자동 발급: Let's Encrypt 인증서 자동 발급 스크립트 - 프로덕션 nginx 설정: octodocs.site 도메인 전용 설정 - Dockerfile 개선: Backend/WebSocket 실행 구조 일관성 개선 - Healthcheck 추가: 서비스 간 의존성 관리 개선 배포 명령어: - yarn deploy:init # SSL 인증서 발급 - yarn deploy # 프로덕션 배포 - yarn deploy:logs # 로그 확인 기술 스택: - Docker Compose (자체 완결형) - PostgreSQL + Redis (컨테이너) - Let's Encrypt (SSL 자동 발급/갱신) - Nginx (리버스 프록시)
1 parent 15781ae commit ea62d22

File tree

7 files changed

+386
-12
lines changed

7 files changed

+386
-12
lines changed

compose.deploy.yml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
version: "3.8"
2+
3+
# OctoDocs 프로덕션 배포용 Docker Compose
4+
# compose.local.yml 기반, octodocs.site 도메인 사용
5+
6+
services:
7+
postgres:
8+
image: postgres:16-alpine
9+
environment:
10+
POSTGRES_USER: ${DB_USER}
11+
POSTGRES_PASSWORD: ${DB_PASSWORD}
12+
POSTGRES_DB: ${DB_NAME}
13+
volumes:
14+
- postgres_data:/var/lib/postgresql/data
15+
networks:
16+
- net
17+
healthcheck:
18+
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
19+
interval: 10s
20+
timeout: 5s
21+
retries: 5
22+
restart: always
23+
24+
redis:
25+
image: redis:latest
26+
environment:
27+
REDIS_HOST: ${REDIS_HOST}
28+
REDIS_PORT: ${REDIS_PORT}
29+
networks:
30+
- net
31+
healthcheck:
32+
test: ["CMD", "redis-cli", "ping"]
33+
interval: 30s
34+
retries: 3
35+
start_period: 10s
36+
timeout: 5s
37+
restart: always
38+
39+
backend:
40+
build:
41+
context: .
42+
dockerfile: ./services/backend/Dockerfile.local
43+
image: backend:latest
44+
env_file:
45+
- .env.deploy
46+
volumes:
47+
- .env.deploy:/app/.env
48+
# 소스 코드 마운트
49+
- ./apps/backend:/app/apps/backend
50+
- ./apps/frontend:/app/apps/frontend
51+
# 의존성 캐시를 위한 볼륨
52+
- backend_node_modules:/app/node_modules
53+
- backend_app_node_modules:/app/apps/backend/node_modules
54+
- frontend_app_node_modules:/app/apps/frontend/node_modules
55+
depends_on:
56+
postgres:
57+
condition: service_healthy
58+
redis:
59+
condition: service_healthy
60+
networks:
61+
- net
62+
expose:
63+
- "5173"
64+
- "3000"
65+
healthcheck:
66+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
67+
interval: 10s
68+
timeout: 5s
69+
retries: 5
70+
start_period: 30s
71+
restart: always
72+
73+
websocket:
74+
build:
75+
context: .
76+
dockerfile: ./services/websocket/Dockerfile.local
77+
image: websocket:latest
78+
env_file:
79+
- .env.deploy
80+
volumes:
81+
- .env.deploy:/app/.env
82+
# 소스 코드 마운트
83+
- ./apps/websocket:/app/apps/websocket
84+
# 의존성 캐시를 위한 볼륨
85+
- websocket_node_modules:/app/node_modules
86+
- websocket_app_node_modules:/app/apps/websocket/node_modules
87+
depends_on:
88+
postgres:
89+
condition: service_healthy
90+
redis:
91+
condition: service_healthy
92+
networks:
93+
- net
94+
expose:
95+
- "4242"
96+
healthcheck:
97+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4242/health"]
98+
interval: 10s
99+
timeout: 5s
100+
retries: 5
101+
start_period: 30s
102+
restart: always
103+
104+
nginx:
105+
build:
106+
context: .
107+
dockerfile: ./services/nginx/Dockerfile.local
108+
ports:
109+
- "80:80"
110+
- "443:443"
111+
depends_on:
112+
backend:
113+
condition: service_healthy
114+
websocket:
115+
condition: service_healthy
116+
networks:
117+
- net
118+
volumes:
119+
# Let's Encrypt 인증서 마운트
120+
- ./data/certbot/conf:/etc/letsencrypt:ro
121+
- ./data/certbot/www:/var/www/certbot:ro
122+
# 프로덕션 nginx 설정 사용
123+
- ./services/nginx/conf.d/default.deploy.conf:/etc/nginx/conf.d/default.conf:ro
124+
restart: always
125+
126+
# SSL 인증서 자동 갱신
127+
certbot-renewer:
128+
image: certbot/certbot:latest
129+
volumes:
130+
- ./data/certbot/conf:/etc/letsencrypt
131+
- ./data/certbot/www:/var/www/certbot
132+
- ./data/certbot/log:/var/log/letsencrypt
133+
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot --webroot-path=/var/www/certbot; sleep 12h & wait $${!}; done;'"
134+
restart: always
135+
136+
networks:
137+
net:
138+
139+
volumes:
140+
postgres_data:
141+
backend_node_modules:
142+
backend_app_node_modules:
143+
frontend_app_node_modules:
144+
websocket_node_modules:
145+
websocket_app_node_modules:

compose.local.yml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ services:
6161
ports:
6262
- "5173:5173" # Vite dev server
6363
- "3000:3000" # 백엔드 API 포트
64+
healthcheck:
65+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
66+
interval: 10s
67+
timeout: 5s
68+
retries: 5
69+
start_period: 30s
6470

6571
websocket:
6672
build:
@@ -85,6 +91,12 @@ services:
8591
- net
8692
ports:
8793
- "4242:4242" # WebSocket 포트
94+
healthcheck:
95+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4242/health"]
96+
interval: 10s
97+
timeout: 5s
98+
retries: 5
99+
start_period: 30s
88100

89101
nginx:
90102
build:
@@ -94,8 +106,10 @@ services:
94106
- "80:80"
95107
- "443:443"
96108
depends_on:
97-
- backend
98-
- websocket
109+
backend:
110+
condition: service_healthy
111+
websocket:
112+
condition: service_healthy
99113
networks:
100114
- net
101115
volumes:

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
"docker:dev:down": "docker compose -f compose.local.yml down",
1818
"docker:dev:clean": "docker compose -v -f compose.local.yml down",
1919
"docker:dev:fclean": "docker compose -v -f compose.local.yml down --rmi all",
20-
"ssl:generate": "cd services/nginx/ssl && bash ./generate-cert.sh"
20+
"ssl:generate": "cd services/nginx/ssl && bash ./generate-cert.sh",
21+
"deploy:init": "bash scripts/deploy-init.sh",
22+
"deploy": "docker compose -f compose.deploy.yml up -d --build",
23+
"deploy:down": "docker compose -f compose.deploy.yml down",
24+
"deploy:logs": "docker compose -f compose.deploy.yml logs -f",
25+
"deploy:restart": "docker compose -f compose.deploy.yml restart",
26+
"deploy:clean": "docker compose -v -f compose.deploy.yml down"
2127
},
2228
"dependencies": {
2329
"turbo": "^2.3.0"

scripts/deploy-init.sh

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/bin/bash
2+
3+
# OctoDocs 프로덕션 배포 초기화 스크립트
4+
# Let's Encrypt SSL 인증서 자동 발급
5+
6+
set -e
7+
8+
echo "🚀 OctoDocs 프로덕션 배포 초기화 시작..."
9+
echo ""
10+
11+
# 프로젝트 루트 디렉토리로 이동
12+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
13+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
14+
cd "$PROJECT_ROOT"
15+
16+
# .env.deploy 파일 확인
17+
if [ ! -f .env.deploy ]; then
18+
echo "❌ .env.deploy 파일이 없습니다."
19+
exit 1
20+
fi
21+
22+
echo "✅ .env.deploy 파일 확인 완료"
23+
24+
# certbot 데이터 디렉토리 생성
25+
mkdir -p data/certbot/conf
26+
mkdir -p data/certbot/www
27+
mkdir -p data/certbot/log
28+
29+
echo "✅ certbot 디렉토리 생성 완료"
30+
31+
# 도메인 설정
32+
DOMAIN="octodocs.site"
33+
34+
35+
echo ""
36+
echo "📋 SSL 인증서 발급 정보:"
37+
echo " 도메인: $DOMAIN, www.$DOMAIN"
38+
echo " 이메일: $EMAIL"
39+
echo ""
40+
41+
# 기존 인증서 확인
42+
if [ -d "data/certbot/conf/live/$DOMAIN" ]; then
43+
echo "⚠️ 기존 인증서가 존재합니다."
44+
read -p "기존 인증서를 삭제하고 재발급하시겠습니까? (y/N): " -n 1 -r
45+
echo
46+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
47+
echo "✅ 기존 인증서를 유지합니다."
48+
exit 0
49+
fi
50+
echo "🗑️ 기존 인증서 삭제 중..."
51+
rm -rf data/certbot/conf/live/$DOMAIN
52+
rm -rf data/certbot/conf/archive/$DOMAIN
53+
rm -rf data/certbot/conf/renewal/$DOMAIN.conf
54+
fi
55+
56+
# compose.init.yml을 사용하여 certbot 실행
57+
echo ""
58+
echo "🔐 Let's Encrypt SSL 인증서 발급 중..."
59+
echo " (약 1-2분 소요됩니다)"
60+
echo ""
61+
62+
docker compose -f compose.init.yml up certbot
63+
64+
# 발급 결과 확인
65+
if [ -d "data/certbot/conf/live/$DOMAIN" ]; then
66+
echo ""
67+
echo "✅ SSL 인증서 발급 완료!"
68+
echo ""
69+
echo "📂 인증서 위치:"
70+
echo " - 인증서: data/certbot/conf/live/$DOMAIN/fullchain.pem"
71+
echo " - 개인키: data/certbot/conf/live/$DOMAIN/privkey.pem"
72+
echo ""
73+
echo "🎉 이제 'yarn deploy' 명령어로 배포할 수 있습니다!"
74+
else
75+
echo ""
76+
echo "❌ SSL 인증서 발급 실패"
77+
echo ""
78+
echo "💡 다음 사항을 확인해주세요:"
79+
echo " 1. 도메인 DNS가 이 서버 IP를 가리키는지 확인"
80+
echo " 2. 80번 포트가 열려있는지 확인"
81+
echo " 3. 방화벽 설정 확인"
82+
echo ""
83+
echo "📝 로그 확인: data/certbot/log/"
84+
exit 1
85+
fi
86+
87+
# compose.init.yml 정리
88+
docker compose -f compose.init.yml down
89+
90+
echo ""
91+
echo "✅ 초기화 완료!"

services/backend/Dockerfile.local

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ RUN yarn install
1515

1616
EXPOSE 3000
1717

18-
# 개발 모드로 실행
18+
# Backend만 개발 모드로 실행
19+
WORKDIR /app/apps/backend
1920
CMD ["yarn", "dev"]

0 commit comments

Comments
 (0)