Docker Compose

2025. 8. 8. 18:36Infra

Docker Compose

여러 개의 컨테이너로 구성된 애플리케이션을 정의하고 실행하기 위한 도구.

  • 명령어 단순화 : docker run에 붙이던 옵션들을 YAML 파일에 모두 정리할 수 있다.
  • 서비스 전체 관리 : docker-compose up 명령으로 모든 서비스를 한 번에 띄울 수 있다.
  • 네트워크 자동화 : 모든 서비스를 위한 전용 내부 네트워크를 자동 생성한다. 서비스들은 네트워크 안에서 컨테이너 이름으로 서로를 쉽게 찾아 통신할 수 있다.

 

Docker Compose 설치

#Docker Compose 플러그인 설치
sudo apt-get update
sudo apt-get install -y docekr-compose-plugin

#설치 확인
docker compose version

 

프로젝트 구조 정리

~/test-docker/
├── docker-compose.yml      # (새로 작성할 파일)
│
├── spring-app/
│   ├── app                 # (애플리케이션 코드, 빌드 파일(.jar))
│   └── Dockerfile          # (기존 Dockerfile)
│
├── python-app/
│   ├── main.py             # (애플리케이션 코드)
│   ├── requirements.txt    # (의존성 목록)
│   └── Dockerfile          # (기존 Dockerfile)
│
└── nginx/                  # (새로 만든 폴더)
    ├── Dockerfile          # (새로 작성할 Nginx용 Dockerfile)
    └── myapp.conf          # (전에 만들어뒀던 Nginx 설정 파일 복사)

이렇게 정리했다.

 

Nginx 컨테이너화

vim ~/test-docker/nginx/Dockerfile

Nginx용 Dockerfile을 생성한다.

# 공식 Nginx 베이스 이미지를 가져온다.
FROM nginx:stable-alpine

# 베이스 이미지 내부에서 default 파일 삭제.
# ec2 서버의 파일 시스템에서 삭제하는 게 아니다!
RUN rm /etc/nginx/conf.d/default.conf

# ec2의 파일을 이미지 내부로 복사.
COPY tuji.conf /etc/nginx/conf.d/

공식 Nginx 베이스 이미지는 /etc/nginx/conf.d/default.conf 파일을 포함한다.

기본 포함된 "Welcome to nginx!" 대신 내가 만든 설정으로 대체하는 내용이다.

 

ec2 서버의 nginx 설정 파일(tuji.conf)을 수정해서 localhost가 아닌, Docker 네트워크의 서비스를 바라보도록 해야 한다.

기존 localtion /api/spring/ 에서 proxy_pass가 localhost:8080과 같이 되어 있는데, spring-app:8080으로 바꾼다.

api/python도 localhost:8000을 fastapi-app:8000으로 변경했다.

 

docker-compose.yml

네트워크와 환경 변수들을 정의한다.

민감 정보는 vault, aws secret 같은 전용 저장소에 저장하는 게 좋지만, 일단 지금은 여기에 직접 주입한다.

vim ~/test-docker/docker-compose.yml

docker-compose.yml을 생성한다.

더보기

version: '3.8'

services:
  # 1. Nginx 서비스 (리버스 프록시)
  nginx:
    build: ./nginx
    container_name: test_nginx
    ports:
      - "80:80"
    networks:
      - test_network
    depends_on:
      - spring-app
      - fastapi-app

  # 2. Spring Boot 서비스
  spring-app:
    build: ./spring-app
    container_name: test_spring
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      # 여기에 DB 접속 정보 등 환경변수를 넣는다.
    networks:
      - test_network
    depends_on:
      - mysql-db
      - redis-cache

  # 3. FastAPI 서비스
  fastapi-app:
    build: ./fastapi-app
    container_name: test_fastapi
    networks:
      - test_network
    depends_on:
      - mysql-db
      - redis-cache

  # 4. MySQL 데이터베이스 서비스
  mysql-db:
    image: mysql:8.0
    container_name: test_db
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: test_db
      MYSQL_USER: test_user
      MYSQL_PASSWORD: test_user_password
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - test_network

  # 5. Redis 캐시 서비스
  redis-cache:
    image: redis:alpine
    container_name: test_redis
    networks:
      - test_network

# Docker가 관리할 네트워크와 볼륨을 정의
networks:
  test_network:
    driver: bridge

volumes:
  mysql_data:

nginx:
    build: ./nginx
    container_name: test_nginx
    ports:
      - "80:80"
    networks:
      - test_network
    depends_on:
      - spring-app
      - fastapi-app
  • nginx : docker-compose.yml 파일 내에서 식별하는 서비스 이름.
  • build : 서비스를 위한 Docker 이미지를 ./nginx에 있는 Dockerfile로 빌드해서 사용.
  • container_name : 서비스로부터 생성될 컨테이너에 고정된 이름 부여.
  • ports : 외부(host)포트:내부(컨테이너)포트 형식으로 포트 연결.
    ec2 서버 80 포트 요청을 컨테이너 내부 80 포트로 전달.
  • networks: 컨테이너를 격리된 가상 네트워크에 연결. IP 주소가 아닌 서비스 이름으로 통신 가능.
  • depends_on : 서비스들의 시작 순서 제어. 지정된 서비스들이 정상 실행 중일 때 동작.
mysql-db:
    image: mysql:8.0
    container_name: test_db
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: test_db
      MYSQL_USER: test_user
      MYSQL_PASSWORD: test_user_password
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - test_network
  • environment : MySQL 서비스 초기화 및 구성. 볼륨이 비어있는 최소 실행 시에만 적용된다.
  • 다른 서비스들과 같이 ec2에 설치된 MySQL과는 무관하게 새로운 환경(컨테이너)에 MySQL을 설치하고 설정하게 된다.
