🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

마이크로서비스 통합 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 22. · 2 Views

마이크로서비스 통합 완벽 가이드

Spring Cloud를 활용한 마이크로서비스 아키텍처 구축부터 통합 테스트까지, 실무에서 바로 적용할 수 있는 완벽한 프로젝트 가이드입니다. Eureka Server, Config Server, API Gateway를 활용하여 확장 가능한 시스템을 만드는 방법을 배웁니다.


목차

  1. 아키텍처_설계
  2. Eureka_Server_구축
  3. Config_Server_구축
  4. Gateway_구축
  5. 마이크로서비스_등록
  6. 통합_테스트

1. 아키텍처 설계

김개발 씨는 지금까지 단일 애플리케이션만 개발해왔습니다. 그런데 최근 회사에서 대규모 프로젝트를 맡게 되었고, 선배 박시니어 씨가 "이번엔 마이크로서비스로 가야 할 것 같은데요"라고 말했습니다.

김개발 씨는 마이크로서비스라는 단어는 들어봤지만, 실제로 어떻게 설계해야 할지 막막했습니다.

마이크로서비스 아키텍처는 하나의 큰 애플리케이션을 여러 개의 작은 서비스로 나누어 개발하는 방식입니다. 마치 레고 블록처럼 각각의 서비스를 독립적으로 개발하고 배포할 수 있습니다.

Spring Cloud는 이러한 마이크로서비스를 효과적으로 관리하고 통합할 수 있는 도구를 제공합니다.

다음 코드를 살펴봅시다.

// 마이크로서비스 아키텍처 구성 예시
// 1. Eureka Server - 서비스 디스커버리 (포트: 8761)
// 2. Config Server - 중앙 설정 관리 (포트: 8888)
// 3. API Gateway - 라우팅 및 로드밸런싱 (포트: 8080)
// 4. User Service - 사용자 관리 (포트: 8081)
// 5. Order Service - 주문 관리 (포트: 8082)
// 6. Product Service - 상품 관리 (포트: 8083)

// 아키텍처 의존성 흐름
Client -> API Gateway -> [User/Order/Product Service]
                    ↓
              Eureka Server
                    ↓
              Config Server

김개발 씨는 박시니어 씨 앞에 앉아 진지한 표정으로 물었습니다. "선배님, 지금까지는 하나의 프로젝트에 모든 기능을 넣었는데, 왜 굳이 여러 개로 나눠야 하나요?" 박시니어 씨는 미소를 지으며 대답했습니다.

"좋은 질문이에요. 만약 우리 쇼핑몰 서비스에서 주문 기능에만 버그가 생겼다고 생각해봐요.

단일 애플리케이션이라면 전체 서비스를 다시 배포해야 하죠. 하지만 마이크로서비스라면 주문 서비스만 수정하고 배포하면 됩니다." 마이크로서비스 아키텍처란 무엇일까요?

쉽게 비유하자면, 마이크로서비스는 마치 백화점과 같습니다. 백화점에는 의류 매장, 식품 매장, 전자제품 매장이 각각 독립적으로 운영되지만, 고객은 하나의 백화점으로 인식합니다.

각 매장은 자신의 재고를 관리하고, 독자적으로 영업 시간을 조정할 수 있습니다. 이처럼 마이크로서비스도 각 기능을 독립적인 서비스로 운영합니다.

왜 마이크로서비스가 필요한가요? 전통적인 단일 애플리케이션 방식에는 여러 문제가 있었습니다.

첫째, 코드베이스가 거대해지면서 한 사람이 전체를 이해하기 어려워졌습니다. 김개발 씨도 경험했듯이, 작은 수정 하나를 위해 수천 줄의 코드를 읽어야 했습니다.

둘째, 배포 시간이 길어졌습니다. 전체 애플리케이션을 다시 빌드하고 테스트하는 데 몇 시간씩 걸렸습니다.

더 큰 문제는 한 부분의 버그가 전체 시스템을 다운시킬 수 있다는 점이었습니다. 셋째, 기술 스택을 유연하게 선택할 수 없었습니다.

한 번 Java로 시작하면 모든 기능을 Java로 개발해야 했습니다. 특정 기능에 더 적합한 기술이 있어도 사용할 수 없었습니다.

마이크로서비스 아키텍처의 등장 바로 이런 문제를 해결하기 위해 마이크로서비스 아키텍처가 등장했습니다. 마이크로서비스를 사용하면 각 서비스를 독립적으로 개발하고 배포할 수 있습니다.

사용자 관리 팀은 User Service만 담당하고, 주문 관리 팀은 Order Service만 집중할 수 있습니다. 무엇보다 한 서비스의 장애가 다른 서비스에 영향을 주지 않는다는 큰 이점이 있습니다.

Spring Cloud 핵심 구성요소 Spring Cloud는 마이크로서비스 구축에 필요한 도구들을 제공합니다. 먼저 Eureka Server는 서비스 디스커버리 역할을 합니다.

마치 전화번호부처럼 각 서비스의 위치를 기록하고 관리합니다. 다음으로 Config Server는 모든 서비스의 설정을 중앙에서 관리합니다.

데이터베이스 접속 정보나 API 키 같은 설정을 각 서비스마다 따로 관리하는 대신, 한 곳에서 통합 관리할 수 있습니다. 마지막으로 API Gateway는 클라이언트의 모든 요청을 받아 적절한 서비스로 라우팅합니다.

