[나 혼자 스프링부트!] 3) Spring Cloud Config Server/Client 설정

프로젝트를 진행하면서 다양한 서비스의 프로젝트 환경 설정 정보를 Spring Cloud Config Server와 GitHub Repository를 이용해 중앙에서 관리하면 클라이언트의 환경설정 정보를 따로 수정할 필요 없이 한 번의 수정만 가능할 것 같아 도입하기로 결정했다.

🥇 Spring Cloud Config Repository

각 서비스 환경과 서비스 별 개발, 테스트, 로컬 환경을 구분해 파일을 관리하기 위해서 GitHub Repository를 하나 생성한다.

해당 레포지토리에는 Yaml파일만 관리하는 용도로 사용한다.

각각의 환경 별 설정 파일을 구성해 업로드한다.

# 로컬 환경 DB 설정
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/serverTimezone=Asia/Seoul&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true
    username: root
    password: root

--- 
# 클라우드 환경 DB 설정
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://클라우드 공개 IP:3306/serverTimezone=Asia/Seoul&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true
    username: 클라우드 DB User 이름
    password: 클라우드 DB User 패스워드

🥈 Spring Cloud Config Server

위에서 Configuration 파일을 관리하는 레포지토리를 통해서 파일들의 내용들을 엔드포인트에 따라 불러올 수 있다. (설명 수정 필요)

Gradle 패키지를 start.spring.io에서 만든다. Dependacny는 Spring actuator, Config Server 라이브러리를 추가한다.

프로젝트를 생성한 후 빌드한 뒤 application.properties (application.yml) 파일을 수정해준다.

yml파일 수정 중 Private Repository를 사용하게 되는 경우 추가적으로 환경설정을 해준다.

server:
  port: 8088    # Spring Cloud Config Server 포트
spring:
  application:
    name: config-server # Confing Server  이름
  cloud:
    config:
      server:
        git:
         # uri: https://github.com/jymaeng95/spring-cloud-config-repository.git # public Repository의 경우 각 환경 별 Yaml 파일을 관리하는 깃헙 주소
           uri: [email protected]:jymaeng95/spring-cloud-config-repository.git     # private Repsoitory의 경우 ssh 키 발급해서 사용
           ignore-local-ssh-settings: true
           # Private Repository의 경우 개인키를 설정에 업로드
					 private-key: | 
             -----BEGIN EC PRIVATE KEY-----
             MHcCAQEEIIQf9VslUAT8vxL6sUBTaKuftWw7E6utoMcsdl4sl3/loAoGCCqGSM49
             ...
             -----END EC PRIVATE KEY-----
           host-key: AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= # ssh-keyscan github.com의 hostmname
           host-key-algorithm: ecdsa-sha2-nistp256  # ssh-keygen -m PEM -t ecdsa -f 파일명
           timeout: 4
# actuator 기본 설정
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    shutdown:
      enabled: true

Yaml 파일을 수정해준 뒤 실제 프로젝트를 실행시키는 스프링 컨테이너에 @EnableConfigServer 애노테이션을 추가해준다.

package com.test.springcloudconfig;

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

