MSA 환경에서 API Gateway 연결 트러블슈팅 - Genie-Uss/genieus GitHub Wiki

발생 문제

API Gateway가 Eureka 서버에 성공적으로 연결되었으나 서비스 호출 시 네트워크 연결 오류 발생함.

io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: null: /172.18.0.8:10000
Caused by: java.net.NoRouteToHostException: null

원인 분석

flowchart TB
    %% 사용자
    User(["사용자"]) 
    
    %% 퍼블릭 VPC
    subgraph PublicVPC["퍼블릭 VPC"]
        API_Gateway["[퍼블릭 EC2] API Gateway"]
    end
    
    %% 프라이빗 VPC
    subgraph PrivateVPC["프라이빗 VPC"]
        subgraph DockerNetwork["Docker 네트워크"]
            Eureka["Eureka Server(서비스 디스커버리)"]
            AuthService["AUTH-SERVICE [172.18.0.8:10000]"]
            OtherService1["USER-SERVICE"]
            OtherService2["PRODUCT-SERVICE"]
            OtherService3["기타 서비스"]
            
            %% 내부 Docker 네트워크에서의 연결
            Eureka --- AuthService
            Eureka --- OtherService1
            Eureka --- OtherService2
            Eureka --- OtherService3
        end
    end
    
    %% 연결 관계
    User -->|"HTTP 요청"| API_Gateway
    API_Gateway -->|"서비스 디스커버리 성공"| Eureka
    API_Gateway -.->|"서비스 호출 실패 (NoRouteToHostException)"| AuthService

    %% 스타일 설정
    classDef publicService fill:#ffcc99,stroke:#ff9933,stroke-width:2px
    classDef privateService fill:#99ccff,stroke:#3366cc,stroke-width:2px

    class API_Gateway publicService
    class Eureka,AuthService,OtherService1,OtherService2,OtherService3 privateService

    linkStyle 5 stroke:#009900,stroke-width:2px,color:#009900
    linkStyle 6 stroke:#ff0000,stroke-width:2px,stroke-dasharray:5 5,color:#ff0000

Loading
  • API Gateway는 Eureka에서 AUTH-SERVICE를 찾았으나(172.18.0.8:10000) 실제 네트워크 경로 없음
  • API Gateway: 퍼블릭 인스턴스(EC2)에 배포됨
  • 유레카 서버 + 마이크로서비스들: 프라이빗 인스턴스(EC2) 내부의 Docker 네트워크에 배포됨
  • Gateway가 서비스 호출 시 사용하는 IP(172.18.0.8)는 프라이빗 Docker 네트워크 내부 주소라 퍼블릭 인스턴스에서 직접 접근 불가능함

해결 방안 검토

  1. AWS Transit Gateway/VPC Peering 사용:
    • 퍼블릭 VPC와 프라이빗 VPC 간 피어링으로 직접 통신 가능하게 함
    • 복잡한 네트워크 설정 필요함
  1. 로드 밸런서 사용:
    • 프라이빗 인스턴스의 서비스들 앞에 내부 로드 밸런서 배치
    • API Gateway가 로드 밸런서 통해 서비스 접근하도록 함
    • 추가 비용 발생함
  1. 리버스 프록시 설정:
    • 프라이빗 인스턴스에 NGINX 같은 리버스 프록시 설치
    • 퍼블릭 API Gateway가 프록시 통해 마이크로서비스 접근하도록 함
    • 구성이 비교적 간단함
  1. 서비스 메시 도입:
    • Istio 같은 서비스 메시로 네트워크 통신 관리
    • 러닝 커브와 오버헤드 발생함

최종 해결책

API Gateway도 내부 네트워크에 두고 NGINX만 프록시로 퍼블릭 인스턴스에 배치함.