고객은 하나의 주소로 접속하지만, Gateway가 내부적으로 여러 서비스로 요청을 분배합니다. 아키텍처 설계의 핵심 원칙 위의 구성도를 살펴보면 흐름을 이해할 수 있습니다.

클라이언트는 API Gateway로만 요청을 보냅니다. Gateway는 Eureka Server에 등록된 서비스 목록을 확인하고, 적절한 서비스로 요청을 전달합니다.

각 서비스는 Config Server에서 설정을 가져와 실행됩니다. 포트 번호도 체계적으로 관리해야 합니다.

Eureka Server는 관례적으로 8761번 포트를 사용합니다. Config Server는 8888번, Gateway는 8080번을 사용하는 것이 일반적입니다.

각 비즈니스 서비스는 8081번부터 순차적으로 할당합니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

예를 들어 대형 쇼핑몰을 개발한다고 가정해봅시다. 회원가입과 로그인은 User Service가 담당하고, 상품 조회는 Product Service가 처리합니다.

주문과 결제는 Order Service에서 관리합니다. 블랙 프라이데이처럼 주문이 폭증하는 날에는 Order Service만 인스턴스를 늘려 대응할 수 있습니다.

Netflix, Amazon, Uber 같은 글로벌 기업들이 이런 패턴을 적극적으로 사용하고 있습니다. 수백 개의 마이크로서비스를 운영하면서도 안정적인 서비스를 제공합니다.

주의사항 하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 서비스를 너무 잘게 나누는 것입니다.

"마이크로"라는 단어에 집착해서 모든 기능을 별도 서비스로 만들면, 오히려 관리가 복잡해집니다. 따라서 비즈니스 도메인을 기준으로 적절한 크기로 나누어야 합니다.

정리 다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 화이트보드에 아키텍처를 그려보며 고개를 끄덕였습니다.

"아, 이제 왜 마이크로서비스가 필요한지 알겠어요!" 마이크로서비스 아키텍처를 제대로 이해하면 확장 가능하고 유지보수하기 쉬운 시스템을 설계할 수 있습니다. 여러분도 오늘 배운 내용을 바탕으로 실제 프로젝트 설계에 도전해 보세요.

실전 팁

💡 - 서비스는 비즈니스 도메인 단위로 나누되, 너무 잘게 쪼개지 마세요

  • 포트 번호를 체계적으로 관리하면 개발 시 혼란을 줄일 수 있습니다
  • 시작은 작게, 필요에 따라 점진적으로 서비스를 분리하세요

2. Eureka Server 구축

아키텍처 설계를 마친 김개발 씨는 이제 실제 구현에 들어갔습니다. 박시니어 씨가 "먼저 Eureka Server부터 만들어야 해요"라고 말했습니다.

김개발 씨는 "Eureka가 뭐죠?"라고 물었고, 박시니어 씨는 웃으며 "서비스들의 전화번호부라고 생각하면 돼요"라고 답했습니다.

Eureka Server는 Netflix에서 개발한 서비스 디스커버리 서버입니다. 마치 전화번호부처럼 모든 마이크로서비스의 위치 정보를 저장하고 관리합니다.

각 서비스는 시작할 때 Eureka에 자신을 등록하고, 다른 서비스를 호출할 때 Eureka에서 위치를 조회합니다.

다음 코드를 살펴봅시다.

// EurekaServerApplication.java
package com.example.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer  // Eureka Server 활성화
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

김개발 씨는 박시니어 씨의 설명을 듣고도 여전히 의아했습니다. "선배님, 그냥 IP 주소와 포트를 설정 파일에 적어두면 안 되나요?" 박시니어 씨는 고개를 저었습니다.

"좋은 질문이에요. 만약 Order Service가 3개 인스턴스로 늘어났다고 생각해봐요.

그때마다 모든 서비스의 설정 파일을 수정하고 재배포해야 할까요? Eureka를 사용하면 그럴 필요가 없어요." Eureka Server란 정확히 무엇일까요?

쉽게 비유하자면, Eureka Server는 마치 아파트 관리실과 같습니다. 새로운 입주자가 들어오면 관리실에 신고하고, 택배 기사는 관리실에 물어보면 어느 동 몇 호에 배달해야 하는지 알 수 있습니다.

이처럼 Eureka Server도 각 서비스의 위치를 기록하고, 다른 서비스가 조회할 수 있게 합니다. 왜 Eureka가 필요한가요?

Eureka가 없던 시절에는 어땠을까요? 개발자들은 각 서비스의 IP 주소와 포트를 직접 설정 파일에 적어야 했습니다.

예를 들어 User Service가 "192.168.1.10:8081"에서 실행된다면, 이 정보를 Gateway와 다른 모든 서비스에 하드코딩해야 했습니다. 문제는 서비스가 다른 서버로 이동하거나 포트가 변경될 때 발생했습니다.

모든 설정 파일을 찾아서 수정하고, 모든 서비스를 재배포해야 했습니다. 더 큰 문제는 Auto Scaling 환경에서였습니다.

트래픽이 증가해서 서비스 인스턴스가 자동으로 늘어나면, 새로운 인스턴스의 주소를 어떻게 알 수 있을까요? Eureka Server의 등장 바로 이런 문제를 해결하기 위해 Eureka Server가 등장했습니다.

Eureka Server를 사용하면 서비스가 시작할 때 자동으로 등록됩니다. 다른 서비스는 IP 주소를 몰라도 되고, 단지 서비스 이름만 알면 됩니다.

