Docker Compose 명령어 및 실습, 에러 대응

0

TIL

목록 보기
189/195

프로젝트를 진행하며 사용해왔던 Docker Compose를 왜 사용하는지에 대해 알아보자

일단 Docker Compose는 여러개의 docker 컨테이너들을 하나의 서비스로 정의하고 묶음으로 관리할 수 있게하는 도구이다.

  • 실행되는 여러개의 애플리케이션들을 한번에 관리하는데 도움이 된다.
  • 환경변수 등 복잡한 명령어들을 간소화 시킬 수 있다.(MySQL에서 PASSWORD 설정 등)

많이 사용했던 docker compose up이 이 명령어이다.(포그라운드에서 실행)

# compose.yml
services: # docker compose에서는 하나의 컨테이너를 services라고 명한다.
  my-web-server: # 내가 붙이고싶은 컨테이너의(서비스) 이름
    container_name: webserver # 아래 설정된 이미지로 컨테이너를 생성할 때의 컨테이너 이름
    image: nginx # 이미지
    ports: # 매핑될 포트
      - 80:80

이제 여기에 백그라운드에서 실행시키고 싶다면
docker compose up -d


+ Docker CLI <-> compose.yml 쉽게 변환하도록 도와주는 사이트


Docker Compose 명령어 정리

  • compose.yml파일에서 정의한 설정들을 기반으로 컨테이너들을 실행
docker compose up # 포그라운드
docker compose up -d # 백그라운드
  • docker compose 중지 및 삭제
    docker compose down

  • compose.yml로 설정된 컨테이너들 중 실행 중인 컨테이너를 확인
    docker compose ps

  • compose.yml로 설정된 컨테이너들 모두를 확인
    docker compose ps -a

  • docker compose의 로그를 확인
    `docker compose logs

  • 이미지를 다시 빌드하고 실행시켜야 할 때(ex:수정 사항이 있는 프로젝트 빌드 시)
    docker compose up --build

  • DockerHub에서 최신 이미지를 가져와 실행시키고 싶을 때

docker compose pull
# 컨테이너에 필요한 이미지를 찾을 때 원래는 로컬 환경에서 먼저 찾아보고, 없다면 DockerHub에서 가져오게되는데
# 만약 DockerHub에 최신 이미지 버전이 올라와서 그걸 이용해서 실행시키고 싶을 경우

Docker Compose 실습 - MySQL 실행해보기

원래 MySQL을 docker로 실행시켰을 때 명령어
docker run -e MYSQL_ROOT_PASSWORD=[비밀번호] -p 3306:3306 -v [경로]:[경로] -d mysql

이거를 docker compose로 실행해보자

#compose.yml
services:
  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: [비밀번호]
    volumes:
      - ./mysql_data:/var/lib/mysql # docker compose로는 상대경로 설정 가능
    ports:
      - "3306:3306"

docker compose up -d

제대로 실행됐는지 확인

이제 docker compose down을 하더라도 볼륨 설정을 해놨기 때문에 데이터는 유지된다.


Docker Compose 실습 - 2개의 컨테이너 띄우기(Spring Boot, MySQL)

보통 프로젝트에서 스프링부터와 데이터베이스를 같이 사용하는데 이 때 Docker Compose를 이용한다.

https://start.spring.io/

의존성을 추가한 스프링 프로젝트를 만들고 실행한다.

// AppController

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AppController {
    @GetMapping("/")
    public String home() {
        return "Hello World!";
    }
}
# application.yml

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

FROM openjdk:17-jdk

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

ENTRYPOINT ["java", "-jar", "/app.jar"]
# compose.yml(수정 전)

services:
  my-server:
    build: .
    ports:
      - "8080:8080"

  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: password123
      MYSQL_DATABASE: mydb
    volumes:
      - ./mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"

여기서 스프링부트가 실행될 때 application.yml에 mysql이 켜져있지 않으면 에러가 발생하게 된다.

그러므로 compose.yml에 추가 설정을 해줘야한다.
my-db가 제대로 실행되고있는지 확인한 뒤에 my-server를 실행시킨다.

# compose.yml(수정 후)

services:
  my-server:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - my-db

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

이제 docker compose ps로 확인해보면
이상하게 my-db는 실행되고있지만 my-server는 보이지 않는다.

my-server 컨테이너의 로그를 확인해보면
Failed to initialize JPA EntityManagerFactory
라면서 DB가 실행되어있지 않아서 에러가 발생했다.

왜??

각각의 컨테이너는 고유한 네트워크망과 IP주소를 가지고 있다.

그 말은 스프링부트 서버 컨테이너의 입장에서

# application.yml

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

application.yml 파일에 localhost:3306로 설정해놨으므로 다른 컨테이너의 포트를 찾을 수 없는 것이다.

그러면 어떻게해??

# application.yml

	# ...
    url: jdbc:mysql://my-db:3306/mydb
	# ...

application.yml 파일에 localhost 대신
compose.yml에 설정한 서비스 이름을 찾아서 접근이 가능하다.


파일들을 수정하고 다시 빌드단계부터 compose up을 해보면

에러 없이 정상적으로 작동한다.

0개의 댓글