Spring Cloud Config
정의
- 클라이언트-서버 구조를 통해 여러 마이크로서비스의 외부 설정 정보를 관리할 수 있도록 해주는 기술
- 환경설정 정보를 반환하는 API 서버의 역할을 한다고 보면 된다.
- 해당 기술을 사용한 환경설정 정보용 서버를 Config Server라고 부른다.
- Config Server로부터 환경설정 정보를 받는 쪽은 Config Client라고 부른다.
등장 배경
마이크로서비스라는 것은 서로 다른 개별의 애플리케이션이다.
그런데 마이크로서비스의 종류가 한,두가지면 상관이 없겠지만,
만약 서비스의 종류가 100개가 넘는 대형 프로젝트라면
환경설정 정보가 변동된다면 100개가 넘는 서비스마다 값을 바꿔줘야 할 것이다.
이런 상황에서 등장한 것이 Spring Cloud Config다.
Git이나 SVN, 파일 시스템 등 외부 저장소에 환경설정 정보를 저장하고,
해당 저장소에서 properties나 yaml같은 환경설정 파일을 읽어서,
그 값을 각 마이크로서비스에 전달해준다.
특징
- 중앙 집중식 설정 관리
- 설정 파일을 하나의 장소에 모아 관리한다.
- Git, SVN, 파일 시스템 등이 해당한다.
- 버전 관리
- Git이나 SVN같은 형상 관리 시스템을 통해 설정 변경 이력 관리 가능.
- 동적 설정 반영
- 설정 변경 시 실시간으로 클라이언트에 반영할 수 있다.
- Webhook이나 메시지 브로커를 통해 반영한다.
- Spring Cloud Bus라는 기술을 함께 사용해야 한다.
- 환경별 설정 지원
- application-{profile}.yml 형식으로 다양한 환경에 따른 설정이 가능하다.
- dev, test, prod 등으로 구분한다.
- 암호화/복호화 지원
- 비밀번호나 API 키같은 민감한 정보를 안전하게 저장할 수 있다.
- 물론 저장소 자체의 보안도 신경을 써야 한다.
- 외부 저장소에 저장하는 것은 편리함의 성격이 강하다.
- 보안의 성격도 있긴하지만 편리함이 더 크다.
장점
- 중앙화된 관리
- 하나의 서버에서 모든 설정을 관리할 수 있다.
- 환경별 분리
- dev/test/prod 환경에 맞는 설정 파일을 분리해서 관리할 수 있다.
- 유연한 저장소 연동
- Git, SVN, File System 등 다양한 저장소를 지원한다.
- 자동화 및 지속적 배포 연계
- CI/CD 파이프라인과 통합할 수 있다.
- 실시간 설정 반영
- Spring Cloud Bus와 연계 시 재시작 없이 설정을 반영할 수 있다.
단점
- 의존성 증가
- Config Server에 문제가 생기면 전체 시스템에 영향이 간다.
- 초기 설정 복잡
- 서버/클라이언트 구성 및 Git 연동 등 설정이 복잡할 수 있다.
- 보안 문제
- 민감 정보가 Git에 저장될 경우 유출될 가능성이 존재한다.
- 그래서 암호화가 필수다.
- 성능 이슈
- 대규모 시스템에서는 설정 파일 로딩 시 병목이 발생할 수도 있다.
- 실시간 반영 조건 복잡
- Spring Cloud Bus, RabbitMQ, Kafka 등 추가 구성이 필요하다.
저장소 활용하기
저장소 종류별로 환경설정 파일을 작성하는 방법을 알아보자.
Local Git Repository
로컬 리포지토리에서는 깃 저장소의 주소만 설정하면 된다.
spring:
application:
name: config-service
cloud:
config:
server:
git:
uri: file:///C:/git/cloud_config
default-label: master
Remote Git Repository
리모트 리포지토리에서는 저장소의 주소를 입력하면 된다.
public repository일 때는 이대로 사용하면 되고,
private repository일 때는 username과 password를 함께 명시하면 된다.
spring:
application:
name: config-service
cloud:
config:
server:
git:
uri: 리포지토리_주소
default-label: master
Native File Repository
spring:
application:
name: config-service
cloud:
config:
server:
native:
search-locations: file:///C:/git/cloud_config
관련 속성 설명
spring.cloud.config.server.git.uri
- 저장소의 주소
spring.cloud.config.server.git.username
- 사용자명
spring.cloud.config.server.git.password
- 비밀번호
spring.cloud.config.server.git.default-label
- 브랜치명
- 별도로 설정하지 않으면 main으로 되어 있다.
- 만약에
NoSuchLabelException
터지면 여기가 문제다.
spring.cloud.config.server.native.search-locations
- 폴더 경로
- 끝에 s가 붙은 것을 알 수 있지만 여러 개를 지정할 수 있다.
위 속성들말고도 다양한 속성들이 있다.
파일명 짓기
환경설정 파일명도 규칙에 맞게 지어야 한다.
{애플리케이션명}-{프로파일}.yaml
의 구조로 작성하면 된다.
만약 애플리케이션명이 ecommerce
고 프로파일이 prod
라면,
파일명은 ecommerce-prod.yaml
이 된다.
참고로 첫번째 대시를 기준으로 읽기 때문에
프로파일에도 대시가 들어가도 된다.
대략 ecommerce
라는 앱의 운영 베타버전이면
ecommerce-prod-beta.yaml
이 될 것이다.
Spring Cloud Config 연동 (Config Server)
build.gradle
Config Server용 프로젝트를 생성한 뒤 build.gradle에 아래의 의존성을 추가해주자.
implementation 'org.springframework.cloud:spring-cloud-config-server'
그리고 앞선 프로젝트들처럼 아래의 내용도 함께 추가해주자.
ext {
set('springCloudVersion', "2024.0.1")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
Config Server 역할 부여
이제 @SpringBootApplication
애노테이션이 있는 클래스로 이동해서
@EnableConfigServer
애노테이션을 추가함으로써
해당 프로젝트가 Config Server로 동작하게 하자.
Spring Cloud Bus 연동 (GateWay Service, MicroService)
build.gradle
Config Server랑 연동할 서비스의 build.gradle에 아래의 의존성을 추가해주자.
implementation 'org.springframework.cloud:spring-cloud-starter-config'
Config Server 연동 (스프링 부트 2.4 미만)
스프링 부트 2.4 미만 버전에는 bootstrap.yml
이라는 파일을 통해서
Config Server와 연동했었다. (정확하게는 bootstrap-{profile}.yml)
그래서 아래와 같은 파일을 만들게 되면 Config Server와 연동이 가능했다.
spring:
cloud:
config:
uri: http://localhost:8888
그리고 스프링 부트 2.4에서는 의존성도 하나 더 추가해줘야 한다.
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
의존성을 추가하는 게 아니라 환경설정 파일에
spring.cloud.bootstrap.enabled=true
를 설정해도 된다.
Config Server 연동 (스프링 부트 2.4 이상)
스프링 부트 2.4부터는
application.yml
파일과 bootstrap.yml
파일이
하나로 합쳐졌다.
스프링 부트 2.4부터는 application.yaml
파일에 아래와 같이 설정하면 된다.
spring:
config:
import: optional:configserver:http://127.0.0.1:8888/
참고로 optional
prefix가 없으면 Config Server에 연결할 수 없을 때
애플리케이션이 종료되어 버리니 주의하자.
설정 파일 우선 순위
- 프로젝트의 application.yaml
- 저장소의 application.yaml
- 프로젝트의 application-{profile}.yaml
- 저장소의 {application name}/{application name}-{profile}
참고로 순서대로 읽다가 동일한 키 값이 있으면 덮어씌워지니 주의하자.
공통된 설정 사용
바로 직전의 설정 파일의 우선 순위에 보면,
2번째 순위에 저장소의 application.yaml가 해당하는 것을 볼 수 있다.
그래서 만약 user-service
와 order-service
라는
마이크로서비스가 있다고 가정한다면,
application.yaml 파일 하나를 통해 공통된 설정을 공유할 수 있다.
만약 application.yaml 파일이 없다면
4번째 순위에 해당하는 파일명이 존재해야 한다.
설정 정보 주입하기
값을 실제로 사용하려면 값을 미리 저장할 클래스 및 필드를 정의해야 한다.
아래는 예시용 클래스다.
@Setter
@Getter
@RefreshScope
public class SampleConfig {
@Value("token.secret")
private String secret;
}
@Value
애노테이션을 통해 설정 정보에 있는 값을 읽어 들인다.
그리고 @RefreshScope
가 있으면 Config Server에서 반환하는
설정 정보의 값이 바뀌었을 때 애플리케이션 서버를 재실행한다.
만약 생성자를 사용하고 싶다면 @PostConstructor
애노테이션을 사용해야 한다.
그렇지 않으면 생성자가 먼저 만들어지고,
그 다음에 @Value
를 실행하기 때문에 원하지 않는 동작이 발생할 수 있다.
그리고 @PostConstructor
를 사용하게 되면,
@RefreshScope
가 있어도 서버가 재실행 됬을 때 생성자를 재실행하지는 않는다.
그럴 때는 아래의 코드를 추가해주자.
@EventListener(RefreshScopeRefreshedEvent.class)
public void onRefresh(RefreshScopeRefreshedEvent event) {
// 재실행 관련 내용
}