Skip to main content

Command Palette

Search for a command to run...

[ 살펴보기 ] Docker - Compose

Updated
4 min readView as Markdown
[ 살펴보기 ] Docker - Compose
C

A developer living in Busan, Korea

지난 포스트를 통해 Docker image 생성과 container의 실행 그리고 네트워크 연결과 volume을 통한 데이터 관리등 여러가지 기능을 살펴보았다. 이제 이 모든 과정을 하나의 파일에서 관리할 수 있는 compose에 대해 살펴보자

Docker compose는 YAML 문법을 통해 작성하고 version, services, network와 같은 top-level element를 통해 실행할 application의 상세 내용을 구성하고 compose를 실행하면 compose YAML 파일에 정의한 구성대로 실행된다

Docker Compose 파일 생성

다음 예를 살펴보자

version: "1.0.0"

services:
  mysql-container:
    container_name: mysql-container
    image: mysql:8
    ports:
      - 3306:3306
    networks:
      - test-volume-network
    volumes:
      - volume-mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=12345

  backend-container:
    container_name: backend-container
    image: test-volume-backend
    ports:
      - 4000:4000
    networks:
      - test-volume-network
    depends_on:
      - mysql-container

volumes:
  volume-mysql:
    name: volume-mysql
    external: true

networks:
  test-volume-network:
    name: test-volume-network
    external: true

지난 포스트에서 살펴본 mysql + volume, backend application을 compose로 구성한 예제이다.

위의 예제에서는 4개의 top-level element가 사용되었다. version, services, volumes, networks.

services에서는 우리가 compose를 통해 실행할 container에 대한 정보를 기입하고 volumes과 network는 해당 container가 사용할 volumes과 networks에 대한 정보를 선언한다

사용된 top level element를 하나씩 살펴보자

volumes:
  volume-mysql: // compose 파일 안에서 volume을 구분하기 위한 이름
    name: volume-mysql
    external: true

compose 실행 시 사용할 volume에 대한 정보를 기입한다. external:true는 이미 생성되어 있는 volume을 사용하겠다는 의미이며 위의 예제에서는 volume-mysql volume을 사용한다 ( name: volume-mysql )

volumes 구문 바로 아래 쪽에 있는 volume-mysql라는 이름은 생성된 volume 이름과는 별개로 compose 파일 안에서 volume을 구분하기 위한 이름이다

다음은 networks 구문을 살펴보자

networks:
  test-volume-network: // compose 파일 안에서 network를 구분하기 위한 이름
    name: test-volume-network
    external: true

networks 구문에서도 역시 external을 통해 이미 존재하는 network를 사용하며 사용하는 network의 이름은 test-volume-network다 ( name: test-volume-network )

마찬가지로 networks 구문 바로 아래 쪽에 있는 test-volume-network라는 이름은 생성된 network 이름과는 별대로 compose 파일 안에서 network를 구분하기 위한 이름이다

다음은 services 구분이다

services:
  mysql-container:
    container_name: mysql-container
    image: mysql:8
    ports:
      - 3306:3306
    networks:
      - test-volume-network
    volumes:
      - volume-mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=12345

  backend-container:
    container_name: backend-container
    image: test-volume-backend
    ports:
      - 4000:4000
    networks:
      - test-volume-network
    depends_on:
      - mysql-container

services 구문에서 우리가 실행할 container의 상세 정보를 기입한다.

우선 mysql-container라는 service를 살펴보자

  mysql-container:
    container_name: mysql-container
    image: mysql:8
    ports:
      - 3306:3306
    networks:
      - test-volume-network
    volumes:
      - volume-mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=12345

container 기반이 되는 image는 mysql:8를 사용하고 port는 3306으로 mapping한다. network는 compose파일 아래 선언해 두었던 test-volume-network 라는 network를 사용한다

volume 역시 compose 파일 아래 선언해 두었던 volume-mysql라는 volume을 사용하여 실행될 container의 /var/lib/mysql 폴더에 해당 volume을 마운트한다 그리고 contianer가 실행될 때 전달할 환경변수는 environment를 통해 전달한다. 위의 예제에서는 MYSQL_ROOT_PASSWORD 환경변수를 선언하고 있다.

이제 backend-container service를 살펴보자

  backend-container:
    container_name: backend-container
    image: test-volume-backend
    ports:
      - 4000:4000
    networks:
      - test-volume-network
    depends_on:
      - mysql-container

