[Spring Cloud] Spring Cloud Config 정리

double-oh·2021년 8월 22일
0
post-thumbnail

Spring Cloud Config 란?

  • Spring Boot로 만든 REST 기반의 어플리케이션 구성정보 관리 오픈소스

Spring Cloud Config 개발 배경

  • 개발자는 어플리케이션 안의 상수(Constants)를 YAML, JSON, XML 등과 같은 파일로 구성정보를 분리한다.
  • 하지만 구성정보가 변경되면 어플리케이션은 재배포되어야한다.
  • 이러한 방식은 어플리케이션 수가 적은 상황에서는 문제가 없겠지만, 수십 개의 마이크로서비스가 실행되는 클라우드 기반의 어플리케이션에서는 통하지 않는다.

Spring Cloud Config 특징

  • 아래 4가지 클라우드 환경 구성관리 시스템 원칙을 따른다.
    1. 분리(segregate): 실제 물리적인 서비스의 배포와 서비스 구성정보를 완전히 분리해야한다. 어플리케이션의 구성정보를 서비스 인스턴스와 함께 배포화면 안되고, 서비스에 환경변수로 전달하거나 중앙 저장소에서 읽어 와 구성정보를 전달해야한다.
    2. 추상화(abstract): 서비스 인터페이스 뒷단에 있는 구성 데이터의 접근 방식을 추상화해야한다. 즉, 서비스 저장소에 직접 액서스하는 코드를 작성하기보다 어플리케이션이 REST 기반의 JSON 서비스를 사용해 구성 데이터를 조회하게 만들어야한다.
    3. 중앙 집중화(centralize): 클라우드 기반의 어플리케이션에는 수백 개의 서비스가 존재할 수 있어, 구성정보를 보관하는 저장소 개수를 최소한으로 줄이는 것이 중요하다. 어플리케이션 구성정보를 가능한 소수 저장소에 집중한다.
    4. 견고성(harden): 어플리케이션 구성정보를 배포된 서비스와 완전히 분리하고 중앙 집중화하므로 어떤 솔루션을 사용하더도 고가용성과 다중성을 구현할 수 있어야한다.
  • Server-Client 아키텍처를 가진다.
    • Spring Cloud Config server는 파일시스템, Git, Redis, Posgresql 등과 같은 저장소 내의 구성 데이터를 읽어온 후, 구성정보에 접근할 수 있도록 REST API를 제공
    • Spring Cloud Config client는 기동될 때, Spring Cloud Config server로부터 조회하고, 해당 구성정보를 이용하여 서비스 기동
    • 저장소의 구성 데이터가 업데이트 되면, Spring Cloud Config Server에는 바로 반영되지만, Spring Cloud Config client에는 바로 반영되지 않는다. 이럴 때는 Spring Boot Actuator의 /actuator/refresh 엔드포인트를 호출하여, 어플리케이션의 구성정보를 다시 읽어오도록 할 수 있다.
  • 대칭키, 비대칭키 암호화 방식을 이용한 구성정보 암호화 설정을 할 수 있다.
  • Spring Cloud Config는 application, profile, label 정보를 이용하여 특정 구성정보를 load한다.

Spring Cloud Config 구현

사전준비

  • Postgres에 구성정보 테이블 생성 및 구성정보 저장
CREATE TABLE spring_cloud.tbl_config_property (
    id serial primary key,
    created_at timestamp,
    application character varying(50) COLLATE pg_catalog."default",
    profile character varying(50) COLLATE pg_catalog."default",
    label character varying(50) COLLATE pg_catalog."default",
    key character varying(50) COLLATE pg_catalog."default",
    value character varying(500) COLLATE pg_catalog."default"
);

INSERT INTO spring_cloud.tbl_config_property(created_at, application, profile, label, key, value) VALUES(NOW(), 'spring-cloud-config-client', 'dev', '0.0.1', 'message', 'hello spring');
INSERT INTO spring_cloud.tbl_config_property(created_at, application, profile, label, key, value) VALUES(NOW(), 'spring-cloud-config-client', 'dev', 'latest', 'message', 'hello cloud');
INSERT INTO spring_cloud.tbl_config_property(created_at, application, profile, label, key, value) VALUES(NOW(), 'spring-cloud-config-client', 'prd', 'latest', 'message', 'hello config');

Spring Cloud Config server 구현

  • 의존성 설정
