'spring cloud config'에 해당되는 글 2건

  1. 2019.02.24 :: Spring Cloud - Spring Cloud Bus
  2. 2019.02.23 :: Spring Cloud - Spring Cloud Config(스프링 클라우드 컨피그)
Web/Spring Cloud 2019. 2. 24. 01:04

Spring Cloud - Spring Cloud Bus



Spring Cloud Bus 는 분산 시스템에 존재하는 노드들을 경량 메시지 브로커(rabbitmq, kafka etc)와 연결하는 역할을 합니다.

구성 변경과 같은 상태변경, 기타관리 등을 브로드캐스트하는데 사용이 가능합니다.

현재 AMQP 브로커를 전송으로 사용하지만 Kafka, Redis도 사용 할 수 있습니다. 그 외의 전송은 아직 지원되지 않습니다.



1. 개요

Spring Cloud Config Server를 구축하게 되면 각 어플리케이션에 대한 설정정보(ex: applicatoin.yml)를 한 곳에서 관리 할 수 있습니다.

  • 하지만 해당 정보가 수정 될 경우 클라이언트 어플리케이션을 재기동해야 하는 것은 변함이 없습니다.

  • 이러한 방식은 이상적이지 않기 때문에 spring-boot-actuator와 @RefreshScope 어노테이션을 추가한 이후에 해당 클라이언트에 아래와 같은 명령을 보내어 재기동 없이 설정정보를 다시 읽어오게 할 수 있습니다.

    $ curl -x POST http://[ip]:[port]/refresh
  • 하지만 클라우드 환경에서는 모든 actuator endpoint에 접근하여 모든 클라이언트 어플리케이션을 refresh 해야 하는 번거로움이 존재합니다. 이러한 문제는 Spring Cloud Bus를 통해서 해결 할 수 있습니다.

  • 아래와 같은 서버(또는 브로커)를 만들도록 하겠습니다.

    • hello-act-client

    • config-server

    • RabbitMQ(Docker)

2. hello-act-client 구축


해당 어플리케이션은 GET request 를 통해 간단한 문자열을 출력하는 어플리케이션입니다.

먼저 간단한 dependency를 추가합니다. (해당 프로젝트는 spring-boot-starter-parent:2.0.2.RELEASE를 사용합니다.)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

application.yml을 작성합니다. 여기서 message.act 는 GET request 호출 시 출력할 문자열입니다.

server:
port: 8090
message:
act: "act"
spring:
application:
name: hello-act

Controller를 작성합니다.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloActController {
@Value("${message.act}")
private String message;
@GetMapping("/")
public String getMessage() {
return message;
}
}

서버를 기동하고 terminal에서 GET request를 호출하면 "act" 라는 메시지가 출력 되는 것을 확인 할 수 있습니다.

$ curl -X GET http://localhost:8090/
act

3. config-server 구축

해당 message를 config 서버에서 읽어와서 출력하기 위해서는 config-server 구축이 필요합니다. 새로운 프로젝트를 생성하고 아래와 같은 dependency를 추가합니다.

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
...
</dependencies>

해당 어플리케이션이 config-server임을 알리기 위해서 @EnablieConfigServer 어노테이션을 추가합니다.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}

해당 서버가 바라보는 config 저장소를 application.yml에 추가합니다. 해당 예제에서는 git 주소를 로컬 git으로 하였습니다.

server:
port: 8091
spring:
cloud:
config:
server:
git:
uri: file:/Users/bristol/bradley/configure

이제 /Users/bristol/bradley/configure 경로에 hello-act-client에서 사용 할 설정 정보를 가져옵니다.

hello-act.yml을 만들어 아래와 같은 설정 정보를 넣습니다.

server:
port: 8090
message:
act: "act"

이 후에 commit 을 해주도록 합니다.

$ git add.
$ git commit -m 'init yml'



4. hello-act-client 수정

config-server를 구축하였으므로 이제 포트정보와 message 정보는 config-server를 통해서 가져오도록 하겠습니다.

먼저 cloud-config를 사용 할 수 있도록 dependency를 추가합니다.

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
...
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
...
</dependencies>

기존의 application.yml 내용 중 아래의 내용을 bootstrap.yml으로 이동하고 application.yml을 삭제합니다.

spring:
application:
name: hello-act
cloud:
config:
uri: http://localhost:8091

해당 서버를 재기동 한 이후 아래와 같이 명령어를 보내면 act 라는 문자열이 출력되는 것을 볼 수 있습니다.

$ curl -X GET http://localhost:8090/
act

configure 폴더에서 메시지 정보를 수정합니다.

message:
act: "hello-act"

다시 commit을 합니다.

$ git add .
$ git commit -m 'change message'

서버 재 기동 없이 아래와 같이 명령어를 보내면 여전히 act 라는 문자열이 출력되는 것을 볼 수 있습니다.

$ curl -X GET http://localhost:8090/
act

5. RefreshScope

