Dev./java

[Spring Cloud] Discovery First Bootstrap Hands-on

인쥭 2021. 7. 21. 15:23
반응형
  • 우리 프로젝트는 Spring Cloud Config Server를 먼저 실행한 후, Eureka 및 기타 서비스 App.을 실행시키는 식으로 동작한다.
  • 때문에 Spring Cloud Config Client가 되는 Eureka 및 기타 서비스 App.은 설정 정보에 Config Server URI를 작성해야만 한다. 
  • 이 과정에서 궁금증이 생겼다. Spring Cloud Config의 정보 또한 Eureka로 관리할 수 있지 않을까?

 

  • 결론부터 말하면, 가능했다. Config First Bootstrap과 Discovery First Bootstrap으로 나누어 아키텍처를 구성해볼 수 있으며,
    이 때 각자 일장일단이 있어 원하는 형태를 선택하도록 되어 있다.
  • 아래의 Hands-On은 Discovery Service에 Config Server의 정보를 등록한 후 Config Client가 이로부터 정보를 Fetch해 나가는 Discovery First Bootstrap 시나리오를 상정하고 작성되었다. 

참고

 

Spring Cloud

Ribbon is a client-side load balancer that gives you a lot of control over the behavior of HTTP and TCP clients. Feign already uses Ribbon, so, if you use @FeignClient, this section also applies. A central concept in Ribbon is that of the named client. Eac

cloud.spring.io

Config First Bootstrap

  • Config Client가 시작할 때 bootstrap.property(또는 .yml)의 spring.cloud.config.uri 정보를 토대로 원격지의 Config Server와 바인딩된 후 Spring 'Environment'를 초기화한다.

Discovery First Bootstrap

  • Eureka와 같은 Discovery Service를 사용하는 경우, Config Server 또한 이에 등록할 수 있다.
  • 이 경우, Discovery Server에서 사용할 Config 정보는 별도의 설정 값으로 관리되어야 한다.
    • Discovery First Bootstrap 방식은 서버가 올라오면서 Service Discovery를 통해 얻어낸 Config Server URI로부터 Fetch하여 등록하는데, Discovery Server는 같은 방식으로 적용이 불가능하다는 의미로 보인다.

 

Hands-on

a). Eureka Server

 

[Spring Cloud Netflix] Eureka Server, Client 설정

Spring Boot 2.5.2 IntelliJ 2020.3.3 1. Eureka Server dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' developmentOnly 'org.springframework.boot:sp..

ingnoh.tistory.com

  • 위 내용대로 설정하였다.

b). Config Server

// build.gradle
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.cloud:spring-cloud-config-server'
}
  • Config Server 또한 Eureka에 등록하고, 이후 Config Client들은 Eureka를 통해 Config Server의 정보를 Fetch하도록 한다.
# application.yml
spring:
  application:
    name: cloud-config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/injuk/spring_cloud_config_demo.git
          default-label: main

server:
  port: 8840
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"
  • eureka 하위의 설정 정보를 추가한다. eureka 서버는 localhost:8761에서 동작하는 것을 가정한다.
// Main 클래스
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigServer {

  public static void main(String[] args) {

    SpringApplication.run(ConfigServer.class, args);
  }
}
  • EnableEurekaClient 어노테이션을 추가한다.
  • 실행 후 http://localhost:8761에 접속하여 등록 여부를 확인해볼 수 있다.

CLOUD-CONFIG-SERVER가 Eureka Client로 등록되었다.

c). Config Client

// build.gradle
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-config'
    implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
}
  • Eureka와 bootstrap.yml을 사용하기 위해 필요한 디펜던시를 명시한다.
# bootstrap.yml
server:
  port: 8850

eureka:
  instance:
    appname: cloud-config-client
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

spring:
  profiles:
    active: dev
  application:
    name: ingnoh-configs
  cloud:
    bootstrap:
      enabled: true
    config:
      discovery:
        enabled: true
        service-id: cloud-config-server

management:
  endpoints:
    web:
      exposure:
        include: "*"
  • Discovery First Bootstrap은 아직 bootstrap.yml을 사용해야 하는 듯 하다.
  • Eureka에 등록하기 위한 정보를 작성하고, spring.cloud의 하위 설정을 통해 bootstrap과 discovery를 활성화한다.
  • 이 때, spring.cloud.config.service-id의 값은 반드시 Spring Cloud Config Server 역할을 하는 App.의
    Service ID와 맞춘다. 해당 정보를 통해 Config Server를 식별하고 설정을 Fetch하게 된다.
// Main 클래스
@SpringBootApplication
@EnableEurekaClient
public class ConfigClient {

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

}
  • 역시 EnableEurekaClient 어노테이션을 활성화한 후 App.을 실행한다.
  • Spring Cloud Config Server의 URI를 작성하지 않았음에도 다음과 같이 설정을 Fetch하는 것을 확인할 수 있다.
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)

2021-07-21 15:04:59.090  INFO 23212 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://10.93.10.166:8840/
2021-07-21 15:04:59.438  INFO 23212 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=ingnoh-configs, profiles=[dev], label=null, version=1e3d857aa06ff0fbebaa6bfc3b1a5a64c0ad425b, state=null
2021-07-21 15:04:59.439  INFO 23212 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/injuk/spring_cloud_config_demo.git/ingnoh-configs-dev.yml'}]
2021-07-21 15:04:59.443  INFO 23212 --- [           main] com.example.demo.ConfigClient            : The following profiles are active: dev
  • 마찬가지로, http://localhost:8761에 접속하여 등록 여부를 확인해볼 수 있다.

CLOUD-CONFIG-CLIENT 역시 Eureka Client로 등록되었다.

  • curl을 통해 설정 정보의 반영 여부를 확인하자.
[~] curl --silent localhost:8840/ingnoh-configs/dev | jq
{
  "name": "ingnoh-configs",
  "profiles": [
    "dev"
  ],
  "label": null,
  "version": "1e3d857aa06ff0fbebaa6bfc3b1a5a64c0ad425b",
  "state": null,
  "propertySources": [
    {
      "name": "https://github.com/injuk/spring_cloud_config_demo.git/ingnoh-configs-dev.yml",
      "source": {
        "hello.ingnoh": "NOTdeveloper"
      }
    }
  ]
}
[~] curl localhost:8850
NOTdeveloper%

 

메모

  • bootstrap.yml을 작성하는 과정에서 'java.lang.IllegalStateException: No instances found of configserver'와 관련된 시행착오가 많았다. 다음의 URL을 참고하도록 하자.
 

Could not locate configserver via discovery if config server starts later · Issue #1498 · spring-cloud/spring-cloud-config

When Config server started first there is no problem, but when config client started before config server this error prints continuously. I am not sure whether this is expected behavior or not. The...

github.com

  • Config First와 Discovery First 중 반드시 어떤 것이 좋다고 할 수는 없는 듯 하다. 각각 일장일단이 있는 방식이므로, 자신의 아키텍처에 맞게 골라 쓰면 되는 것으로 보임!
 

Spring Cloud Config Server — Discovery First Vs Config First

In the previous article, we saw how to bootstrap your first config server. In this article, we will discuss how to set up Config clients…

medium.com