배포
이 가이드는 ASAPJS 애플리케이션을 프로덕션 환경에 배포하기 위한 과정을 설명합니다. 빌드부터 환경 변수 설정, 프로세스 관리, Docker 컨테이너화까지 다룹니다.
프로덕션 빌드
ASAPJS는 모노레포 구조이므로, 의존 패키지를 먼저 빌드한 뒤 애플리케이션을 빌드해야 합니다.
# 1. 모든 패키지 빌드 (core → router + sequelize + socket)
yarn build:packages
# 2. 애플리케이션 빌드 (example 또는 프로젝트)
cd example && yarn build빌드 순서는 패키지 간 의존성에 의해 결정됩니다:
@asapjs/core (의존성 없음)
↓
@asapjs/router + @asapjs/sequelize + @asapjs/socket (core에 의존, 병렬 빌드 가능)
↓
example (모든 패키지에 의존)Tip:
yarn build:packages는 Lerna가 의존성 순서를 자동으로 해결하여 올바른 순서로 빌드합니다.
환경 변수 설정
프로덕션 환경에서는 .env 파일 또는 시스템 환경 변수를 통해 설정을 주입합니다.
# .env (production)
NODE_ENV=production
PORT=3000
# JWT
JWT_SECRET=your-production-secret-key
# Database
DB_HOST=your-db-host.com
DB_PORT=3306
DB_NAME=production_db
DB_USER=app_user
DB_PASSWORD=secure-password
# Optional: DB Sync (첫 배포 시에만 사용)
DB_SYNC=false애플리케이션 진입점에서 dotenv를 사용하여 환경 변수를 로드합니다:
// src/index.ts
import 'reflect-metadata';
import dotenv from 'dotenv';
import { Application } from '@asapjs/core';
import { getSequelize } from '@asapjs/sequelize';
dotenv.config();
const config = {
name: 'My ASAPJS App',
port: Number(process.env.PORT) || 3000,
basePath: 'api',
extensions: ['@asapjs/sequelize'],
auth: {
jwt_access_token_secret: process.env.JWT_SECRET || 'change-me',
},
db: {
username: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'myapp',
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '3306', 10),
dialect: 'mysql',
logging: false,
timezone: '+09:00',
pool: {
max: 10,
idle: 30000,
acquire: 60000,
},
},
};
const app = new Application(__dirname, config);
app.run(async () => {
const sequelize = await getSequelize();
if (process.env.DB_SYNC === 'true') {
await sequelize.sync({ alter: true });
}
console.log(`Server running on port ${config.port}`);
});주의:
DB_SYNC=true는 개발 환경에서만 사용하세요. 프로덕션에서는 마이그레이션 도구를 사용하거나, 최초 배포 시에만 한 번 실행하세요.
데이터베이스 마이그레이션
DB Sync (개발/초기 배포)
Application.run() 콜백에서 Sequelize sync()을 호출하여 테이블을 생성할 수 있습니다:
// packages/core/src/Application.ts 내부의 run() 메서드에서 호출
app.run(async () => {
const sequelize = await getSequelize();
await sequelize.sync({ alter: true }); // 기존 테이블 구조를 변경 사항에 맞게 수정
});ASAPJS example 앱은 별도의 스크립트도 제공합니다:
# DB 테이블 동기화
cd example && yarn db:sync
# 시드 데이터 입력
cd example && yarn db:seed
# 리셋 (동기화 + 시드)
cd example && yarn db:reset헬스체크
RouterModule은 자동으로 /health-check 엔드포인트를 등록합니다. 이 엔드포인트는 SELECT 1 쿼리를 실행하여 DB 연결 상태를 확인합니다.
// packages/router/src/router/index.ts 에서 자동 등록
this.app.get('/health-check', Wrapper(async ({ req, res }) => {
await healthCheck(); // SELECT 1 쿼리로 DB 연결 확인
res.send(`${this.config.name} server is working`);
}));curl http://localhost:3000/health-check
# => "My ASAPJS App server is working"프로세스 관리 (PM2)
프로덕션에서는 PM2 같은 프로세스 관리자를 사용하여 애플리케이션을 관리합니다.
# PM2 설치
npm install -g pm2
# 빌드된 JS 파일로 시작
pm2 start dist/index.js --name "asapjs-app"
# 클러스터 모드 (CPU 코어 수만큼 인스턴스 실행)
pm2 start dist/index.js --name "asapjs-app" -i max
# 로그 확인
pm2 logs asapjs-app
# 재시작
pm2 restart asapjs-app
# 시스템 부팅 시 자동 시작
pm2 startup
pm2 savePM2 설정 파일 (ecosystem.config.js):
module.exports = {
apps: [{
name: 'asapjs-app',
script: 'dist/index.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
}],
};Docker 배포
Dockerfile
FROM node:18-alpine
WORKDIR /app
# 의존성 설치
COPY package.json yarn.lock lerna.json ./
COPY packages/core/package.json packages/core/
COPY packages/router/package.json packages/router/
COPY packages/sequelize/package.json packages/sequelize/
COPY packages/socket/package.json packages/socket/
COPY example/package.json example/
RUN yarn install --frozen-lockfile
# 소스 복사 및 빌드
COPY . .
RUN yarn build:packages
RUN cd example && yarn build
# 실행
EXPOSE 3000
CMD ["node", "example/dist/index.js"]docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- '3000:3000'
environment:
NODE_ENV: production
PORT: 3000
JWT_SECRET: ${JWT_SECRET}
DB_HOST: db
DB_PORT: 3306
DB_NAME: asapjs
DB_USER: root
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: asapjs
ports:
- '3306:3306'
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 10s
timeout: 5s
retries: 5
volumes:
db_data:# 실행
docker-compose up -d
# 로그 확인
docker-compose logs -f app프로덕션 체크리스트
| 항목 | 설명 |
|---|---|
JWT_SECRET | 강력한 시크릿 키를 사용하세요. 기본값('default-secret-key')을 절대 사용하지 마세요. |
DB_SYNC | 프로덕션에서는 false로 설정하세요. 마이그레이션 도구를 사용하세요. |
logging: false | DB 쿼리 로깅을 비활성화하여 성능을 개선하세요. |
pool 설정 | 예상 트래픽에 맞게 max, idle, acquire 값을 조정하세요. |
| Health check | /health-check 엔드포인트를 로드 밸런서에 연결하세요. |
| Swagger 보안 | swagger.useAuth: true와 swagger.userObject로 Swagger UI를 보호하세요. |
| HTTPS | 리버스 프록시(Nginx 등) 뒤에서 HTTPS를 설정하세요. |
관련 문서
Last updated on