[외부 요청] → [NGINX 프록시(퍼블릭)] → [API Gateway(프라이빗)] → [마이크로서비스(프라이빗)]
flowchart TB
    %% 사용자
    User(["사용자"]) 
    
    %% 퍼블릭 VPC
    subgraph PublicVPC["퍼블릭 VPC"]
        NGINX["[퍼블릭 EC2] Nginx 프록시"]
    end
    
    %% 프라이빗 VPC
    subgraph PrivateVPC["프라이빗 VPC"]
        subgraph DockerNetwork["Docker 네트워크"]
            API_Gateway["API Gateway"]
            Eureka["Eureka Server\n(서비스 디스커버리)"]
            AuthService["AUTH-SERVICE"]
            UserService["USER-SERVICE"]
            ProductService["PRODUCT-SERVICE"]
        end

        %% 내부 서비스 간 연결
        Eureka --- AuthService
        Eureka --- UserService
        Eureka --- ProductService
    end
    
    %% 외부 요청 흐름
    User -->|"HTTP 요청"| NGINX
    NGINX -->|"역방향 프록시"| API_Gateway
    API_Gateway -->|"서비스 디스커버리"| Eureka
    API_Gateway -->|"서비스 호출"| AuthService

    %% 스타일 정의
    classDef publicService fill:#ffcc99,stroke:#ff9933,stroke-width:2px
    classDef privateService fill:#99ccff,stroke:#3366cc,stroke-width:2px
    classDef edgeStyle stroke-width:2px

    class NGINX publicService
    class API_Gateway,Eureka,AuthService,UserService,ProductService privateService

Loading

해결책 선택 이유

  1. 아키텍처 단순화: 모든 마이크로서비스와 API Gateway가 같은 Docker 네트워크 내에서 직접 통신 가능함
  2. 보안 향상: API Gateway가 내부에 있어 외부 공격에 직접 노출되지 않음
  3. 네트워크 지연 감소: 같은 네트워크 내 통신으로 지연 감소함
  4. Eureka 서비스 발견 간소화: Docker 내부 IP를 변환 없이 그대로 사용 가능함
  5. 설정 단순화: 복잡한 네트워크 설정이나 VPC 피어링 불필요함

NGINX 구성

server {
    listen 80;
    server_name domain.com;

    location / {
        proxy_pass http://api-gateway:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        ...
    }
}

추가 개선사항

flowchart TB
    %% 사용자
    User(["사용자"]) 
    
    %% 퍼블릭 VPC
    subgraph PublicVPC["퍼블릭 VPC"]
        NGINX["[퍼블릭 EC2] NGINX 프록시"]
    end

    %% 프라이빗 VPC
    subgraph PrivateVPC["프라이빗 VPC"]
        subgraph DockerNetwork["Docker 네트워크"]
            API_Gateway["API Gateway"]
            Eureka["Eureka Server\n(서비스 디스커버리)"]
            AuthService["AUTH-SERVICE"]
            UserService["USER-SERVICE"]
            ProductService["PRODUCT-SERVICE"]
            
            %% 모니터링 및 개발 도구
            Grafana["Grafana"]
            KafkaUI["Kafka UI"]
        end

        %% 내부 서비스 간 연결
        Eureka --- AuthService
        Eureka --- UserService
        Eureka --- ProductService
    end

    %% 외부 요청 흐름
    User -->|"HTTP 요청"| NGINX

    %% 프록시 경로별 연결
    NGINX -->|"프록시: /api"| API_Gateway
    NGINX -->|"프록시: /grafana"| Grafana
    NGINX -->|"프록시: /kafka-ui"| KafkaUI

    %% API Gateway 내 서비스 호출
    API_Gateway -->|"서비스 디스커버리"| Eureka
    API_Gateway -->|"서비스 호출"| AuthService

    %% 스타일 정의
    classDef publicService fill:#ffcc99,stroke:#ff9933,stroke-width:2px
    classDef privateService fill:#99ccff,stroke:#3366cc,stroke-width:2px
    classDef monitoring fill:#ccffcc,stroke:#33aa33,stroke-width:2px

    class NGINX publicService
    class API_Gateway,Eureka,AuthService,UserService,ProductService privateService
    class Grafana,KafkaUI monitoring

Loading
  • 모든 개발자 도구와 모니터링 서비스도 동일한 NGINX 프록시를 통해 접근하도록 구성함.

결론

  • NGINX를 퍼블릭 인스턴스에 단독 배치하고 나머지 모든 서비스를 프라이빗 네트워크에 배치함으로써 보안과 접근성의 균형을 유지하며 네트워크 연결 문제 해결함.
  • 이는 단순하면서도 효과적인 아키텍처로 마이크로서비스 간 통신을 원활히 함.
⚠️ **GitHub.com Fallback** ⚠️