docker

docker compose 를 활용한 컨테이너 관리

경딩 2025. 4. 16. 09:48

Docker Copmose란?

  • 여러개의 Docker 컨테이너들을 하나의 서비스로 정의하고 구성해 하나의 묶음으로 관리할 수 있게 도와주는 툴

Docker Compose 를 사용하는 이유

  •  여러 개의 컨테이너를 관리하는데 용이
    • 여러 개의 컨테이너로 이루어진 복잡한 애플리케이션을 한 번에 관리할 수 있게 해준다.
    • 여러 컨테이너를 하나의 환경에서 실행하고 관리하는데 도움이 된다.
  • 복잡한 명령어로 실행시키던 걸 간소화 시킬 수 있음
    • 이전에 MySQL 이미지를 컨테이너로 실행시킬 때 아래와 같은 명령어를 실행시켰다.
$ docker run -e MYSQL_ROOT_PASSWORD=password123 -p 3306:3306 -v /Users/Documents/Develop/docker-mysql/mysql_data:/var/lib/mysql -d mysql
  • 하지만 Docker Compose  를 사용하면
  • 단순히 compose.yml 을 정의하고 docker compose up 명령어만 실행시키면 된다.

  • 예시
    • Docker Compose (Nginx 설치 및 실행)
    • Docker CLI 로 컨테이너를 실행시킬 때
$ docker run --name webserver -d -p 80:80 nginx

Docker Compose 로 컨테이너를 실행시킬 때

1.compose.yml 파일 작성하기

  • compose.yml
services: # 도커 컴포즈에서는 하나의 컨테이너를 서비스라 부른다. 여러개의 서비스를 적기 전에 초반에 적는 명령어
    my-web-server: # 내가 원하는 컨테이너에 붙이고 싶은 이름
        container_name: web-server
        image: nginx
        ports:
            - 80:80
services:
	my-web-server:
		container_name: webserver
		image: nginx
		ports: 
			- 80:80
  • services:
    • my-web-server : Docekr Compose에서 하나의 컨테이너를 서비스(service)라고 부른다. 이 옵션은 서비스에 이름을 붙이는 기능이다.
  • container_name:
    • web-server : 컨테이너를 띄울 때 붙이는 별칭이다. CLI에서 --name web-server 역할과 동일하다.
  • image:
    • nginx : 컨테이너를 실행시킬 때 어떤 이미지를 사용할 지 정의하는 명령어이다. $ docker run [이미지명]와 동일한 역할이다.
  • ports:
    • 포트 매핑은 어떻게 할 지를 설정하는 옵션이다. CLI에서-p 80:80 역할과 동일하다.

 

2. compose 파일 실행시키기

$ docker compose up -d

docker compose 로 실행시 명령어가 간소화 되었다.

  • docker run --name webserver -d -p 80:80 nginx ->  docker compose up -d

 

3. compose 실행 현황 보기

$ docker compose ps
$ docker ps

 

 

4. compose로 실행된 컨테이너 삭제

$ docker compose down

 


자주 사용하는 Docker Compose CLI 명령어

 

compose.yml에서 정의한 컨테이너 실행

$ docker compose up    # 포그라운드에서 실행
$ docker compose up -d # 백그라운드에서 실행

 

Docker Compose로 실행시킨 컨테이너 확인하기

# compose.yml에 정의된 컨테이너 중 실행 중인 컨테이너만 보여준다. 
$ docker compose ps 

# compose.yml에 정의된 모든 컨테이너를 보여준다.
$ docker compose ps -a

 

Docker Compose 로그 확인하기

# compose.yml에 정의된 모든 컨테이너의 로그를 모아서 출력한다.
$ docker compose logs

 

컨테이너를 실행하기 전에 이미지 재빌드하기

$ docker compose up --build # 포그라운드에서 실행
$ docker compose up --build -d # 백그라운드에서 실행

 

  • compose.yml에서 정의한 이미지 파일에서 코드가 변경 됐을 경우, 이미지를 다시 빌드해서 컨테이너를 실행시켜야 코드 변경된 부분이 적용된다. 그러므로 이럴 때에는 --build 옵션을 추가해서 사용해야 한다.

