Docker Compose 기반 Spring Boot 백엔드, Railway 배포 완전 정복 (Redis/MongoDB/MySQL 포함)

J_log·2025년 9월 18일
0

Docker Compose 기반 Spring Boot 백엔드, Railway 배포 완전 정복 (Redis/MongoDB/MySQL 포함)

들어가며

최근 사이드 프로젝트로 Spring Boot 기반의 RESTful API 서버를 개발하고 있었습니다. 로컬 환경에서는 Docker Compose를 활용해 Redis, MongoDB, MySQL을 함께 운영하며 개발을 진행했는데, 배포 단계에서 고민이 많았습니다.

AWS EC2나 GCP Compute Engine을 사용하자니 설정할 것이 너무 많고, Heroku는 2022년 11월부터 무료 플랜이 사라져서 대안을 찾고 있었죠. 그러던 중 개발자 커뮤니티에서 Railway라는 서비스를 알게 되었고, 직접 마이그레이션해본 경험을 상세히 공유하고자 합니다.

기존 환경 분석

로컬 개발 환경

  • Framework: Spring Boot 3.1.5
  • Java Version: OpenJDK 17
  • Build Tool: Gradle 8.4
  • Database: MySQL 8.0 (주 데이터), MongoDB 6.0 (로그 데이터)
  • Cache: Redis 7.0
  • Container: Docker Compose

Docker Compose 구성

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - MYSQL_HOST=mysql
      - MYSQL_PORT=3306
      - MYSQL_DATABASE=myapp
      - MYSQL_USERNAME=app_user
      - MYSQL_PASSWORD=secure_password
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - MONGO_HOST=mongo
      - MONGO_PORT=27017
      - MONGO_DATABASE=myapp_logs
    depends_on:
      - mysql
      - redis
      - mongo
    networks:
      - app-network

  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_DATABASE=myapp
      - MYSQL_USER=app_user
      - MYSQL_PASSWORD=secure_password
      - MYSQL_ROOT_PASSWORD=root_password
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: redis-server --requirepass redis_password
    volumes:
      - redis_data:/data
    networks:
      - app-network

  mongo:
    image: mongo:6
    environment:
      - MONGO_INITDB_ROOT_USERNAME=mongo_user
      - MONGO_INITDB_ROOT_PASSWORD=mongo_password
      - MONGO_INITDB_DATABASE=myapp_logs
    ports:
      - "27017:27017"
    volumes:
      - mongo_data:/data/db
    networks:
      - app-network

volumes:
  mysql_data:
  redis_data:
  mongo_data:

networks:
  app-network:
    driver: bridge

Dockerfile 구성

FROM openjdk:17-jdk-slim

WORKDIR /app

COPY build/libs/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

주요 기능

  • 인증/인가: JWT 기반 인증 시스템
  • 파일 업로드: MultipartFile 처리 (이미지, 문서)
  • 실시간 알림: WebSocket 연결
  • API 문서화: Swagger/OpenAPI 3.0
  • 로깅: 구조화된 로그를 MongoDB에 저장
  • 캐싱: Redis를 활용한 세션 관리 및 데이터 캐싱

Railway 마이그레이션 과정

1단계: Railway 프로젝트 초기화

Railway 대시보드에서 새 프로젝트를 생성하는 과정은 놀라울 정도로 간단했습니다.

  1. GitHub 연동: Railway에서 "Deploy from GitHub repo" 선택
  2. Repository 선택: 배포할 레포지토리를 선택하면 자동으로 Dockerfile을 인식
  3. 자동 빌드: 첫 번째 배포가 자동으로 시작됨
# Railway CLI 설치 (선택사항)
npm install -g @railway/cli

# 로컬에서 Railway 프로젝트 연결
railway login
railway link [프로젝트-ID]

2단계: 데이터베이스 서비스 추가

Railway의 가장 큰 장점 중 하나는 데이터베이스를 별도로 관리할 필요가 없다는 것입니다.

2-1. MySQL 서비스 추가

Railway Dashboard → Add Service → Database → MySQL

Railway에서 제공하는 MySQL 인스턴스 정보:

  • Host: containers-us-west-xxx.railway.app
  • Port: 6543
  • Database: railway
  • Username: root
  • Password: 자동 생성된 32자리 패스워드

2-2. Redis 서비스 추가

Railway Dashboard → Add Service → Database → Redis

Redis 연결 정보:

  • Host: redis-xxx.railway.app
  • Port: 6379
  • Password: 자동 생성

2-3. MongoDB 서비스 추가

Railway Dashboard → Add Service → Database → MongoDB

MongoDB 연결 정보:

  • Connection URI: mongodb://mongo:xxx@containers-us-west-xxx.railway.app:6034/railway

3단계: 환경변수 구성

Railway는 각 데이터베이스 서비스마다 연결 정보를 환경변수로 자동 제공합니다. 이를 Spring Boot의 application.yml에 맞게 매핑해야 합니다.

