[Docker] 5. 도커 컴포즈

김주희's avatar
Aug 01, 2025
[Docker] 5. 도커 컴포즈
컴포즈로는 배포 못 함!
컴포즈는 로컬에서 연습할 때 사용하는 것
 
호스트 컴퓨터와 컨테이너는 같은 계층 layer에 뜬다.
 
도커 엔진 내에 도커 api 서버가 있음
호스트에서 명령어 → 도커 엔진으로 감
실제로는 명령어가 아니라 프로세스간의 통신을 해야하는데
 
같은 애플리케이션 하나의 클래스에서는 힙을 공유해서 메서드
 
다른 애플리케이션에서는 프로세스간 통신 방법
  1. 서버를 두고 서버에 메세지 던져서 주고 받고
  1. OS로 주고 받고
 
호스트 컴퓨터 - 가상화 →가상 네트워크 (진짜 네트워크 세상(공유기, www(LAN, WAN))은 아님)
 
도커 컴포즈 = pc가 다르면 결합이 안됨
 
도커 엔진 api는 사설 DNS 서버를 가짐→ N1과 N2의 위치를 가짐
 
다른 네트워크 이름으로 찾을 수 있음
IP대역대가 같아짐
CIDR 가능
 
notion image
 

도커 컴포즈 기본

docker-compose.yml 이름 변형 불가!
 
버전마다 문법이 조금씩 다르기 때문에 버전이 중요!
yml은 key값이 붙고 : 뒤에 한 칸을 무조건 띄운다. 내부에 쓸 때는 두 칸 띄운다. -는 배열
 
 
도커 컴포즈는 하나의 컨테이너를 마이크로한 서비스로 본다.
따라서 services 안에는 컨테이너가 들어와야 한다.
  • my_server : 이미지 이름 = 변수
  • build : 이미지 이름 받아서 설정 여기서 쓰고 해서 띄우지 말고 도커 파일을 찾아서 띄우기! 도커 파일로 세팅하기!!!!!!
    • ./server 내부의 Dockerfile로 빌드하겠다
 
 
docker-compose up -d
이미지 굽고 컨테이너 실행하고 등등 다 되어있는거임
근데 apt update 등 모든건 dockerfile에서 하기
 
notion image
 
notion image
 
notion image
 
notion image
 
notion image
 
notion image
 
컴포즈 죽이기…
docker-compose down
notion image
 

기본버전
버전(최신버전으로) 서비스들(= 컨테이너들) 이미지 직접 굽지 말고 Dockerfile쓰기 포트 재시작
 

두 개의 서비스 연결하기

