ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • MSA) 서비스 별 각 인스턴스에서 애플리케이션을 Docker 컨테이너화 후, 발생한 Eureka Client 간의 통신 문제
    SpringBoot 2024. 7. 9. 10:38

     

     

     

     

    개발 서버를 구축하기 위해, 현재 위와 같이

    MSA의 Eureka 서버를 제외하고, 각 서비스들을 각각의 인스턴스에 Blue/Green 무중단 배포를 적용하여

    도커로 컨테이너화 한 상태였습니다.

     

    API Gateway 서버와 Batch Service 서버 모두

    CD가 동작하면 각 서버에 작성한 쉘 스크립트가 실행되어 Blue/Green 무중단 배포를 적용하는 방식입니다.

     

    Batch Service의 쉘 스크립트 일부분

     

    위와 같이 Blue/Green을 적용을 확인하기 위해 각 마이크로 서비스에 헬스 체크 컨트롤러를 만들어 둔 상태였습니다.

     

     

     

    문제

    각 서비스에서 도커 컨테이너가 정상적으로 올라간 것을 확인한 후,

    API Gateway 서버에서 Batch Service의 API를 잘 라우팅 해주는지 확인하기 위해

    아래와 같이 리눅스 상에서 curl 명령을 통해 헬스 체크 API를 요청해 주었으나, 오류가 발생하였습니다.

     

     

    오류를 확인하기 위해 도커 컨테이너의 로그를 확인해보니

    정말 많은 로그들이 쌓여있었고, 그중에 아래 로그가 눈에 띄었습니다.

    java.net.UnknownHostException이라는 오류와 함께 '089327a3ae4f'라는 문구가 로그에 찍혔는데

     

    해당 문자열은 Batch Service에서 띄운 도커 컨테이너 ID 였습니다.

     

     

    Eureka Server

     

    Eureka에 Client의 정보들이 제대로 등록되어 있지 않았던 것을 확인하였고

    이 문제에 대해 해결 방법을 두 가지 방식에 대해 찾았으나, 저는 두 번째 해결 방법으로 결국 문제를 해결했습니다.

    (사실상 해결 방법 1은 현재 제 상황에서 진정한 해결 방법?은 아니였습니다.)

     

     

     

    해결 방법 1

    Docker Network Host 모드로 변경하기

    현재 저의 스크립트를 보면 아래와 같이 app-net이라는 이름으로 Bridge(브리지) 네트워크의 유형으로 실행됩니다.

    왼쪽) 무중단 배포를 위한 스크립트 일부 오른쪽) docker network 리스트

     

     

    브리지 네트워크를 사용하면 아래 사진과 같이

    각 컨테이너는 동일한 호스트 내에서 가상 네트워크 브리지에 연결됩니다.

    Bridge 드라이버를 사용하면 컨테이너 간의 통신이 가능하며 호스트의 네트워크와도 통신할 수 있습니다.

     

    사진 출처) https://hoing.io/archives/24498

     

    그러나 이러한 방식으로 Eureka Client에 등록하는 것은 맞지 않는 방법이었습니다.

     

    Bridge Network 상태에서 아래와 같이 Batch Service에

    Eureka 서버에 서비스 인스턴스를 등록할 때 IP 주소를 우선적으로 사용하도록

    지정하는 설정인 preferIpAddress 설정을 추가해도 가상 네트워크의 IP가 등록이 되어 있었습니다.

    eureka:
      instance:
        instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
        preferIpAddress: true

     

     

    해당 문제를 해결하기 위해서는 도커 네트워크를 호스트모드로 설정하면 됩니다.

     

    컨테이너의 네트워크를 호스트모드로 설정하면

    컨테이너를 host의 네트워크와 동일한 레벨로 설정되며,

    컨테이너 내부의 애플리케이션을 별도의 포트포워딩 없이 바로 서비스하게 됩니다.

    그러나 저의 경우 하나의 애플리케이션에 대해서 두 개의 포트를 가지고 Blue/Green 배포를 수행하고 있으므로

    적절한 해결방법은 아니었습니다.

     

    host 모드를 적용하고 싶다면 아래와 같은 형태의 명령어를 docker run에 추가해 주면 됩니다.

    --network host

     

     

     

    해결 방법 2

    application.yml에 hostname 추가

    첫 번째 방법에서 해결인 줄 알고 좋아했다가 더 큰 문제를 발생하여 몇 시간째 고민하다가

    방향을 틀게 되었는데

     

    두 번째 방법은 생각보다 매우 간단했습니다.

     

    유레카 입장에서 컨테이너 ID는 배포할 때마다 달라지기 때문에 고정적인 값인 IP를 알아야 합니다.

    유레카가 자동으로 Client로 등록한 서비스들의 정보를 알고 있고,

    마이크로 서비스들이 요청할 때마다 정보를 줘야 하기 때문입니다.

     

    아래 사진과 같은 방식으로 Batch Service의 application.yml 파일에

    hostname으로 서버의 EIP를 넣어주면 됩니다.

     

     

    그러면 아래와 같이 API Gateway에서 Batch Service의 API를 요청했을 때,

    값을 잘 받아오는 것을 확인할 수 있었습니다.

     

     

     

Designed by Tistory.