환경설정을 바꿨다고 해서 서버를 재기동하는 것은 불필요한 행위입니다. 따라서 서버 재기동 없이 환경설정을 읽어오는 방법을 알아보겠습니다.

먼저 hello-act-client 어플리케이션에 dependency를 추가합니다.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

@RefreshScope 어노테이션을 추가합니다. @RefreshScope로 표시된 Spring Bean은 사용시 초기화 되는 lazy proxy로 범위는 초기화 된 캐쉬 값으로 작동합니다.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class HelloActController {
@Value("${message.act}")
private String message;
@GetMapping("/")
public String getMessage() {
return message;
}
}

그리고 bootstrap.yml에 아래와 같은 설정을 추가합니다. (기본적으로 actuator로 추가 된 민감한 엔드포인트는 보안에 묶여 있습니다. 아래와 같은 설정을 하거나 특정 url을 노출 시킬 수 있습니다.)

management:
security:
enabled: false

서버를 재기동하고 아래와 같이 명령어를 보내면 hello-act가 출력됩니다.

$ curl -X GET http://localhost:8090/
hello-act

config저장소에서 hello-act.yml을 열어 hello-sds로 변경하고 commit을 합니다.

message:
act: "hello-sds"
$ git add.
$ git commit -m 'change sds'

이제 서버 재기동 없이 터미널에서 아래와 같은 명령어를 보냅니다.

$ curl -X POST http://localhost:8090/actuator/refresh

해당 명령어를 보내면 변경된 프로퍼티가 출력 됩니다. 다시 아래와 같은 명령어를 날리게 되면 변경된 메시지가 출력 되는 것을 확인 할 수 있습니다.

$ curl -X GET http://localhost:8090/
hello-sds



6. Spring Cloud Bus

변경된 설정 값이 반영 되는 것을 확인하였으나 이와 같은 방법은 클라우드환경에서 endpoint 가 늘어날 수록 번거로울수 밖에 없습니다. 따라서 Spring Cloud Bus를 사용해보도록 합니다.

먼저 rabbitmq를 docker로 실행합니다.

$ docker run -d \
--hostname rabbit \
--name rabbit \
-p 15672:15672 \
-p 5672:5672 \
rabbitmq:3.7.5-management

클라이언트 어플리케이션에 아래와 같은 dependency를 추가합니다.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

config 저장소에 hello-act.yml을 아래의 구문을 추가합니다.

spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest

이제 config-server 설정을 변경합니다.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-monitor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

다음으로 config-server의 application.yml을 수정합니다.

spring:
...
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
management:
endpoints:
web:
exposure:
include: "bus-refresh"

이제 모든 서버를 재 기동 한 이후에 hello-act.yml의 메시지 값을 다시 변경합니다.

...
message:
act: "hello-sds-act"
...

기존에는 hello-act 서버에 리퀘스트를 보냈으나 이제는 config-server에 리퀘스트를 보냅니다.

$ curl -X POST http://localhost:8091/actuator/bus-refresh

이후에 hello-act 서버에 GET 리퀘스트를 보내면 변경된 메시지를 확인 할 수 있습니다.

$ curl http://localhost:8090/
hello-sds-act

이러한 방법을 사용하면 코드 저장소(github, gitlab, bitbucket 등)에 webhook 기능을 사용하여 설정파일 변경이후에 commit, push가 일어날 때마다 자동으로 모든 클라우드 노드의 refrshscope 가 적용된 어플리케이션이 환경설정을 다시 읽게 할 수 있습니다.

posted by 여성게
:
Web/Spring Cloud 2019. 2. 23. 12:46

Spring Cloud - Spring Cloud Config(스프링 클라우드 컨피그)


Spring cloud Config(스프링 클라우드 컨피그) 서버는 애플리케이션과 서비스의 모든 환경설정 속성 정보를 저장하고, 

조회하고 관리할 수 있게 해주는 외부화된 환경설정 서버다. 스프링 컨피그는 환경설정 정보의 버전 관리 기능도 지원한다. 

환경설정 속성 정보를 애플리케이션 배포 패키지에서 분리해 외부화하고 외부 소스에서 설정 정보를 읽어노는 방법이다.


위의 그림과 같이 스프링 클라우드 컨피그 서버가 모든 마이크로서비스의 환경설정정보를 가지고 있고,

설정 배포의 작업을 진행한다. 하지만 항상 서버에 접근해서 설정정보를 가져오지는 않고,

첫 애플리케이션 구동 단계에서 설정정보를 가져와 로컬에 캐시를 해둔다. 그리고 만약 컨피그 서버에서

설정정보의 변경이 이루어 진다면 모든 마이크로서비스에 변경 사항을 전파하고, 모든 마이크로서비스는

변경사항을 로컬캐시에 반영한다. 컨피그 서버는 개발 환경별 프로파일 기능도 제공한다.


이번 포스팅은 스프링 클라우드 컨비그 서버의 환경설정 정보를 GitHub에 저장하고 원격에서 설정정보를

불러올 것이다. (SVN 등을 이용해도 무관)




