DEV-STUDY/Infra

도커 컴포즈란?

HwangJerry 2023. 7. 24. 01:43

우리가 single execution jar 파일을 빌드하고 단일 컨테이너만 실행하면 원하는 서비스를 모두 제공할 수 있는 거라면 좋겠지만, 서비스에 따라 레디스와 같은 이미지를 별도 컨테이너에 띄워야 하는 경우도 있고, 서비스가 커지기 시작하면 멀티 모듈을 적용하게 되므로 여러 어플리케이션을 동시에 각각 컨테이너에 올려야 하는 경우도 발생하게 됩니다.

 

이를 원활하게 컨트롤하기 위해 우리는 docker compose를 사용합니다.

 

도커 컴포즈란?

도커 컴포즈는 다중 컨테이너 도커 어플리케이션을 정의하고 실행하기 위한 도구입니다. docker compose를 이용하면 컨테이너 이름으로 다른 application.yml 파일에서 해당 컨테이너에 접근할 수 있습니다. 이는 redis 설정시 host 이름을 설정할 때 사용됩니다.

 

우리는 스프링 어플리케이션 + 레디스 클라이언트가 하나의 컨테이너에 실행되고, 또 다른 컨테이너에 레디스 서버가 실행되어야 합니다. 이는 다중 컨테이너를 활용해야 한다는 의미인데, 아무런 설정을 하지 않으면 컨테이너 간 접근이 이루어질 수 없기에 컨테이너 간 통신이 불가능합니다. (향후에는 nginx 컨테이너도 별도로 연결해줄 예정입니다.)

 

멀티 컨테이너 환경에서는 각 컨테이너끼리 연결시키기 위해 docker compose를 사용해야 합니다. 우리는 이번 실습에서 스프링 어플리케이션 안에 레디스 클라이언트와 스프링 어플리케이션이 있는 것이고, 레디스 서버는 별도의 컨테이너에서 실행되고 있는 것이므로 그렇게 docker-compose.yml을 설정해보도록 하겠습니다.

version: "3" # 도커 컴포즈 버전
services: # 컨테이너 단위로 선언
  redis-server: # 컨테이너 이름
    image: "redis" # 컨테이너에서 사용하는 이미지
  spring-app: # 컨테이너 이름
#    build: . #도커 파일이 존재하는 경로이며, "."으로 작성하면 현재 경로라는 의미
    build: ./underdog-client/
    ports: #포트 매핑
      - "5000:8081"

하나하나 한번 찝고 넘어가 보겠습니다.

  • version : 도커 컴포즈의 버전을 의미합니다. 도커 컴포즈 버전은 도커 엔진 버전에 의존성을 가지므로 가급적 최신 버전을 사용하는 것이 좋습니다. 현재는 버전 3을 가장 많이 사용하는 것 같습니다.
  • services : 각 실행 컨테이너별로 services를 정의해 줍니다. 여기서 service 라는 개념은 컨테이너라고 이해해도 좋을 것 같습니다. 이는 스프링 멀티 모듈에서도 실행 가능한 각각의 모듈을 service라고 칭하는데, 이와 동일하게 인식하셔도 무방할 것 같습니다. 어차피 컨테이너가 어플리케이션이 실행되고 있는 독립된 공간이므로 유사하게 느껴지는 것 같습니다. 하위에는 컨테이너 이름을 선언하여 컨테이너간 설정을 할 수 있습니다.
  • image : 도커 허브에서 바로 받아서 쓰는 이미지로 컨테이너를 돌리려는 경우, 어떤 이미지를 사용하는지를 나타냅니다. 여기서는 우리가 레디스 서버를 컨테이너에 올려야 하므로 "redis" 이미지를 사용하는 것을 명시해 주었습니다.
  • build : 해당 service의 도커파일이 어디에 있는지 명시해줍니다. docker compose 파일은 root 경로에 있었고, 내가 현재 설정한 spring application은 상대 경로로 "./underdog-client/" 에 도커 파일이 있었으므로 이를 통해 이미지를 생성하기 위해 경로를 상대 경로로 명확하게 선언해줍니다.
  • ports : docker run 실행시에 -p 옵션으로써 어떤 포트끼리 매핑할건지를 선언해 줍니다.

 

또 다른 예시를 살펴보겠습니다.

version: "3"
services:

  spring-app:
    container_name: underdog-client
    image: hjc018/underdog-client:1.0.0
    env_file:
      - "./.env"
    hostname : spring-app
    expose:
      - "8080"
    restart: always

  nginx:
    depends_on:
      - underdog-client
    restart: always
    build:
      dockerfile: Dockerfile
      context: ./nginx
    ports:
      - "80:80"

Spring 어플리케이션 서비스 (spring-app):

  • container_name: underdog-client: 컨테이너의 이름을 "underdog-client"로 지정합니다.
  • image: hjc018/underdog-client:1.0.0: Docker 이미지로 사용할 Spring 어플리케이션 이미지를 지정합니다. 이미지 이름은 "hjc018/underdog-client"이고 버전은 "1.0.0"입니다.
  • env_file: 어플리케이션 실행에 필요한 환경 변수들을 지정한 파일 (".env")에서 로드합니다.
  • hostname: spring-app: 호스트 이름을 "spring-app"으로 지정합니다.
  • expose: 컨테이너 내에서 노출할 포트를 지정합니다. 여기서는 Spring 어플리케이션이 8080 포트를 사용합니다.
  • restart: always: 컨테이너가 비정상적으로 종료되면 항상 재시작하도록 설정합니다.

 

Nginx 웹 서버 서비스 (nginx):

  • depends_on: Nginx 서비스가 실행되기 전에 underdog-client (Spring 어플리케이션) 서비스가 먼저 실행되도록 의존성을 설정합니다.
  • restart: always: 컨테이너가 비정상적으로 종료되면 항상 재시작하도록 설정합니다.
  • build: Nginx 컨테이너를 빌드하기 위한 Dockerfile 및 빌드 컨텍스트를 지정합니다. 여기서는 "./nginx" 디렉토리에 있는 Dockerfile을 사용하여 Nginx 컨테이너를 빌드합니다.
  • ports: 호스트의 80번 포트와 컨테이너의 80번 포트를 매핑합니다. 따라서 호스트의 80번 포트를 통해 Nginx 서버에 접근할 수 있습니다.

---

 

docker-compose up 명령어로 컴포즈 파일의 내용을 통해 컨테이너를 일괄적으로 올리고, docker-compose down을 이용하여 올려둔 컨테이너를 일괄적으로 종료할 수 있습니다.

docker-compose up vs. docker-compose up --build

이미지가 없을 때 이미지를 빌드하고 컨테이너 시작,
이미지가 있든 없든 이미지를 빌드하고 컨테이너 시작.

배포할 때에는 안정적으로 수정사항을 반영한 이미지가 배포되는 것이 좋으니까 가급적 --build 옵션을 같이 해주는 것이 더 권장됩니다.

기존에 우리가 알던 것과 같이, detach 옵션을 활용하여 백그라운드에서 실행할 수도 있습니다. 이는 --build 옵션과 같이 적용하면 다음과 같이 됩니다.

docker-compose up -d --build