참고 : docker compose up vs docker compose up --build

  • docker compose up : 이미지가 없을 때만 빌드해서 컨테이너를 실행시킨다. 이미지가 이미 존재하는 경우 이미지를 빌드하지 않고 컨테이너를 실행시킨다.
  • docker compose up --build : 이미지가 있건 없건 무조건 빌드를 다시해서 컨테이너를 실행시킨다.

이미지 다운받기 / 업데이트하기

$ docker compose pull
  • 로컬에 있어도 무조건 도커 허브에서 다운받아짐.
  • compose.yml에서 정의된 이미지를 다운 받거나 업데이트 한다.
    • 로컬 환경에 이미지가 없다면 이미지를 다운 받는다.
    • 로컬 환경에 이미 이미지가 있는데, Dockerhub의 이미지와 다른 이미지일 경우 이미지를 업데이트 한다.

Docker Compose에서 이용한 컨테이너 종료하기

$ docker compose down

Docker Compose 로 프론트엔드(HTML, CSS, Nginx) 실행시키기 

  • compose.yml
services:
    my-web-server:
        container_name: web-server
        image: nginx
        ports:
            - 80:80
  • Dockerfile
    • 현재경로에 생성한 파일 컨테이너의  /usr/share/nginx/html 경로로 복사하기
FROM nginx
COPY . /usr/share/nginx/html

 

도커 컴포즈 없이 빌드시 

  • docker run --name webserver -d -p 80:80 nginx
    웹서버 이름으로 nginx 이미지를 실행시켜라

 

compose.xml 생성시 

services:
    my-web-server:
        build: . # 현재 도커 파일을 기준으로 빌드한 이미지를 씀
        container_name: web-server 
        ports:
            - 80:80

 

명령어 실행

docker compose up -d --build

 

  • 매번 이미지를 빌드해주라는 의미로 build 옵션 붙여줌

 


Docker Compose 로 MySQL 실행시키기

 

Docker CLI 로 컨테이너를 실행시킬 때

$ docker run -e MYSQL_ROOT_PASSWORD=pwd1234 -p 3306:3306 -v /Users/Documents/Develop/docker-mysql/mysql_data:/var/lib/mysql -d mysql
  • 주석버전
docker run \
  -e MYSQL_ROOT_PASSWORD=pwd1234 \  # MySQL root 계정 비밀번호 설정 (환경 변수)
  -p 3306:3306 \                    # 호스트의 3306 포트를 컨테이너의 3306 포트에 매핑 (MySQL 기본 포트)
  -v /Users/Documents/Develop/docker-mysql/mysql_data:/var/lib/mysql \  # 호스트의 디렉토리를 컨테이너의 데이터 디렉토리에 마운트 (데이터 영속성 보장)
  -d \                              # 컨테이너를 백그라운드(detached) 모드로 실행
  mysql                             # 사용할 이미지 이름 (기본적으로 Docker Hub에서 mysql:latest 이미지 사용)

 

위의 CLI 를 compose.yml 파일로 바꿔봅시다

  • compose.yml
services:
  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: pwd1234
    volumes:
      - ./mysql_data:/var/lib/mysql
    ports:
      - 3306:3306

 

compose 파일 실행시키기

 

 

  • docker-compose.yml 파일을 읽어서,
  • 정의된 모든 서비스(예: 웹 서버, DB 등)를 한 번에 생성 및 실행한다.

 

docker compose up -d
docker compose \         # docker-compose.yml 파일을 기준으로 여러 컨테이너를 정의하고 실행
  up \                   # 컨테이너를 생성하고 실행 (필요한 이미지가 없으면 자동으로 pull)
  -d                     # detached 모드: 터미널을 점유하지 않고 백그라운드에서 실행

 

 

compose 실행 현황 보기

$ docker compose ps
$ docker ps

 

컨테이너 접속

>docker exec -it 26 bash 

로그인 되나 확인해보기

mysql -u root -p

 

볼륨 마운트 확인

볼륨도 잘 마운트된것을 확인할 수 있다.

 

 


Docker Compose로 백엔드(Spring Boot) 실행시키기

 

빌드된 스프링부트 jar 파일을 기반으로 Dockerfile 를 만들어보자.