notion image
  • version :
  • services:
  • build:
    • context:
  • ports:
  • restart:
  • networks:
    • drivers:
  • depends_on:
  • environment:
     
    RUN은 build될때 실행되고 ENRYPOINT와 CMD는 build될 때가 아니라 컨테이너가 실행될때 실행된다.
    RUN은 build될때 실행되고 ENRYPOINT와 CMD는 build될 때가 아니라 컨테이너가 실행될때 실행된다.
     
     
     
    db가 먼저 떠야 spring 서버 실행시 db와 연결되면서 터지지 않는다.
     
    depends_on:
    서비스를 이름으로 찾는다는거는
    서비스 이름으로 사설 네트워크로 뜬 가상 컨테이너를 찾아서 켜졌는지, entrypoint가 실행됐는지, 프로세스가 떴는지 등 전부 체크해준다는 것!
    이거 안하면 두 개 동시에 떠서 터진다.
     
    environment : 컨테이너가 떠서 실행이 되는 순간
    디스크에 기록X 컨테이너 뜨기 직전에 잠깐 뜸
     
    근데 dockerfile의 env에 적는건 다름 → 이미지에 환경변수가 귀속된다. 다르다.
    ⇒ 타이밍 문제로 나중에 멘탈깨질수 잇으니 주의…
     
    이미지가 실행됐을 때 외부에 뜨는게 environment
    이미지에 기록되어있는게 Dockerfile의 env
     
     
    notion image
     
    Dockerfile에 맞춰서 docker-compose.yml을 쓰기
     
    hostname에 서비스명을 적으면 찾아줌..
    서비스명으로 DNS을 찾아서 DNS의 IP 주소 갱신 → 서비스 디스커버리 (유레카 디스커버리?
     

    도커파일을 가지고 from myqsl → pull
    env 설정
    이미지가 실행돼서 내부에 환경변수가깔린것
    run 해서 apt update나 시간ㅅㄹ정 가능 → 이때 env에 적은 환경변수 당연히 땡겨짐
    yml에 쓴 내용은 안땡겨짐 이때는 env만 땡겨서 쓰고
    → 굽기위해서 run을하는것과 최종적으로 run을하는 것은 다름
    완전히 구워지고 나서 엔트리포인트로 실행될때는 진짜 실행되는거 이때는 yml파일의 environment의 환경변수를 땡길 수 있음
    ⇒ 중요하니까 기억하기!!!!!!!!!!!!!
     
    from과 copy 사이에 docker run이 된거임
     

    이미지 굽기 위한 프로비저닝 → entrypoint.sh
    계속 RUN써서 dockerfile에서 쓰는건 별로
    스크립트는 따로 만들어서 작성하는게 낫다.
     

    build는 준비
    build를 하면 실행을 해야함
    도커 파일도 빌드를 하면 이미지를 굽는게 목적이므로 직접 실행을 해줘야 됨
    도커 컴포즈는 이미지들을 들고와서 연결해서 실행시켜줌
    context에 도커파일을 뒀으니
    빌드부터 시작됨
     
    서비스 = pods (찐 이름은 이거) = 컨테이너들을 묶는 단위인 "파드(Pod)
     
    엔트리포인트를 기반으로 run이 실행됨
     
    내가 안만들면 디폴트 네트워크가 생겨짐 폴더명으로 생겨짐 → 사설 네트워크가 하나가 뜸 (ex) ex07_network 이런식으로
     
    지금 박스 3개 만들어진거
    notion image
     
    gateway가 만들어지는데 bridge 적으면 host 시스템에서 컨테이너로 바로 접근 못하는
    공유기 = gateway ip
     
     
    같은 클러스터 내에 존재하면 서비스 디스커버리에 의해 이름을 ip 주소로 변환해줌
    notion image
     
     
    뭐부터 실행되는지 적어보면서 추적해보기
    이 컨테이너의 ip를 찾아보는 명령어 등등 명령어 gpt한테 물어보기
     
    notion image
     
    notion image
    Mysql이 실행중이면 종료해야 컨테이너가 실행된다!!
     
    notion image
     
    notion image
    docker inspect 컨테이너ID
     
    notion image
    notion image
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    전체 코드

    docker-compose.yml

    version: "3.8" services: my_db: build: context: ./db ports: - "3306:3306" restart: always networks: - backend_network volumes: - my_db_data:/var/lib/mysql 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
     

    db/Dockerfile

    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

    db/init.sql

    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;

    server/Dockerfile

    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"]

    server/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
     

     
    docker-compose up을 하면 build가 1번
    실행시에만 depends-on이 발동 build할때는 X
     
    notion image
    notion image
     
     
     
    dockerfile의 env에 환경변수로 서비스명을 적어두면 서비스가 아직 안떴기 때문에 서비스에 뜰 때 dns에 등록되므로 my_db글자가 환경변수에 찍힘 ip주소가 아니라. 그래서 멘탈이 깨져용
     
    이미지 구워지는 순간에는 DNS에 my_db 없음 이미지 둘 다 구워지고 나서 컨테이너 뜨니까
     
     
    뭐가 interceptor..?낚아채서 my_db
     
    순서
    yml에 rds_hostname 땡길때 my_db라고 적혀있으니까 도커가 낚아채서 실제 ip를 찾음 그리고 걔가 등록된다.
     
     

    브릿지는 포트포워딩으로만 들어가고 host로 바로 못들어감 근데 몰라도 되고 걍 다 쓰면댐
    notion image
     
    Share article

    jay0628