순간을 성실히, 화려함보단 꾸준함을

[Docker] docker-compose 첫 사용기! 본문

나의 개발 메모장

[Docker] docker-compose 첫 사용기!

폭발토끼 2023. 12. 24. 12:25

안녕하세요.
오늘은 글또 9기 2번째 글을 적으려고 합니다.

주제는 Dockerfile 과 docker-compose 를 활용한 개발환경 세팅하기 입니다.
docker-compose 가 무엇인지도 몰랐지만 이번 기회에 공부도 하면서 직접 토이 프로젝트에 적용해보았습니다.

 

반드시 docker 가 로컬 컴퓨터에 설치가 되어 있어야 합니다.

windows, mac 같은 경우는 docker desktop 을 설치하면 docker compose 를 자동으로 사용할 수 있습니다.

배경

왜 갑자기 docker-compose 를 사용하게 된걸까요??
토이프로젝트 api 들이 개발이 어느정도 진행 된 상황에서 aws ec2 에 배포를 할 예정입니다.
배포환경에서는 db 를 mysql 을 사용할 예정인데, 로컬환경에서는 H2 database 를 사용하고 있습니다.

 

현재 프론트개발자 1명, 백엔드 개발자 2명 이렇게 개발을 하고 있는 상황인데 개발환경이 바뀌면 함께 개발하고 있는 분들 또한 변경이 발생하게 됩니다.(각자 로컬에서 프론트 프로젝트/백엔드 프로젝트 를 각각 띄워서 진행하고 있거든요,,,ㅠㅠ)

그래서 이를 어떻게 하면 최소화 할 수 있을까? 고민하다가 백엔드 프로젝트를 이미지화 시켜서 도커환경에서 컨테이너로 띄워버리면 각 로컬 환경에서 docker desktop 만 설치하여 실행시키면 될 것 같다는 생각이 들었습니다.

과정

먼저 spring boot 프로젝트를 이미지화 시킬 수 있는 Dockerfile 을 정의하였습니다.

# Use the official OpenJDK base image
FROM openjdk:11-jdk

# Copy the jar file into the image
COPY ./build/libs/diray-0.0.1-SNAPSHOT.jar app.jar

# Set the entry point to start the application
ENTRYPOINT ["java","-jar","/app.jar"]

FROM : 해당 프로젝트를 실행시키기 위해 토대가 되는 이미지를 지정합니다. 전 java 11 버전을 사용하고 있으니 openjdk:11-jdk 라는 이미지를 정의하였습니다.


COPY : 이미지에 파일이나 폴더를 추가하는 역할입니다. (build 가 완료된 .jar 파일 위치) (복사할 경로 위치), 전 gradle 로 build 하고 있으므로 .jar 파일이 위치한 경로를 입력해주었고, app.jar 라는 파일명으로 복사할 것을 명시해주었습니다.

 

ENTRYPOINT : 컨테이너를 실행할 명령어를 정의해줍니다. 제가 정의한 명령어들은 결국 java -jar /app.jar 라는 명령어로 실행됩니다. 즉, jar 파일을 실행시키는 것 입니다.

첫번째 단계는 끝났습니다. 그 다음은 정의한 Dockerfile 을 가지고 docker-compose.yml 을 정의해봅시다.

version: '3'
services:
  mysql:
    image: mysql:8.0
    container_name: mysql_db
    ports:
      - "3306:3306" # HOST:CONTAINER
    environment:
      MYSQL_DATABASE: diarydb
      MYSQL_ROOT_HOST: '%'
      MYSQL_ROOT_PASSWORD: admin
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - D:/mysql/data:/var/lib/mysql
    networks:
      - app_network

  backend:
    build:
      dockerfile: Dockerfile
      context: ./
    container_name: app_backend
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql_db:3306/diarydb?useSSL=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: admin
    depends_on:
      - mysql
    ports:
      - "8080:8080"
    volumes:
      - ./:/app
    networks:
      - app_network

networks:
  app_network:

mysql 컨테이너와 제 프로젝트 (jar) 컨테이너를 정의해주었습니다.

 

mysql 에서 주의할 점은 개인 로컬 환경에서 3306 port 를 이미 사용하고 계시는 분들이 있습니다. 이때는 기존 3306 port 를 죽이던가 아니면 HOST port 를 변경 해야합니다.

  mysql:
    image: mysql:8.0
    container_name: mysql_db
    ports:
      - "3307:3306" # HOST:CONTAINER
    environment:
      MYSQL_DATABASE: diarydb
      MYSQL_ROOT_HOST: '%'
      MYSQL_ROOT_PASSWORD: admin
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - D:/mysql/data:/var/lib/mysql
    networks:
      - app_network