Eureka가 실제 위치를 알려주기 때문입니다. 무엇보다 서비스 인스턴스가 늘어나거나 줄어들어도 자동으로 감지한다는 큰 이점이 있습니다.

Eureka Server 프로젝트 생성 위의 코드를 한 줄씩 살펴보겠습니다. 먼저 @EnableEurekaServer 어노테이션이 핵심입니다.

이 어노테이션 하나만 추가하면 일반 Spring Boot 애플리케이션이 Eureka Server로 변신합니다. Spring Cloud의 자동 설정 기능이 모든 복잡한 작업을 처리해줍니다.

SpringApplication.run() 메서드는 일반적인 Spring Boot 애플리케이션 시작 방식과 동일합니다. Eureka Server도 결국 하나의 Spring Boot 애플리케이션입니다.

설정 파일 구성 Eureka Server를 실행하려면 application.yml 설정도 필요합니다. 포트는 8761번을 사용하는 것이 관례입니다.

중요한 점은 Eureka Server 자신은 다른 Eureka에 등록할 필요가 없다는 것입니다. 따라서 eureka.client.register-with-eurekafetch-registry 속성을 false로 설정합니다.

이렇게 하면 자기 자신을 클라이언트로 등록하려는 시도를 막을 수 있습니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

예를 들어 쇼핑몰 서비스에서 Order Service가 User Service를 호출해야 한다고 가정해봅시다. Eureka 없이는 "http://192.168.1.10:8081/users/123" 같은 하드코딩된 URL을 사용해야 합니다.

하지만 Eureka가 있으면 "http://user-service/users/123"처럼 서비스 이름만 사용하면 됩니다. 많은 기업에서 Kubernetes와 함께 Eureka를 사용합니다.

Kubernetes가 컨테이너를 관리하고, Eureka가 서비스 위치를 관리하는 조합입니다. Eureka 대시보드 확인 Eureka Server를 실행하고 브라우저에서 http://localhost:8761에 접속하면 웹 대시보드를 볼 수 있습니다.

여기서 현재 등록된 모든 서비스의 상태를 실시간으로 확인할 수 있습니다. 대시보드에는 각 서비스의 이름, 인스턴스 개수, 상태 정보가 표시됩니다.

빨간색으로 표시되면 해당 서비스에 문제가 있다는 신호입니다. 주의사항 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 Eureka Server를 단일 인스턴스로만 운영하는 것입니다. Eureka Server가 다운되면 모든 서비스 디스커버리가 중단됩니다.

따라서 운영 환경에서는 Eureka Server를 최소 2개 이상 클러스터로 구성해야 합니다. 정리 다시 김개발 씨의 이야기로 돌아가 봅시다.

Eureka Server를 실행하고 대시보드를 확인한 김개발 씨는 신기한 표정을 지었습니다. "와, 이렇게 간단하게 서비스 레지스트리를 만들 수 있다니!" Eureka Server를 제대로 구축하면 동적으로 변화하는 마이크로서비스 환경을 효과적으로 관리할 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - Eureka Server는 8761번 포트를 사용하는 것이 관례입니다

  • 운영 환경에서는 Eureka Server를 클러스터로 구성하세요
  • 대시보드에서 서비스 상태를 실시간으로 모니터링할 수 있습니다

3. Config Server 구축

Eureka Server 구축을 마친 김개발 씨는 다음 단계로 넘어갔습니다. 박시니어 씨가 "이제 Config Server를 만들어야 해요"라고 말했습니다.

김개발 씨는 "설정 파일은 각 프로젝트에 있으면 안 되나요?"라고 물었고, 박시니어 씨는 "서비스가 10개, 20개로 늘어나면 관리가 불가능해요"라고 답했습니다.

Config Server는 모든 마이크로서비스의 설정을 중앙에서 관리하는 서버입니다. 마치 도서관 사서가 모든 책을 한곳에서 관리하듯이, Config Server는 데이터베이스 접속 정보, API 키, 환경별 설정을 통합 관리합니다.

Git 저장소와 연동하여 설정 변경 이력도 추적할 수 있습니다.

다음 코드를 살펴봅시다.

// ConfigServerApplication.java
package com.example.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer  // Config Server 활성화
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

김개발 씨는 지금까지 각 프로젝트마다 application.yml 파일을 만들어 관리해왔습니다. "이게 뭐가 문제인가요?" 박시니어 씨는 노트북을 열어 실제 프로젝트를 보여주었습니다.

"봐요, 우리 회사에는 개발, 스테이징, 운영 환경이 있어요. 각 환경마다 데이터베이스 주소가 다르죠.

서비스가 10개라면 총 30개의 설정 파일을 관리해야 해요. 데이터베이스 비밀번호를 변경하면 어떻게 될까요?" Config Server란 정확히 무엇일까요?

쉽게 비유하자면, Config Server는 마치 학교 교무실의 학적부와 같습니다. 각 반 선생님이 학생 정보를 따로 관리하는 대신, 교무실에서 통합 관리하면 정보가 일관되고 변경도 쉽습니다.

이처럼 Config Server도 모든 서비스의 설정을 한곳에 모아 관리합니다. 왜 Config Server가 필요한가요?

Config Server가 없던 시절에는 어땠을까요? 개발자들은 각 서비스마다 설정 파일을 관리해야 했습니다.

User Service의 application.yml, Order Service의 application.yml, Product Service의 application.yml을 각각 편집했습니다. 문제는 공통 설정을 변경할 때 발생했습니다.

