[docker-compose]온프레미스 환경에서 Docker Compose로 서비스 구성하기

2025. 12. 31. 17:17·DevOps/Docker

이번 글은 온프레미스(on-premise) 환경에서 Docker Compose를 사용해 여러 서비스를 하나의 시스템으로 구성하면서 겪었던 실제 시행착오와 설계 결정을 정리한 기록입니다! 

 

구성한 시스템은 다음과 같음.

  • Next.js (프론트엔드)
  • Spring Boot API
  • FastAPI (AI / OCR / Chat)
  • PostgreSQL
  • Qdrant (Vector DB)
  • vLLM (GPU 기반 LLM Inference)

특히 이번 환경은 온디맨드 서버 제공형이라

  • 서버가 항상 켜져 있지 않고
  • 필요할 때만 기동했다가 종료되며
  • 별도 로드밸런서(Nginx 등)를 두지 않는 구조

라는 제약이 있었음.

 

이 글에서는 아래 내용을 중심으로 정리하려 합니다.

  • 포트는 어떻게 열고 맞췄는지
  • Docker 네트워크를 왜 하나로 묶었는지
  • Nginx 없이도 운영이 가능한 이유
  • .env를 서비스 단위로 분리한 이유
  • SSH 포트포워딩으로 로컬에서 테스트한 방법

 

1. 전체 아키텍처 개요

모든 서비스는 단일 Docker Compose로 관리하게끔 구현을 했습니다. 

추후 서버에 설정을 할 때마다 하나씩 하기 귀찮아서 통합으로 해두고, 그 설정파일의 .env만 변경할 수 있게끔 하는게 궁극적인 목표였습니다.

[브라우저]
   ↓ :3000
[Next.js]
   ↓ http://keural-api:8088
[Spring API]
   ↓ http://keural-fastapi:8000
[FastAPI]
   ↓
[Qdrant / vLLM]

핵심 포인트는 다음 두 가지

  • 컨테이너 간 통신은 Docker 네트워크 이름으로만
  • 외부 접근은 필요한 포트만 host에 바인딩

 

2. Docker 네트워크를 하나로 묶은 이유

networks:
  keural-network:
    external: true

모든 서비스는 이 네트워크 하나에 붙인다.

services:
  keural-api:
    networks:
      - keural-network

이렇게 하면 컨테이너 간 통신은 IP가 아니라 서비스 이름으로 가능해짐.

http://keural-api:8088
http://keural-fastapi:8000
http://qdrant:6333

 

도커 컴포즈로 엮지 않아도, 개별적으로 띄워져있는 도커에 network 설정하면 서비스 이름으로 가능해짐! 

장점

  • 서버 IP가 바뀌어도 영향 없음
  • 로컬 / 다른 서버 환경에서도 동일
  • 설정을 env로만 제어 가능

 

3. 포트 매핑 전략

 

외부에 반드시 노출해야 하는 포트만 열어두었습니다.

서비스내부 포트외부 포트

Next.js 3000 3000
Spring API 8088 8088
FastAPI 8000 8000
vLLM 8000 21434
Qdrant 6333 6333
PostgreSQL 5432 5432
ports:
  - "3000:3000"

컨테이너 간 통신에는 포트 매핑이 전혀 필요 없음!

 

Docker 네트워크 안에서는 이미 열려 있음.

 


 

4. Nginx를 쓰지 않은 이유

 

이번 환경에서는 Nginx를 의도적으로 사용하지 않았습니다.

 

 

이유 1. 온디맨드 서버

  • 서버가 항상 켜져 있지 않음
  • 복잡한 리버스 프록시 설정 불필요

이유 2. Docker 네트워크가 이미 내부 라우터 역할

keural-next → keural-api → keural-fastapi

이 흐름은 Docker가 이미 해결해준다.

이유 3. 장애 포인트 최소화

  • Nginx는 또 하나의 장애 지점
  • 설정 실수 시 전체 서비스 다운

이유 4. 추후 확장 가능

필요해지면 그때 추가할 계획인데,,, 아마 부하 분산이 들어갈 시점에 넣지 않을까 싶습니다.

 


 

5. 환경변수(.env)를 서비스 단위로 분리한 이유

 

기존 mvp 단계에서는 .env 하나로 시작했지만, 각 개발 파트가 다른 부분을 고려해서 .env를 분리했습니다.또한 보안 상의 이유도 있었어요.(왠지 좋지 않을 거 같아서..)

 

  • 프론트가 DB 비밀번호를 알 필요가 없음
  • FastAPI가 JWT secret을 알 필요가 없음

 

그래서 다음처럼 분리했다.

.env.api
.env.fast
.env.next
keural-api:
  env_file:
    - .env.api

 

장점

  • 보안 분리
  • 설정 책임 분리
  • 서버 교체 시 env만 교체

이미지는 공통, 설정은 환경별이라는 전략!

 


 

6. Spring 멀티모듈(common + api)과 환경변수 주입

 

Spring 구조는 다음과 같았습니다.

 

  • common 모듈: 설정 / 공통 코드
  • api 모듈: 실제 실행 JAR

 

실행은 api.jar 하나지만,

