여러 개의 도커 컨테이너를 정의하고 한 번에 실행 및 관리가 가능
- 도커 컨테이너 간 통신이 필요할 때 docker-compose를 통해 여러 컨테이너 및 네트워크를 한 번에 실행 및 관리할 수 있음
- docker-compose로 배포는 불가능 : 로컬 테스트용
네트워킹
- a 컨테이너 4개 중 첫 번째 a 컨테이너와 두 번째 a 컨테이너를 통신시키려고 할 때, 3가지 방법을 통해 통신이 가능
- OS를 통해 바로 통신
- LAN 통신 (공유기 내부망 통신)
- WAN 통신 (외부 통신)
- Docker의 컨테이너들끼리 통신을 할 때 네트워크로 묶어서 1, 2, 3 유형의 통신이 가능
- 내부망일 경우 1번, Docker 내부 컨테이너들끼리는 2번, 외부 서버와의 통신은 3번 유형의 통신 진행

- Docker Engine은 가상 DNS를 통한 내부의 가상 네트워크망 구성 가능
- 네트워크 망 안에는 여러 컨테이너들을 담을 수 있음
- 한 네트워크 망 안에서는 내부 통신 가능
- 다른 네트워크끼리 통신할 때는 Docker Engine 내부 DNS를 통해 네트워크를 찾아서 통신
- 외부 네트워크는 Host OS를 통해 통신

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


- localhost:8080으로 진입하여 블로그 확인
- 기본 더미 데이터가 없기 때문에 글, 유저가 존재하지 않음
- 회원가입 및 글 쓰기 정상 작동 확인






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


Share article