Railway 제공 환경변수

# MySQL
MYSQL_URL=mysql://root:xxx@containers-us-west-xxx.railway.app:6543/railway
MYSQLHOST=containers-us-west-xxx.railway.app
MYSQLPORT=6543
MYSQLDATABASE=railway
MYSQLUSER=root
MYSQLPASSWORD=xxx

# Redis
REDIS_URL=redis://:xxx@redis-xxx.railway.app:6379
REDISHOST=redis-xxx.railway.app
REDISPORT=6379
REDISPASSWORD=xxx

# MongoDB  
MONGO_URL=mongodb://mongo:xxx@containers-us-west-xxx.railway.app:6034/railway
MONGOHOST=containers-us-west-xxx.railway.app
MONGOPORT=6034
MONGOUSER=mongo
MONGOPASSWORD=xxx
MONGODATABASE=railway

application.yml 수정

spring:
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:prod}
    
  # MySQL 설정
  datasource:
    url: jdbc:mysql://${MYSQLHOST:localhost}:${MYSQLPORT:3306}/${MYSQLDATABASE:myapp}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    username: ${MYSQLUSER:root}
    password: ${MYSQLPASSWORD:password}
    driver-class-name: com.mysql.cj.jdbc.Driver
    
  # JPA 설정
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
        format_sql: true
        
  # MongoDB 설정
  data:
    mongodb:
      host: ${MONGOHOST:localhost}
      port: ${MONGOPORT:27017}
      database: ${MONGODATABASE:myapp_logs}
      username: ${MONGOUSER:}
      password: ${MONGOPASSWORD:}
      authentication-database: admin
      
  # Redis 설정
  data:
    redis:
      host: ${REDISHOST:localhost}
      port: ${REDISPORT:6379}
      password: ${REDISPASSWORD:}
      timeout: 60000
      jedis:
        pool:
          max-active: 8
          max-wait: -1
          max-idle: 8
          min-idle: 0

# 서버 설정
server:
  port: ${PORT:8080}
  
# JWT 설정
jwt:
  secret: ${JWT_SECRET:your-secret-key}
  expiration: ${JWT_EXPIRATION:3600000}
  
# 파일 업로드 설정
file:
  upload:
    path: ${FILE_UPLOAD_PATH:/tmp/uploads}
    max-size: ${FILE_MAX_SIZE:10485760}

4단계: Railway Variables 설정

Railway 대시보드에서 Variables 탭으로 이동해 다음 환경변수들을 추가했습니다.

# Spring 프로파일
SPRING_PROFILES_ACTIVE=prod

# JWT 설정
JWT_SECRET=your-super-secure-jwt-secret-key-here
JWT_EXPIRATION=3600000

# 파일 업로드 설정
FILE_UPLOAD_PATH=/app/uploads
FILE_MAX_SIZE=10485760

# 로깅 레벨
LOGGING_LEVEL_ROOT=INFO
LOGGING_LEVEL_COM_MYAPP=DEBUG

# Railway 포트 (자동 설정됨)
PORT=${{PORT}}

5단계: 배포 및 테스트

코드를 GitHub에 push하면 Railway가 자동으로 배포를 시작합니다.

git add .
git commit -m "Configure Railway deployment"
git push origin main

배포 과정은 Railway 대시보드의 Deployments 탭에서 실시간으로 확인할 수 있습니다.

  1. Build Phase: Dockerfile 기반 이미지 빌드
  2. Deploy Phase: 컨테이너 실행 및 health check
  3. Live: 서비스 활성화 완료