Spring Boot 프로젝트 빌드하기

$ ./gradlew clean build

 

 

Dockerfile 작성하기

Dockerfile

FROM openjdk:21-jdk

COPY build/libs/*SNAPSHOT.jar /app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app.jar"]

 

FROM openjdk:21-jdk                     # Java 21 JDK 기반 이미지 사용
COPY build/libs/*SNAPSHOT.jar /app.jar  # 빌드된 JAR 파일을 컨테이너로 복사
EXPOSE 8080                             # 애플리케이션이 사용하는 포트 (문서화 목적)
ENTRYPOINT ["java", "-jar", "/app.jar"] # 컨테이너 실행 시 JAR 실행

 

참고) compose를 작성하지 않고 Docker CLI로 실행시킬 때

$ docker build -t hello-server .        # 이미지 생성
$ docker run -d -p 8080:8080 hello-server # 컨테이너 실행 (호스트:컨테이너 포트 연결)

도커파일 생성 후 이미지를 만들기 위해 

docker build -t my-server .

명령어를 수행하였다. 

 

하지만 컴포즈를 쓰면 해당 명령어가 필요 없어진다.

Docker Compose를 사용하면 docker build와 docker run을 한 번에 처리할 수 있음.

 

compose.yml

services:
  my-server:
    build: .              # 현재 디렉토리에서 Dockerfile을 사용하여 이미지 빌드
    ports:
      - "8080:8080"       # 호스트:컨테이너 포트 매핑

 

build : .  : compose.yml 이 존재하는 디렉토리(.) 에 있는 Docker 로 이미지를 생성해 컨테이너를 띄우겠다는 의미이다.

 

compose 파일 실행시키기

$ docker compose up -d --build

 

  • --build : 서비스 실행 전에 이미지를 다시 빌드함
  • -d : 백그라운드(detached) 모드로 실행

핵심 요약


 

항목 설명
build: . 현재 디렉토리의 Dockerfile을 사용해 이미지 생성
docker compose up 이미지 빌드 + 컨테이너 실행
EXPOSE vs ports EXPOSE는 내부 포트 명시 (문서화), ports는 실제 외부 연결 설정

Spring Boot, MySQL 컨테이너 동시에 띄워보기

 

Spring Boot, MySQL 컨테이너 동시에 띄워보기

 

스프링부트 의존성 추가

    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation 'mysql:mysql-connector-java:8.0.33'
    implementation 'org.springframework.boot:spring-boot-starter-web'

간단한 코드 작성

AppController

@RestController
public class AppController {
  @GetMapping("/")
  public String home() {
    return "Hello, World!";
  }
}

 

application.yml에 DB 연결을 위한 정보 작성하기

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: pwd1234
    driver-class-name: com.mysql.cj.jdbc.Driver

 

불필요한 테스트 코드 삭제

 

 

Dockerfile 작성하기

Dockerfile

FROM openjdk:21-jdk

COPY build/libs/*SNAPSHOT.jar /app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app.jar"]

 

 

compose.yml 파일 작성하기

compose.yml

services:
  my-server:
    build: .
    ports:
      - 8080:8080
    depends_on:
      my-db:
        condition: service_healthy

  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: pwd1234
      MYSQL_DATABASE: mydb
    volumes:
      - ./mysql_data:/var/lib/mysql
    ports:
      - 3306:3306
    healthcheck:
      test: ["CMD", "mysqladmin", "ping"]
      interval: 5s
      retries: 10

 

compose.yml(주석)

services:
  my-server:
    build: .  # 현재 디렉토리에 있는 Dockerfile로 my-server 이미지를 빌드합니다.
    ports:
      - 8080:8080  # 호스트의 8080 포트를 컨테이너의 8080 포트에 매핑합니다 (웹 애플리케이션 접근용).
    depends_on:
      my-db:
        condition: service_healthy  # my-db 서비스가 healthcheck를 통과할 때까지 기다린 후 my-server를 시작합니다.

  my-db:
    image: mysql  # 공식 MySQL 이미지를 사용합니다 (명시된 버전 없으므로 기본 latest 사용).
    environment:
      MYSQL_ROOT_PASSWORD: pwd1234  # root 사용자 비밀번호 설정.
      MYSQL_DATABASE: mydb  # 컨테이너 시작 시 자동으로 생성될 데이터베이스 이름.
    volumes:
      - ./mysql_data:/var/lib/mysql  # 호스트의 ./mysql_data 디렉토리를 MySQL 데이터 저장소에 마운트 (데이터 영속화).
    ports:
      - 3306:3306  # 호스트의 3306 포트를 컨테이너의 3306 포트에 매핑 (DB 접근용).
    healthcheck:
      test: ["CMD", "mysqladmin", "ping"]  # MySQL 서버가 살아있는지 확인하는 health check 명령.
      interval: 5s  # health check를 5초마다 수행합니다.
      retries: 10  # 최대 10번 health check를 재시도합니다 (모두 실패 시 unhealthy 처리).

 

Spring Boot 프로젝트 빌드하기

$ ./gradlew clean build

 

compose 파일 실행시키기

$ docker compose up -d --build

 

compose 실행 현황 보기

$ docker compose ps
$ docker ps
$ docker logs [Container ID]

 

Spring Boot 컨테이너의 로그를 열어보면 아래와 같이 에러 메시지가 떠있다. 아래 에러 메시지는 DB와 연결이 제대로 이루어지지 않았을 때 발생하는 에러이다.

 

mysql 컨테이너는 잘 떴지만 스프링 부트 jar 는 뜨지 않았다.

mysql 이 잘 떳는지 GUI 로 확인해보자!

 

왜 db 까지 잘 생성되었지만 스프링 웹에서 연결하지 못했을까?

 

컨테이너로 실행시킨 Spring Boot가 MySQL에 연결이 안 되는 이유

각각의 컨테이너는 자신만의 네트워크망과 IP 주소를 가지고 있다. 호스트 컴퓨터 입장에서 localhost는 호스트 컴퓨터를 가리키지만, Spring Boot 컨테이너 입장에서 localhost는 Spring Boot 컨테이너를 가리킨다.

 

Spring Boot 의 코드 작성 시 DB 정보를 localhost 로 입력하였따.

Spring Boot 가 실행되는 환경인 컨테이너 입장에서 localhost:3306 라는 주소는, Spring Boot 컨테이너 내부에 있는 3306번 포트에 연결을 시도하게 되었다.

하지만 Spring Boot 가 실행되는 컨테이너 내부의 3306  포트는 아무것도 실행되고 있지 않다.

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: pwd1234
    driver-class-name: com.mysql.cj.jdbc.Driver

 

 

그럼 어떻게 Spring Boot의 컨테이너에서 다른 컨테이너에 존재하는 MySQL에 연결을 할 수 있을까?

compose.yml에서 정의한 Service 이름으로 서로 통신할 수 있다. 바로 예시로 알아보자.

 

Spring Boot의 DB 정보를 아래와 같이 수정한 뒤 시도해보기

application.yml

spring:
  datasource:
    url: jdbc:mysql://my-db:3306/mydb
    username: root
    password: pwd1234
    driver-class-name: com.mysql.cj.jdbc.Driver

 

우리가 이전에 작성했던 compose.yml을 보면 각 컨테이너에 service 이름(my-server, my-db)을 작성했었다.

compose.yml

services:
  my-server:
    build: .
    ports:
      - 8080:8080
    depends_on:
      my-db:
        condition: service_healthy
  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: pwd1234
      MYSQL_DATABASE: mydb
    volumes:
      - ./mysql_data:/var/lib/mysql
    ports:
      - 3306:3306
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping" ]
      interval: 5s
      retries: 10

service 이름컨테이너의 주소를 뜻한다. 해당 컨테이너의 IP 주소와 같은 역할을 한다.

 

위와 같이 코드를 수정한 뒤에 다시 한 번 컨테이너를 실행시켜보자.

$ ./gradlew clean build
$ docker compose down
$ docker compose up --build -d

$ docker ps # 정상적으로 Spring Boot, MySQL이 실행된 걸 확인할 수 있다.

 

참고자료 : 비전공자도 이해할 수 있는 Docker 입문/실전