서비스 디스커버리: Eureka로 마이크로서비스 등록/연결

서비스 디스커버리 는 MSA 구조에서 필수적인 기능으로, 수많은 마이크로서비스가 서로를 동적으로 탐색하고 통신할 수 있도록 해준다.
MSA 구조에서는 수많은 서비스가 독립적으로 동작하며, 네트워크를 통해 서로 통신해야 한다.
이때 고정된 IP나 포트를 사용하는 대신, 각 서비스가 자신을 등록하고 서로를 동적으로 탐색할 수 있도록 하는 메커니즘이 필요하다.
Spring Cloud에서 제공하는 Eureka는 이런 서비스 디스커버리를 가능하게 해주는 대표적인 도구다.

1. Eureka 구성 요소

  • Eureka Server: 서비스 레지스트리 역할. 모든 서비스가 여기에 자신을 등록하거나 다른 서비스를 조회한다.
  • Eureka Client: 마이크로서비스 애플리케이션. 실행 시 Eureka Server에 자신을 등록하고, 다른 서비스 정보를 조회한다.

2. Eureka Server 설정

의존성 추가 (discovery-server/build.gradle.kts)

dependencies {
    implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-server")
}

애플리케이션 설정 (application.yml)

server:
  port: 8761

spring:
  application:
    name: discovery-server

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

서버 어플리케이션 클래스

@SpringBootApplication
@EnableEurekaServer
class DiscoveryServerApplication

fun main(args: Array<String>) {
    runApplication<DiscoveryServerApplication>(*args)
}

3. 클라이언트 서비스 설정

모든 마이크로서비스는 Eureka Client로 동작하게 설정한다.

의존성 추가 (예: user-service/build.gradle.kts)

dependencies {
    implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
}

application.yml 설정

spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

서비스 실행 후 http://localhost:8761 에 접속하면, 각 마이크로서비스가 정상적으로 등록된 것을 확인할 수 있다.

유레카 서버에 서비스가 등록된 모습


4. Gateway와 Eureka 통합

Gateway 서비스 역시 Eureka Client로 등록되며, 라우팅 시 URI를 lb://서비스이름 형태로 사용한다.
이는 로드밸런싱과 디스커버리를 동시에 처리할 수 있게 해준다.

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**

5. 서비스 간 통신 예시

user-service에서 auth-service의 기능을 호출하려면 Eureka를 통해 서비스 이름으로 직접 접근할 수 있다.

@RestController
class TestController(private val restTemplate: RestTemplate) {

    @GetMapping("/test-auth")
    fun testAuth(@RequestHeader("Authorization") authorization: String): ResponseEntity<String> {
        val headers = HttpHeaders()
        headers.set("Authorization", authorization)
        val entity = HttpEntity<String>(headers)
        val response = restTemplate.exchange(
            "http://auth-service/hello",
            HttpMethod.GET,
            entity,
            String::class.java
        )
        return response
    }
}

RestTemplate이나 WebClient를 사용할 때도 load-balanced 빈을 설정하면 Eureka에서 인스턴스를 찾아 자동으로 호출해준다.

@Configuration
class RestTemplateConfig {
    @LoadBalanced
    @Bean
    fun restTemplate(builder: RestTemplateBuilder): RestTemplate =
        builder.build()
} 

6. 테스트결과

서비스 디스커버리 를 통해 서비스를 호출한 결과 화면
[Postman] 


[Gateway (8080)]  --(Eureka로 user-service 인스턴스 조회)-->


[user-service]  --(Eureka로 auth-service 인스턴스 조회)-->


[auth-service] (토큰 검증 후 응답)


[user-service]


[Gateway]


[Postman]

Postman → Gateway → user-service → auth-service

이 모든 과정에서 Eureka가 서비스 위치를 동적으로 연결해주고,
Gateway가 API 진입점 역할을 하며,JWT 인증이 end-to-end로 일관되게 적용된 것을 확인 할 수 있다.


유연한 서비스 탐색의 핵심, Eureka

Eureka는 MSA에서 필수적인 서비스 디스커버리 기능을 안정적으로 제공한다.
고정된 주소에 의존하지 않고 서비스 이름 기반으로 연결되므로, 유연하고 탄력적인 아키텍처를 설계할 수 있다.
다음 포스트에서는 Config Server를 활용해 서비스별 설정을 중앙에서 통합 관리하는 방법을 정리할 예정이다.

이전편 보기
API 라우팅 – Spring Cloud Gateway로 인증/비인증 API 라우팅

참고

자세한 코드는 아래 저장소에서 확인 가능하다.
Github – 저장소

댓글 남기기