Nodejs

 

이번 강의에서는 NestJS 마이크로서비스 아키텍처를 운영하면서 포트 관리와 게이트웨이(Gateway) 서버의 역할을 어떻게 정리하는지 다룹니다.

 

기존에는 각 마이크로서비스가 개별 포트를 통해 직접 통신했지만, 이번에 게이트웨이 리소스를 추가하여 모든 외부 통신을 게이트웨이를 통해 처리하도록 구조를 개선했습니다.

 

1. 기존 구조: 마이크로서비스 개별 포트 사용

NestJS에서 마이크로서비스를 운영할 때 흔히 다음과 같은 구조를 사용합니다:

  • user-service → 3001 포트

  • product-service → 3002 포트

  • order-service → 3003 포트

  • payment-service → 3004 포트

  • notification-service → 3005 포트

각 서비스는 자체 포트에서 HTTP 서버를 띄우거나, gRPC, TCP, Kafka 등의 트랜스포트를 활용해 서로 직접 통신합니다.

이 방식은 단순하고 직관적이지만, 서비스 개수가 늘어날수록 관리해야 할 포트가 많아지고 외부 클라이언트가 접근하기 복잡해지는 단점이 있습니다.

 

 

2. 게이트웨이(Gateway) 도입

이를 개선하기 위해 API Gateway 개념을 도입합니다. 게이트웨이는 클라이언트와 직접 연결되는 단일 진입점(Entry Point) 역할을 하며, 내부 마이크로서비스와는 메시지 기반 통신을 수행합니다.

구조 변경 전/후 비교

변경 전:

Client → User-Service (3001)
       → Product-Service (3002)
       → Order-Service (3003)
       → Payment-Service (3004)
       → Notification-Service (3005)

변경 후:

Client → Gateway (3000)
             ├─ User-Service (마이크로서비스 포트 제거)
             ├─ Product-Service (마이크로서비스 포트 제거)
             ├─ Order-Service (마이크로서비스 포트 제거)
             ├─ Payment-Service (마이크로서비스 포트 제거)
             └─ Notification-Service (마이크로서비스 포트 제거)

핵심 포인트: 마이크로서비스의 외부 포트를 닫고, 모든 요청은 Gateway를 통해서만 들어오도록 한다.

 

 

3. NestJS에서 Gateway 적용하기

3.1 Gateway 애플리케이션 생성

nest g app gateway

생성된 게이트웨이 애플리케이션은 HTTP 서버를 띄우고, 내부적으로 다른 마이크로서비스와 연결합니다.

 

 

3.2 Gateway에서 마이크로서비스 연결

// apps/gateway/src/main.ts
async function bootstrap() {
  const app = await NestFactory.create(GatewayModule);

  app.connectMicroservice({
    transport: Transport.TCP,
    options: { host: 'user', port: 4001 },
  });

  app.connectMicroservice({
    transport: Transport.TCP,
    options: { host: 'product', port: 4002 },
  });

  app.connectMicroservice({
    transport: Transport.TCP,
    options: { host: 'order', port: 4003 },
  });

  app.connectMicroservice({
    transport: Transport.TCP,
    options: { host: 'payment', port: 4004 },
  });

  app.connectMicroservice({
    transport: Transport.TCP,
    options: { host: 'notification', port: 4005 },
  });

  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();

이제 외부에서는 3000번 포트(Gateway) 만 사용합니다.

 

 

 

4. 마이크로서비스에서 포트 제거

각 마이크로서비스(user, product, order, payment, notification)는 더 이상 HTTP 서버를 직접 띄울 필요가 없습니다. 따라서 docker-compose.yml에서도 ports 설정을 주석 처리했습니다.

예시 (apps/user/src/main.ts):

// main.ts (Before)
async function bootstrap() {
  const app = await NestFactory.create(UserModule);
  await app.listen(process.env.HTTP_PORT || 3001);
}

// main.ts (After)
async function bootstrap() {
  const app = await NestFactory.createMicroservice(UserModule, {
    transport: Transport.TCP,
    options: { host: '0.0.0.0', port: process.env.TCP_PORT || 4001 },
  });

  await app.listen();
}

docker-compose.yml에서도 HTTP_PORT는 남아있지만, 실제 외부 노출은 하지 않습니다.

 

 

5. Docker Compose에서의 구조

이번 강의에서 사용한 docker-compose.yml의 핵심 포인트:

  • Gateway만 외부 포트 노출 (3000:3000)

  • 각 마이크로서비스는 TCP_PORT 환경변수만 사용하여 Gateway와 통신

  • PostgreSQL, MongoDB 등 데이터베이스 컨테이너는 각 서비스 전용으로 분리

  • depends_on과 healthcheck로 서비스 안정성 보장

즉, 클라이언트 → Gateway (3000) → 내부 마이크로서비스(TCP 포트) → DB 구조로 정리됩니다.

 

 

 

6. 장점

단일 포트 관리 → 클라이언트는 항상 Gateway 포트만 알면 됨
보안성 향상 → 마이크로서비스는 외부에 직접 노출되지 않음
유연한 라우팅 → 인증, 로깅, 캐싱 등을 Gateway에서 공통 처리 가능
확장성 → 서비스가 늘어나도 클라이언트 단의 복잡성이 증가하지 않음
Docker Compose 기반 손쉬운 실행 → docker compose up 만으로 전체 아키텍처 구동

 

 

 

이번 단계에서는 기존의 여러 포트 기반 마이크로서비스 통신 구조Gateway 기반 단일 진입점 구조로 개선했습니다.

이제 클라이언트는 Gateway를 통해서만 마이크로서비스와 통신하며, 마이크로서비스는 내부 TCP 기반 메시지 통신만 수행합니다.

이를 통해 포트 관리 부담을 줄이고, 보안성과 확장성을 확보할 수 있으며, Docker Compose를 활용해 개발 및 배포 환경에서도 일관된 실행 구조를 유지할 수 있습니다.

 

 

 

 

 

about author

PHRASE

Level 60  라이트

싸움에 있어서는 한 사람이 천 사람을 이길 수도 있다. 그러나 자기자신을 이기는 자야말로 가장 위대한 승리자이다. -석가모니

댓글 ( 0)

댓글 남기기

작성