[Docker] 8. Docker Compose

문정준's avatar
Aug 01, 2025
[Docker] 8. Docker Compose

여러 개의 도커 컨테이너를 정의하고 한 번에 실행 및 관리가 가능

  • 도커 컨테이너 간 통신이 필요할 때 docker-compose를 통해 여러 컨테이너 및 네트워크를 한 번에 실행 및 관리할 수 있음
  • docker-compose로 배포는 불가능 : 로컬 테스트용
 

네트워킹

  • a 컨테이너 4개 중 첫 번째 a 컨테이너와 두 번째 a 컨테이너를 통신시키려고 할 때, 3가지 방법을 통해 통신이 가능
      1. OS를 통해 바로 통신
      1. LAN 통신 (공유기 내부망 통신)
      1. WAN 통신 (외부 통신)
  • Docker의 컨테이너들끼리 통신을 할 때 네트워크로 묶어서 1, 2, 3 유형의 통신이 가능
    • 내부망일 경우 1번, Docker 내부 컨테이너들끼리는 2번, 외부 서버와의 통신은 3번 유형의 통신 진행
notion image
  • Docker Engine은 가상 DNS를 통한 내부의 가상 네트워크망 구성 가능
    • 네트워크 망 안에는 여러 컨테이너들을 담을 수 있음
    • 한 네트워크 망 안에서는 내부 통신 가능
    • 다른 네트워크끼리 통신할 때는 Docker Engine 내부 DNS를 통해 네트워크를 찾아서 통신
    • 외부 네트워크는 Host OS를 통해 통신
notion image

docker-compose

  • yml 파일로 작성
    • 문법 및 띄어쓰기가 매우 중요 : 간격이 다르면 실행 안됨
  • services : 실행시킬 container 종류
    • build : 이미지를 구울 옵션 선택
      • context : Dockerfile을 작성된 경로에서 찾음
      • image : Docker hub의 이미지 선택
    • ports : 오픈할 포트 (포트 포워딩 시 작성 필요)
    • restart : 재시작 타이밍 설정
    • depends_on : 해당 컨테이너 실행 된 이후에 실행 (실행 순서 설정)
    • environment : 환경 변수 설정
      • Dockerfile 내 env는 image에 귀속되지만 compose 내부 environment는 컨테이너 실행 때 잠시 실행되고 사라짐
      • compose에 작성하는 환경 변수는 Dockerfile 내 env를 사용해도 됨 : 먼저 생성됨
    • networks : 네트워크망 설정
version: '3.8' services: my_db: build: context: ./db ports: - "3306:3306" restart: always networks: - backend_network my_server: build: context: ./server ports: - "8080:8080" restart: always depends_on: - my_db environment: - RDS_HOSTNAME=my_db - RDS_PORT=3306 - RDS_USERNAME=ssar - RDS_PASSWORD=ssar1234 - RDS_DB_NAME=blogdb networks: - backend_network networks: backend_network: driver: bridge frontend_network: driver: bridge
 

Dockerfile + entrypoint.sh

  • Dockerfile 실행 시 미리 명령을 다 적어두는 것보다 컨테이너 실행 시 실행시킬 shell 파일을 작성해두는 것이 좋음
    • RUN 명령어가 너무 많으면 파일 해석이 어려움
    • 이때 사용하는 것이 entrypoint.sh
    • image를 미리 build한 후 이후에 실행할 때 자동으로 실행시킬 스크립트를 미리 작성 후 ENTRYPOINT를 통해 파일 실행 시점을 지정
FROM openjdk:11-jdk-slim RUN apt-get update RUN apt-get install -y git WORKDIR /app COPY ./entrypoint.sh ./entrypoint.sh RUN ["chmod", "+x", "entrypoint.sh"] EXPOSE 8080 ENTRYPOINT ["/bin/bash", "./entrypoint.sh"]
git clone https://github.com/busanuv/blog-last.git cd blog-last chmod +x gradlew ./gradlew build chmod +x build/libs/*.jar java -jar -Dspring.profiles.active=docker build/libs/*.jar
 

