Docker-Compose
1. 개요
도커 컴포즈는 공통적인 목적을 갖는 애플리케이션 스택을 YAML 형식으로 정의하고, 이를 실행하기 위한 다중 컨테이너 관리 도구이다.
애플리케이션 스택의 공통성은 동일한 목표를 달성하기 위해 협력하는 다양한 애플리케이션 구성 요소를 말한다. 예를 들어, 웹 애플리케이션을 만들 때 일반적으로 3-Tier 구조를 사용하는데, 데이터베이스로 MySQL이나 Oracle을 사용하고, API 애플리케이션을 위해 백엔드를 Flask, FastAPI, 또는 Node.js로 구성하며, 사용자 인터페이스(UI)로는 React나 Vue.js를 사용하게 된다. 이 세 가지 애플리케이션은 공통적인 목표를 위해 협력한다고 볼 수 있다.
- 위와 같은 애플리케이션 스택을 도커 컴포즈를 통해 YAML 파일로 정의하여, 한번에 서비스를 실행하고 관리할 수 있다.
- 도커 컴포즈로 실행된 컨테이너는 각각 독립적인 기능을 가지며, 공통 네트워크로 구성되어 컨테이너 간 통신이 쉽다.
- 도커 컴포즈는 테스트, 개발, 운영 등 모든 환경에서 사용할 수 있는 오케스트레이션 도구 중 하나이다.
- 다양한 관리 기능을 제공하지 않기 때문에 주로 테스트 및 개발 환경에 적합하다. 운영 환경에서는 자동 확장, 모니터링, 복구와 같은 기능을 제공하는 도구인 도커 스웜이나 쿠버네티스와 함께 사용하는 것을 권장한다.
2. 설치
- Windows나 Mac에서는 Docker Desktop을 설치하면 도커 컴포즈가 기본적으로 포함되어 있다.
- Linux에서는 GitHub에서 도커 컴포즈를 다운로드받아 설치해야 한다.
sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
- 실행 권한 부여:
sudo chmod +x /usr/local/bin/docker-compose
- 실행 권한 확인:
ls -l /usr/local/bin/docker-compose
- 시스템 PATH에 도커 컴포즈를 추가하여 쉽게 실행할 수 있도록 설정
- PATH에 추가하거나, 기존에 설정된 PATH에 심볼릭 링크를 설정하여 실제 위치를 직접 입력하지 않고 실행할 수 있게 한다.
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
- 설치된 버전 확인:
docker-compose --version
- 기존 버전을 삭제하고 다른 버전을 설치하고자 할 경우:
sudo rm /usr/local/bin/docker-compose
sudo rm /usr/bin/docker-compose
3. YAML(yml) 파일
YAML은 사람이 쉽게 읽고 쓸 수 있도록 만들어진 텍스트 기반의 데이터 형식이다.
들여쓰기를 통해 계층을 구분하며, 공백의 수로 블록을 나눈다.
JSON과 달리 주석을 달 수 있으며, 한글을 사용할 때 별도의 인코딩 없이 바로 사용할 수 있다.
JSON은 주로 API 작성에 많이 사용되지만, YAML은 환경 설정 파일을 작성할 때 주로 사용된다.
- 들여쓰기는 반드시 공백을 사용해야 하며, 탭은 사용할 수 없다.
- 배열은 각 항목 앞에
-
를 붙여 작성한다.
4. 실습
아래 명령을 통해 MySQL 컨테이너를 실행할 수 있다:
docker run -d --name=mysql-vtest -p 3306:3306 --restart=always -e MYSQL_ROOT_PASSWORD=ys1234 -e MYSQL_DATABASE=dockertest -v $(pwd)/db-data:/var/lib/mysql mysql:5.7
- 디렉터리를 생성:
mkdir -p compose/db-data
docker-compose.yml
파일 작성 예시:
version: '3.3'
services:
mydb:
image: mariadb:10.4.6
restart: always
environment:
- MYSQL_ROOT_PASSWORD=ys1234
- MYSQL_DATABASE=appdb
volumes:
- ./db-data:/var/lib/mysql
ports:
- '3307:3306'
- 컨테이너 실행:
docker-compose up
- 컨테이너 상태 확인:
docker-compose ps
- 컨테이너 내 bash 접속:
docker exec -it 컨테이너이름 /bin/bash
- MySQL 접속:
mysql -uroot -p
- 데이터베이스 확인:
show databases;
- 컨테이너 중지:
docker-compose down
5. Docker-Compose 실행 옵션
docker-compose up
명령을 사용할 때, -d
옵션이 없으면 포그라운드에서 실행되므로 작업이 끝날 때까지 프롬프트로 돌아오지 않는다. 작업을 백그라운드에서 실행하고 프롬프트로 돌아오려면 -d
옵션을 사용해야 한다.
docker-compose up -d
기본적으로 도커 컴포즈는 디렉터리이름_default
라는 네트워크를 자동으로 생성하며, 이 네트워크 내에서 각 컨테이너는 서비스명으로 통신할 수 있다. 필요하다면 네트워크를 직접 정의하여 연결할 수도 있다.
6. Docker-Compose 파일 작성 요령
1) version
도커 엔진 릴리즈와 연관이 있으며, YAML 파일의 첫 번째에 명시된다.
- 예를 들어,
version: '3.3'
은 도커 엔진 버전 17 이상이 필요하다. - 버전이 맞지 않으면, `ERROR: Version in “./docker-compose.yaml” is unsupported` 에러가 발생한다.
- 이 에러가 발생하는 경우:
- 도커 컴포즈가 오래 된 경우
- 도커 엔진과 버전이 맞지 않는 경우
- 들여쓰기의 공백 수가 하위 레벨과 맞지 않는 경우
2) services
- 각 컨테이너 서비스를 정의하는 영역이다. 공식 이미지를 사용하려면
image:
옵션을 통해 지정한다. - 공식 이미지 `nginx`를 이용하고자 하눈 경우, 다음과 같이 작성한다.
services:
myweb:
image: nginx:latest
mydb:
image: mariadb:10.4.6
build
Dockerfile을 이용해 이미지를 직접 빌드할 때 사용된다.
- 현재 디렉터리에 Dockerfile 이라는 이름으로 만들어진 경우에는 `build: .`을 설정하면 된다.
- 파일 이름이 다르거나, 다른 디렉터리에 존재하는 경우에는 `context`와 `dockerfile`이라는 하위 옵션을 이용한다.
web:
build: .
web:
build:
context: .
dockerfile: ./compose/pyfla/Dockerfile-py
기타 옵션
- container_name: 컨테이너 이름을 지정하는 옵션이다.
- 지정하지 않으면 디렉터리 이름과 서비스 이름을 조합하여 생성된다 : `디렉터리이름_서비스이름_숫자`
- docker run의 `--name` 옵션과 동일
- 지정하지 않으면 디렉터리 이름과 서비스 이름을 조합하여 생성된다 : `디렉터리이름_서비스이름_숫자`
- ports: 내부 포트와 외부 포트를 바인딩하는 옵션이다.
- `docker run`의 `-p`와 동일
- expose: 호스트 운영체제와 직접 연결하는 포트를 구성하지 않고, 서비스만 포트를 노출하는 것
- 필요시 링크로 연결되 서비스와 서비스 간의 통신을 할 때 사용한다.
- networks: 컨테이너가 연결될 네트워크를 지정하며, 생략 시 기본 네트워크가 자동으로 생성된다.
- `docker run --net` 또는 network와 동일
- volumes: 호스트 디렉터리와 컨테이너 디렉터리를 연결할 때 사용된다.
- `docker run`의 `-v`나 `--volume` 옵션과 동일
- environment: 서비스 내부의 환경 변수를 설정하는 것
- 환경 변수가 많은 경우는 파일로 만들어서 env_file 옵션에 파일 명을 지정한다.
- `docker run -e` 옵션 과 동일
services:
myweb:
environment:
env_file:./envfile.env
command
: 컨테이너가 시작된 후 실행할 명령어를 지정한다.
command: /bin/bash
restart
: 컨테이너 재시작 정책을 설정한다. 옵션으로no
,always
,on-failure
등이 있다.- no: 수동으로 재시작
- always: 컨테이너 수동 제어를 제외하고 항상 재시작
- on-failure: 오류가 있을 때 재시작
- depends_on: 서비스 간 종속성을 설정하며, 먼저 실행되어야 할 서비스를 명시할 수 있다.
- 먼저 실행해야 하는 서비스를 지정하면 이 옵션에 지정된 서비스가 먼저 시작된다.
- web을 실행할 때, db가 안 켜져 있으면 에러가 난다.
- 이런 경우, depends_on 을 이용하여 db를 먼저 실행하게 한다.
services:
myweb:
depends_on:
- mydb
mydb:
3) 네트워크 정의
networks
는 여러 컨테이너 간 통신을 설정하는 최상위 네트워크 키를 정의한다.- 자동으로 네트워크가 생성되며, 외부 네트워크를 사용하려면
external
옵션을 사용한다. - 다중 컨테이너들이 사용할 최상위 네트워크 키를 정의하고 이하 하위 서비스 단위로 이 네트워크를 선택할 수 있다.
- networks 옵션을 지정하지 않으면 기본 네트워크가 자동으로 생성됩니다.
- 도커에서 생성한 기존 네트워크를 지정하는 경우는 external 옵션에 name 속성에 기재한다.
- 이미 도커 엔진에서 만든 vswitch-ap 라는 네트워크를 docker-compose에서 사용하고자 하는 경우:
networks:
default:
external:
name: vswitch-ap
4) 볼륨 정의
volumes
는 컨테이너의 데이터를 호스트 디렉토리에 저장하거나, 여러 컨테이너 간 데이터를 공유할 수 있도록 설정하는 옵션이다.
volumes:
db_data:{}
web_data:{}
🪄 도커 컴포즈를 사용한 서비스 구성도 예시
- DB (1521): 데이터베이스 서버로, 포트 1521을 사용하여 백엔드와 연결된다. DB는 백엔드 애플리케이션이 데이터를 저장하고 불러오는 저장소 역할을 한다.
- Back-End (8080): 실제 비즈니스 로직을 처리하는 서버로, 포트 8080을 통해 Front-End와 통신한다. 또한, DB와도 연결되어 데이터를 주고받는다. 여기서 DB와는 노출된 포트(EXPOSE) 1521로 연결된다.
- Front-End (80, 443): 사용자에게 화면을 제공하는 서비스이다. 웹 브라우저가 접근할 수 있는 포트 80(HTTP)과 443(HTTPS)을 사용하여 사용자와 직접 통신한다. 백엔드 서비스와도 연결되어 데이터를 주고받는다.
주요 연결
- 클라이언트는 API Gateway를 통해 백엔드 API로 요청을 보낸다.
- API 게이트웨이는 여러 Back-End API로 요청을 라우팅한다.
- Section 2에서는 Front-End가 Back-End와 연결되어 있으며, Back-End는 DB와 연결된다.
이 구조는 마이크로서비스 아키텍처나 클라우드 환경에서 자주 볼 수 있는 구성 방식으로, API 게이트웨이를 통해 클라이언트 요청을 분배하고, 프론트엔드와 백엔드가 서로 통신하며 데이터베이스와도 연결되는 형태이다.
7. 도커 명령어와 도커 컴포즈 YAML 비교
도커 명령어와 도커 컴포즈는 모두 컨테이너를 관리하는 도구이지만, 목적과 사용 방식에 차이가 있다.
도커 명령어는 주로 단일 컨테이너를 관리하는 데 사용되며, 개별적으로 컨테이너를 실행하고 설정한다.
반면, 도커 컴포즈는 여러 개의 컨테이너를 효율적으로 관리하고 연동할 수 있는 YAML 파일을 통해 정의된 설정을 일괄 처리하는 방식이다.
도커 컴포즈를 사용하면 설정의 재사용성을 높이고, 반복적인 명령 입력에 따른 실수를 줄일 수 있다. 특히, 워드프레스와 같은 프레임워크를 MySQL 또는 MariaDB와 연동할 때 유용하다.
도커 명령어와 도커 컴포즈 옵션 비교
도커 명령어 | 도커 컴포즈 옵션 |
---|---|
--name |
container_name |
-p |
ports (배열) |
--net |
networks (배열) |
--restart |
restart |
-v |
volumes (배열) |
-e |
environment (배열) |
--link |
depends_on |
이미지 이름 | image |
워드프레스와 MySQL 8.0 연동
워드프레스는 블로그를 구축하는 데 사용되는 프레임워크이며, 데이터베이스 연결이 필수적이다. 여기서는 MySQL 8.0과 워드프레스 5.7을 연동하는 과정을 도커 명령어와 도커 컴포즈로 각각 살펴본다.
도커 명령어로 구성
- 데이터 영구 저장을 위한 볼륨 생성
$ docker volume create mydb_data
$ docker volume create myweb_data
$ docker volume ls
- 볼륨 위치 확인
$ docker inspect --type volume mydb_data
- 네트워크 생성
2개의 컨테이너를 묶어 줄 네트워크를 생성한다. (IP는 자동으로 설정된다.)
$ docker network create myapp_net
$ docker network ls
$ docker network inspect myapp_net
- MySQL 8.0 컨테이너 생성
docker run -dit --name=mysql_app -v mydb_data:/var/lib/mysql --restart=always -p 3306:3306 --net=myapp_net -e MYSQL_ROOT_PASSWORD=ys1234 -e MYSQL_DATABASE=wpdb mysql:8.0
- 워드프레스 5.7 컨테이너 생성
docker run -dit --name=wordpress_app -v myweb_data:/var/www/html -v ${PWD}/myweb-log:/var/log --restart=always -p 8888:80 --net=myapp_net --link mysql_app:mysql -e WORDPRESS_DB_HOST=mysql_app:3306 -e WORDPRESS_DB_NAME=wpdb -e WORDPRESS_DB_USER=wpuser -e WORDPRESS_DB_PASSWORD=wppassword wordpress:5.7
- 워드프레스 구동 확인
localhost:8888
Docker Compose로 동일 작업 구성
- 디렉토리 생성 및 이동
$ mkdir my_wp && cd $_
docker-compose.yml
작성
version: "3.9"
services:
mydb:
image: mysql:8.0
container_name: mysql_app
volumes:
- mydb_data:/var/lib/mysql
restart: always
ports:
- "3306:3306"
networks:
- backend-net
environment:
MYSQL_ROOT_PASSWORD: ys1234
MYSQL_DATABASE: wpdb
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppassword
myweb:
image: wordpress:5.7
container_name: wordpress_app
ports:
- "8888:80"
networks:
- backend-net
- frontend-net
volumes:
- myweb_data:/var/www/html
- ${PWD}/myweb-log:/var/log
restart: always
environment:
WORDPRESS_DB_HOST: mydb:3306
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppassword
WORDPRESS_DB_NAME: wpdb
depends_on:
- mydb
volumes:
mydb_data: {}
myweb_data: {}
networks:
frontend-net: {}
backend-net: {}
- Docker Compose 실행
$ docker-compose up -d
만약 볼륨 관련 에러가 발생하면, 기존 볼륨을 삭제하고 다시 시도하면 된다.
이렇게 도커 명령어와 도커 컴포즈를 통해 동일한 환경을 구축할 수 있다. 도커 컴포즈는 여러 서비스를 쉽게 정의하고 실행할 수 있도록 해주며, 코드 재사용과 유지보수가 훨씬 용이하다.