배포가 완료되면 Railway에서 제공하는 도메인 (예: https://myapp-production-xxxx.up.railway.app)으로 접근할 수 있습니다.

성능 및 모니터링

Railway 제공 메트릭

Railway 대시보드에서 다음과 같은 메트릭을 실시간으로 확인할 수 있습니다.

  • CPU 사용량: 평균 15-20% (유휴 상태 기준)
  • 메모리 사용량: 약 300MB (Spring Boot JVM 기본 설정)
  • 네트워크 I/O: 인바운드/아웃바운드 트래픽
  • 응답 시간: 평균 200ms 이하

로그 모니터링

Railway는 실시간 로그 스트리밍을 제공합니다.

# Railway CLI로 로그 확인
railway logs --follow

# 특정 서비스 로그만 확인
railway logs --service mysql --follow

Health Check 구성

Spring Boot Actuator를 활용해 health check 엔드포인트를 구성했습니다.

@RestController
@RequestMapping("/actuator")
public class HealthController {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Autowired
    private DataSource dataSource;
    
    @GetMapping("/health")
    public ResponseEntity<Map<String, String>> health() {
        Map<String, String> status = new HashMap<>();
        
        try {
            // MySQL 연결 확인
            try (Connection connection = dataSource.getConnection()) {
                status.put("mysql", "UP");
            }
            
            // Redis 연결 확인
            redisTemplate.opsForValue().set("health-check", "OK");
            status.put("redis", "UP");
            
            status.put("status", "UP");
            return ResponseEntity.ok(status);
            
        } catch (Exception e) {
            status.put("status", "DOWN");
            status.put("error", e.getMessage());
            return ResponseEntity.status(503).body(status);
        }
    }
}

비용 분석

Railway 요금 체계

Railway는 사용량 기반 과금 모델을 사용합니다.

  • Compute: $0.000463/vCPU/minute
  • Memory: $0.000231/GB/minute
  • Egress: $0.10/GB
  • Storage: 데이터베이스별 별도 과금

실제 사용 비용 (월간)

  • Spring Boot App: CPU 0.5, Memory 512MB → 약 $8/월
  • MySQL: 약 $5/월
  • Redis: 약 $3/월
  • MongoDB: 약 $4/월
  • Total: 약 $20/월

$20 무료 크레딧으로 약 1개월간 무료 사용이 가능합니다.

기존 솔루션과 비교

  • AWS EC2 t3.micro: $8.5/월 + RDS $15/월 + ElastiCache $13/월 = $36.5/월
  • Heroku: Dyno $7/월 + PostgreSQL $9/월 + Redis $15/월 = $31/월
  • Railway: 약 $20/월 (올인원)

최적화 및 팁

1. 빌드 시간 최적화

# Multi-stage build로 빌드 시간 단축
FROM gradle:7.6-jdk17 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

FROM openjdk:17-jdk-slim
COPY --from=build /home/gradle/src/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

2. 환경별 배포 설정

Railway에서는 브랜치별로 다른 환경을 구성할 수 있습니다.

  • main 브랜치 → Production 환경
  • develop 브랜치 → Staging 환경

3. 자동 SSL 및 도메인

Railway는 자동으로 HTTPS를 적용하고, 커스텀 도메인도 쉽게 연결할 수 있습니다.

Settings → Environment → Custom Domain → Add Domain

4. 백업 설정

각 데이터베이스는 자동 백업이 활성화되어 있지만, 중요한 데이터는 별도 백업 전략을 수립하는 것이 좋습니다.

🚨 주의사항 및 한계점

장점

  • 간편한 배포: Dockerfile만 있으면 즉시 배포 가능
  • 통합 관리: DB까지 한 곳에서 관리
  • 자동 스케일링: 트래픽에 따른 자동 확장
  • 실시간 모니터링: 로그, 메트릭 실시간 확인
  • 합리적인 가격: 소규모 프로젝트에 적합

한계점

  • 지역 제한: 아직 아시아 리전 없음 (레이턴시 약 150-200ms)
  • 커스터마이징 제약: 고도의 인프라 커스터마이징이 어려움
  • 대용량 트래픽: 대규모 서비스에는 부적합할 수 있음
  • 한국어 지원: 공식 한국어 문서 부재

추천 대상

  • 사이드 프로젝트 및 MVP 개발
  • 스타트업 초기 단계
  • 개인 포트폴리오 프로젝트
  • 프로토타입 개발 및 테스트

향후 계획

1. CI/CD 파이프라인 구성

GitHub Actions와 Railway를 연동한 자동 배포 파이프라인을 구축할 예정입니다.

# .github/workflows/deploy.yml
name: Deploy to Railway

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install Railway CLI
        run: npm install -g @railway/cli
      - name: Deploy to Railway
        run: railway deploy
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}

2. 모니터링 강화

Prometheus + Grafana를 통한 커스텀 메트릭 수집과 New Relic 연동을 검토하고 있습니다.

3. 로드 테스트

Apache JMeter를 활용해 Railway 환경에서의 성능 한계를 측정하고, 최적화 포인트를 찾을 계획입니다.

결론

Docker Compose에서 Railway로의 마이그레이션은 예상보다 훨씬 수월했습니다. 특히 데이터베이스 관리의 복잡성이 크게 줄어들었고, 배포 과정도 자동화되어 개발에만 집중할 수 있게 되었습니다.

Railway는 다음과 같은 경우에 특히 추천합니다.

  1. 빠른 MVP 배포가 필요한 경우
  2. 인프라 관리보다 개발에 집중하고 싶은 경우
  3. 합리적인 비용으로 풀스택 환경을 구축하고 싶은 경우

물론 대규모 트래픽을 처리해야 하거나, 특수한 인프라 요구사항이 있다면 AWS나 GCP를 고려하는 것이 좋습니다. 하지만 개인 프로젝트나 스타트업 초기 단계라면 Railway가 매우 실용적인 선택지라고 생각합니다.


참고 자료

💡 Railway $20 크레딧 받기: 여기서 가입

1개의 댓글

comment-user-thumbnail
2025년 9월 23일

주워갑니다

답글 달기