DB 설정

  • 서버를 실행하기 에 DB가 생성되어 있어야 함
    • DB 내부에서 사용할 환경변수를 우선 설정 : image에 귀속
    • init.sql 파일 작성 : 테이블 생성
FROM mysql COPY init.sql /docker-entrypoint-initdb.d/init.sql ENV MYSQL_USER=ssar ENV MYSQL_PASSWORD=ssar1234 ENV MYSQL_ROOT_PASSWORD=root1234 ENV MYSQL_DATABASE=blogdb CMD ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"] EXPOSE 3306
use blogdb; CREATE TABLE IF NOT EXISTS user_tb ( id integer auto_increment, created_at timestamp, email varchar(20) not null, password varchar(60) not null, username varchar(20) not null unique, profile varchar(100), primary key (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; CREATE TABLE IF NOT EXISTS board_tb ( id integer auto_increment, content varchar(10000), created_at timestamp, title varchar(100) not null, user_id integer, primary key (id), constraint fk_board_user_id foreign key (user_id) references user_tb (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; CREATE TABLE IF NOT EXISTS reply_tb ( id integer auto_increment, comment varchar(100) not null, created_at timestamp, board_id integer, user_id integer, primary key (id), constraint fk_reply_board_id foreign key (board_id) references board_tb (id), constraint fk_reply_user_id foreign key (user_id) references user_tb (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; FLUSH PRIVILEGES;
 

실행 결과

  • DB를 우선 실행하고, 그 다음 서버를 실행함
    • docker-compose 실행/종료 명령어는 다음과 같이 입력
# docker-compose 실행 (백그라운드) docker-compose up -d # docker-compose 종료 docker-compose down
notion image
notion image
 
  • localhost:8080으로 진입하여 블로그 확인
    • 기본 더미 데이터가 없기 때문에 글, 유저가 존재하지 않음
    • 회원가입 및 글 쓰기 정상 작동 확인
notion image
 
notion image
notion image
notion image
notion image
notion image
 

Docker Compose 네트워킹 및 로직

  • docker-compose에서 컨테이너의 build를 우선 실행
    • build는 image를 다운로드 받거나 Dockerfile을 읽어서 수행
      • Dockerfile의 from 명령어가 실행되면 잠시 컨테이너가 실행됨 : 이미지를 다운받음
      • env, run 등의 명령어를 통해 이미지가 build되기 전 작업을 수행
        • env는 해당 이미지가 build되면 귀속됨
      • entrypoint, cmd 등의 명령어를 읽어 이미지가 실행될 때 실행할 명령을 저장하고 build
      • 이때 env에 서비스명을 적으면 안 됨
        • docker-compose는 가상 DNS를 통한 Service Discovery를 제공
        • 이때, 실행되는 타이밍은 실제로 컨테이너가 run될 타이밍
        • 컨테이너가 run 되기 전에 서비스명을 적을 경우 내부 컨테이너에서는 이를 주소로 인식할 수 없기 때문에 그냥 문자열로 인식함
        • 주소가 바인딩되지 않았기 때문에 서버가 실행되며 에러 발생의 위험 발생
    • 이미지들이 build되고 난 이후 각 컨테이너들이 실행되면 Docker 내부에서 가상 IP를 지정
      • 이때, 묶인 네트워크 망에 따라 IP를 규칙에 맞게 지정
      • 각 컨테이너들이 실행되면 가상 IP를 부여받고, 가상 DNS 및 각 네트워크 망의 라우팅 테이블에 정보가 저장됨
        • 라우팅 테이블을 통해 해당 컨테이너를 찾아갈 때 필요한 MAC 주소는 가상으로 부여됨
        • 서버가 실행되다가 종료되어 다시 실행되면 주어진 IP가 변할 수 있음
          • 이때, Service Discovery를 통해 해당 서비스명으로 IP를 찾기 때문에 동적으로 변경
 
  • Dockerfile 내부에서 선언한 env와 docker-compose에서 작성한 environment의 이름이 같을 경우, docker-compose에서 작성한 environment 값으로 덮어씀
    • 우선순위 : docker run -e [ ] > docker-compose의 environment > Dockerfile 내부 env
notion image
notion image
 
Share article

sxias