Spring Cloud - Config Server

INCHEOL'S·2021년 3월 10일
0

spring-cloud

목록 보기
1/1

MSA를 공부하며 만들어보았던 Spring Cloud의 Config Server를 정리해 놓으려고 한다.

Config Server 와 이를 이용하는 Config Client를 만들어 공부했던 내용을 복습해보자.

준비물은 아래와 같이 3가지 정도가 필요했다. 그리고 추가적으로 @RefreshScope도 알아보았다.

  1. Git Repository (Config 정보를 저장해 놓기 위함)
  2. Config Server (Client별로 Config 정보를 제공하기 위함)
  3. Config Client (Config Server를 통해 Config 정보를 제공받는 서버)
  4. @RefreshScope

1. Git Repository

먼저 설정 정보를 저장해 놓을 Git Repository를 생성하자.

실제로 Config 정보들이 저장될 수 있는 레파지토리는 파일시스템, 유레카,

Config Client의 appname, profile을 이용해 환경 설정을 분리하여 사용가능하기 때문에
아래 그림과 같이 /{search-path}/{appname}-{profile}.properties 여러개 만들어 두었다.

실제로 사용하는 Config Client의 설정에 따라 원하는 프로퍼티 파일을 읽어 들일 수 있다.

2. Config Server

아래 depency만 추가하고 @EnableConfigServer 애너테이션을 붙여주고,
Config가 저장된 저장소 주소를 기입해 주어야 한다.
그리고 Config Server가 읽어들일 search-path도 작성해주면 되는데, git 저장소에 /remind/remind-dev.properties 경로중 /remind 부분이 search-path에 해당하니 경로 이름에 알맞게 잘 작성해주면 된다.

이로써 우리는 간단히 Config Server를 사용할 준비를 마쳤다.

데이터베이스 접속 정보같은 보안이 유지되어야 하는 정보들을 암호화 처리하여 저장할 수도 있는데 지금은 모두 평문으로 저장되고 서비스된다. 암호화 처리는 다음글에 남겨놓아야겠다.

spring-cloud.version은 Hoxton.SR7을 사용했다.

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
		</dependency>

	<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>
@SpringBootApplication
@EnableConfigServer
public class ConfigserverApplication {

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

}
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/incheol1024/config-repository.git
          search-paths: remind

3. Config Client

마지막으로 Config Server가 제공하는 Config 정보들을 사용하는 애플리케이션(Config Client)을 만들어보아서 Config Server가 잘 작동하는 지 확인해보자.
특별한 것은 아니고 우리가 일반적으로 만드는 애플리케이션이며 단지 설정 정보들을 애플리케이션 내부에서 관리하는 것이 아닌 Config Server에게 제공받아 구동 된다. 우리는 Config Server에서 제공받으라고 설정만 해주면 된다.

Config Server를 이용하는 Spring Boot 애플리케이션을 만들어보자.

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

web 의존성은 설정 정보를 제대로 읽어 들였는지 요청을 통하여 값을 확인할 용도로 넣어뒀다.
그리고 actuator 의존성을 추가한 이유는 config 정보가 변경되면 애플리케이션이 live 상태인데도 불구하고 변경 된 값을 업데이트 할 수 있도록 refresh 엔드포인트를 제공하기 때문이다. 조금의 설정값 변경 때문에 빌드, 배포 절차를 밟지 않아도 된다니.. 아주 해피하다!

우선 우리가 필요한 것은 bootstrap.yml 이다. 이 녀석은 애플리케이션에서 application.properties, application.yml을 읽어들이기 전에 Config Server에서 설정 정보를 읽어들이기 위한 파일이다.
즉, 애플리케이션 설정 파일의 외부화를 Spring Boot에서 bootstrap.yml을 통해 유저에게 제공한다.
여기에는 Config Server의 정보와 우리가 필요로 하는 설정 파일이름 spring.applcation.name 을 적어주어 애플리케이션이 원하는 정보를 가져오도록 한다.

아래와 같이 설정해주자. 나는 Config Server를 포트 8888로 띄워놨기 때문에 주소를 아래와 같이 설정해주었다.
그리고 appname을 remind로 설정하고 애플리케이션을 기동할때 -Dspring.profiles.active=prod 옵션을 넣어줄 것이다. 그렇다면 애플리케이션에서는 localhost:8888 서버에서 remind-prod.properties 받아올 것이다.

spring:
  application:
    name: remind
  cloud:
    config:
      uri: http://localhost:8888

확인을 위해 Config의 값을 가져오는 Controller와 Service를 만들었다.

@RestController
@RequestMapping(value = "/config")
@RequiredArgsConstructor
public class ConfigController {

    private final ConfigService configService;

    @GetMapping("/my-favorite")
    public Map<String, String> getMyFavorite() {
        return configService.getMyFavorite();
    }

}
@Service
@RefreshScope
public class ConfigService {

    @Value("${my.favorite.food}")
    private String food;

    @Value("${my.favorite.coffee}")
    private String coffee;

    public Map<String, String> getMyFavorite() {
        Map<String, String> keyword = new HashMap<>();
        keyword.put("food", food);
        keyword.put("coffee", coffee);
        return keyword;
    }

}

그리고 요청을 날려 값이 정상적으로 주입됐는지 확인해보자.

  • remind-prod.proerties
  • 요청 결과

값이 정상적으로 주입됐는지 확인하였다.

4. @RefreshScope

만약 우리의 git Config Repository에 값이 변경되었다고 해보자.
나의 최애 음식이 my.favorite.food=pasta 로 바뀐 것이다.
그러면 Config Client Application에 주입됐던 값도 변경이 될까?
그렇지 않다. 하지만 변경 가능하도록 할 수 있다.

변경 가능하도록 하기 위해서는 위의 서비스코드에서 @RefreshScope 애너테이션과 Atuator 의존성이다.

@RefreshScope을 달아두면 프로터피 주입 refresh 에 대한 기회를 제공한다. 이것은 단지 기회를 제공할 뿐이지 애너테이션을 붙였다고해서 자동으로 변경된 값으로 refresh 되지 않는다.
우리는 refresh를 하기 위해 spring-starter-actuator 의존성을 추가하였다.
우리는 actuator가 제공하는 endpoint를 통해 refresh를 할 수 있다.

보안상 atuator가 제공하는 endpoint들이 막혀있지만 일단 오픈하여 테스트해보자.

Config Client의 application.properties에 다음과 같이 설정을 해줬다.

management.endpoints.web.exposure.include=*

그리고 git Config Repository의 remind-prod.properties 값 중 my.favorite.food=pasta 로 변경해보자.

  • 변경된 Config 정보

그리고 요청을 날려 값을 확인해보자.

  • refresh 요청 전 값 확인

아직 값이 바뀌지 않았다. @RefreshScope을 달아뒀었지만, /actuator/refresh 로 리프레쉬 요청을 날리지 않았기 때문이다.

리프레쉬 요청을 날려보자.

무언가 값이 날라왔다.

"my.favorite.food" 라는 값이 왔는데 내가 변경했던 프로퍼티의 키값이다. 이녀석이 변경되었다고 알려주는 것 같다.

리프레쉬를 했으니 이제 정말 값이 변경되어 주입됐는지 확인해볼 차례다.

  • refresh 요청 후 값 확인

끝.

profile
제주하르방백년초콜릿 먹고싶네요. 아, 저는 백엔드 개발자입니다.

0개의 댓글