만약 Git 사용법이 익숙하지 않다면 밑의 링크에서 Git사용법을 익히고 와도 좋다.


▶︎▶︎▶︎GitHub - 간단한 Git사용법(로컬 레포지토리,원격 레포지토리)

▶︎▶︎▶︎GitHub - Git 사용법 2 (branch, checkout, reset 등)

▶︎▶︎▶︎Github - eclipse(이클립스)와 local repository(로컬레포지토리) 연동





스프링부트프로젝트를 생성할 때, 위 이미지와 같이 Config Server & Actuator를 체크해준다.


기존에 기본으로 생성됬던 application.properties를 bootstrap.properties로 변경해준다.

스프링 클라우드 컨피그는 application.properties가 아닌 bootstrap.properties를 이용한다.



1
2
3
4
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/yeoseong/spring-cloud-configserver.git
management.security.enabled=false
management.endpoint.env.enabled=true
cs



bootstrap.properties를 위와같이 작성한다. 간단히 설명하면

컨피그 서버의 포트는 8888, 환경설정 파일을 관리하는 원격 Git을 서버는 ~.git이라는 것이다.

나머지는 액츄에이터에 대한 설정파일이다.



1
2
3
4
5
6
7
8
9
@EnableConfigServer
@SpringBootApplication
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
}
cs


@EnableConfigServer 어노테이션을 붙여서 해당 애플리케이션은 컨피그서버임을 명시해준다.


그 다음은 해당 컨피그 서버를 이용하는 클라이언트 작성이다.


새로운 스프링부트 프로젝트를 생성하고, Config Client와 Actuator,WEB를 체크해준 후 위의 과정과 동일하게

application.properties -> bootstrap.properties로 바꿔준다.



1
2
3
spring.application.name=configclient
spring.profiles.active=dev
spring.cloud.config.uri=http://localhost:8888
cs



해당 애플리케이션 이름은 configclient고, 프로파일은 dev이며, 설정정보를 받아올 컨피그 서버의 주소는 ~:8888이라는 뜻이다.

이 설정들은 다 의미가 있고 중요한 설정이다. 우선 애플리케이션 이름은 깃에 저장될 프로퍼티 파일의 이름이고, 프로파일은 해당 프로퍼티의

프로파일이라는 뜻이다. 즉, 깃허브에는 {name}-{profile}.properties라는 환경설정 파일이 저장되어 있고,

이 설정파일을 불러오기위한 설정이라고 생각하면된다. 

애플리케이션 별로 환경설정 파일을 분리하고, 한 애플리케이션에 대한 설정이지만 프로파일 별로 설정파일을 유지할 수도 있는 것이다.




이제 깃허브에 configclient-dev.properties라는 파일을 작성하고 예제로 설정파일에 밑의 이미지와 같은 내용을 기입한다.






마지막으로 예제 애플리케이션을 작성한다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@SpringBootApplication
public class ConfigclientApplication implements CommandLineRunner{
    
    @Value("${application.service.name}")
    private String serviceName;
    
    @Override
    public void run(String... args) throws Exception {
        // TODO Auto-generated method stub
        
        System.out.println(serviceName);
        
        
    }
 
    public static void main(String[] args) {
        SpringApplication.run(ConfigclientApplication.class, args);
    }
 
}
cs



해당 예제는 CommandLineRunner를 이용하여 애플리케이션 구동시점에 간단히 콘솔에 

프로퍼티에 작성한 내용을 출력하였다.


▶︎▶︎▶︎CommandLineRunner란?


이제 애플리케이션을 구동해보자, 아마 Console에 "configclient2"라는 문자열이 찍혔을 것이다.


그 다음은 만약 환경설정 파일이 변경이 되었다면


해당 인스턴스에게 refresh요청을 보낸다.

파라미터는 필요없다.

>http://localhost:8080/refresh(POST)



1
2
3
4
5
6
7
8
9
10
11
12
    @RefreshScope
    @RestController
    class ConfigClientController {
        
        @Value("${application.service.name}")
        private String serviceName;
        
        @GetMapping("/config")
        public String config() {
            return serviceName;
        }
    }
cs


하지만 이미 주입된 프로퍼티값을 변경하기 위해서는 @RefreshScope라는

어노테이션을 붙여준다. 이렇게하면 애플리케이션 재시작 없이 환경설정 값을 바꿔줄 수 있다.


하지만 여기에서 마이크로서비스가 여러개이고, 관리되는 환경설정이 여러개라면 일일이 

위의 요청을 보내야 할까? 아니다.

>http://localhost:8080/bus/refresh(POST)


하나의 인스턴스에게 위의 요청을 한번만 보내면 모든 인스턴스에게 환경설정 변경정보가 전파된다.


만약 위의 요청을 사용하려면

management.security.enabled=false

설정을 꼭 해줘야한다.


설정파일을 적절한 값으로 변경하고 refresh 한후에 해당 컨트롤러에 다시 요청을 보내보자.

아마 변경된 프로퍼티를 읽어서 반환해줄 것이다.

posted by 여성게
: