🏛️ Lab 06. 모놀리스에서 MSA 분리 & 프로덕션 배포
Database-per-Service 마이크로서비스 전환 및 클라우드 실서버 운영
“하나의 거대한 덩어리(Monolith)에서 각자의 데이터베이스를 가진 독립적인 마이크로서비스(MSA)로! 그리고 마침내 실제 클라우드 서버에 살아있는 사이트로 런칭합니다!”
실전 프로젝트의 마지막 관문입니다. Lab 05까지 완성한 3-Tier 모놀리스 시스템을 API Gateway(Nginx)를 전면에 두고, ‘Auth(인증) 서비스’와 ‘Expedition(게시판) 서비스’로 도메인 분리합니다. 각 서비스가 독립된 PostgreSQL 데이터베이스를 소유하는 Database-per-Service 패턴을 실현하고, 최종적으로 공인 도메인과 HTTPS(SSL)가 적용된 클라우드 실서버에 상용 배포하는 프로덕션 워크플로를 완성합니다.
🎯 학습 목표
- 모놀리스의 한계(코드 충돌, 전체 배포 위험)를 극복하기 위한 마이크로서비스 아키텍처(MSA)의 분리 원칙과 트레이드오프를 이해합니다.
- API 게이트웨이(Nginx)를 구축하여 단일 진입점(포트 80/443)에서 URL 경로(
/api/auth/*,/*)에 따라 서로 다른 백엔드 마이크로서비스로 라우팅합니다. - 데이터 결합도를 끊어내기 위해 서비스별로 독립된 데이터베이스(
pgsql_auth,pgsql_expedition)를 운영하는 Database-per-Service를 도커로 구현합니다. - 실제 리눅스 클라우드 서버(Ubuntu/Debian VPS)에 코드를 배포하고, Let’s Encrypt 무료 SSL 인증서를 발급받아 암호화된
https://사이트로 정식 오픈합니다.
🏗️ MSA 분산 아키텍처 다이어그램
[ 외부 클라이언트 (웹 / 모바일) ]
│
▼ (포트 80, 443)
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ [ L7 API Gateway : Nginx Alpine ] │
│ • 단일 공인 IP / 도메인 (https://docker.jiny.dev) │
│ • SSL/TLS Termination & 라우팅 분기 │
└───────────────────────────┬────────────────────────────────┬───────────────────────────┘
│ │
┌───────────────────────┘ └───────────────────────┐
│ 경로: /api/auth/* │ 경로: /* (메인 웹 & 게시판)
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ [ Auth Microservice ] │ │ [ Expedition Microservice ] │
│ PHP 8.5 Laravel (was_auth) │ │ PHP 8.5 Laravel (was_board) │
│ • 회원가입, 로그인, JWT 토큰 │ │ • 탐험일지 등록/조회/삭제 │
└───────────────┬───────────────┘ └───────────────┬───────────────┘
│ (독립 연결) │ (독립 연결)
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ [ PostgreSQL Auth DB ] │ │ [ PostgreSQL Board DB ] │
│ • Named Volume: auth_db │ │ • Named Volume: board_db │
│ • 회원 테이블만 격리 저장 │ │ • 게시글 데이터만 격리 저장 │
└───────────────────────────────┘ └───────────────────────────────┘
⚙️ 1. API 게이트웨이 Nginx 라우팅 설정 (docker/nginx/gateway.conf)
Nginx가 똑똑하게 요청 주소를 보고 알맞은 백엔드 컨테이너로 패스하도록 설정합니다:
resolver 127.0.0.11 valid=5s;
server {
listen 80;
server_name localhost;
# 1. 인증 마이크로서비스 라우팅 (/api/auth/*)
location /api/auth/ {
# 'auth_was' 컨테이너의 FastCGI 포트로 전달
set $auth_backend auth_was;
fastcgi_pass $auth_backend:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/auth/public/index.php;
}
# 2. 메인 게시판 마이크로서비스 라우팅 (/*)
location / {
# 'board_was' 컨테이너의 FastCGI 포트로 전달
set $board_backend board_was;
fastcgi_pass $board_backend:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/board/public/index.php;
}
}
🐳 2. MSA 전용 compose.msa.yaml 선언
서비스별로 WAS와 PostgreSQL을 완벽하게 분리하여 선언합니다:
services:
# ========================================================
# 1. API Gateway (Nginx)
# ========================================================
gateway:
image: nginx:alpine
container_name: msa_gateway
ports:
- "80:80"
volumes:
- ./docker/nginx/gateway.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- auth_was
- board_was
networks:
- msa_net
# ========================================================
# 2. Auth Domain (인증 서비스 & 독립 DB)
# ========================================================
auth_was:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: msa_auth_was
environment:
DB_CONNECTION: pgsql
DB_HOST: auth_pgsql
DB_PORT: 5432
DB_DATABASE: auth_db
DB_USERNAME: auth_user
DB_PASSWORD: auth_password
depends_on:
auth_pgsql:
condition: service_healthy
networks:
- msa_net
auth_pgsql:
image: postgres:16-alpine
container_name: msa_auth_pgsql
environment:
POSTGRES_DB: auth_db
POSTGRES_USER: auth_user
POSTGRES_PASSWORD: auth_password
volumes:
- auth_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U auth_user -d auth_db"]
interval: 5s
timeout: 3s
retries: 5
networks:
- msa_net
# ========================================================
# 3. Board Domain (탐험일지 게시판 서비스 & 독립 DB)
# ========================================================
board_was:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: msa_board_was
environment:
DB_CONNECTION: pgsql
DB_HOST: board_pgsql
DB_PORT: 5432
DB_DATABASE: board_db
DB_USERNAME: board_user
DB_PASSWORD: board_password
depends_on:
board_pgsql:
condition: service_healthy
networks:
- msa_net
board_pgsql:
image: postgres:16-alpine
container_name: msa_board_pgsql
environment:
POSTGRES_DB: board_db
POSTGRES_USER: board_user
POSTGRES_PASSWORD: board_password
volumes:
- board_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U board_user -d board_db"]
interval: 5s
timeout: 3s
retries: 5
networks:
- msa_net
volumes:
auth_data:
board_data:
networks:
msa_net:
driver: bridge
💡 MSA의 위력: 이제 게시판 DB(
board_pgsql)에 장애가 발생하여 뻗더라도, 사용자 인증 DB(auth_pgsql)는 완전히 독립된 컨테이너와 볼륨으로 격리되어 있으므로 로그인 기능은 정상 작동합니다. 이것이 바로 장애 격리(Fault Isolation)입니다!
☁️ 3. 실제 리눅스 클라우드 서버 프로덕션 배포 5단계
로컬에서 완성한 도커 프로젝트를 AWS EC2, GCP Compute Engine, 또는 저렴한 VPS(가상 개인 서버)에 상용 배포하는 표준 5단계 절차입니다.
Step 1: 클라우드 서버 생성 및 도커 엔진 설치
Ubuntu 22.04 / 24.04 LTS 가상서버에 접속한 후 도커를 설치합니다:
# 최신 공식 Docker Engine 자동 설치 스크립트 실행
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
newgrp docker
Step 2: 클라우드 방화벽(보안 그룹) 개방
클라우드 콘솔의 방화벽 규칙에서 다음 포트를 오픈합니다:
80(HTTP): 웹 접속 및 Let’s Encrypt 도메인 소유권 검증용443(HTTPS): SSL 보안 암호화 통신용22(SSH): 관리자 원격 접속용
Step 3: 소스코드 복제 및 프로덕션 환경설정
git clone https://github.com/your-username/docker-laravel-project.git
cd docker-laravel-project
cp .env.example .env.production
Step 4: 프로덕션 성능 캐싱 최적화
프로덕션 환경에서는 속도를 위해 라라벨의 설정, 라우트, 뷰 파일을 미리 바이트코드로 컴파일해 둡니다:
docker compose -f compose.yaml exec was php artisan config:cache
docker compose -f compose.yaml exec was php artisan route:cache
docker compose -f compose.yaml exec was php artisan view:cache
docker compose -f compose.yaml exec was php artisan migrate --force
Step 5: Let’s Encrypt 무료 SSL/TLS 인증서 발급
Certbot 컨테이너를 일회성으로 실행하여 무료 SSL 인증서를 자동 발급받습니다:
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
-p 80:80 \
certbot/certbot certonly --standalone \
-d yourdomain.com --agree-tos -m your-email@example.com --no-eff-email
발급된 /etc/letsencrypt/live/yourdomain.com/ 인증서 경로를 Nginx 설정의 ssl_certificate에 바인드 마운트하면 자물쇠 표시가 뜨는 완벽한 https:// 보안 웹사이트가 완성됩니다!
🏆 대단원의 완주: 수강생이 이룬 놀라운 도약!
[ 처음 시작할 때 ]
"도커가 뭔지, 리눅스가 뭔지도 잘 모르는 초보 대학생"
▼
[ 1학기 마스터 ]
"PHP 8.5 & Nginx & PostgreSQL 3-Tier 웹사이트를 직접 구축하고 클라우드 서버에 배포한 주니어 메이커"
▼
[ 2학기 최종 수료 ]
"대규모 트래픽 부하를 수평 스케일아웃하고, 모놀리스를 마이크로서비스(MSA)로 분리하며,
무중단 롤링 배포와 실시간 관제탑을 다루는 기업 현업 수준의 DevOps/SRE 엔지니어!"
여러분의 훌륭한 탐험을 응원합니다.
지금 바로 Lab 01. PHP 8.5 라라벨 보안 Dockerfile 제작부터 나만의 도커 원정대 웹사이트를 손수 구축해 보세요!