내용은 mysql-container service와 크게 다를게 없지만 depends_on을 통해 해당 container의 의존 관계를 표현할 수 있다. 즉, backend-container가 정상 작동하기 위해서 mysql-container가 먼저 작동 하고 있어야 하므로 위 처럼 depends_on에 mysql-container를 설정해두면 compose를 통해 application을 실행할 때 mysql-container가 구동된 다음 backend-container가 구동된다 ( backend application에서 mysql 접속 설정시 host 는 mysql container 이름으로 설정 되어야 한다. ( [ 살펴보기 ] Docker - Volume 포스트 참고 )

Docker Container 사이의 통신

도커 컨테이너가 생성되면 도커 엔진은 해당 컨테이너에 가상 IP를 부여한다. 도커 네트워크에 연결된 컨테이너는 이 네트워크 범위에 포한되는 IP를 부여 받게 되는데 이를 통해 컨테이너는 서로 통신할 수 있게 된다.

그리고 도커 자체에 DNS 서비스가 내장되어 있다. 컨테이너 이름을 조회하여 컨테이너의 IP를 찾을 수 있기에 컨테이너가 삭제되고 새로 생성되어 해당 컨테이너 IP가 변경되더라도 컨테이너 이름으로 IP를 찾기에 문제없이 다른 컨테이너와 통신할 수 있다

Docker Compose 실행하기

이제 작성한 compose를 작동시켜 보자. compose 파일의 이름을 docker-compose.yml로 만들고 compose 파일이 있는 위치에서 다음 명렁어를 실행한다

docker compose up

위의 명령어를 실행하면 default로 현재 위치의 docker-compose.yml 파일을 기준으로 compose 리소스를 생성한다. 하지만 다른 위치에 있거나 다음 이름의 compose파일을 사용하고자 한다면 아래와 같이 -f 명령어를 사용한다

docker compose -f docker-compose-dev.yml up

background mode로 compose를 실행하고자 한다면 다음과 같이 -d 옵션을 추가해주자

docker compose up -d

위의 command를 실행 시키는 디렉터리에 docker-compose.yml가 있으면 해당 파일을 기준으로 실행한다

만약 docker-compose가 아니라 다른 이름의 compose 파일을 사용해서 application을 실행시키고자 한다면 다음과 같이 -f option을 사용한다

docker compose -f docker-compose-frontend.yml

compose 파일 구성에 이상이 없다면 다음과 같이 compose 파일 아래 선언한 container들이 정상적으로 생성되어 운영되는 걸 확인할 수 있다.

compose를 통해 생성된 container를 종료하고 삭제하는 command는 다음과 같다

docker compose down

환경변수 따로 관리하여 전달하기

Compose config 파일에 값을 바로 작성할 수 없는 환경변수가 있다면 환경변수를 관리하는 .env 파일을 따로 작성하여 compose를 실행할 때 함께 넘길 수 있다. 다음 예제를 살펴보자

// docker-compose.yml

version: "1.0.0"

services:
  mysql-container:
    container_name: mysql-container
    image: mysql:8
    ports:
      - 3306:3306
    networks:
      - test-volume-network
    volumes:
      - volume-mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

...
// .env.dev

MYSQL_ROOT_PASSWORD=12345

위의 예제와 같이 compose 파일의 환경변수를 .env.dev 파일에서 받아 사용할 수 있도록 변경되었다. 그리고 compose를 실행할 때 --env-file 옵션을 통해 우리가 따로 작성한 .env.dev 파일에 선언된 환경변수를 넘겨줄 수 있다

docker compose --env-file .env.dev up

다음과 같이 compose 파일에서 어떤 env 파일을 통해 환경 변수를 가져올 것인지 설정할 수 도 있다

// docker-compose.yml

version: "1.0.0"

services:
  mysql-container:
    container_name: mysql-container
    image: mysql:8
    ports:
      - 3306:3306
    networks:
      - test-volume-network
    volumes:
      - volume-mysql:/var/lib/mysql
    env_file:
      - .env.dev

...

위의 예제처럼 environment 속성 대신 env_file 속성에 env 파일을 선언해주면 해당 env 파일에 선언된 환경 변수가 사용되며 docker compose를 실행할 때 --env-file option을 별도로 줄 필요도 없다.

More from this blog

[ 살펴보기 ] TypeORM - Transactions, Migration

Transation Database 종류에 따라 detail한 부분은 차이점이 조금씩 있겠지만 각 sql statement는 개별적인 transaction block을 통해 실행되며 Database 설정에 따라 sql statement의 실행 결과가 자동으로 commit되어 영구히 적용되거나 commit을 직접 실행하기 전까지는 영구히 적용되지 않을 수 있다. 대부분의 경우 default로 sql statement 실행 결과가 자동으로 comm...

Feb 9, 20256 min read
[ 살펴보기 ] TypeORM - Transactions, Migration

Dev Diary

184 posts