spring-app:
    build: ./spring-app
    container_name: test_spring
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      # 여기에 DB 접속 정보 등 환경변수를 넣는다.
    networks:
      - test_network
    depends_on:
      - mysql-db
      - redis-cache
  • environment : 컨테이너 내부 환경 변수 설정. mysql-db  environment와 달리 컨테이너가 실행될 때마다 적용된다.
    • 설정을 코드와 분리하기 위함이다.
    • DB 접속 비밀번호나 외부 API 키 같은 설정 값들을 소스 코드에 직접 하드코딩하는 대신, 실행 시점에 외부에서 주입해주는 방식이다.
    • 동일한 Docker 이미지를 개발, 테스트, 운영 환경에서 설정만 바꿔가며 재사용할 수 있다.
  • SPRING_PROFILES_ACTIVE : 환경에 따라 애플리케이션 동작 방식 결정. 개발(dev), 테스트(test), 운영(prod).
    • application.yml : 모든 환경 공통
    • application-dev.yml : 개발 환경 전용
    • application-prod.yml : 운영 환경 전용
    • 테스트 환경 전용 파일은 src/test/resources에 application.yml 파일을 생성하는 게 권장된다.
    • 개발 단계 :  .yml 파일들은 src/main/resources 폴더에 위치하며 빌드 시 .jar 파일에 함께 패키징된다.
    • 배포 단계 :  application-prod.yml 파일(환경 변수)을 따로 생성하고 빌드된 .jar 파일 내부의 .yml 파일에 덮어쓴다.
      1. jar 파일 내부에 있는 application.yml을 읽어 모든 설정의 기본값을 만든다.
      2. 활성화된 프로파일(prod)에 맞춰 .jar 내부의 application-prod.yml을 읽고 기본값과 겹치는 설정이 있으면 덮어쓴다.
      3. .jar 파일 외부의 특정 경로(config/)에 application-prod.yml 파일이 있으면 이 내용으로 겹치는 부분을 다시 덮어쓴다.(이건 컨테이너 환경에서는 잘 사용되지 않음. 진짜 제대로 관리하려면 vault, secret manager 써야 함. 코드와 설정을 분리해도 파일은 그 자체로 또 다른 관리 대상이 되기 때문.)
    • 일단 지금(공부 중)은 환경 변수 주입 방식을 익히자. (SPRING_DATASOURCE_URL 등등..)
    • DB URL : mysql-db 서비스에 접속하기 위한 url인데, host는 서비스 이름(mysql-db), port는 기본 포트 3306, 나머지는 mysql-db의 environment 설정값으로 적으면 된다.
      SPRING_DATASOURCE_URL=jdbc:mysql://mysql-db:3306/test_db
volumes:
  mysql_data:

Docker 컨테이너는 기본적으로 일회성이다. 컨테이너를 삭제하는 순간, 안에 있던 모든 데이터도 사라진다.

예를 들어, MySQL 버전을 업그레이드하기 위해 기존 컨테이너를 삭제하고 새로 만들면 모든 작업이 날아간다.

이 문제를 해결(영속성 보장)하기 위해 컨테이너 외부의 저장 공간을 컨테이너 내부 특정 폴더와 연결(마운트)하는 방식이 볼륨이다.

 

 

Docker Compose 실행

# 모든 서비스의 이미지 빌드 및 백그라운드 실행
docker compose up --build -d

중간에 docker-compose.yml에 fastapi 폴더 경로를 잘못 설정해서 redis-cache, mysql-db를 성공적으로 pull을 했다가 중단됐었다.

docker-compose.yml을 수정하고 다시 빌드를 했는데, Docker가 이전 빌드 시도에서 캐시된 버전을 사용해서 빠르게 실행될 수 있었다.

WARN[0000] /home/ubuntu/test-docker/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion

의미 : docker-compose.yml에 적어둔 version 속성이 구식이라 무시하겠다. 헷갈릴 수 있으니 삭제를 권장한다.

과거에는 버전을 명시하는 게 필수적이었으나, 최신 Docker는 docker-compose가 아닌 docker compose라는 통합 플러그인 방식을 사용한다. 이 방식이 Compose Specification이라는 단일 표준을 따르기에 버전을 명시할 필요가 없다.

 

80번 포트가 사용 중이라는 에러가 발생했다.

sudo systemctl stop nginx
sudo systemctl disable nginx

Nginx를 서버에 직접 설치해뒀었기 때문이다. 중지시키고 자동 실행도 비활성화하자.

이미지가 제대로 만들어졌으나 포트 연결할 때 문제가 발생한 거라 빌드를 빼고 docker compose up -d만 명령하면 된다.

 

docker compose ps

실행 중인 모든 서비스의 상태 확인.

test_db, test_fastapi, test_nginx, test_redis, test_spring이 모두 정상 동작 중이다.

# 특정 서비스의 로그 실시간 확인
docker compose logs -f spring-app
# 모든 서비스 중지 및 컨테이너/네트워크 삭제
docker compose down

로그 그만 보고 싶으면 Ctrl+C.

 

모든 애플리케이션을 하나의 파일로 관리하기 완성~ 짝짝짝!!!!!!!

이제 CI/CD만 하면 된다!

'Infra' 카테고리의 다른 글

Jenkins-GitLab 연동  (0) 2025.08.11
Jenkins 시작  (2) 2025.08.11
컨테이너  (3) 2025.08.07
GPG(GNU Privacy Guard)  (4) 2025.08.06
Docker 설치  (0) 2025.08.06