Docker Container 간 통신하기

na.ram·2024년 9월 29일
post-thumbnail

Docker 컨테이너 간 통신하는걸 두 가지 방법으로 테스트 해봤다.

Docker로 각각 컨테이너를 띄워서 통신시키는 방법과
Docker Compose를 통해 한 번에 띄워서 통신시키는 방법이다.

각각 컨테이너를 띄워서 통신

먼저 통신시킬 컨테이너들을 띄워야 한다.
Redis, MySQL, Spring Boot를 띄워서 통신시킬 예정이다.
미리 Redis와 MySQL 최신 버전 이미지와 Spring Boot 이미지를 준비했다.


혹시 이미지 다운받는 명령어가 헷갈린다면 명령어는 아래와 같다.

docker pull {이미지명}:{버전태그}

이후에는 당연히 각 컨테이너들을 실행시켜준다.
기본적으로 컨테이너를 실행시키는 명령어는 아래와 같다.

docker run -p {호스트포트}:{도커포트} {이미지}

그렇지만 컨테이너명을 주지 않으면 네트워크 연결할 때 귀찮으니까 이렇게 실행한다.
sudo docker run -it --name mysql -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD={비밀번호} mysql
sudo docker run -it --name redis -d -p 6379:6379 --hostname redis redis

이렇게 올린 MySQL과 Redis 컨테이너가 정상 실행이 된다면 Spring Boot 컨테이너를 올린다. 그러면 당연하지만 컨테이너 간 통신이 되지 않아 실패한다. ㄱ-

그 이유는 도커 컨테이너는 모두 별도의 로컬 IP를 갖게 되기 때문이고,
도커 컨테이너에서 localhost는 자기 자신의 컨테이너 IP를 가리키게 된다.

(실제로 MySQL 컨테이너의 IPAddress와 Redis 컨테이너의 IPAddress가 다름을 확인할 수 있다)


따라서 우리가 올린 Spring Boot에서 MySQL이나 Redis로 통신을 할 때 localhost로 작성된 것들이 모두 Spring Boot 컨테이너 자신을 가리키기 때문에 실패하는 것이다.

그러니 이를 서로 통신할 수 있게 해주기 위해 네트워를 만들어줄 것이다.
(MySQL과 Redis는 서로 통신을 할 필요가 없기 때문에 네트워크를 두 개 만들었다.)

# 네트워크 생성
docker network create --driver=bridge mysql-network
docker network create --driver=bridge redis-network

그리고 미리 만들어뒀던 MySQL 컨테이너와 Redis 컨테이너에 새로 생성한 네트워크들을 연결해준다.
# 컨테이너에 네트워크 연결
docker network connect redis-network redis
docker network connect mysql-network mysql

마지막으로 Spring Boot 컨테이너 역시도 네트워크를 연결해주는데, Spring Boot는 MySQL, Redis 모두와 통신해야 하므로 두 개의 네트워크를 연결해준다.

# 컨테이너 생성
docker create -it --name test-app --env-file=.env -p 8080:8080 delivery-service-app

# 생성한 컨테이너에 네트워크 연결
docker network connect mysql-network test-app
docker network connect redis-network test-app

# 컨테이너 실행
docker start test-app

application.properties 파일은 아래와 같이 설정되어있다.


application.properties 파일에 환경변수로 설정된 부분들은 모두 컨테이너를 실행할 때 -e 옵션을 통해 설정해주거나 .env 파일에 작성해 위와 같이 실행해야 정상적으로 Spring Boot 컨테이너가 동작할 수 있다.

환경변수를 하나하나 설정해주기는 귀찮으므로(..) docker가 설치된 디렉토리에 .env 파일을 생성해주고 아래와 같이 작성해준다.

DATABASE_URL=jdbc:mysql://{MySQL컨테이너명}:3306/{DB명}
USERNAME=root
PASSWORD={비밀번호}
HOSTNAME=redis
JWT_SECRET_KEY={JWT시크릿키}

이제 Postman에서 API를 호출해서 정상적으로 실행이 되는지를 확인해보겠다.
먼저, 회원가입 API를 통해 MySQL과는 정상적으로 통신이 되는 것을 확인할 수 있다.


Redis의 경우에는 확인하기가 까다로워 redis-cli를 통해 key가 저장되어 있는지 확인했다.


컨테이너끼리 정상적으로 통신하는 것을 확인할 수 있다.


Docker Compose로 컨테이너 간 통신

먼저 Docker Compose를 사용할 수 있도록 다운로드를 받아준다.

brew install cask docker-compose

그리고 docker-compose.yml을 생성해서 아래와 같이 작성한다.

version: "3.8"

services:
  mysql: # 서비스명
    image: mysql:latest
    container_name: mysql-delivery # 컨테이너명
    ports:
      - "3306:3306"
    environment: # 환경변수
      MYSQL_ROOT_PASSWORD: {비밀번호}
    networks: # 네트워크
      - mysql-delivery-net

  spring:
    image: delivery-service-app:latest
    container_name: delivery
    env_file: # 환경변수 파일
      - ./.env
    ports:
      - "8080:8080"
    depends_on: # service 간의 종속성
      - mysql # spring 서비스는 mysql 서비스가 실행된 이후에 실행되어야 한다.
      - redis # spring 서비스는 redis 서비스가 실행된 이후에 실행되어야 한다.
    networks:
      - redis-delivery-net
      - mysql-delivery-net

  redis:
    image: redis:latest
    container_name: redis-delivery
    hostname: "redis"
    ports:
      - "6379:6379"
    networks:
      - redis-delivery-net

networks:
  mysql-delivery-net:
    driver: bridge
  redis-delivery-net:
    driver: bridge

이후에 docker-compose.yml을 실행해서 컨테이너들을 한 번에 띄운다.

docker-compose up

그러면 아래처럼 모든 컨테이너가 한 번에 실행되는 것을 확인할 수 있고


각각 띄웠을 때처럼 회원가입 API를 호출해보면 MySQL과는 정상적으로 통신이 되는 것을 확인할 수 있다.


역시나 똑같이 redis-cli를 통해 key가 저장되어 있는지 확인했다.


컨테이너끼리 정상적으로 통신하는 것을 확인할 수 있다.

0개의 댓글