예를 들어 로그 레벨을 INFO에서 DEBUG로 변경하려면 모든 서비스의 설정 파일을 수정하고, 모든 서비스를 재배포해야 했습니다. 더 큰 문제는 보안이었습니다.

데이터베이스 비밀번호 같은 민감한 정보가 각 프로젝트의 Git 저장소에 흩어져 있었습니다. Config Server의 등장 바로 이런 문제를 해결하기 위해 Config Server가 등장했습니다.

Config Server를 사용하면 모든 설정을 하나의 Git 저장소에서 관리할 수 있습니다. 설정을 변경하면 서비스를 재배포하지 않고도 즉시 반영할 수 있습니다.

무엇보다 Git의 버전 관리 기능으로 설정 변경 이력을 추적할 수 있다는 큰 이점이 있습니다. Config Server 프로젝트 생성 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 @EnableConfigServer 어노테이션이 핵심입니다. 이 어노테이션 하나로 일반 Spring Boot 애플리케이션이 Config Server로 변신합니다.

Eureka Server와 마찬가지로 매우 간단합니다. 설정 파일에서 Git 저장소 위치를 지정해야 합니다.

spring.cloud.config.server.git.uri 속성에 설정 파일들이 있는 Git 저장소 URL을 입력합니다. Git 저장소 구성 Config Server는 Git 저장소에서 설정 파일을 읽어옵니다.

저장소 구조는 다음과 같이 구성합니다. 루트 디렉토리에 user-service.yml, order-service.yml, product-service.yml 같은 파일을 만듭니다.

환경별 설정은 파일명에 프로파일을 추가합니다. 예를 들어 user-service-dev.yml은 개발 환경, user-service-prod.yml은 운영 환경 설정입니다.

Config Server가 자동으로 적절한 파일을 선택해서 제공합니다. 설정 읽어오기 테스트 Config Server를 실행한 후 브라우저에서 http://localhost:8888/user-service/dev에 접속하면 user-service의 개발 환경 설정을 JSON 형태로 볼 수 있습니다.

이 URL 패턴은 /{application}/{profile} 형식입니다. 실제로 접속해보면 Git 저장소의 설정 내용이 JSON으로 변환되어 표시됩니다.

각 서비스는 이 API를 통해 자신의 설정을 가져옵니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

예를 들어 쇼핑몰 서비스에서 결제 API 키를 변경해야 한다고 가정해봅시다. Config Server 없이는 모든 서비스의 설정 파일을 수정하고 재배포해야 합니다.

하지만 Config Server가 있으면 Git 저장소의 설정만 수정하고, 각 서비스에 refresh 요청을 보내면 됩니다. 많은 기업에서 Config Server와 함께 암호화 기능을 활용합니다.

민감한 정보는 암호화해서 Git에 저장하고, Config Server가 복호화해서 제공합니다. 동적 설정 갱신 Config Server의 강력한 기능 중 하나는 Spring Cloud Bus와 함께 사용하면 설정이 변경될 때 모든 서비스에 자동으로 알릴 수 있다는 점입니다.

Git 저장소의 설정을 수정하면 Webhook이 발동하고, Bus를 통해 모든 서비스가 새로운 설정을 가져옵니다. 이렇게 하면 서비스를 재시작하지 않고도 설정을 변경할 수 있습니다.

김개발 씨는 이 기능을 보고 "이거 진짜 편리하네요!"라고 감탄했습니다. 주의사항 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 모든 설정을 Config Server에 넣는 것입니다. Config Server 자체의 설정은 각 서비스에 있어야 합니다.

그렇지 않으면 "Config Server에 접속하려면 Config Server의 주소가 필요한데, 그 주소는 Config Server에 있다"는 순환 참조가 발생합니다. 정리 다시 김개발 씨의 이야기로 돌아가 봅시다.

Config Server를 구축하고 테스트해본 김개발 씨는 고개를 끄덕였습니다. "이제 설정 관리가 정말 편해지겠어요!" Config Server를 제대로 활용하면 수십 개의 마이크로서비스 설정을 효율적으로 관리할 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - Config Server 자체의 설정은 각 서비스의 bootstrap.yml에 작성하세요

  • Git 저장소에는 민감한 정보를 암호화해서 저장하세요
  • Spring Cloud Bus와 함께 사용하면 동적 설정 갱신이 가능합니다

4. Gateway 구축

김개발 씨는 Eureka와 Config Server를 모두 구축했습니다. 이제 박시니어 씨가 "클라이언트가 여러 서비스에 직접 접근하면 안 되니까, Gateway를 만들어야 해요"라고 말했습니다.

김개발 씨는 "Gateway가 왜 필요한가요?"라고 물었고, 박시니어 씨는 "호텔 프론트 데스크 같은 거예요"라고 답했습니다.

API Gateway는 클라이언트의 모든 요청을 받아 적절한 마이크로서비스로 라우팅하는 관문입니다. 마치 호텔 프론트 데스크처럼 고객의 요청을 받아 해당 부서로 연결해줍니다.

인증, 로깅, 로드밸런싱 같은 공통 기능도 Gateway에서 처리할 수 있습니다.

다음 코드를 살펴봅시다.

// GatewayApplication.java
package com.example.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient  // Eureka 클라이언트 활성화
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

김개발 씨는 의문이 생겼습니다. "클라이언트가 User Service는 8081번 포트로, Order Service는 8082번 포트로 직접 접근하면 안 되나요?" 박시니어 씨는 고개를 저었습니다.

"그렇게 하면 문제가 많아요. 첫째, 클라이언트가 모든 서비스의 주소를 알아야 해요.

