2. Docker Compose 다루기
1. Docker Compose 서비스 정의
- 다음은
Dockerfile
을 Docker Compose로 변환하여 간략하게 다중 컨테이너 애플리케이션을 정의해 본다.
1) Docker Compose YAML services
파라미터
version: "1.0" # Docker Compose 버전 정보
services: # 서비스 목록 정의
mongodb: # 서비스 이름 정의
image: mongo # 해당 서비스에서 사용할 이미지
restart: always # 컨테이너 실행 시 항상 재시작
command: sh -c "echo -_-" # 컨테이너 실행 시 커맨드
working_dir: / # 컨테이너 실행 시 작업 디렉터리
environment: # 서비스 환경변수 정의
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: secret
volumes: # 컨테이너에서 호스트로 마운트
- type: bind
source: ./data/db # 호스트 경로
target: /data/db # 컨테이너 내부 경로
container_name: "mongodb" # 컨테이너 이름 정의
ports: # 서비스의 포트 정의
- "27017:27017" # 호스트포트:컨테이너포트
2) App 서비스 정의
$ sudo docker run -dp 3000:3000 \
-w /app -v ${PWD}:/app \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:12-alpine \
sh -c "yarn install && yarn run dev"
- 위의
docker run
명령어를 다음과 같이 Docker Compose로 작성이 가능하다.
version: "3.8"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
- Docker Compose의 장점 중 하나로는 상대 경로 입력이 가능하며, YAML(
.yml
)로 구성하여 설정 파일의 가독성이 좋아진다.
3) MySQL 서비스 정의
$ docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:5.7
- 다음과 같이 Docker Compose로 작성이 가능하다.
version: "3.8"
services:
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
4) App과 MySQL 서비스 결합
version: "3.8"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
- 위와 같이 YAML 파일(
.yml
) 하나에app
,mysql
두 개의 설정을 한꺼번에 정의하여 실행 환경을 빠르게 구성할 수 있다. - 이렇게 작성된 설정 파일로 한꺼번에 관리가 되어 서비스를 올리고 내리는 것을 쉽게 할 수 있다.
2. 주요 명령어
docker-compose
에서 사용하는 명령어는 기존 Docker에 있는 명령어와 비슷하다.- 최신 버전의 Dockerd에는 Compose가 내장되어 있어
docker-compose
대신docker compose
명령어로도 실행이 가능하다.
1) up
docker-compose.yml
파일의 내용에 따라 이미지를 빌드하고 서비스를 실행한다.
up
명령어로 Compose 실행 시 단계별 진행 사항은 다음과 같다.
1] 서비스를 띄울 네트워크 설정
2] 필요한 볼륨 생성 혹은 이미 존재하는 볼륨과 연결
3] 필요한 이미지 Pull
4] 필요한 이미지 Build
5] 서비스 의존성에 따라 서비스 실행
up
명령어의 주된 옵션은 다음과 같다.
1] -d
- 서비스를 백그라운드로 실행
2] --force-recreate
- 컨테이너를 지우고 새로 생성
3] --build
- 서비스 시작 전 이미지를 새로 생성
4] -f
- 기본으로 제공하는
docker-compose.yml
이 아닌 별도의 파일명을 실행할 때 사용 sudo docker-compose -f docker-compose.yml -f docker-compose-test.yml up
형태와 같이 사용 가능- 위와 같이 YAML을 두 개 이상 설정할 경우 앞에 있는 파일보다 뒤에 있는 파일이 우선
2) down
- 실행 중인 서비스를 삭제한다.
- 이때 컨테이너와 네트워크를 삭제하면, 옵션에 따라 볼륨도 같이 삭제할 수 있다.
down
명령어의 주된 옵션은 다음과 같다.
1] -v
, --volume
- 볼륨까지 같이 삭제
- DB 데이터를 초기화하는 데 용이
- 모든 설정을 초기화하고 새로 시작하는 데 사용
3) stop
, start
- 서비스를 멈추거나, 멈춰 있는 서비스를 시작한다.
4) ps
- 현재 환경에서 실행 중인 각 서비스의 상태를 표시한다.
5) exec
- 실행 중인 컨테이너에서 명령어를 실행한다.
- 명령어는 다음과 같은 패턴으로 실행된다.
sudo docker-compose exec app ./upload_logs.sh
sudo docker-compose exec mysql mysql -uroot -psecret todos
6) run
docker run
과 마찬가지로 특정 명령어를 일회성으로 실행한다.run
은exec
와 비슷한 역할을 실행하지만 다른 점은 컨테이너 재실행의 여부이다.run
은 실행 시 새로운 컨테이너를 띄우는 반면,exec
는 실행되어 있는 컨테이너에 접속한다.exec
는 프로세서를 실행시켜 놓을 때 사용되고,run
은 Batch성 작업에 특화되어 있다.
run
명령어의 주된 옵션은 다음과 같다.
1] --rm
- 해당 명령어가 종료된 뒤 컨테이너도 종료
7) logs
- 출력으로 나온 로그를 확인할 때 사용한다.
- Docker의
logs
와 마찬가지로--follow
또는-f
를 지정하여 실시간으로 나오는 로그를 확인할 수 있다.
8) config
docker-compose
에 최종적으로 적용된 설정을 보여준다.sudo docker-compose -f docker-compose.yml -f docker-compose-test.yml up
와 같이 여러 개의 YAML 파일을 실행시켰을 경우 최종적으로 적용된 설정을 확인하기 좋은 옵션이다.
3. Docker Compose Enviornment
- Docker Compose의 장점으로는 파일 하나를 정의해 놓으면 여러 곳에서 동일한 동작을 보장하는 것이다.
- 하지만 각 실행 환경에 따라 변경되어야 하는 옵션들이 있는데, 이것들 때문에 일일이 파일을 수정하는 건 비효율적이다.
- 그래서 각 실행하는 환경마다 환경변수 파일을 정의하여 동일한 Compose 파일로 각각의 환경과 동적인 옵션으로 실행이 가능하다.
1) .env
파일
- 기본적으로
sudo docker-compose up
을 한 상태에서,.env
파일을 찾아 파일 내부에 있는 값을 환경변수로 사용한다.
$ cat .env # 환경변수 파일
TAG=v1.5
$ cat docker-compose.yml # Compose 파일
version: '3'
services:
web:
image: "webapp:${TAG}"$ # .env 파일의 TAG 변수 사용
$ sudo docker-compose config # 실제 적용된 옵션
version: '3'
services:
web:
image: 'webapp:v1.5'
$ export TAG=v2.0 # export를 사용하여 환경변수 지정 가능
$ sudo docker-compose config
version: '3'
services:
web:
image: 'webapp:v2.0'
- 여러 파일에서 동일한 환경변수를 설정할 때 사용할 값을 선택하기 위해, Compose에서 사용하는 우선순위는 다음과 같다.
1] Compose 파일(docker-compose.yml
)
2] Shell Environment Variables($ export ...
)
3] Environment 파일(.env
)
4] Dockerfile
5] Variable is not defined
- 여러 복합적인 상황에 따라서 의도하지 않은 설정이 들어가지 않게 우선순위를 잘 파악하는 것이 중요하다.
2) 상황에 따른 .env
적용 예제
dev
,prod
,local
환경에 따라서.env.dev
,.env.prod
,.env.local
형식으로 할당을 줄 수 있다.- 이때
--env-file
옵션으로 환경변수 파일 지정이 가능하다.
3) CLI Environment
- 다음의 명령어는 각각 그 아래의 Compose 파일이 일치하게 매핑된다.
4. Compose Network 설정 옵션
version: "3.8"
services:
app:
build: .
ports:
- "8000:8000"
db:
image: postgres
ports:
- "8001:5432"
- 위의 Compose 파일을 실행했을 때 네트워크가 생성되는 과정은 아래와 같다.
- 이때 프로젝트 이름은
myapp
이라고 가정한다.
1] myapp_default
네트워크 생성
2] app
컨테이너 생성
app
이라는 이름으로myapp_default
에 접속
3] db
컨테이너 생성
db
라는 이름으로myapp_default
에 접속
- 네트워크가 구성된 이후
postgres://db:5432
주소로 접속이 가능하다. - 내부 컨테이너끼리는
postgres://db:5432
로 접속하고, 외부에서는postgres://{DOCKER_IP}:8001
로 접속해야 한다. - 컨테이너 업데이트를 위해 다시 시작할 경우에는 컨테이너 이름은 같지만 다른 IP로 네트워크가 생성되어 IP 베이스는 IP를 다시 찾아서 연결해야 하고, 다른 컨테이너에서는 기존에 접속했던 컨테이너 이름으로 재연결을 시도해야 한다.
1) links
links
는 다른 서비스의 컨테이너와 연결시켜 주는 역할을 하고 있다.- 이름만 지정하거나,
{name}:{alias}
형식으로 지정할 수 있다.
links
는 레거시 기능으로 공식 페이지에서는 권장하지 않는 방법이다.depend_on
처럼 의존성 관계가 맺어지며, 네트워크와 함께 사용될 때는 하나 이상의 네트워크가 관리되기 때문에 네트워크만 사용하길 권장한다.
2) Custom Network
- Custom Network를 통해 좀 더 복잡한 네트워크 토폴로지를 만들 수 있다.
version: "3"
services:
proxy:
build: ./proxy
networks:
- frontend
app:
build: ./app
networks:
- frontend
- backend
db:
image: postgres
networks:
- backend
networks: # top-level network
frontend:
driver: custom-driver-1 # Use a custom driver
backend:
driver: custom-driver-2 # Use a custom driver which takes special options
driver_opts:
foo: "1"
bar: "2"
top-level
의networks
옵션에서 커스텀하게 지정이 가능하다.- 위와 같이 설정하면
app
에서만proxy
,db
에 접근 가능하고,db
와proxy
는 서로 접근이 불가능하게 설정이 된다.
3) IPv4
, IPv6
IPv6
를 사용하기 위해서는top-level
의networks
옵션에enable_ipv6
옵션이 반드시 들어가야 한다.
version: "2.4"
services:
app:
image: nginx:alpine
networks:
app_net:
ipv4_address: 172.16.238.10
ipv6_address: 2001:3984:3989::10
networks:
app_net:
enable_ipv6: true
ipam:
driver: default
config:
- subnet: "172.16.238.0/24"
- subnet: "2001:3984:3989::/64"
4) Default Network
default
를 이용하여 자체 네트워크를 지정하면서 앱 전체의 기본적인 네트워크 구성이 가능하다.
version: "3"
services:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres
networks:
default:
driver: custom-driver-1 # Use a custom driver
5) User Pre Existing Network
- 기존 외부의 네트워크를 사용하려면 다음과 같이
external
을 사용하여 명시해야 한다.
5. Docker Compose Version
1) Versioning
- docker-compose.yml 상단에 작성하는 Compose File Format의 버전을 명시해 줘야 한다.
- Versioning은 버전별로 다음과 같은 특징이 있다.
1] Version 1
- 버저닝을 생략
2] Version 2
- 마이너 버전(
2.x
)까지 설정해야 한다. - 생략 시
2.0
으로 적용된다.
3] Version 3
- 도커 스웜과 같이 사용되도록 디자인되었다.
2) Version Dependency
- 다음은 각 Docker 버전별 사용가능한
docker-compose.yml
버전이다.
(1) Version 1
Version 1
은 Deprecated되었다.
(2) Version 2
Compose 1.6.0
이상Docker Engine of version 1.10.0+.
에서 동작- YAML 문서에 버전명을 마이너 버전까지 작성
- 모든 각각의 서비스는
services
아래에 선언하여 다중 컨테이너 구성 volumes
에 Named Volumes 생성 가능networks
에 Network 생성 가능- 기본적으로 모든 컨테이너는 애플리케이션 전체의 기본 네트워크에 연결되며 서비스 이름과 동일한 호스트 이름에서 검색 가능
- 다음은
Version 2
의 예시이다.
version: "2.4"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
networks:
- front-tier
- back-tier
redis:
image: redis
volumes:
- redis-data:/var/lib/redis
networks:
- back-tier
volumes:
redis-data:
driver: local
networks:
front-tier:
driver: bridge
back-tier:
driver: bridge
Version 2
에서 추가된 파라미터 중 중요한 항목은aliases
,depends_on
이 있다.
version: "2.4"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
- 실행 시
depends_on
에 명시된db
,redis
가 실행된 다음web
이 실행된다. - 실행 순서가 중요한 작업에서 유용하게 사용이 가능하다.
(3) Version 3
Version 3
에서 삭제된 파라미터는 다음과 같다.
1] volume_driver
2] volumes_from
3] cpu_shares
4] cpu_quota
5] cpuset
6] mem_limit
7] memswap_limit
8] extends
9] group_add
- 추가된 파라미터는 다음과 같다.
1] deploy
Version 3.1
에서 추가된 파라미터는 다음과 같다.
1] secrets
Version 3.2
에서 추가된 파라미터는 다음과 같다.
1] build - cache_from
2] ports
, volume
에 LONG SYNTAX
지원
3] network driver option - attachable
4] deploy - endpoint_mode
5] deploy - placement preference
Version 3.3
에서 추가된 파라미터는 다음과 같다.
1] build - labels
2] credential_spec
3] configs
Version 3.4
에서 추가된 파라미터는 다음과 같다.
1] build - target
, network
2] healthcheck - start_preiod
3] update - order
4] volumes - name
Version 3.5
에서 추가된 파라미터는 다음과 같다.
1] service - isolation
2] networks, secrets, configs - name
3] build - shm_size
Version 3.6
에서 추가된 파라미터는 다음과 같다.
1] tmpfs
2] volume mount type - tmpfs
Version 3.7
에서 추가된 파라미터는 다음과 같다.
1] service - init
2] deploy - rollback_config
3] root of service
, network
, volume
, secre
t에 extension-fields 제공
Version 3.8
에서 추가된 파라미터는 다음과 같다.
1] placement - max_replicas_per_node
2] config, secret - template_driver
option (swarm에 배포 시에만 적용)
3] secret - driver
, driver_opts
(swarm에 배포 시에만 적용)