@SpringBootApplication
@EnableConfigServer		// Spring Cloud Config Server로 사용하겠다는 어노테이션
public class SpringCloudConfigApplication {

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

실행한 후 환경 설정 Yaml 파일의 이름을 엔드포인트로 호출해본다.

http://localhost:8088/config/local 엔드포인트로 호출한다.

호출이 성공하고 Github Repository의 config-local.yml 파일에 작성한 내용들을 잘 가져옴을 확인할 수 있다.

📌 Spring Cloud Config Server Endpoint

GET /{application}/{profile}[/{label}]
GET /{application}-{profile}.yml
GET /{label}/{application}-{profile}.yml
GET /{application}-{profile}.properties
GET /{label}/{application}-{profile}.properties
  • application : Spring Cloud Config Client의 application.properties (application.yml)파일에 정의한 spring.application.name 속성 값을 의미한다.
  • profile : Spring Cloud Config Client의 application.properties (application.yml) 파일에 정의한 spring.profiles.active 속성 값을 의미한다.
  • label : Optional 값으로, Git branch 정보를 의미한다.

🥉 Spring Cloud Config Client

Server가 잘 동작하는 것을 확인했으므로, 클라이언트 프로젝트를 생성해주자.

클라이언트 프로젝트를 생성할 때 “Config Client”, “ Spring web”, “Spring Boot Actuator” 의존성을 추가해서 생성해준다.

프로젝트를 생성해 빌드해준 뒤 application.properties(application.yml) 파일을 수정해준다.

spring:
  application:
    name: config      # 어플리케이션 이름 = Github 레포지토리에서 관리하는 파일 애플리케이션 이름
  profiles:
    active: local     # 애플리케이션 환경 = local, dev
  config:
    import: optional:configserver:http://localhost:8088 # import:optional:configserver사용 -> Spring cloud config server 주소 
server:
  port: 9001     # Spring Cloud Config Client 주소

# 클라이언트 코드에서 Actuator 설정
management:
  endpoints:
    web:
      exposure:
        include: "*"

application.yml 파일을 수정했다면, config Server가 Git Repository를 스캔해서 가져온 파일들을 애플리케이션 환경 엔드포인트에 맞게 잘 가져오는지 테스트를 해본다.

설정 정보를 가져와 필드에 넣어주기 위해서 LocalConfig 클래스를 생성해서 코드를 작성한다.

설정 정보를 불러오는 클래스에는 @RefreshScope 를 반드시 넣어준다. 해당 애노테이션은 Git Repository에 있는 Config 파일을 수정했을시 /actuator/refesh 엔드포인트를 호출함으로 써 변경된 설정 값을 갱신해주는 역할을 하는 Spring Actuator 애노테이션이다.

마지막으로, 엔드포인트 호출 시에 변수에 넣은 값들을 String 형태로 호출하기 위해 toString()메소드까지 추가했다.

package com.test.springcloudclient.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@RefreshScope       // Config.yml 파일 변경 시 변경된 내용을 actuator를 통해 변경값을 갱신
@Component
public class LocalConfig {
    // {application-profiles}.yml 에 정의한 내용을 해당 변수에 넣어줌
    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    @Override
    public String toString() {
        return "LocalConfig{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

다음으로, Controller 클래스를 생성해 실제 필요 엔드포인트 호출 시 Spring Cloud Config Server를 통해 GitHub Repository에 있는 값을 제대로 가져오는지 확인해본다.

package com.test.springcloudclient.controller;

import com.test.springcloudclient.config.LocalConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/service")
public class LocalController {

    // Configuration 주입
    private final LocalConfig localConfig;

    // 생성자 주입
    public LocalController(LocalConfig localConfig) {
        this.localConfig = localConfig;
    }

    // /service/local 엔드포인트 호출 시 "config-local.yml에 정의한 내용 불러옴"
    @GetMapping("/local")
    public String loadLocalConfig() {
        return localConfig.toString();
    }
}

테스트를 위한 Config 파일과 Controller 클래스를 생성했다면 Config Server 와 Config Client를 실행해서 확인해본다.

http://localhost:9001/service/local 을 호출 했을 때 아래와 같이 파일에 입력한 설정정보를 가져오는 것을 확인할 수 있다.

마지막으로, 위에서 LocalConfig 클래스에 작성한 @RefreshScope 이 잘 작동하는지 확인한다.

Config Server 와 Config Client를 실행시킨 상태에서 GitHub Repository의 config yml 파일을 수정한 후 Git에 push 한다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/serverTimezone=Asia/Seoul&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=true
    username: woi Refresh Scope Test !!!
    password: wei Refresh Scope Success !!!

클라이언트 단에서 POST http://localhost:9001/actuator/refresh 엔드포인트를 호출해 갱신해준다.

다시 클라이언트에서 http://localhost:9001/config/local을 호출 한 후 결과를 확인한다.

변경한 내용으로 잘 수정된 것을 확인할 수 있다.

📄 References

[spring boot 설정하기 - 14] spring cloud config (1) 설정 및 테스트 소스 : https://otrodevym.tistory.com/entry/spring-boot-설정하기-14-spring-cloud-config-설정-및-테스트-소스?category=815039

Spring Cloud Config: 소개와 예제 : https://madplay.github.io/post/introduction-to-spring-cloud-config

좋은 웹페이지 즐겨찾기