둘째, 서비스가 추가되면 클라이언트 앱도 업데이트해야 하죠. 셋째, 인증 같은 공통 로직을 모든 서비스에 중복해서 작성해야 해요." API Gateway란 정확히 무엇일까요?

쉽게 비유하자면, API Gateway는 마치 대형 병원의 접수처와 같습니다. 환자는 접수처에서 증상을 말하면, 접수처가 내과, 외과, 정형외과 중 적절한 곳으로 안내해줍니다.

환자는 각 진료과의 위치를 몰라도 되고, 접수처만 알면 됩니다. 이처럼 API Gateway도 클라이언트 요청을 받아 적절한 서비스로 연결해줍니다.

왜 API Gateway가 필요한가요? API Gateway가 없던 시절에는 어땠을까요?

클라이언트는 각 서비스의 주소를 모두 알아야 했습니다. 모바일 앱이라면 User Service 주소, Order Service 주소, Product Service 주소를 모두 저장해야 했습니다.

문제는 서비스 주소가 변경되거나 서비스가 추가될 때 발생했습니다. 더 큰 문제는 CORS(Cross-Origin Resource Sharing)와 인증이었습니다.

각 서비스마다 CORS 설정을 해야 하고, JWT 토큰 검증 로직을 중복해서 작성해야 했습니다. 보안 정책이 변경되면 모든 서비스를 수정해야 했습니다.

API Gateway의 등장 바로 이런 문제를 해결하기 위해 API Gateway가 등장했습니다. API Gateway를 사용하면 클라이언트는 하나의 주소만 알면 됩니다.

http://gateway.example.com 이 주소 하나로 모든 서비스에 접근할 수 있습니다. 무엇보다 인증, 로깅, 속도 제한 같은 공통 기능을 Gateway에서 한 번만 구현하면 된다는 큰 이점이 있습니다.

Spring Cloud Gateway 설정 위의 코드를 한 줄씩 살펴보겠습니다. 먼저 @EnableDiscoveryClient 어노테이션이 중요합니다.

이 어노테이션을 추가하면 Gateway가 Eureka Server에 등록되고, 다른 서비스의 위치도 조회할 수 있습니다. application.yml 설정에서 라우팅 규칙을 정의합니다.

예를 들어 /users/로 시작하는 요청은 user-service로, /orders/로 시작하는 요청은 order-service로 전달합니다. 라우팅 규칙 작성 라우팅 규칙은 매우 직관적입니다.

spring.cloud.gateway.routes 속성에 배열 형태로 작성합니다. 각 라우트는 id(고유 식별자), uri(목적지 서비스), predicates(조건)로 구성됩니다.

urilb://user-service처럼 lb 프로토콜을 사용하면 로드밸런싱이 자동으로 적용됩니다. user-service가 3개 인스턴스로 실행 중이라면 Gateway가 요청을 분산해서 전달합니다.

필터 적용 Gateway의 강력한 기능 중 하나는 필터입니다. 요청이 서비스로 전달되기 전이나 응답이 클라이언트로 돌아가기 전에 처리를 추가할 수 있습니다.

예를 들어 모든 요청에 공통 헤더를 추가하거나, 응답 시간을 로깅하거나, JWT 토큰을 검증할 수 있습니다. 김개발 씨는 "와, 이거 정말 유용하네요"라고 감탄했습니다.

실무 활용 사례 실제 현업에서는 어떻게 활용할까요? 예를 들어 쇼핑몰 서비스에서 클라이언트가 상품 목록을 조회한다고 가정해봅시다.

클라이언트는 **GET http://gateway:8080/products**로 요청합니다. Gateway는 이 요청이 /products로 시작하므로 product-service로 라우팅합니다.

만약 사용자가 로그인하지 않았다면 Gateway의 인증 필터에서 요청을 거부합니다. 로그인한 사용자라면 JWT 토큰에서 사용자 ID를 추출해서 헤더에 추가하고, product-service로 전달합니다.

로드밸런싱과 Circuit Breaker Gateway는 Eureka와 통합되어 자동으로 로드밸런싱을 제공합니다. product-service가 3개 인스턴스로 실행 중이라면 Round-Robin 방식으로 요청을 분산합니다.

또한 Circuit Breaker를 적용하면 특정 서비스가 응답하지 않을 때 빠르게 실패 처리할 수 있습니다. 계속 기다리는 대신 미리 정의한 fallback 응답을 반환합니다.

주의사항 하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 Gateway에 너무 많은 로직을 넣는 것입니다.

Gateway는 라우팅과 공통 기능만 담당해야 합니다. 비즈니스 로직을 Gateway에 작성하면 단일 장애 지점이 됩니다.

따라서 Gateway는 최대한 가볍게 유지해야 합니다. 정리 다시 김개발 씨의 이야기로 돌아가 봅시다.

Gateway를 구축하고 테스트해본 김개발 씨는 신기한 표정을 지었습니다. "이제 클라이언트는 하나의 주소로 모든 서비스를 사용할 수 있겠네요!" API Gateway를 제대로 구축하면 클라이언트와 서비스 사이의 복잡성을 효과적으로 숨길 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 라우팅 규칙은 명확하고 일관성 있게 작성하세요 (예: /users/, /orders/)

  • Gateway는 가볍게 유지하고, 비즈니스 로직은 각 서비스에 작성하세요
  • Circuit Breaker를 적용하여 장애 전파를 방지하세요

5. 마이크로서비스 등록

