Skip to Content

배포

이 가이드는 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 save

PM2 설정 파일 (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: falseDB 쿼리 로깅을 비활성화하여 성능을 개선하세요.
pool 설정예상 트래픽에 맞게 max, idle, acquire 값을 조정하세요.
Health check/health-check 엔드포인트를 로드 밸런서에 연결하세요.
Swagger 보안swagger.useAuth: trueswagger.userObject로 Swagger UI를 보호하세요.
HTTPS리버스 프록시(Nginx 등) 뒤에서 HTTPS를 설정하세요.

관련 문서

  • BootstrapApplication 클래스와 IConfig 인터페이스
  • Swagger — Swagger UI 보안 설정
  • Testing — 테스트 환경에서의 disableListenServer 사용
Last updated on