ext {
	set('springCloudVersion', "Hoxton.SR4")
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

dependencies {
	// spring cloud config server 의존성
	implementation 'org.springframework.cloud:spring-cloud-config-server'

	// postgresql 의존성
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
	compile 'org.postgresql:postgresql'
}
  • application.yml 설정 (resources 폴더 아래에 위치)
server:
  port: 8081

spring:
  application:
    name: "spring-cloud-config-server"

  profiles:
    active: jdbc

  cloud:
    config:
      server:
        jdbc:
          sql: SELECT key, value FROM spring_cloud.tbl_config_property WHERE APPLICATION=? and PROFILE=? and LABEL=?
          order: 0

  jpa:
    database: POSTGRESQL
    show-sql: true

  datasource:
    hikari:
      connection-timeout: 5000
      maximum-pool-size: 10
    platform: postgres
    url: jdbc:postgresql://{postgresql ip주소}:5432/postgres
    username: postgres
    password: root123!
    driver-class-name: org.postgresql.Driver
    validationQuery: "SELECT 1"
  • 어노테이션 설정
@SpringBootApplication
@EnableConfigServer  //spring cloud config server 서비스를 위한 어노테이션
public class SpringCloudConfigApplication {

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

}
  • 실행 후 구성정보 조회 api 호출
    • db 내용을 변경한 후에, api 재호출하면 변경된 구성정보가 나타난다.

Spring Cloud Config Client 구현

  • 의존성 설정
ext {
	set('springCloudVersion', "Hoxton.SR4")
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

dependencies {
	// spring cloud config 의존성
	implementation('org.springframework.cloud:spring-cloud-starter-config')
	
	// spring actuator 의존성
	implementation('org.springframework.boot:spring-boot-starter-actuator')
}
  • bootstrap.yml 설정 (resources 폴더 아래에 위치)
    • bootstrap.yml은 application.yml보다 먼저 참조되기 때문에 여기에다가 환경 설정 내용을 작성하는 것이다.
server:
  port: 8082

spring:
  application:
    name: spring-cloud-config-client
  cloud:
    config:
      profile: dev  # 서비스가 실행될 profile
      label: 0.0.1  # 서비스가 실행될 label
      uri: http://localhost:8081  # spring cloud config server 위치
  • application.yml 설정 (resources 폴더 아래에 위치)
# /actuator/refresh를 위해 추가
management:
  endpoints:
    web:
      exposure:
        include: "refresh"
  • 구성정보 연결 객체 작성
@RefreshScope  // refresh로 데이터 로드하기 위한 어노테이션
@Component
@Getter
@Setter
public class MessageProperty {

    @Value("${message}")
    private String message;
}
  • controller 작성
@RestController
public class MessageController {

    private final MessageProperty serviceConfig;

    public MessageController(MessageProperty serviceConfig) {
        this.serviceConfig = serviceConfig;
    }

    @GetMapping("/message")
    String message() {
        return serviceConfig.getMessage();
    }
}
  • 실행 후 /message api 호출
    • db 내용을 변경한 후에, api를 재호출하면 변경된 구성정보가 나타나지 않는다.
    • /actuator/refresh를 POST로 호출
      curl -X POST http://localhost:8082/actuator/refresh
    • /message api를 재호출하면 변경된 구성정보가 나타난다.

구성정보 암호화

Spring Cloud Config 사용시 고려사항

  • @RefreshScope를 통해서 동적으로 로드 되는 구성정보는 사용자가 정의한 구성정보만 해당된다. 즉, Spring Data를 통한 데이터베이스 설정 등은 /actuator/refresh, @RefreshScope를 이용하여 동적 로드 할 수 없다.
  • Spring Cloud Config를 사용하려면, 구성정보를 제공하는 서버가 실행되어야하므로 추가적인 서버 resource or 단독 서버/VM 필요
  • Spring Cloud Config server가 monolithic한 장애지점이 될 수 있다.
  • DB에 저장되어 있는 구성정보가 변경되면, 클라이언트의 /actuator/refresh api를 1회 호출해야 구성정보가 업데이트 된다. 클라이언트가 많다면, 클라이언트 수만큼 api를 호출해야하는 문제가 있다.
    • 유레카와 같은 서비스 디스커버리 기법을 이용하여 해당 문제를 해결한다고 한다.

별첨

여러 구성정보 관리 오픈소스

### 참고자료 - 스프링 마이크로서비스 코딩 공작소: https://books.google.co.kr/books?id=VACDDwAAQBAJ&printsec=frontcover&hl=ko#v=onepage&q&f=false - 스프링 - Spring Cloud Config 예제: https://yaboong.github.io/spring-cloud/2018/11/25/spring-cloud-config/
profile
Yes, Code Wins Arguments!!

0개의 댓글