김개발 씨는 이제 실제 비즈니스 로직을 담당할 마이크로서비스를 만들 차례입니다. 박시니어 씨가 "User Service부터 만들어 볼까요?

Eureka에 등록하는 방법을 보여드릴게요"라고 말했습니다. 김개발 씨는 "어렵나요?"라고 물었고, 박시니어 씨는 "어노테이션 하나면 돼요"라고 웃으며 답했습니다.

마이크로서비스를 Eureka Server에 등록하면 다른 서비스가 위치를 조회할 수 있습니다. 마치 전화번호부에 자신의 번호를 등록하는 것처럼, 각 서비스는 시작할 때 Eureka에 자신의 정보를 알립니다.

Config Server에서 설정을 가져오고, Gateway를 통해 요청을 받을 수 있게 됩니다.

다음 코드를 살펴봅시다.

// UserServiceApplication.java
package com.example.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.*;

@SpringBootApplication
@EnableDiscoveryClient  // Eureka 클라이언트 활성화
@RestController
@RequestMapping("/users")
public class UserServiceApplication {

    @GetMapping("/{id}")
    public String getUser(@PathVariable String id) {
        // 실제로는 DB에서 조회하지만 예제는 간단히
        return "User ID: " + id + ", Name: 김개발";
    }

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

김개발 씨는 새로운 Spring Boot 프로젝트를 생성했습니다. "이제 이걸 Eureka에 등록해야 하는데, 복잡한 설정이 필요한가요?" 박시니어 씨는 고개를 저었습니다.

"전혀요. @EnableDiscoveryClient 어노테이션 하나만 추가하면 돼요.

나머지는 Spring Cloud가 자동으로 처리해줍니다." 마이크로서비스 등록이란 무엇일까요? 쉽게 비유하자면, 마이크로서비스 등록은 마치 새로운 직원이 회사에 입사할 때 인사팀에 등록하는 것과 같습니다.

이름, 부서, 연락처를 등록하면 다른 직원들이 사내 주소록에서 찾을 수 있습니다. 이처럼 서비스도 Eureka에 등록하면 다른 서비스가 찾을 수 있게 됩니다.

왜 서비스 등록이 필요한가요? 서비스 등록이 없던 시절에는 어땠을까요?

각 서비스는 다른 서비스의 IP 주소와 포트를 직접 알아야 했습니다. Order Service가 User Service를 호출하려면 "192.168.1.10:8081" 같은 주소를 하드코딩해야 했습니다.

문제는 서비스가 다른 서버로 이동하거나 포트가 변경될 때 발생했습니다. 더 큰 문제는 Health Check였습니다.

User Service가 다운되어도 Order Service는 그 사실을 모르고 계속 요청을 보냈습니다. 타임아웃이 발생할 때까지 기다려야 했고, 사용자는 느린 응답을 경험했습니다.

Eureka 클라이언트의 등장 바로 이런 문제를 해결하기 위해 Eureka 클라이언트가 등장했습니다. 서비스가 시작할 때 Eureka Server에 자동으로 등록됩니다.

30초마다 heartbeat를 보내서 "저 아직 살아있어요"라고 알립니다. 무엇보다 서비스가 다운되면 Eureka가 자동으로 감지해서 목록에서 제거한다는 큰 이점이 있습니다.

코드 상세 분석 위의 코드를 한 줄씩 살펴보겠습니다. 먼저 @EnableDiscoveryClient 어노테이션이 핵심입니다.

이 어노테이션을 추가하면 애플리케이션이 시작할 때 Eureka Server를 찾아 자신을 등록합니다. application.yml에 Eureka Server 주소만 설정하면 됩니다.

@RestController@RequestMapping은 일반적인 REST API 컨트롤러입니다. /users/{id} 경로로 GET 요청이 오면 사용자 정보를 반환합니다.

실제 프로젝트에서는 데이터베이스에서 조회하겠지만, 예제는 간단히 문자열을 반환합니다. application.yml 설정 서비스를 등록하려면 몇 가지 설정이 필요합니다.

먼저 spring.application.name을 설정합니다. 이 이름으로 Eureka에 등록되고, 다른 서비스가 이 이름으로 호출합니다.

eureka.client.service-url.defaultZone에는 Eureka Server 주소를 입력합니다. http://localhost:8761/eureka/가 기본값입니다.

eureka.instance.prefer-ip-address를 true로 설정하면 hostname 대신 IP 주소로 등록됩니다. Config Server와 통합 서비스는 Config Server에서 설정도 가져와야 합니다.

bootstrap.yml 파일을 만들어 Config Server 주소를 설정합니다. bootstrap.yml은 application.yml보다 먼저 로드되므로, Config Server에서 설정을 가져온 후 애플리케이션이 시작됩니다.

이렇게 하면 데이터베이스 접속 정보 같은 설정을 Config Server에서 중앙 관리할 수 있습니다. 김개발 씨는 "와, 이렇게 연결되는 거구나"라고 감탄했습니다.

서비스 간 통신 User Service가 등록되었으니, 이제 Order Service에서 User Service를 호출해봅시다. RestTemplate 또는 WebClient를 사용하면 됩니다.

중요한 점은 URL에 IP 주소 대신 서비스 이름을 사용한다는 것입니다. http://user-service/users/123 처럼 작성하면, Eureka가 실제 IP 주소로 변환해줍니다.

로드밸런싱도 자동으로 적용됩니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

예를 들어 쇼핑몰 서비스에서 주문을 생성할 때를 가정해봅시다. Order Service는 먼저 User Service를 호출해서 사용자가 유효한지 확인합니다.

다음으로 Product Service를 호출해서 재고를 확인합니다. 모든 검증이 통과하면 주문을 생성합니다.

각 서비스는 서로의 IP 주소를 모르지만, Eureka를 통해 원활하게 통신할 수 있습니다. 많은 기업에서 수십 개의 마이크로서비스를 이런 방식으로 연결합니다.

Health Check와 장애 처리 Eureka 클라이언트는 기본적으로 30초마다 heartbeat를 보냅니다. Eureka Server는 90초 동안 heartbeat를 받지 못하면 해당 서비스를 목록에서 제거합니다.

actuator 의존성을 추가하면 더 상세한 Health Check를 설정할 수 있습니다. 데이터베이스 연결 상태, 디스크 용량 같은 정보를 포함할 수 있습니다.

주의사항 하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 서비스 이름을 대문자로 작성하는 것입니다.

"UserService" 대신 "user-service"처럼 소문자와 하이픈을 사용하는 것이 관례입니다. 따라서 일관된 네이밍 규칙을 따라야 합니다.

정리 다시 김개발 씨의 이야기로 돌아가 봅시다. User Service를 실행하고 Eureka 대시보드를 확인한 김개발 씨는 뿌듯한 표정을 지었습니다.

"제 서비스가 등록되었어요!" 마이크로서비스를 제대로 등록하면 동적인 서비스 디스커버리와 로드밸런싱을 자동으로 활용할 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 서비스 이름은 소문자와 하이픈을 사용하세요 (user-service, order-service)

