이재홍의 언제나 최신 Docker - Unit 8.2 docker-compose.yml 파일 작성하기

저작권 안내
  • 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
  • 책 또는 웹사이트의 내용을 발췌, 요약하여 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.

Docker Compose 사용하기

이재홍 http://www.pyrasis.com

docker-compose.yml 파일 작성하기

이제 앞에서 docker run 명령으로 생성해본 컨테이너들을 Docker Compose로 만들어보겠습니다. Docker Compose는 docker-compose.yml 파일에 생성할 컨테이너들을 정의합니다.

먼저 mysql 컨테이너부터 만들어보겠습니다. docker run 명령을 다시 한번 살펴보면 다음과 같은 형태입니다.

$ sudo docker network create example-network
$ sudo docker run -d --name mysql --network example-network -v mysql-data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=examplepassword \
    -e MYSQL_DATABASE=db \
    mysql:5.7

다음 내용을 app 디렉터리 아래에 docker-compose.yml 파일로 저장합니다.

app/docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:5.7
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: examplepassword
      MYSQL_DATABASE: db

volumes:
  mysql-data:
  • docker-compose.ymlversion으로 시작합니다. 버전은 시간이 지남에 따라 계속 올라갑니다.
  • services: 생성하고자하는 컨테이너는 services 아래에 나열합니다.
    • mysql: 컨테이너 이름입니다. 여기서는 mysql로 정했습니다.
      • image: Docker 이미지 이름과 태그를 지정합니다.
      • volumes: 데이터 볼륨 매핑입니다. 여기서는 mysql-data 볼륨을 /var/lib/mysql에 연결합니다. docker volume create로 생성한 볼륨을 docker run 명령에서 -v 옵션으로 사용하는 것과 같습니다.
    • environment: 환경 변수 설정입니다. <환경 변수 이름>: <값> 형식으로 나열합니다. docker run 명령의 -e 옵션과 같습니다.
  • volumes: 데이터 볼륨을 생성합니다. docker volume create와 같습니다.

다음 명령을 실행하여 MySQL 컨테이너를 생성해보겠습니다(docker compose 명령은 반드시 docker-compose.yml이 있는 디렉터리에서 실행해야 합니다).

$ sudo docker compose up -d
[+] Running 3/3
 ⠿ Network app_default      Created                                    0.9s
 ⠿ Volume "app_mysql-data"  Created                                    0.2s
 ⠿ Container app-mysql-1    Started                                    3.7s

app_default라는 네트워크는 자동으로 생성됩니다(app이 앞에 붙는 이유는 현재 디렉터리 이름이 app이라서 그렇습니다).

docker ps 명령으로 컨테이너 목록을 출력해보면 app-mysql-1 컨테이너가 생성된 것을 볼 수 있습니다.

$ sudo docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED              STATUS              PORTS                 NAMES
5ce3fc0c7e71   mysql:5.7     "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp   app-mysql-1

docker compose ps 명령을 입력하면 Docker Compose로 생성한 컨테이너의 목록을 보여줍니다.

$ sudo docker compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
app-mysql-1         "docker-entrypoint.s…"   mysql               running             3306/tcp, 33060/tcp

docker exec 명령과 마찬가지로 Docker Compose에도 docker compose exec라는 명령이 있습니다. 이 명령을 사용해서 MySQL 데이터베이스에 접근해보겠습니다.

$ sudo docker compose exec -it mysql mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.39 MySQL Community Server (GPL)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

mysql> 프롬프트가 표시되면 다음 SQL 쿼리를 입력하여 Users 테이블을 생성합니다. 그리고 exit를 입력하여 프롬프트에서 빠져나옵니다.

mysql> USE db;
Database changed
mysql> CREATE TABLE Users (id VARCHAR(100) NOT NULL, password VARCHAR(100) NOT NULL, PRIMARY KEY (id));
Query OK, 0 rows affected (0.76 sec)

mysql> exit
Bye

이제 app.js 실행 부분을 추가해보겠습니다. app 컨테이너의 docker run 명령은 다음과 같은 모양입니다.

$ sudo docker run -it --name app -p 8080:8080 -w /app -v ~/app:/app --network example-network \
    -e MYSQL_HOST=mysql \
    -e MYSQL_USER=root \
    -e MYSQL_PASSWORD=examplepassword \
    -e MYSQL_DB=db \
    node:16-alpine sh -c "npm install && node app.js"

docker-compose.yml 파일을 열고 services 아래에 app 부분을 추가합니다.

app/docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:5.7
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: examplepassword
      MYSQL_DATABASE: db
    healthcheck:
      test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD']
      interval: 10s
      timeout: 2s
      retries: 100

  app:
    image: node:16-alpine
    command: sh -c "npm install && node app.js"
    ports:
      - 8080:8080
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: examplepassword
      MYSQL_DB: db
    depends_on:
      mysql:
        condition: service_healthy

