[도커] 개발환경분리 with Docker, Docker-compose

이진수·2023년 7월 16일

도커

목록 보기
1/1

🗂️ 개발환경 분리

📖 서론

지금까지 프로젝트를 진행하면서 데이터베이스를 한 개만 띄우고 그곳에 테스트를 진행하고 잘 되면 drop하고 배포를 하는 방식으로 해왔습니다. 배포하고 땡! 인 공모전이나 학교 프로젝트였기 때문에 이렇게 진행해도 문제가 없었습니다.

마음 한 켠에는 실제로 서비스를 배포할 때는 이렇게 하지 않을텐데.. 라는 생각이 있었지만 기한 마추기 급급했던 프로젝트들을 진행하며 시도해보진 못했습니다.

그리고 저번 회고 글에서 언급한 내용인 "학기 중에 진행한 프로젝트에서 도커를 사용하여 편리하게 오라클을 설치 및 이용한 경험" 덕분에 도커에 흥미가 생겼고, 방학을 맞이하여 도커를 입문하였습니다.

🪝 도커 학습 및 분리를 마음먹은 계기

도커에 입문하여 전체적인 구조와 동작흐름을 파악한 뒤 Dockerfile도 만들어보고 Docker image의 구조(base layer, layer ...) 및 명령어를 학습한 뒤 포트매핑하여 ec2에 배포까지 해봤습니다. 여기에서 느낀 점이 있는데 이는 추후에 다른 글에서 작성해보겠습니다.

분리를 마음먹은 계기는 거창한 건 아닌데요..🤭
도커 공부를 진행하면서 또한 docker-compose도 학습하여 간단한 명령어로 컨테이너를 띄우는 것까지 했습니다.
뜬금 없을 수 있는데 제가 여기까지 느낀 점은 배포가 편리하다가 아니라
음.. 개발환경 분리가 편하겠는데? 였습니다.

🛫 분리 시작

실제로 닥친 상황이 아니기 때문에 스스로 시뮬레이션을 진행했습니다.
가정한 상황은 API 서버 1개에 운영 중인 db가 있고, 이 운영 db를 건드리지 않는 로컬 db에서 테스트하는 시나리오 입니다.

먼저 docker를 분리하기 전에 설정관련 파일인 application.yml파일을 먼저 분리하기로 했습니다.

API서버는 Spring Boot로 진행하여서 application.yml이 있는 상황입니다.
그래서 먼저 이 설정파일을 운영과, 개발로 나누어줬습니다
(application-dev.yml, application-prod.yml)

그리고 application.yml을 다음과 같이 작성하였습니다.

spring:
  profiles:
    active: (dev or prod)

이때 active 부분을 dev나 prod로 바꿔서 진행하면 됩니다.
dev로 실행하면 application-dev.yml파일이 실행되고, prod로 실행하면 application-prod.yml파일이 실행됩니다.

이를 확인하기 위해서 application-dev.yml 마지막 부분에

greeting:
  message: this is dev application.yml

application-prod.yml 마지막 부분에

greeting:
  message: this is prod application.yml

를 작성하고 테스트를 진행할 컨트롤러에 출력시켜봤습니다.


dev로 실행한 경우

로그에 The following 1 profile is active:"dev"로 잘 뜨고 헬로 메소드의 메세지가 잘 들어간 걸 확인할 수 있습니다.


prod로 실행한 경우


이 경우도 잘 뜨는 것을 확인했습니다.


🐳 도커 컴포즈 분리

도커 컴포즈 파일도 application.yml 파일처럼 분리가 가능합니다. 그래서 저는 docker-compose-prod.yml과 docker-compose-dev.yml로 구성하였습니다.

docker-compose-prod
이 경우 RDS와 연결된 운영 DB를 연결하는 부분이 application-dev.yml에 있기때문에 스프링만 빌드하는 도커파일을 사용하였습니다.

version: "3"
services:
  spring:
    build:
      context: .
      dockerfile: Dockerfile
    image: docker-actions-spring-prod
    ports:
        - "8080:8080"

