[Docker] 도커 컨테이너 간 통신 트러블 슈팅
0. 들어가기 전에
바톤 프로젝트를 진행하면서 마주쳤던 컨테이너 간의 통신 문제를 재현해보고 해결 방법을 알아보겠습니다.
1. 문제 상황
바톤 프로젝트는 아래와 같이 백엔드 인프라 환경이 구성되어있습니다.
간단하게 설명하자면 깃허브에서 dev/BE
로의 push 이벤트가 발생하면 github actions로 빌드를 하고 빌드된 파일을 이미지로 만들어 docker hub에 push 합니다. 그 후 dev
EC2안에 있는 self hosted runner가 이미지가 업데이트된 것을 확인하고 이미지를 pull을 받아 자동으로 실행시켜 줍니다. deploy 환경에도 마찬가지입니다.
이 중에서 문제가 발생했던 환경은 public subnet(dev) 입니다. 저희 백엔드에서는 환경 분리의 용이성 때문에 DB를 모두 도커안에 띄우기로 했는데요. 이 과정에서 SpringBoot가 아래와 같은 오류를 보내면서 DB를 찾을 수 없는 현상을 맞이하게 됩니다.
2. 문제 해결 과정
기존 코드를 살펴보면 다음과 같습니다.
spring:
datasource:
url: jdbc:mysql://localhost:3306/baton_dev
driver-class-name: com.mysql.cj.jdbc.Driver
username: USERNAME
password: PASSWORD
데이터베이스를 찾지 못했기에 데이터베이스 관련 설정을 살펴봤습니다. 완벽한 설정 아닌가요?
Spring Boot와 MySQL은 하나의 EC2 안에 같이 띄워져 있으니 localhost
라고 설정을 해놨습니다. SSH 터널링을 이용해 접속했을 때 아무런 문제가 없었기에 되는 줄 알았습니다. 하지만 실패했습니다.
이 방법은 아니라 생각하고 '컨테이너가 통신하려면 다른 방법이 있지 않을까?' 라는 생각을 떠올렸습니다. 그러다 생활코딩에서 들은 docker의 네트워크가 생각났습니다.
도커의 네트워크는 같은 호스트의 두 개 이상의 컨테이너가 있을 때 컨테이너끼리 소통할 수 있게 하는 방법입니다.
docker create network baton
docker network connect baton spring-baton
docker network connect baton mysql
위와 같은 방식으로 같은 baton이라는 네트워크를 만들어 컨테이너 간 연결을 해줬습니다.
하지만 이 역시 실패를 했습니다.
컨테이너에서 localhost는 컨테이너를 가리키는 의미한다는 걸 나중에 깨달았습니다.
한 컨테이너 안에 spring과 mysql이 동시에 띄워진 상황이 아니라 소용이 없었던 것이었죠.
그래서 저는 네트워크 IP를 찾아봤습니다.
docker inspect mysql
mysql 컨테이너를 조사해 연결된 네트워크(baton)을 찾아서 해당하는 컨테이너 IP 주소를 application.yml
의 url에 입력해 줬습니다.
spring:
datasource:
url: jdbc:mysql://NETWORK_CONTAINER_IP:3306/baton_dev
driver-class-name: com.mysql.cj.jdbc.Driver
username: USERNAME
password: PASSWORD
그 후 다행히도 애플리케이션을 정상적으로 실행시킬 수 있었습니다.
그렇다면 컨테이너의 이름은 서로 unique하니 같은 네트워크로 연결되어 있으면 이름으로 구별해줄 수 있지 않을까? 라는 생각이 또 들었습니다.
추가적으로 컨테이너 이름으로 설정파일을 변경하고 실행시켰더니 이 방법도 성공했습니다.
spring:
datasource:
url: jdbc:mysql://CONTAINER_NAME:3306/baton_dev
driver-class-name: com.mysql.cj.jdbc.Driver
username: USERNAME
password: PASSWORD
3. 결론
도커 안의 두 컨테이너 사이의 통신을 하는 방법에 대해서 알아봤습니다. 결론적으로 네트워크상에 있는 컨테이너 아이피와 컨테이너 이름 두 가지의 방법으로 연결을 할 수 있었습니다. 저는 이번에 두 가지를 모두 해 보고 후자의 방식을 추천해 드립니다. 왜냐하면 한 컨테이너는 여러 네트워크에 존재 할 수 있는데 네트워크마다 IP주소가 다르게 지정이 되기 때문입니다. 또한 컨테이너가 삭제되고 다시 실행되면 변경될 여지가 크기 때문입니다. 하지만 컨테이너 이름 같은 경우에는 프로그래머가 직접 지정할 수 있으니 좀 더 쉽게 관리할 수 있다고 생각됩니다.
도커 공부를 조금 한 상태에서 트러블 슈팅하는 과정은 정말로 어려웠습니다. 앞으로 도커를 쓸 일이 많을 것 같으니, 공부를 좀 더 열심히 해야겠습니다.
'개발 > [우테코]' 카테고리의 다른 글
바톤의 DB Replication (0) | 2023.10.14 |
---|---|
build 할 때 Rest Docs 파일이 생성이 안되는 문제 트러블 슈팅 (0) | 2023.08.20 |
[Nginx] 하나의 EC2 안에서 React와 Spring 통신하기 (2) | 2023.08.06 |
[Docker] 바톤 팀 인프라 구조로 알아보는 도커 (0) | 2023.07.23 |
바톤 팀이 Java17를 사용하는 이유 (2) | 2023.07.16 |