Docker Compose 는 다수의 "docker build" 와 다수의 "docker run" 명령어를 대체하는 도구(orchestration 명령 모음)
Docker compose 툴로 다수의 container 들을 한 번에 손쉽게 관리할 수 있음
하나의 Docker compose 를 사용하여 모든 container 들을 빌드, 실행, 및 중지/중단 할 수 있음
Docker compose 는 Dockerfile 을 대체하는 용도가 아니며,
역시 image 혹은 container 대체하는 용도가 아님
Docker compose 는 여러 host 위에서 동작하는 다중 컨테이너들을 관리하는 데 적합하지 않음
단지 하나의 동일한 host 위에서 동작하는 다중 컨테이너들을 관리할 수 있음
Docker compose 에서 관리하는 Container 들은 기본적으로 -d --rm 옵션을 갖게 됨
Docker compose 에서 관리하는 Container 들은 모두 하나의 네트워크로 묶이게 됨
즉, 하나의 동일한 Docker compose 파일에 정의된 모든 서비스(Containers)는
(별다른 네트워크 설정을 하지 않아도) 동일한 네트워크의 일부가 되어 서로 통신이 가능함
Docker compose 구성 내에서 Container 는 "Service" 라는 이름으로 불림
이 Service 에 어떤 port 를 열것인지 어떤 네트워크를 붙일 것인지
볼륨을 추가 할 것인지 환경변수를 추가할 것인지 등등을 docker compose 내에 정의할 수 있음
Docker compose 구성 파일은 "docker-compose.yml" 혹은 "docker-compose.yaml" 라는 이름으로 만듦
docker-compose.yml 의 포맷은 다음 예제(왼쪽)와 같음
< docker-compose.yml > version: "3.8" services: mongodb_container: image: 'mongo' volumes: - data:/data/db environment: - MONGO_INITDB_ROOT_USERNAME=max - MONGO_INITDB_ROOT_PASSWORD=secret networks: - goals-net container2: ... container3: ... volumes: data: |
< 동일한 역할을 하는 기존 docker 명령어 > docker run \ --name mongodb_container \ -v data:/data/db \ --network goals-net \ -e MONGO_INITDB_ROOT_USERNAME=max \ -- MONGO_INITDB_ROOT_PASSWORD=secret \ -d \ --rm \ mongo |
- version : Docker comose 사양의 버전을 지정
(앱이나 docker-compose.yml 파일의 버전이 아님)
version 은 해당 docker-compose yml 파일에서 사용할 수 있는 기능에 영향을 미친다고 함
계속 업데이트되는 Docker compose 중에서 어느 기능을 사용할 지 version 으로 고정시켜주는 거라고 함
(근데 최근 문서를 보니 version 은 안 쓰는 것 같기도..? 일단 강의 내용만 따라가보자)
- services : Container 를 지정
위 예제에서는 총 세 개의 containers 를 생성함
mongodb_container, container2, container3
각 container 가 어떤 이미지를 기반으로 생성될지, 어떤 네트워크에 붙을지 등을 정의하면 됨
- image : 생성될 container 의 기반으로 사용할 이미지
- volumes : container 볼륨 설정
volume 여러개 추가 가능
ro 등의 옵션을 추가할 수 있음 (예를 들어 -v data:/data/db:ro)
- environment : container 내에서 사용할 환경 변수 지정
위 예제처럼
environment:
- MONGO_INITDB_ROOT_USERNAME=max
이렇게 지정해도 되고 아래처럼 지정해도 됨
environment:
MONGO_INITDB_ROOT_USERNAME: max
혹은 environment 대신 env_file 을 사용하여, 환경변수 파일(mongo.env)을 넣어 지정할 수 있음
env_file:
- ./env/mongo.env
환경변수 파일(mongo.env) 내용은 다음과 같아야 함
MONGO_INITDB_ROOT_USERNAME=max MONGO_INITDB_ROOT_PASSWORD=secret |
- networks : container 에 추가 network 를 붙임
위에서 설명한 것처럼, Docker compose 가 관리하는 모든 서비스(Containers) 는
자동으로 하나의 기본 네트워크에 묶이게 되지만
networks 명령어를 추가하면 해당 Container 에는 추가 네트워크가 붙게됨
위 예제에서 mongodb_container 는 기본 네트워크와 goals-net 네트워크 두 군데에 붙게 됨
- (마지막줄에 있는) volumes : container 에 적용한 volume 의 이름을 넣어주는 곳
위의 예제에서 mongodb_container 에 volume 이름이 "data" 이므로
마지막 volumes 명령어에 "data" 를 넣어주었음.
이렇게 따로 사용되는 volume 이름을 넣어줌으로써, Docker 가 명명된 volume 이름을 인식할 수 있다고 함
(익명 volume 이나 path 를 직접 지정한 bind mount volume 은 마지막 volumes 명령어로 넣어주지 않아도 됨)
추가로, 다른 서비스에서 동일한 volume 이름을 사용하면, 그 volume 이 공유된다고 함
(서로 다른 Container 들이 host 머신 상의 동일한 volume 을 동시에 사용 가능)
docker-compose.yml 파일을 생성한 후, 동일한 위치에서 아래 명령어 실행
docker-compose up -d |
그러면 docker-compose.yml 에 설정한 모든 서비스가 시작됨
(-d 옵션이 없으면 Docker compose 자체가 attached 모드로 시작됨)
docker-compose.yml 실행을 중지하려면 아래 명령어 실행
docker-compose down |
위 명령어로 volume 은 제거되지 않는데,
만약 제거하고 싶다면 -v 옵션을 붙임 (docker-compose down -v)
docker-compose.yml 의 다른 예제도 확인해봄
< docker-compose.yml > version: "3.8" services: backend_container: # build: ./backend build: context: ./backend dockerfile: Dockerfile args: default_port: 80 ports: - '80:80' - '123:443' volumes: - ./backend:/app stdin_open: true tty: true depends_on: - mongodb_container - A_container |
< 동일한 역할을 하는 기존 docker 명령어 > docker run \ --name backend_container \ --rm \ -d \ --build-arg default_port=80 \ -p 80:80 \ -p 123:443 \ -v my/path/backend:/app \ -i \ -t \ ... |
- build : service 를 생성할 이미지를 직접 빌드해서 사용함
단순히 build: ./backend 이런 식으로 짧게 쓸 수 있고 (이 경우, Dockerfile 이름은 반드시 "Dockerfile" 이어야 함)
context: 와 dockerfile: 등 을 추가하여 좀 더 자세하게 명시할 수 있음
context: 는 Dockerfile 이 존재하는 위치이며, build 했을 때 기준이 되는 위치임
위의 예제에서 ./backend 위치를 기준으로 build 를 진행하며 COPY 등의 기준 위치가 됨
dockerfile: 은 Dockerfile의 이름임
(위의 예제에서 Dockerfile 의 이름은 default 인 "Dockerfile" 이지만, 내 맘대로 지은 "eyeballsfile" 도 될 수 있겠지)
args: 를 통해 Dockerfile 내부에서만 사용 가능한 상수값을 지정할 수 있음
Dockerfile 생성할 때 넣은 ARG 명령 사용한 것과 동일한 부분임
- ports : service 에서 노출하고 싶은 포트 지정 가능
위 예제의 '80:80' 은 service 포트(앞 80)와 이미지 내부 포트(뒤 80)가 연결됨
'123:443' 은 service 포트(앞 123)와 이미지 내부 포트(뒤 443)가 연결됨
service 사용자는 80 혹은 123 포트를 사용하여 이미지 내부 80 혹은 443 으로 접근 가능
- volumes : 위 예제와 같이 상대 경로에 해당하는 위치를 volume 으로 mount 가능
이렇게 경로를 이용하여 mount 한 경우, 마지막줄에 volume 의 이름을 넣어주지 않아도 괜찮음
- stdin_open tty : 사용자가 해당 service 와의 상호작용(interactive)을 필요로 하는 경우 true
- depends_on : docker compose 를 통해 동시에 여러 container(service) 들을 생성할 때
이미 실행되고 있는 다른 container 에 의존성을 설정할 수 있음
예를 들어 A container 가 먼저 실행되고 그 후에 B container 를 실행할 수 있도록 순서를 정할 수 있다는 의미
위의 예제에선, 'mongodb_container' 와 'A_container' 두 개의 container 가
먼저 실행 된 이후에 'backend_container' container 가 나중에 실행될 것임
docker-compose.yml 을 통해 생성한 container 들을 docker ps 를 통해 확인하면
우리가 지정한 이름과 조금 다른 것을 확인할 수 있음
위에 docker-compose.yml 예제를 통해 mongodb_container, backend_container 두 가지 container 를 생성 후
docker ps 명령어를 확인해보면 아래와 같은 이름이 보임
- docker-practice_backend_container_1
- docker-practice_mongodb_container_1
container 이름은 service 이름에 접두사와 접미사가 붙은 형태이며
접두사 "docker-practice" 는 프로젝트 폴더 이름,
접미사 "1" 은 증가하는 숫자임
위와 같은 이름 대신, 직접 container 이름을 지정하려면 container_name 명령어를 사용하면 됨
이를테면
services: backend_container: container_name: backend_container |
docker run \ --name backend_container \ ... |
container 이름에 접두사, 접미사가 붙긴 했지만,
docker compose 가 생성한 기본 network 에서는 우리가 지정한 service 의 이름으로 container 끼리 통신이 가능함
즉, backend_container 에서 "mongodb_container" 이름으로 mongodb_container 에 접근 가능하다는 것임
docker container 의 기반이 되는 각 이미지는
docker run 명령어 실행시 실행되는 기본 프로세스(pid 1번 프로세스)가 있음
이 기본 프로세스를 이미지 변경 없이(즉, Dockerfile 의 CMD, ENTRYPOINT 추가를 통한 업데이트 없이) 바꿀 수 있음
예를 들어 다음과 같이 실행한 경우
- docker run -it node
node 라는 이미지는 기본 프로세스가 "node" 이기 때문에 node 가 실행됨
하지만 다음과 같이 실행한 경우
- docker run -it node npm init
"node" 대신 "npm init" 이라는 명령에 의한 프로세스가 기본 프로세스로 실행됨
따라서 npm init 명령에 의한 프로세스가 해당 컨테이너의 생명주기에 관여함
CMD 가 존재하는 Dockerfile 로 빌드한 이미지를 docker run 으로 실행할 때
뒤에 추가 명령어를 붙여서, 기본 프로세스를 덮어쓰게되면
CMD 로 지정한 실행명령어가 사라지고 run 뒤에 붙인 추가 명령어가 대신 실행됨
예를 들어보자
< Dockerfile > |
FROM ubuntu:latest CMD ["echo", "hello eyeballs!"] |
< docker run 명령어 > |
docker run --rm myimage echo "bye" |
docker run 을 실행하면 CMD 에 의해 "hello eyeballs!" 가 출력되어야 하지만
run 뒤에 추가한 echo "bye" 명령어에 의해 "bye" 가 대신 출력됨
CMD 와 비슷한 역할을 하는 ENTRYPOINT 는 조금 다르게 동작함
ENTRYPOINT 가 존재하는 Dockerfile 로 빌드한 이미지를 docker run 으로 실행할 때 뒤에 추가 명령어를 붙이면
ENTRYPOINT 로 지정한 실행명령어의 뒤에 추가한 명령어가 붙어 같이 실행됨
예를 들어보자
< Dockerfile > |
FROM ubuntu:latest ENTRYPOINT ["echo", "hello"] |
< docker run 명령어 > |
docker run --rm myimage "eyeballs" |
docker run 명령어 뒤에 "eyeballs" 를 추가해 줌
docker run 을 실행하면 ENTRYPOINT 에 의해 실행되는 echo hello 뒤에 eyeballs 가 붙어서
echo hello eyeballs 라는 명령어가 기본 프로세스가 되었음
따라서 "hello eyeballs" 가 출력됨
비슷한 논리로, Docker Compose 를 통해 기본 프로세스를 덮어쓸 수 있음
다음과 같은 Dockerfile 과 docker-compose.yml 이 존재한다고 하자
< docker-compose.yml > | < Dockerfile > |
version: "3.8" services: my_service: build: ./ |
FROM ubuntu:latest ENTRYPOINT ["echo", "hello"] |
< docker compose 명령어 > |
docker compose run [service 이름] [추가 명령어] docker compose run my_service docker compose run my_service eyeballs |
위와 같이 docker compose run 명령어 뒤에
service 이름과 추가할 명령어를 넣으면
기본 프로세스에 영향을 미칠 수 있음
위 예제에서는 Dockerfile 이 ENTRYPOINT 명령어를 실행하기 때문에
명령어가 뒤에 추가되어 hello eyeballs 가 출력되었음
docker compose run --rm my_service 처럼 --rm 옵션을 추가해주면
docker compose run 명령어를 통해 실행된 컨테이너가 stop 될 때 컨테이너 자체를 삭제할 수 있음
docker-compose.yml 에 설정된 services 중 내가 원하는 service 만 실행할 수 있음
아래와 같은 docker-compose.yml 에서 bb_svc, cc_svc 만 실행하고 싶다고 하자
< docker-compose.yml > |
version: "3.8" services: aa_svc: ... bb_svc: ... cc_svc: ... dd_svc: .. |
아래와 같이 docker compose up 명령어 뒤에 service 이름을 넣어주면
지명된 services 만 실행됨
docker compose up -d bb_svc cc_svc |
'Docker' 카테고리의 다른 글
[Docker] Udemy Docker & Kubernetes : 실전 가이드 필기 - Kubernetes 데이터 & 볼륨 (0) | 2024.01.15 |
---|---|
[Docker] Udemy Docker & Kubernetes : 실전 가이드 필기 - Kubernetes 핵심 개념 (1) | 2023.12.17 |
[Docker] Udemy Docker & Kubernetes : 실전 가이드 필기 - Docker (1) | 2023.10.03 |
[Docker] CentOS 7 Dockerfile (0) | 2022.07.20 |
[Docker] docker-compose 명령어, YAML 문법 공부 (1) | 2022.02.20 |