docker (4) - docker compose
compose의 목적
단일 container에 대해서 docker run
명령어를 사용해 container를 띄울 수 있기는 하다. 그렇지만, Docker Compose를 사용함으로써 환경 변수, 볼륨, 포트 등을 docker-compose.yml
파일에 명시하여 보다 선언적이고 재현 가능한 방식으로 container를 구성하고 실행할 수 있다.
Docker Compose는 단일 container 어플리케이션에도 사용할 수 있지만 주로 여러 container를 함께 관리하고 조정할 때 그 효율성이 두드러진다.
단일 container 예
docker run의 명령을 docker-compose.yml 내용으로 작성하기 위해서는, 해당 명령어의 각 옵션을 docker-compose.yml 파일의 형식에 맞추어 작성해야 한다.
version: '3.8' # 사용할 docker-compose 버전을 명시
services: # 관리할 서비스들을 정의
web-server: # 서비스 이름을 정의
image: my-simple-web-server-image # 사용할 이미지를 명시
container_name: my-simple-web-server-container # 컨테이너 이름을 설정
ports:
- "80:80" # 호스트의 포트와 컨테이너의 포트를 매핑
이를 실행할 때는 docker-compose up -d 를 사용한다. 여기서 -d 는 데몬 형식으로 상주하는 것을 뜻한다. (탭 문자 \t를 사용하지 않도록 조심)
여러 container 를 연결해서 사용하는 예
mysql container와 nodejs container를 연결해서 서비스를 한번 만들어보자.
mysql image
- official image를 사용 것이다.
- mysql의 경우 /docker-entrypoint-initdb.d 폴더 속에 db, table 생성에 관한 sql을 넣어두면 container가 생성될 때 초기화가 된 채로 생성된다.
nodejs image
- nodejs의 경우에는 server.js를 host에서 복사하면서 이미지를 생성할 것이다. express와 mysql2 설치도 필요하다.
- 이를 위해 Dockerfile을 하나 만들자
# Use the official Node.js 18 image as a parent image
FROM node:18
# Set the working directory in the container
WORKDIR /usr/src/app
# Install Node.js dependencies
RUN npm install express mysql2
# Bundle app source
COPY server.js .
# Expose port 3000 to access the server
EXPOSE 3000
# Run the server when the container launches
CMD ["node", "server.js"]
서버는 db에서 모든 user목록을 조회해 화면에 뿌려주고, 새 사용자를 입력하거나 삭제하는 간단한 기능을 가진다.
다음과 같이 image를 생성하자.
➜ docker build -t my-nodejs -f NodejsDockerfile .
docker-compose.yml
- official mysql image와 위에서 만든 my-nodejs image를 사용하는 yml을 만들어보자.
version: '3.8'
services:
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: testpw
MYSQL_DATABASE: test_db
ports:
- "3307:3306"
volumes:
- "./init_db.sql:/docker-entrypoint-initdb.d/init_db.sql"
command: --default-authentication-plugin=mysql_native_password
web:
image: my-nodejs
ports:
- "3000:3000"
environment:
DB_HOST: db
DB_USER: root
DB_PASSWORD: testpw
DB_NAME: test_db
depends_on:
- db
- mysql 초기화에 필요한 init_db.sql 내용은 아래와 같다. test_db를 먼저 만들고, id(pk), name, email 을 field로 가지는 user table을 하나 만든다.
CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;
CREATE TABLE IF NOT EXISTS user ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
docker-compose up -d 로 띄워보자. localhost:3000 으로 접속도 해 보고, localhost:3307 / root / testpw 로 mysql data도 확인해보자. (참고로 mysql client인 sequel ace는 mac의 app store에 있다. )


docker-compose.yml 자세히 보기
몇가지 눈여겨볼 지점이 있다.
db나 web은 service name
이라고 하는데, 이는 docker내 container간에 형성되는 docker network의 host name으로도 사용된다. 위에서 db
라고 정의했으므로 web쪽 env의 DB_HOST에도 db
라고 적혀있는 것이다.
외부에 다른 port를 오픈할 수 있다. 나의 경우 이미 mysql port 3306을 사용하고 있어서 외부에는 3307을 오픈했다. 여기서 중요한 점이 있다. 외부에는 3307로 노출되었지만 docker network 내부에서는 여전히 3306을 사용한다는 점이다. 이로 인해 server.js 내에서는 별도로 3307등의 port를 지정하지 않아도 이 서비스는 잘 작동한다. (바꾸면 오히려 안됨)
이 mysql container는 데이터를 container내부에 두므로, container가 삭제되면 자료도 모두 날아간다. 이를 피하기 위해서는 적당한 파일이나 폴더를 mount해서 사용해야 한다. 지난시간에 다루었던 내용과 동일하다.
결론
이렇게 4편의 글을 통해 docker에 대해 간단하게 알아보았다. 어떤 컴퓨터에서나 구구절절한 세팅 없이 간단하게 독립된 환경을 띄울 수 있는 것이 docker의 가장 큰 매력인 것 같다.
어느 정도 익숙해졌다면 로컬 환경에서도 적극적으로 사용하고, 나아가 Kubernetes 등 docker기반 활용도 공부해보자.