위 처럼 3307 로 변경하시면 됩니다.(꼭 3307 이 아니어도 다른 포트면 됩니다)

 

또한, environment 부분인데요. 해당 내용은 mysql 유저에 관한 정보들을 정의해주면 되는데 전 root 로 정의하였습니다.
다른 유저로 접속하고 싶다 하시면

    environment:
      MYSQL_DATABASE: diarydb
      MYSQL_USER: user
      MYSQL_USER_PASSWORD: userpwd
      MYSQL_ROOT_HOST: '%'
      MYSQL_ROOT_PASSWORD: admin

위와 같이 따로 추가를 해주면 되는데, 이때 정의만 한다고 유저가 생성되는 건 아닌 것 같더라구요. 전 위와 같이 user 를 정의하고 docker compose 를 실행시켜보았을때 mysql 에 접속이 되지 않았습니다.

그리고 mysql8.0 을 사용하시고 계시다면 반드시 command 부분을 정의해주어야 합니다.

 

volumn 은 백업을 굳이 안하고 싶다고 하시면 빼도 되지만 networks 는 반드시 정의해주어야 합니다. 그래야지 독립되어 있는 mysql containerjar container 가 동일한 네트워크를 통해 커넥션을 맺을 수 있기 때문입니다.

mysql 에 관한 주의할 점은 여기까지 적으면 충분할 것 같습니다.


다음으로는 backend project 에 대해서 말씀드리겠습니다.

가장 중요한 부분은 depends_on 입니다. 생각해보시면 jar 컨테이너는 mysql 컨테이너가 먼저 실행이 되어야지만 db connection 을 맺을 수 있습니다. 그런데 mysql 컨테이너 보다 jar 컨테이너가 먼저 실행되면,,,,???낭패겠죠?

그래서 docker compose 에서는 이를 위해 depends_on 이라는 명령어를 통해 순서를 정의해줄 수 있습니다.

app_backend 라는 컨테이너는 mysql 에 의존하고 있습니다. 그러니 mysql 을 먼저 실행시켜주세요. 라는 뜻입니다.

 

절대 빼먹으면 안됩니다!!

또, 해맸던 부분이 있었는데 datasource 를 정의해주는 부분이었습니다.

    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql_db:3306/diarydb?useSSL=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: admin

url 을 어떻게 정의해줘야하는지 조금 해맸는데요 아래와 같습니다.

jdbc:{database 정의}://{mysql container 이름}:{실행시킨 port number}/{mysql database 이름}?useSSL=false&allowPublicKeyRetrieval=true

docker compose 에 관한 간단한 명령어를 알아보겠습니다.

docker compose up : 컨테이너를 생성하고 실행시킵니다. 보통 백그라운드로 실행시키기 때문에 맨 마지막에 -d 를 붙여줍니다.
ex) docker compose up -d

 

docker compose down : 컨테이너와 네트워크를 종료하고 삭제합니다. 이때, 정말 주의할 점은 docker images 를 삭제하는 것이 아닙니다. 따라서 application.yml 을 변경한다던가 소스 수정이 발생했을때는 기존 image 들을 삭제한 뒤 다시 clean - build 를 실행시켜주어야 합니다.

 

docker compose logs : 실행중인 컨테이너의 log 들을 확인할 수 있습니다. 다만 docker desktop 을 사용하시고 계시다면 desktop 에서도 간단하게 확인하실 수 있으십니다.

 

자 그럼 다 끝났습니다. 한번 실행시켜 볼까요?

 

docker compose up -d 명령어를 입력하였습니다.

터미널에 정상적으로 create 된걸 확인할 수 있습니다.
docker desktop 에서도 확인해보죠.

잘 실행된거 같죠??ㅎㅎ

한번 postman 으로 요청을 직접 보내봅시다.

응답값이 없어서 response body 에 아무값도 없긴 하지만 200 status code 가 잘 내려온 것 같습니다!!

혹시 모르니 log 를 확인해보도록 하죠

멋지네요.이로써 성공했습니다.

결과 및 느낀점

사실 하루종일 삽질해 가면서 세팅했었습니다....문제의 원인은 전 docker compose down 하면 아에 초기화가 되는 줄 알고 소스를 수정하고 저 명령어만 입력했었거든요...근데 절대 아니라는거,,,image 들은 그대로 남아있기 때문에 반드시 image 들도 삭제하고 다시 build 를 실행해주어야 합니다. ㅋㅋ

 

docker 에 관하여 익숙치 않았긴 했는데 이번 기회에 재밌게 진행했던 것 같습니다.ㅎㅎ
얼른 팀원들에게도 같이 공유를 해야겠네요 ㅎㅎㅎ

감사합니다.