*docker-compose-dev
이 경우 위 코드의 dockerfile부분이 Dockerfile.dev로 바뀌고
services에 spring뿐만 아니라 mysql까지 생성해주고 묶어서 빌드해줬습니다. (mysql폴더에 mysql을 위한 도커파일이 존재합니다)

version: "3"
services:

  mysql:
    build: ./mysql
    restart: unless-stopped
    container_name: test_mysql
    ports:
      - "3306:3306"
    volumes:
      - ./mysql/mysql_data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: <db이름>
      MYSQL_ROOT_PASSWORD: <db패스워드 지정>

  spring:
    build:
      context: .
      dockerfile: Dockerfile.dev
    image: docker-actions-spring-dev
    ports:
      - "8080:8080"
    depends_on:
      - mysql
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/test_db
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: <db 패스워드>

그래서 각각
docker-compose -f docker-compose-prod.yml up --build
docker-compose -f docker-compose-dev.yml up --build
를 통해 도커 컴포즈를 띄워주면
잘 뜨는 것을 확인할 수 있습니다.

🚧 난관

😵‍💫 application.yml 분리가 안돼!
맨 처음 도커 컴포즈로 개발 환경을 분리하려고 위의 명령어를 계속 쳤는데 바뀌지 않았습니다.
왜 안바뀌지 했는데 제가 작성한 dockerfile은

FROM openjdk:11-jdk

WORKDIR usr/src/app

ARG JAR_FILE=build/libs/docker-actions-0.0.1-SNAPSHOT.jar

COPY ${JAR_FILE} app.jar

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

이런 식이였고, 새로 빌드해주지 않으면 jar파일이 바뀌지 않아서 도커 이미지 캐시 보관 장소에서 그냥 꺼내 쓰는 것이었습니다. (이거 알아내기 까지도 좀 오래 걸렸습니다 ㅠㅠ) 그래서
COPY src/main/resources/application.yml application.yml명령어를 도커파일에 추가했고 이 이후로는 새로 빌드를 하지 않아도 application.yml파일의 active부분만 변경해도 잘 동작하였습니다.

🤔 서버랑 mysql 연결이 안돼!
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
mysql 컨테이너를 컨테이너로 묶어서 띄우는데 자꾸 연결이 안됐습니다.
왜 안바뀌지 찾아보니 mysql이 뜨기 전에 spring이 먼저 뜬다는 문제와 url 문제임을 추측했습니다.

이 전 docker-compose파일은 아래와 같았고,

environment:
	SPRING_DATASOURCE_URL: jdbc:mysql://localhost:3306/test_db

docker 내부에서 localhost는 mysql 서버가 실행 중인 호스트 시스템의 네트워크가 아닌 컨테이너 자체 네트워크를 참조한다는 것을 알아냈고

environment:
	SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/test_db

로 바꿔주었습니다.

그리고 docker-compose에서는 depends_on 이라는 특정 서비스가 실행된 후에 실행되게 하는 명령어가 있었습니다.
그래서 services의 spring 부분에

depends_on:
 	- mysql

을 추가하여 mysql이 실행된 후에 spring service가 실행되도록 하였습니다.

이렇게 해서 해결!!


마무리

이 글에 작성된 것들 모두 처음 사용해보는 것이며 막 찾아보면서 하다보니 오개념이 있을 수 있습니다.
만약 발견해주신다면 보완점이나 수정사항 말씀해주시면 학습하는데 큰 도움이 될 것 같습니다!!

그리고 앞으로 진행 해볼 사항은 도커로 배포하는 편리함을 아직 와닿지 못해서 github actions로 CI/CD를 진행해보고 최종적으로는 ECR을 사용한 ECS배포도 도전해보려고 합니다.

감사합니다 :)

profile
여유로운 마인드

2개의 댓글

comment-user-thumbnail
2023년 7월 17일

저도 개발자인데 같이 교류 많이 해봐요 ㅎㅎ! 서로 화이팅합시다!

1개의 답글