volumes:
  mysql-data:
  • mysql
    • healthcheck: MySQL 컨테이너가 생성되면서 MySQL 데이터베이스도 생성하는데 이때 시간이 조금 걸립니다. MySQL 데이터베이스가 생성되지 않은 상태로 app에서 SQL 쿼리를 실행하게 되면 에러가 발생합니다. 따라서 10초 간격으로 mysqladmin ping을 실행하여 MySQL 데이터베이스가 생성되었는지 검사하고, MySQL 데이터베이스가 완전히 생성되었을 때 app 컨테이너를 생성하도록 합니다.
  • app: 컨테이너 이름은 app으로 지정했습니다.
    • image: Node.js를 사용하기 위해 node:16-alpine를 지정했습니다.
    • command: 컨테이너를 생성했을 때 실행할 명령(command)입니다. docker run 명령에서 가장 마지막에 들어가는 부분을 여기에 넣습니다.
    • ports: 호스트와 연결할 포트를 지정합니다. docker run 명령의 -p 옵션과 같습니다.
    • working_dir: command의 명령이 실행될 디렉터리입니다. docker run 명령의 -w 옵션과 같습니다.
    • volumes: 앞의 MySQL과는 달리 호스트의 현재 디렉터리 .//app에 연결합니다.
    • environment: docker run 명령에 지정했던 것과 동일하게 환경 변수를 나열합니다.
    • depends_on: 데이터베이스 컨테이너가 생성되지 않은 상태에서 app 컨테이너가 먼저 생성되면 안 됩니다. 따라서 depends_onmysql을 설정하여 mysql 컨테이너가 생성된 뒤에 app 컨테이너가 생성되도록 합니다. 특히, conditionservice_healthy를 지정해서 healthcheck가 정상 상태가 될 때까지 기다립니다. 즉, MySQL 데이터베이스가 완전히 생성될 때까지 기다립니다.

다음 명령을 실행하여 추가된 app 컨테이너도 생성합니다.

$ sudo docker compose up -d
[+] Running 2/2
 ⠿ Container app-mysql-1  Running                                      0.0s
 ⠿ Container app-app-1    Started                                      3.8s

docker compose ps 명령으로 컨테이너 목록을 확인해봅니다. 다음과 같이 app-app-1 컨테이너가 보이면 정상적으로 생성된 것입니다.

$ sudo docker compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
app-app-1           "docker-entrypoint.s…"   app                 running             0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
app-mysql-1         "docker-entrypoint.s…"   mysql               running             3306/tcp, 33060/tcp

웹 브라우저에서 http://<컨테이너 IP 주소 또는 도메인>:8080으로 접속해봅니다(Docker Desktop에서 실행했다면 http://127.0.0.1:8080입니다).

다음과 같은 데이터가 표시되면 MySQL 데이터베이스에 정상적으로 데이터를 쓰고 읽어온 것입니다.

{"id":"hellouser","password":"examplepassword"}

이번에는 Docker Compose로 만든 컨테이너들을 정지, 재시작, 삭제하는 방법을 알아보겠습니다.

docker compose stop 명령으로 컨테이너들을 정지시킵니다.

$ sudo docker compose stop
[+] Running 2/2
 ⠿ Container app-app-1    Stopped                                      3.7s
 ⠿ Container app-mysql-1  Stopped                                      4.7s

정지된 컨테이너들을 시작하려면 docker compose start 명령을 사용합니다.

$ sudo docker compose stop
[+] Running 2/2
 ⠿ Container app-mysql-1  Started                                      4.0s
 ⠿ Container app-app-1    Started                                      3.7s

만약 컨테이너들이 시작된 상태에서 재시작하고 싶다면 docker compose restart 명령을 사용합니다.

$ sudo docker compose stop
[+] Running 2/2
 ⠿ Container app-app-1    Started                                    13.8s
 ⠿ Container app-mysql-1  Started                                     5.4s

마지막으로 컨테이너들을 모두 삭제할 때는 docker compose down 명령을 사용합니다.

$ sudo docker compose down
[+] Running 3/3
 ⠿ Container app-app-1    Removed                                    12.1s
 ⠿ Container app-mysql-1  Removed                                     3.2s
 ⠿ Network app_default    Removed                                     1.1s

만약 데이터베이스 볼륨도 삭제하고 싶다면 docker volume rm 명령을 사용합니다.

$ sudo docker volume ls
DRIVER    VOLUME NAME
local     app_mysql-data
$ sudo docker volume rm app_mysql-data

저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

2022-10-03