EKS – Docker Compose 활용한 다중 컨테이너 환경 구축

docker 컨테이너를 기반으로 서버 환경을 구축할 때 발생하는 불편함이 다소 있다
  • 개별 컨테이너 수동 생성 및 관리의 번거로움: 여러 서비스(예 Spring 애플리케이션, MySQL, Redis)를 각각 Docker 컨테이너로 띄울 때, 각 컨테이너마다 docker run 명령어를 입력해야 하는 불편함이 있다
  • 컨테이너 간 통신 설정의 복잡성: Spring 컨테이너 내부에서 호스트 PC의 서비스에 접근하기 위해 localhost 대신 host.docker.internal을 사용해야 하는 등 네트워크 설정에 대한 이해와 변경이 필요하다

Docker Compose

Docker Compose는 여러 개의 Docker 컨테이너를 단일 서비스로 정의하고 실행하기 위한 도구이다. docker-compose.yml 이라는 YAML 파일을 사용하여 애플케이션의 모든 서비스를 구상하며, 단일 명령어로 정의된 모든 서비스를 시작, 중지, 재시작할 수 있다

  • 설치: Docker를 설치하면 Docker Compose도 함께 설치되므로 별도의 설치 과정이 필요 없다
    • Docker Desktop을 설치한 경우, Linux에서는 버전에 따라 다른 듯 하다
  • 활용: 주로 로컬 개발 환경에서 복수의 컨테이너를 일괄적으로 기동하고, 컨테이너 간의 통신을 위한 네트워크를 간편하게 구성할 때 유용하게 사용된다

Docker Compose의 주요 이점

컨테이너 일괄 관리

  • docker-compose.yml 파일에 MySQL. Redis, Spring 서버 등 모든 서비스 컨테이너의 설정(이미지, 포트, 환경 변수 등)을 정의한다
  • docker compose up -d 명령어 하나로 정의된 모든 컨테이너를 동시에 빌드하고 백그라운드에서 실행할 수 있다
  • docker compose down 명령어로 모든 컨테이너를 한 번에 중지하고 삭제할 수 있어 관리의 효율성이 극대화된다
  • 변경된 소스 코드를 반영하여 이미지를 새로 빌드하고 컨테이너를 실행하려면 docker compose up -d –build 명령어를 사용한다 (특히 Spring 애플리케이션과 같이 직접 빌드하는 서비스에 필수적)

간편한 컨테이너 간 통신

  • Docker Compose는 기본적으로 정의된 모든 서비스 컨테이너를 하나의 네트워크에 자동으로 연결한다
  • 이 덕분에 application.yml에서 localhost나 host.docker.internal 대신 docker-compose.yml에 정의된 서비스 이름을 사용하여 다른 컨테이너에 접근할 수 있다
  • 예를 들어, mydb라는 이름으로 정의된 MySQL 컨테이너에 접근하려면 Spring 컨테이너의 환경 변수에서 jdbc:mysql://mydb:3306/…와 같이 설정할 수 있다
  • 이는 Spring 애플리케이션 application.yml을 localhost 기준으로 유지하고, Docker Compose로 실행할 때만 환경 변수를 통해 설정을 덮어쓰도록 하여 로컬 개발과 도커 환경 간의 전환을 유연하게 만든다

docker-compose.yml 파일 예시 및 설명

<> Yaml