  • bootstrap.yml에 Config Server 설정을 작성하세요
  • actuator를 추가하여 상세한 Health Check를 구성하세요

6. 통합 테스트

김개발 씨는 드디어 모든 구성요소를 만들었습니다. Eureka Server, Config Server, Gateway, 그리고 User Service까지.

박시니어 씨가 "이제 전체가 제대로 작동하는지 테스트해봐야죠"라고 말했습니다. 김개발 씨는 긴장된 표정으로 "어디서부터 시작하면 될까요?"라고 물었습니다.

통합 테스트는 모든 마이크로서비스가 함께 작동하는지 확인하는 과정입니다. 마치 오케스트라의 리허설처럼, 각 악기가 개별적으로는 완벽해도 함께 연주했을 때 문제가 생길 수 있습니다.

Eureka, Config, Gateway, 각 서비스를 순서대로 실행하고 전체 흐름을 테스트합니다.

다음 코드를 살펴봅시다.

// 통합 테스트 실행 순서
// 1. Eureka Server 시작 (8761 포트)
// 2. Config Server 시작 (8888 포트)
// 3. Gateway 시작 (8080 포트)
// 4. User Service 시작 (8081 포트)

// 테스트 스크립트 예시
// Gateway를 통한 User Service 호출
curl http://localhost:8080/users/123

// 예상 응답
// User ID: 123, Name: 김개발

// Eureka 대시보드 확인
// http://localhost:8761
// 등록된 서비스: GATEWAY, USER-SERVICE

김개발 씨는 여러 개의 터미널 창을 열었습니다. "이 모든 서비스를 다 실행해야 하나요?" 박시니어 씨는 고개를 끄덕였습니다.

"네, 그래야 실제 운영 환경과 비슷한 상황에서 테스트할 수 있어요. 하지만 걱정 마세요.

순서만 지키면 어렵지 않아요." 통합 테스트란 정확히 무엇일까요? 쉽게 비유하자면, 통합 테스트는 마치 새로 지은 집의 점검과 같습니다.

개별 방은 완벽해도 수도관 연결이 잘못되었거나 전기 배선에 문제가 있을 수 있습니다. 집 전체를 점검해야 실제로 살 수 있는지 확인할 수 있습니다.

이처럼 통합 테스트도 모든 서비스가 함께 작동하는지 검증합니다. 왜 통합 테스트가 필요한가요?

통합 테스트 없이 바로 배포하면 어떻게 될까요? 각 서비스는 개별적으로 완벽하게 작동할 수 있습니다.

User Service 단독으로 실행하면 문제없이 동작합니다. 하지만 Gateway와 연결하면 라우팅 규칙이 잘못되어 404 에러가 발생할 수 있습니다.

더 큰 문제는 설정 불일치였습니다. Config Server의 설정과 각 서비스의 기대값이 다르면 런타임 에러가 발생합니다.

운영 환경에 배포한 후에 이런 문제를 발견하면 긴급 롤백해야 하는 상황이 생깁니다. 통합 테스트의 시작 바로 이런 문제를 사전에 발견하기 위해 통합 테스트가 필요합니다.

통합 테스트를 하면 서비스 간 통신이 제대로 작동하는지 확인할 수 있습니다. Eureka 등록이 정상적으로 되는지, Gateway 라우팅이 올바른지, Config Server 설정이 정확히 적용되는지 검증합니다.

무엇보다 실제 사용자 시나리오를 미리 테스트할 수 있다는 큰 이점이 있습니다. 단계별 실행 가이드 위의 실행 순서를 따라가 봅시다.

먼저 Eureka Server를 시작합니다. 다른 모든 서비스가 Eureka에 등록되어야 하므로, Eureka가 가장 먼저 실행되어야 합니다.

8761번 포트로 실행되고, 브라우저에서 대시보드를 확인할 수 있습니다. 다음으로 Config Server를 시작합니다.

각 서비스가 시작할 때 Config Server에서 설정을 가져오므로, Config Server도 먼저 실행되어야 합니다. 8888번 포트로 실행되고, Git 저장소와 연결을 확인합니다.

Gateway와 서비스 실행 Config Server가 준비되면 Gateway를 시작합니다. Gateway는 Eureka에 등록되고, 다른 서비스의 위치를 조회할 준비를 합니다.

8080번 포트로 실행됩니다. 마지막으로 User Service를 시작합니다.

User Service는 Config Server에서 설정을 가져오고, Eureka에 등록하고, Gateway의 라우팅 대상이 됩니다. 8081번 포트로 실행됩니다.

Eureka 대시보드 확인 모든 서비스가 실행되면 Eureka 대시보드를 확인합니다. http://localhost:8761에 접속하면 "Instances currently registered with Eureka" 섹션에 GATEWAY와 USER-SERVICE가 표시되어야 합니다.

각 서비스 옆에 빨간 글씨가 없고 초록색 상태라면 정상적으로 등록된 것입니다. 김개발 씨는 "와, 제 서비스들이 모두 등록되었어요!"라고 기뻐했습니다.

Gateway를 통한 API 호출 이제 실제로 API를 호출해봅시다. 중요한 점은 User Service에 직접 요청하지 않고, Gateway를 통해 요청한다는 것입니다.

터미널에서 **curl http://localhost:8080/users/123**를 실행합니다. Gateway는 /users/ 경로를 보고 user-service로 라우팅합니다.

User Service는 요청을 처리하고 "User ID: 123, Name: 김개발"을 반환합니다. 로드밸런싱 테스트 User Service를 여러 개 실행해서 로드밸런싱을 테스트할 수도 있습니다.

같은 서비스를 다른 포트(8081, 8082, 8083)로 실행하면 Eureka에 3개 인스턴스가 등록됩니다. Gateway를 통해 같은 요청을 여러 번 보내면, 각 인스턴스가 번갈아가며 응답하는 것을 확인할 수 있습니다.

각 서비스의 로그를 보면 요청이 분산되는 것이 보입니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

예를 들어 쇼핑몰 서비스의 전체 시나리오를 테스트한다고 가정해봅시다. 사용자가 로그인하고, 상품을 검색하고, 장바구니에 담고, 주문하는 전체 과정을 Gateway를 통해 테스트합니다.

각 단계마다 여러 서비스가 협력합니다. User Service가 인증을 처리하고, Product Service가 상품 정보를 제공하고, Order Service가 주문을 생성합니다.

통합 테스트로 이 모든 흐름을 검증할 수 있습니다. 자동화 테스트 작성 통합 테스트를 자동화하면 더욱 효율적입니다.

Testcontainers를 사용하면 Docker로 모든 서비스를 자동으로 실행하고 테스트할 수 있습니다. Spring Cloud Contract를 사용하면 서비스 간 계약을 정의하고 검증할 수 있습니다.

User Service가 제공하는 API 스펙이 변경되면, Order Service의 테스트가 자동으로 실패하여 호환성 문제를 조기에 발견합니다. 주의사항 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 모든 서비스를 동시에 실행하는 것입니다. 실행 순서를 지키지 않으면 서비스가 Eureka를 찾지 못하거나 Config Server에 접속할 수 없습니다.

따라서 반드시 Eureka → Config → Gateway → 각 서비스 순서로 실행해야 합니다. 정리 다시 김개발 씨의 이야기로 돌아가 봅시다.

모든 테스트가 성공한 김개발 씨는 박시니어 씨에게 화면을 보여주었습니다. "선배님, 전부 성공했어요!" 통합 테스트를 제대로 수행하면 운영 환경 배포 전에 대부분의 문제를 발견할 수 있습니다.

여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 서비스 실행 순서를 반드시 지키세요: Eureka → Config → Gateway → 각 서비스

