Docker 컨테이너로 Spring, MySQL 연동

rivkode·2024년 1월 11일
0

이번 글은 CI/CD 를 구축하기 위한 첫번째 글로 Docker Image 생성, Container 생성하는 내용을 담아보았습니다

Docker Compose로 spring 컨테이너와 MySQL 컨테이너를 연동하기 위해 로컬에서 먼저 명령어로 테스트를 해보려고 합니다

테스트 절차는 아래와 같습니다

  1. Spring, MySQL 이미지 만들기
  2. 이미지를 컨테이너화 하기
  3. Postman으로 요청, 응답 받기

이 글은 연동 방법을 공유하는 것도 있지만 동작원리에 대해서도 설명을 하므로 내용이 길어질 수 있습니다.

먼저 각 이미지를 만들어줍니다.

Spring 프로젝트의 경우 프로젝트 폴더로 이동 후 아래 명령어로 빌드파일을 생성합니다.
1. ./gradlew build -x test (-x test의 경우 테스트 없이 빌드를 진행한다는 의미입니다)
2. Dockerfile을 만들어줍니다. 이때 위치는 가장 바깥쪽인 build.gradle 이 있는 곳과 동일한 위치입니다.
2-1 Dockerfile은 아래와 같이 만들어줍니다.
JDK11 기준

FROM openjdk:11
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
  1. docker build -t (docker 이미지 이름) . ex docker build -t spring-project . 이때 주의할 점은 뒤에 꼭 '.' 을 붙여줘야합니다.
  2. docker images 명령어를 통해 생성된 images 를 확인합니다.

MySQL 의 경우 dockerhub에 올라가있는 이미지를 pull 받으시면 됩니다.
1. docker pull mysql:8.0.22
2. docker images 명령어를 통해 생성된 images 를 확인합니다.

이미지가 만들어지면 이후 각 이미지를 컨테이너화 하면 됩니다.

이 과정에서 docker network를 사용하여 각 컨테이너를 동일한 네트워크내에 속하도록 설정해줘야 컨테이너끼리 통신이 가능합니다.

"같은 컴퓨터내에 있으니까 그냥 통신할 수 있는거 아닌가요 ?" 라는 의문이 생길 수 있습니다.
하지만 이렇게 하지 않으면 통신할 수 없는 이유는

"기본적으로 Docker 컨테이너는 독립적인 환경에서 실행이 되므로 다른 컨테이너와 통신을 할 수 없습니다."

라는 답변을 들으실 것입니다.

컨테이너들을 하나의 도커 네트워크로 연결시킨다면 서로 통신할 수 있습니다.

하는 법은 생각보다 간단합니다.

docker network create docker-network -> 네트워크 생성
docker network connect docker-network container-name -> 컨테이너를 네트워크에 연결

저희가 궁금한 것은

"그래서 네트워크에 연결하면 무슨일이 일어나는걸까 ?"

입니다.

docker 컨테이너를 생성하게 되면 호스트와 통신하기 위한 eth0라는 네트워크 인터페이스를 할당받습니다. 이때 동시에 호스트에도 veth(virtual ethernet)라는 네트워크 인터페이스가 할당되고 컨테이너에 할당된 eth0 인터페이스와 통신하게 됩니다.

아래 그림과 설명을 참고해주세요.

docker network connect 명령어를 사용하여 컨테이너를 네트워크에 연결하면 다음과 같은 일련의 동작이 발생합니다

  1. 네트워크 인터페이스 할당: 컨테이너가 네트워크에 연결되면, 컨테이너는 해당 네트워크에 대한 새로운 네트워크 인터페이스를 할당받게 됩니다. 이 인터페이스는 컨테이너 내부에서 사용되는 가상의 네트워크 연결점입니다.

  2. veth 인터페이스 생성: 호스트에도 컨테이너와 통신하기 위한 가상 Ethernet 인터페이스인 veth(가상 이더넷)가 생성됩니다. 이 veth 인터페이스는 호스트와 컨테이너 간에 데이터를 주고받는데 사용됩니다.

  3. 브리지 연결: 호스트에 생성된 veth 인터페이스는 도커 브리지 네트워크에 연결됩니다. 이 브리지 네트워크는 호스트와 다른 컨테이너 간의 통신을 중개하는 역할을 합니다.

  4. 라우팅 규칙 추가: 호스트의 라우팅 테이블에 적절한 라우팅 규칙이 추가되어 컨테이너와 호스트 간에 패킷이 올바르게 라우팅되도록 합니다.

  5. DNS 등록: 컨테이너는 Docker 네트워크에 등록되어 DNS 서비스를 통해 도커 네트워크 내의 다른 컨테이너를 도메인 이름으로 참조할 수 있습니다.

이렇게 네트워크에 컨테이너를 연결하면 컨테이너 간에 통신이 가능하게 되며, 호스트와도 통신할 수 있게 됩니다. 이 과정은 도커가 컨테이너 간의 네트워크 통신을 관리하고 isolation(격리)을 유지하기 위해 수행하는 것입니다.

쉽게 말해 docker network에 연결을 하게 되면 같은 네트워크 내에서 인터페이스를 통해 통신을 할 수 있게 됩니다.

이제 동작원리를 알았으니 docker network를 만든 뒤 각 이미지를 컨테이너로 만들어주겠습니다.

docker network create pre_net prenet 이라는 이름의 network를 생성하였습니다.

MySQL 컨테이너에 Spring 프로젝트를 연결을 해야하므로 MySQL 컨테이너를 먼저 생성하도록 하겠습니다.

MySQL 의 경우 아래의 명령어로 컨테이너화 할 수 있습니다.
docker run -d --name preonb_db
--network pre_net
-p 3307:3307 (저의 경우 이미 3306포트를 사용중으로 3307로 하였습니다)
-e MYSQL_ROOT_PASSWORD=root
-e MYSQL_DATABASE=preonb
-e MYSQL_USER=root
-e MYSQL_PASSWORD=root
-v mysql:/var/lib/mysql
--restart unless-stopped mysql:8.0.22

Spring 프로젝트의 경우 아래의 명령어로 컨테이너화 할 수 있습니다.
docker run -d --name preonb --network pre_net -p 8080:8080
--link preonb_db:mysql
-e PREONB_DB_HOST=db:3307
-e PREONB_DB_USER=root
-e PREONB_DB_PASSWORD=root
-e PREONB_DB_NAME=preonb
--restart unless-stopped preonb:latest

이때 db url은 다음과 같이 설정해줍니다.
url: jdbc:mysql://preonb_db:3306/db (MySQL 컨테이너 이름이 preonb_db, 데이터베이스이름이 db일 경우)
그리고 최초에 생성한 MySQL 컨테이너는 데이터베이스가 없으므로 아래의 절차를 따라 생성해줍니다.

접속방법
docker exec -it preonb_db mysql -u root -p (user가 root일 경우)
비밀번호 입력
접속완료!
create database db;

위와 같이 컨테이너화 및 docker network 연결까지 마쳤으면 로컬에서 테스트를 할 준비가 완료되었습니다.

현재 제 로컬의 컨테이너 리스트, 네트워크 상태입니다.

이제 Postman 테스트를 진행해보겠습니다.

간단하게 게시글을 작성해보겠습니다.

Create

Read

이상으로 Docker Compose 를 하기 전 로컬에서 테스트를 진행해보았습니다!

0개의 댓글