version: '3.8' # Docker Compose 파일 형식 버전 (큰 의미 없음)
services: # 정의할 서비스(컨테이너)들을 나열
  mydb: #MySQL 서비스 정의
    image: mysql # 사용할 Docker 이미지
    environment: #컨테이너 내부 환경 변수 설정
      - MYSQL_ROOT_PASSWORD=1234
      - MYSQL_DATABASE=ordersystem
    ports: # 호스트와 컨테이너 포트 매핑 (호스트포트:컨테이너포트)
      - "3306:3306"

  myredis: # Redis 서비스 정의
    image: redis
    ports:
      - "6379:6379"

  my-spring: # Spring 애플리케이션 서비스 정의
    build: # 이미지를 빌드하는 설정 (Dockerfile 경로 지정)
      context: . # Dockerfile이 있는 디렉토리 (현재 디렉토리)
      dockerfile: Dockerfile # 사용할 Dockerfile 이름
    ports:
      - "8080:8080"
    depends_on: # 이 시버스가 시작되기 전에 먼저 실행되어야 할 서비스 지정
      - mydb
      - myredis
    restart: on-failure:10 # 컨테이너 실패 시 최대 10번 재시작 시도
    environment: # Spring 애플리케이션의 환경 변수 설정 (application.yml 설정 덮어씀)
      - SPRING_DATASOURCE_URL=jdbc:mysql://mydb:3306/ordersystem?useSSL=false&allowPublicKeyRetrieval=true # 서비스 이름 'mydb' 사용
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=1234
      - SPRING_REDIS_HOST=myredis # 서비스 이름 'myredis' 사용
  • services: 여러 컨테이너 서비스들을 정의하는 섹션이다
  • image: Docker Hub 등에서 사용할 이미지 이름을 지정한다
  • build: 현재 프로젝트 내의 Dockerfile을 사용하여 이미지를 직접 빌드할 때 사용한다. context는 Dockerfile이 있는 경로를, dockerfile은 Dockerfile 파일 이름을 명시한다
  • environment: 컨테이너 내부에 환경 변수를 설정한다. Spring 애플리케이션의 경우, SPRING_DATASOURCE_URL과 같은 변수를 통해 application.yml의 설정을 덮어쓸 수 있다. 여기서 mydb, myredis와 같이 서비스 이름을 사용하여 컨테이너 간 통신을 설정하는 것이 핵심이다
  • posts: 호스트 포트와 컨테이너 내부의 포트를 매핑한다 (예: 3306:3306은 호스트의 3306번 포트를 컨테이너의 3306번 포트에 연결)
  • depends_on: 서비스 간의 의존성을 정의한다. my-spring 서비스는 mydb와 myredis가 먼저 시작된 후에 실행된다
    • 이는 시작 순서만 보장하며, 서비스가 완전히 준비되었음을 의미하지 않는다
  • restart: on-failure:10: 컨테이너가 오류로 종료될 경우 최대 10번 재시작을 시도한다. 이는 depends_on 만으로는 부족할 수 있는 서비스 준비 완료 시간을 보완하여, DB 스키마 생성 등 시간이 필요한 작업으로 인해 Spring 애플리케이션이 초기에 실패하더라도 자동으로 북구되도록 돕는다

Docker Compose의 활용: 로컬 개발 환경 최적화

  • 팀 개발 환경 표준화: 새로운 팀원이 합류했을 때, 복잡한 로컬 환경 설정 가이드를 제공하는 대신 git clone 후 docker compuse up -d 명령어 하나로 모든 개발 환경(DB, 캐시, 백엔드 서버 등)을 손쉽게 구축하고 바로 개발을 시작할 수 있도록 할 수 있다. 이는 온보딩 시간을 크게 단축하고 개발 생산성을 높인다
  • 일괄된 개발 환경: 모든 개발자가 동일한 Docker 기반의 환경에서 작업하므로, “내 컴퓨터에서는 되는데 다른 사람 컴퓨터에서는 안 되네”와 같은 환경 불일치 문제를 줄여준다

운영 환경에서의 사용

프로덕션(운영) 환경에는 Docker Compose를 직접 사용하는 경우는 상대적으로 적다. 운영 환경에서는 Kubernetes와 같은 오케스트레이션 도구나 클라우드 서비스의 배포 파이프라인을 활용하여 더 복잡하고 확장성 있는 배포 전략을 구현하는 것이 일반적이다. 하지만 로컬 개발 환경에서 Docker Compose의성은 여전히 좋다

<> Bash

docker compose up -d --build
  • 컨테이너가 하나로 보인다. > 를 누를 때 펼쳐진다