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

 

 

 

 

 

 

+ Recent posts