common 모듈의 application.yml도 함께 로딩되기 때문에

 

api.jar로 실행해도 common.yml의 설정은 적용된다.

 

그래서 common.yml에는 주소 하드코딩을 하지 않고 전부 env 기반으로 작성했습니다.

chat:
  fastapi:
    url: ${CHAT_FAST_API_URL:http://fastapi:8000}

Docker Compose에서 .env.api로 주입하면 끝이다.

 


 

7. SSH 포트 포워딩으로 로컬에서 테스트하기

 

서버는 내부망에만 열려 있어서

로컬에서 바로 접근할 수 없었다.

 

그래서 SSH 포트 포워딩을 사용했습니다.

ssh -N \
  -L 13000:127.0.0.1:3000 \
  -L 18088:127.0.0.1:8088 \
  -L 18000:127.0.0.1:8000 \
  -L 21434:127.0.0.1:21434 \
  user@server-ip

이후 로컬에서

http://localhost:13000

으로 Next.js 접근 가능.

 

SSH 세션이 살아있는 동안만 유효하다. 다만, 테스트를 해보니 로그인이 되지는 않더라구요. 이부분은 추후 게시글로 다뤄볼려구 합니다.

 


 

8. Docker Compose 스크립트 정리

 

Scripts 파일

./scripts/up.sh                  # 전체 기동
./scripts/restart_service.sh     # 특정 서비스 재시작
./scripts/logs_follow.sh         # 서비스 로그 추적
./scripts/gpu_check.sh           # GPU 상태 확인
./scripts/recreate.sh            # env 변경 후 재기동
./scripts/show_all_logs.sh       # 통합 로그

 

통합 로그 스크립트 사용법

./show_all_logs.sh error
./show_all_logs.sh info
./show_all_logs.sh debug

인자 없으면 전체 로그 출력.

 


 

9. 서버 재부팅 시 자동 기동

 

각 서비스에 다음 옵션을 넣었습니다.

restart: always

또한 서버 부팅 시 Docker 자체가 자동 시작되도록 설정.

 

서버가 재부팅돼도 compose는 자동 복구된다.

 


 

10. 결론

 

이번 온프레미스 환경에서 얻은 가장 큰 교훈

 

Docker Compose만으로도 충분히 운영이 가능하다

 

 

  • Nginx 없이도 가능
  • IP 하드코딩 없이 가능
  • env 분리로 유지보수 가능

 

'DevOps > Docker' 카테고리의 다른 글

[Docker compose - Postgres 설정] 부팅 이슈 해결하기 (Internship : Infra)  (0) 2026.01.20
[docker-compose]온프렘 도커 배포 실전 삽질기 (네트워크, 쿠키, 헬스체크 해결편)  (0) 2025.12.31
[Docker] 실행 방법  (0) 2025.12.11
[docker] 개념 정리  (0) 2025.12.10
[BuildX & 서버 이전] FastAPI + PaddleOCR 서버 이전기: "exec format error"와 Docker Buildx 완벽 가이드  (0) 2025.12.07
'DevOps/Docker' 카테고리의 다른 글
  • [Docker compose - Postgres 설정] 부팅 이슈 해결하기 (Internship : Infra)
  • [docker-compose]온프렘 도커 배포 실전 삽질기 (네트워크, 쿠키, 헬스체크 해결편)
  • [Docker] 실행 방법
  • [docker] 개념 정리
yeseul-kim01
yeseul-kim01
  • yeseul-kim01
    슬 개발일지
    yeseul-kim01
  • 전체
    오늘
    어제
    • 분류 전체보기 (79)
      • 자격증 (1)
        • 정보보안기사 (0)
      • DevOps (17)
        • Docker (6)
        • Kubernetes (1)
        • GitHub Actions (0)
        • AWS (4)
        • Monitoring (1)
        • Nginx (1)
        • GCP (3)
      • ServerDev (34)
        • SpringBoot (13)
        • DJango (5)
        • FastAPI (14)
        • Next (0)
        • Flask (0)
        • Database (2)
      • Algorithm (2)
        • BFS (0)
        • DFS (1)
        • 다익스트라 (0)
      • CS (8)
      • Data Engineering (1)
      • AI&MLOps (2)
      • Architecture (6)
      • Software Engineering (0)
        • Library Packaging (0)
      • Project (5)
        • docx-generator (0)
        • speak-note (2)
        • ms-serving (1)
        • keyshield (2)
      • ProgrammingLanguages (3)
        • Python (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    FastAPI - CORS 마스터
    프로젝트기록-speaknote
    실무일기-인프라편
    SpringBoot
    트러블슈팅
    FastAPI
    MLops
    KeyShield
    depends
    STT
    Django
    비동기처리
    멀티모듈
    docker
    실시간시스템
    rag
    실무일기-백엔드편
    백엔드
    프로젝트기록-KeyShield
    아키텍처설계
    SpeakNote
    KServe
    NLP부트캠프
    하이브리드아키텍처
    Kubernetes
    아키텍처
    동시성제어
    di
    grpc
    multipartfile
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
yeseul-kim01
[docker-compose]온프레미스 환경에서 Docker Compose로 서비스 구성하기
상단으로

티스토리툴바