Docker Compose로 여러 컨테이너 띄워보기
지난번에 미처 정리하지 못했던 Docker Compose를 이용하여 여러 컨테이너를 띄우는 법에 대해 정리해본다.
Docker Compose 이용하여 여러 컨테이너 한 번에 띄우기
Docker Compose를 이용하여 3개의 컨테이너를 한 번에 띄우고 싶은 상황이라고 가정해보자. Spring Boot 프로젝트 하나와 Redis, PostgreSQL 이렇게 3개를 한 번에 띄우고 싶은 상황이다.
이런 상황에서 사용할 수 있는 간단한 docker-compose.yml 파일을 작성해보았다. 아래 같이 작성한 뒤 docker compose up 명령어만 이용하면 한 번에 3개의 컨테이너를 띄울 수 있다.
version: "3"
services:
backend-app:
build: .
container_name: spring-boot-app
ports:
- "8080:8080"
depends_on:
postgres-db:
condition: service_healthy
cache-server:
condition: service_healthy
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres-db:5432/moomoodb
SPRING_DATASOURCE_USERNAME: moomoo
SPRING_DATASOURCE_PASSWORD: moomoopassword
SPRING_REDIS_HOST: cache-server
SPRING_REDIS_PORT: 6379
postgres-db:
image: postgres
container_name: moomoo-postgres
environment:
POSTGRES_USER: moomoo
POSTGRES_PASSWORD: moomoopassword
POSTGRES_DB: moomoodb
volumes:
- moomoo_postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD", "pg_isready", "-U", "moomoo"]
interval: 30s
retries: 3
timeout: 10s
start_period: 10s
cache-server:
image: redis
container_name: moomoo-redis
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
retries: 3
timeout: 5s
start_period: 5s
위와 같이 작성한 파일을 두고 중요한 부분만 추가로 설명해보려고 한다.
먼저 파일을 보면 services 아래에 있는 backend-app, postgres-db, cache-server 이렇게 3개의 서비스가 실행되고 3개의 컨테이너가 띄워진다는 것을 알 수 있다.
컨테이너 명은 container_name 으로 spring-boot-app, moomoo-postgres, moomoo-redis로 지정해주었다.
먼저 backend-app 서비스를 살펴보면 depends_on 이라는 부분이 보일 것이다. depends_on을 사용해서 컨테이너들의 실행 순서를 지정해줄 수 있다. backend-app은 PostgreSQL과 Redis가 띄워진 뒤에 실행되어야한다. 따라서 depends_on에 2개의 서비스를 넣어주면 실행 순서를 지정해줄 수 있다.
그런데 단순히 depends_on에 이렇게 두 서비스의 이름만 넣어주면 이 두 서비스가 정상적으로 실행되고 있는지 여부는 확인하지 않고 그냥 실행 순서만 보장해주게 된다. 따라서 healthcheck를 수행해 healthy한지 확인한 후에 backend-app이 실행되도록 하려고 condition을 추가해주었다.
healtcheck는 postgres-db와 cache-server 아래에 있는 healthcheck를 통해 수행된다. 여러가지 옵션들이 있는데 간단히 살펴보면 test를 통해 컨테이너가 정상적으로 실행중인지 확인하는 명령어를 정의할 수 있고, interval은 healthcheck가 수행되는 간격을 지정해줄 수 있다. 이렇게 다양한 옵션들이 있으니 찾아보고 적절히 사용해주면 된다.
그런 다음 다시 backend-app의 environment를 통해 환경 변수들을 집어넣어 준 것을 볼 수 있다. 이 부분은 Spring Boot 프로젝트 내의 application.yml에 작성할 수도 있다. 만약 양쪽에 같은 변수와 값이 존재하면 docker-compose.yml의 environment의 값이 사용된다.
여기서 주목해야할 부분은 SPRING_DATASOURCE_URL과 SPRING_REDIS_HOST이 부분이다. 도커를 사용하지 않고 로컬 환경에서 실행할 때는 아마 저 'jdbc:postgresql://postgres-db:5432/moomoodb'와 'cache-server'가 'jdbc:postgresql://localhost:5432/moomoodb'와 'localhost'였을 것이다.
도커의 컨테이너는 각각 독립적인 환경에서 실행된다. 따라서 Spring Boot의 입장에서 localhost는 Spring Boot가 돌아가고 있는 컨테이너 자신을 가리킬 것이다. 거기에는 당연히 PostgreSQL과 Redis가 실행중이지 않기 때문에 아무것도 없을 것이다.
Docker Compose를 이용해 컨테이너들을 띄우게 되면 자동으로 기본 네트워크에 연결시켜준다. 그리고 서비스 이름을 이용하여 서로 쉽게 통신이 가능하다. 따라서 위와 같이 postgre-db와 cache-server 같은 서비스 이름으로 연결이 가능한 것이다.
현재 위의 코드에는 PostgreSQL과 Redis 모두 포트 매핑을 해두어서 호스트에서도 접근이 가능하다. 다시 말해 외부에서 접근이 가능하다. 그런데 보안상 이유로 외부에서는 오직 Spring Boot 앱에만 접근이 가능하고 PostgreSQL과 Redis는 외부에서 접근이 불가능하도록 만들고 싶을 수도 있을 것이다. 이럴때는 포트 매핑을 제거하면 된다. 그러면 Spring Boot앱은 PostgreSQL과 Redis에 접근이 가능하지만, 외부에서는 오직 Spring Boot 앱에만 접근이 가능하고, PostgreSQL과 Redis에 직접 접근이 불가능하게 만들 수 있다.
이처럼 Docker Compose는 네트워크 설정도 간편하게 해준다. Docker Compose에는 networks라는 옵션이 있고 이를 이용해 다양한 네트워크 설정도 쉽게 할 수 있다. 이 부분은 필요시 Docker Network와 함께 학습하여 적용해볼 수 있을 것이다.
여기까지 여러 개의 컨테이너를 한 번에 띄우는 법에 대해 아주 간단하게 정리해보았다. 개인적으로는 실습을 통해서 직접 해보는게 가장 빠르게 습득할 수 있었던 것 같아서 어떤 프로젝트든 비슷하게 띄워보는 것을 추천해본다.