  • Eureka 대시보드에서 모든 서비스가 등록되었는지 확인하세요
  • Testcontainers로 통합 테스트를 자동화하면 효율적입니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#SpringCloud#Microservices#EurekaServer#APIGateway#ConfigServer#Spring Cloud

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

Istio 설치와 구성 완벽 가이드

Kubernetes 환경에서 Istio 서비스 메시를 설치하고 구성하는 방법을 초급 개발자도 쉽게 이해할 수 있도록 실무 스토리와 비유로 풀어낸 가이드입니다. istioctl 설치부터 사이드카 주입까지 단계별로 학습합니다.

서비스 메시 완벽 가이드

마이크로서비스 간 통신을 안전하고 효율적으로 관리하는 서비스 메시의 핵심 개념부터 실전 도입까지, 초급 개발자를 위한 완벽한 입문서입니다. Istio와 Linkerd 비교, 사이드카 패턴, 실무 적용 노하우를 담았습니다.

Helm 마이크로서비스 패키징 완벽 가이드

Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.

관찰 가능한 마이크로서비스 완벽 가이드

마이크로서비스 환경에서 시스템의 상태를 실시간으로 관찰하고 모니터링하는 방법을 배웁니다. Resilience4j, Zipkin, Prometheus, Grafana, EFK 스택을 활용하여 안정적이고 관찰 가능한 시스템을 구축하는 실전 가이드입니다.

Prometheus 메트릭 수집 완벽 가이드

Spring Boot 애플리케이션의 메트릭을 Prometheus로 수집하고 모니터링하는 방법을 배웁니다. Actuator 설정부터 PromQL 쿼리까지 실무에 필요한 모든 내용을 다룹니다.