# ============================================================================= # SOSO 서버 - 프로덕션 인프라 구성 # ============================================================================= # # 이 파일은 SOSO 애플리케이션의 전체 인프라를 정의합니다. # # 포함된 서비스들: # - Jenkins: CI/CD 파이프라인 (자동 빌드, 테스트, 배포) # - API: SOSO 메인 애플리케이션 서버 (Spring Boot) # - Proxy: 리버스 프록시 (Caddy - HTTPS, 라우팅) # - Database: MySQL 데이터베이스 (사용자, 게시글, 댓글 등) # - Redis: 캐시 및 세션 스토어 # - Watchtower: 컨테이너 자동 업데이트 # # 네트워크: 모든 서비스는 soso_net 네트워크로 연결 # 볼륨: 데이터 영속성을 위한 named volume 사용 # ============================================================================= # Docker Compose 프로젝트 이름 명시 # 이 설정으로 모든 컨테이너, 네트워크, 볼륨의 이름이 통일됩니다. # 환경변수나 디렉토리명에 관계없이 항상 동일한 프로젝트명으로 관리됩니다. name: soso-server services: # ============================================================================= # Jenkins CI/CD 서버 # ============================================================================= # # GitHub 푸시 시 자동으로 트리거되어 다음 작업을 수행: # 1. 코드 체크아웃 및 테스트 실행 # 2. Spring Boot JAR 파일 빌드 # 3. Docker 이미지 생성 # 4. 프로덕션 환경에 자동 배포 # # 주요 기능: # - Java 21 기반 (최신 LTS) # - Docker-in-Docker로 컨테이너 제어 # - Git 자동 설정 (컨테이너 재시작 시) # - 자동 권한 설정 스크립트 # ============================================================================= jenkins: build: context: ./infrastructure/jenkins # 커스텀 Dockerfile 위치 dockerfile: Dockerfile container_name: jenkins user: root # Docker 소켓 접근을 위한 root 권한 필요 environment: TZ: Asia/Seoul # 한국 시간대 설정 JAVA_OPTS: "-Djenkins.install.runSetupWizard=false" # 초기 설정 위저드 건너뛰기 JENKINS_OPTS: "--prefix=/jenkins" # URL 프리픽스 설정 (/jenkins 경로) ports: - "8080:8080" # Jenkins 웹 UI 접근 포트 - "50000:50000" # Jenkins 에이전트 연결 포트 volumes: - jenkins_data:/var/jenkins_home # Jenkins 설정 및 작업 데이터 영속화 - /var/run/docker.sock:/var/run/docker.sock # Docker-in-Docker (호스트 Docker 제어) networks: [soso_net] # 내부 네트워크 연결 restart: unless-stopped # 시스템 재부팅 시 자동 시작 healthcheck: # Jenkins 서비스 상태 확인 test: ["CMD-SHELL", "curl -f http://localhost:8080/login || exit 1"] interval: 30s # 30초마다 상태 확인 timeout: 10s # 10초 내 응답 없으면 실패 retries: 3 # 3번 실패 시 unhealthy 상태 start_period: 60s # 시작 후 60초 대기 시간 # ============================================================================= # SOSO API 애플리케이션 서버 # ============================================================================= # # Spring Boot 기반의 메인 애플리케이션 서버 # # 주요 기능: # - REST API 제공 (사용자, 게시글, 댓글, 좋아요 등) # - JWT 기반 인증/인가 # - 카카오 OAuth 소셜 로그인 # - AWS S3 이미지 업로드 # - Redis 기반 캐싱 및 세션 관리 # - JPA/Hibernate 기반 데이터베이스 ORM # # 보안: # - 외부 직접 접근 차단 (expose만 사용) # - Caddy 프록시를 통해서만 접근 가능 # ============================================================================= api: image: ${API_IMAGE:-localtest/soso-server:latest} # Jenkins가 빌드한 이미지 사용 container_name: soso-api environment: TZ: Asia/Seoul # 한국 시간대 설정 SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod} # 프로덕션 프로파일 # ================================================================= # 데이터베이스 연결 설정 (컨테이너 네트워크 내부 통신) # ================================================================= DB_HOST: db # MySQL 컨테이너 서비스명 DB_PORT: 3306 # MySQL 기본 포트 DB_NAME: ${DB_NAME:-soso} # 데이터베이스명 DB_USER: ${DB_USER:-soso_user} # 애플리케이션 전용 계정 DB_PASS: ${DB_PASS:-12341234} # 데이터베이스 비밀번호 # ================================================================= # JPA/Hibernate 설정 # ================================================================= JPA_DDL: ${JPA_DDL:-update} # 스키마 자동 생성/업데이트 (update 모드) # ================================================================= # Redis 캐시 설정 (컨테이너 네트워크 내부 통신) # ================================================================= REDIS_HOST: redis # Redis 컨테이너 서비스명 REDIS_PORT: 6379 # Redis 기본 포트 # ================================================================= # 애플리케이션 설정 # ================================================================= FRONTEND_ORIGIN: ${FRONTEND_ORIGIN} # CORS 허용 프론트엔드 URL JWT_SECRET: ${JWT_SECRET} # JWT 토큰 서명 비밀키 JWT_AT_VALIDITY: ${JWT_AT_VALIDITY:-1800000} # Access Token 유효시간 (30분) JWT_RT_VALIDITY: ${JWT_RT_VALIDITY:-1209600000} # Refresh Token 유효시간 (14일) # ================================================================= # 외부 서비스 연동 # ================================================================= # 카카오 OAuth 소셜 로그인 KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID} # 카카오 앱 클라이언트 ID KAKAO_REDIRECT_URIS: ${KAKAO_REDIRECT_URIS} # 카카오 로그인 리다이렉트 URL # AWS S3 이미지 저장소 AWS_REGION: ${AWS_REGION} # AWS 리전 (ap-northeast-2) AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} # AWS 액세스 키 AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} # AWS 시크릿 키 AWS_S3_BUCKET: ${AWS_S3_BUCKET} # S3 버킷명 S3_BASE_URL: ${S3_BASE_URL} # S3 이미지 베이스 URL # Apache Kafka (현재 미사용) KAFKA_BOOTSTRAP: ${KAFKA_BOOTSTRAP} # Kafka 브로커 주소 depends_on: # 서비스 시작 순서 의존성 db: condition: service_healthy # MySQL이 healthy 상태일 때 시작 redis: condition: service_healthy # Redis가 healthy 상태일 때 시작 expose: ["8080"] # 내부 네트워크에만 포트 노출 (보안) networks: [soso_net] # 내부 네트워크 연결 restart: unless-stopped # 장애 시 자동 재시작 healthcheck: # API 서버 상태 확인 test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"] interval: 10s # 10초마다 상태 확인 (빠른 피드백) timeout: 3s # 3초 내 응답 없으면 실패 retries: 5 # 5번 실패 시 unhealthy 상태 (Spring Boot는 15-20초면 시작) start_period: 30s # 시작 후 30초 대기 시간 (실제 시작 시간에 최적화) labels: - "com.centurylinklabs.watchtower.enable=true" # Watchtower 자동 업데이트 활성화 # ============================================================================= # 리버스 프록시 (Caddy) # ============================================================================= # # 모든 외부 트래픽의 진입점 역할 # # 주요 기능: # - 자동 HTTPS/SSL 인증서 (Let's Encrypt) # - 요청 라우팅 (API, Jenkins, Swagger 등) # - 보안 헤더 자동 추가 # - Gzip 압축 # - 정적 파일 캐싱 # - 무중단 설정 리로드 # # 라우팅: # - / → Jenkins (임시, 나중에 프론트엔드로 변경 예정) # - /api/* → API 서버 # - /jenkins/* → Jenkins 관리자 페이지 # - /swagger-ui/* → API 문서 # ============================================================================= proxy: image: caddy:2 # 공식 Caddy v2 이미지 container_name: soso-proxy environment: TZ: Asia/Seoul # 한국 시간대 설정 ports: - "80:80" # HTTP 포트 (HTTPS로 리다이렉트) - "443:443" # HTTPS 포트 (메인 접속점) volumes: - ./infrastructure/Caddyfile:/etc/caddy/Caddyfile:ro # Caddy 설정 파일 (읽기 전용) - caddy_data:/data # SSL 인증서 및 데이터 저장소 - caddy_config:/config # Caddy 내부 설정 저장소 depends_on: # 서비스 시작 순서 의존성 api: condition: service_healthy # API가 정상일 때 시작 # Jenkins 의존성 제거: Jenkins가 unhealthy여도 Proxy는 정상 작동 # Jenkins는 관리 페이지일 뿐, 핵심 서비스 아님 networks: [soso_net] # 내부 네트워크 연결 restart: unless-stopped # 장애 시 자동 재시작 healthcheck: # Caddy 설정 파일 검증 test: ["CMD", "caddy", "validate", "--config", "/etc/caddy/Caddyfile"] interval: 30s # 30초마다 설정 유효성 확인 timeout: 10s # 10초 내 검증 완료 retries: 3 # 3번 실패 시 unhealthy 상태 # ============================================================================= # 데이터베이스 (MySQL) # ============================================================================= # # SOSO 애플리케이션의 메인 데이터 저장소 # # 저장되는 데이터: # - 사용자 정보 (users) # - 게시글 및 댓글 (posts, comments) # - 좋아요 정보 (post_likes, comment_likes) # - 이미지 메타데이터 (post_images) # - 기타 애플리케이션 데이터 # # 주요 설정: # - UTF-8 완전 지원 (utf8mb4) # - 엄격한 SQL 모드 (데이터 무결성 보장) # - 네이티브 비밀번호 인증 (호환성) # - 초기화 스크립트 지원 # ============================================================================= db: image: mysql:8.4 # MySQL 8.4 LTS 버전 container_name: soso-mysql environment: TZ: Asia/Seoul # 한국 시간대 설정 MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword} # root 계정 비밀번호 MYSQL_DATABASE: ${DB_NAME:-soso} # 애플리케이션 데이터베이스 자동 생성 MYSQL_USER: ${DB_USER:-soso_user} # 애플리케이션 전용 계정 생성 MYSQL_PASSWORD: ${DB_PASS:-12341234} # 애플리케이션 계정 비밀번호 command: # MySQL 서버 시작 옵션 [ "--character-set-server=utf8mb4", # 한글 및 이모지 완전 지원 "--collation-server=utf8mb4_0900_ai_ci", # 최신 정렬 규칙 (대소문자 구분 안함) "--mysql-native-password=ON", # 기존 인증 방식 사용 (호환성) "--sql-mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO" # 엄격한 SQL 모드 ] volumes: - mysql_data:/var/lib/mysql # 데이터 영속화 (재시작 후에도 데이터 보존) - ./infrastructure/mysql-init:/docker-entrypoint-initdb.d:ro # 초기화 SQL 스크립트 networks: [soso_net] # 내부 네트워크만 접근 restart: unless-stopped # 장애 시 자동 재시작 healthcheck: # MySQL 서버 상태 확인 test: ["CMD-SHELL", "mysqladmin ping -h localhost -u${DB_USER} -p${DB_PASS} --silent"] interval: 10s # 10초마다 상태 확인 timeout: 5s # 5초 내 응답 없으면 실패 retries: 10 # 10번 실패 시 unhealthy 상태 start_period: 30s # 시작 후 30초 대기 시간 # ============================================================================= # 캐시 및 세션 스토어 (Redis) # ============================================================================= # # 고성능 인메모리 데이터 저장소 # # 사용 목적: # - API 응답 캐싱 (성능 향상) # - 사용자 세션 관리 # - 임시 데이터 저장 (JWT 블랙리스트 등) # - 실시간 기능 지원 (향후 알림 등) # # 주요 설정: # - AOF 영속성 활성화 (데이터 손실 방지) # - 메모리 제한 256MB (적절한 리소스 사용) # - LRU 정책 (메모리 부족 시 오래된 데이터 자동 삭제) # ============================================================================= redis: image: redis:7-alpine # Redis 7 (경량 Alpine 기반) container_name: soso-redis environment: TZ: Asia/Seoul # 한국 시간대 설정 command: # Redis 서버 실행 옵션 [ "redis-server", # Redis 서버 실행 "--appendonly", "yes", # AOF 영속성 활성화 (데이터 손실 방지) "--maxmemory", "256mb", # 최대 메모리 사용량 제한 "--maxmemory-policy", "allkeys-lru", # 메모리 부족 시 LRU 알고리즘으로 데이터 삭제 ] volumes: - redis_data:/data # AOF 파일 영속화 (재시작 후 데이터 복구) networks: [soso_net] # 내부 네트워크만 접근 restart: unless-stopped # 장애 시 자동 재시작 healthcheck: # Redis 서버 상태 확인 test: ["CMD", "redis-cli", "ping"] # PING 명령으로 응답성 확인 interval: 10s # 10초마다 상태 확인 timeout: 3s # 3초 내 응답 없으면 실패 retries: 5 # 5번 실패 시 unhealthy 상태 # ============================================================================= # 자동 업데이트 (Watchtower) # ============================================================================= # # 컨테이너 이미지 자동 업데이트 서비스 # # 주요 기능: # - Docker Hub에서 새로운 이미지 버전 자동 감지 # - 라벨 기반 선택적 업데이트 (api 서비스만) # - 자동 컨테이너 재시작 # - 이전 이미지 자동 정리 # # 업데이트 대상: # - API 서버 (watchtower.enable=true 라벨이 있는 경우) # - 기타 인프라 서비스들은 수동 관리 # ============================================================================= watchtower: image: containrrr/watchtower # Watchtower 공식 이미지 container_name: watchtower environment: TZ: Asia/Seoul # 한국 시간대 설정 WATCHTOWER_CLEANUP: "true" # 이전 이미지 자동 정리 WATCHTOWER_INCLUDE_RESTARTING: "true" # 재시작 중인 컨테이너도 포함 WATCHTOWER_POLL_INTERVAL: 300 # 5분마다 새 이미지 확인 WATCHTOWER_LABEL_ENABLE: "true" # 라벨이 있는 컨테이너만 업데이트 volumes: - /var/run/docker.sock:/var/run/docker.sock # Docker 데몬 제어를 위한 소켓 접근 restart: unless-stopped # 장애 시 자동 재시작 # ============================================================================= # 네트워크 설정 # ============================================================================= # # 모든 서비스들이 안전하게 통신할 수 있는 격리된 네트워크 # # 특징: # - 브리지 네트워크 (컨테이너 간 통신) # - 서비스명으로 DNS 해결 (db, redis, api 등) # - 외부와 격리된 내부 통신 # - 172.18.0.0/16 서브넷 사용 # ============================================================================= networks: soso_net: name: soso_net # 네트워크명 driver: bridge # 브리지 드라이버 (기본값) ipam: # IP 주소 관리 config: - subnet: 172.18.0.0/16 # 사용할 IP 대역 # ============================================================================= # 영구 볼륨 설정 # ============================================================================= # # 컨테이너 재시작/재생성 시에도 데이터를 보존하는 영구 저장소 # # 각 볼륨의 역할: # - jenkins_data: Jenkins 설정, 빌드 히스토리, 플러그인 # - mysql_data: MySQL 데이터베이스 파일 # - redis_data: Redis AOF 파일 (데이터 복구용) # - caddy_data: SSL 인증서, Caddy 데이터 # - caddy_config: Caddy 내부 설정 # ============================================================================= volumes: jenkins_data: name: jenkins_data # Jenkins 데이터 영속화 mysql_data: name: mysql_data # MySQL 데이터베이스 영속화 redis_data: name: redis_data # Redis 데이터 영속화 caddy_data: name: caddy_data # Caddy SSL 인증서 영속화 caddy_config: name: caddy_config # Caddy 설정 영속화