Spring Cloud Config Server는 분산 시스템에서 구성 파일을 중앙에서 관리하고 동적으로 업데이트할 수 있도록 해주는 중요한 도구입니다. 이는 애플리케이션이 여러 환경에서 일관성 있게 실행될 수 있도록 구성 관리 문제를 해결합니다. 여기서 Spring Cloud Config Server를 사용하는 이유와 장단점을 살펴보겠습니다.
장점
- 중앙화된 설정 관리: 여러 애플리케이션의 설정을 한 곳에서 관리할 수 있어, 설정 파일의 중복을 줄이고 일관성을 유지할 수 있습니다.
- 환경별 설정 관리: 로컬, 개발, 테스트, 프로덕션 등 환경별로 설정을 구분하여 관리할 수 있으며, 이를 통해 각 환경에 맞는 설정을 쉽게 적용할 수 있습니다.
- 실시간 설정 변경 반영: Spring Cloud Bus 또는 Actuator와 연계하여, 애플리케이션을 재시작하지 않고도 실시간으로 설정 변경을 반영할 수 있습니다.
- 버전 관리 시스템과의 연동: Git, SVN 등 버전 관리 시스템을 통해 설정 파일을 관리할 수 있어, 설정 변경 내역을 추적하고 롤백할 수 있습니다.
- 구성의 일관성: 여러 서비스가 동일한 설정을 참조할 수 있어, 복잡한 마이크로서비스 아키텍처에서도 설정의 일관성을 유지할 수 있습니다.
- 보안: 민감한 정보(예: 데이터베이스 비밀번호)를 외부 저장소에 저장하고 암호화된 상태로 관리할 수 있어, 보안성도 강화됩니다.
단점
- 복잡도 증가:
중앙 집중식 설정 서버를 도입하면서 추가적인 서버 관리가 필요하며, 네트워크 장애가 발생할 경우 구성 파일을 가져오는 데 어려움이 있을 수 있습니다. - 성능 문제:
구성 서버에 다수의 마이크로서비스가 연결될 경우 요청이 몰리면서 성능 저하가 발생할 수 있습니다. 이를 해결하기 위해 캐싱과 같은 최적화가 필요합니다. - 의존성 증가:
구성 서버가 다운되거나 접근할 수 없을 때 애플리케이션이 설정을 가져오지 못해 문제가 발생할 수 있습니다. 이를 대비하여 로컬 캐시 전략을 사용하는 것이 필요합니다. - 보안 문제:
설정 파일에 보안 정보가 포함되어 있을 경우, 관리 및 보안에 신경을 많이 써야 합니다. 이를 위해 암호화와 보안 인증이 필요합니다.
Spring Cloud Config 설정 파일 우선순위
1.Spring Boot 내부 우선순위 규칙: Spring Boot는 기본적으로 여러 application.yml 파일을 다양한 프로파일, 위치, 소스에서 읽어들이며, 이 파일들은 Spring Boot의 기본 우선순위 규칙에 따라 적용됩니다. 이 우선순위는 다음과 같습니다.
- 명령줄 인수 (Command Line Arguments): 가장 높은 우선순위를 가집니다. 예를 들어, --spring.profiles.active=prod와 같은 인수로 프로파일을 지정하면 다른 설정보다 우선됩니다.
- JVM 시스템 프로퍼티: -Dspring.profiles.active=prod와 같은 방식으로 JVM 시스템 프로퍼티로 설정한 값이 반영됩니다.
- 운영체제 환경 변수: SPRING_PROFILES_ACTIVE=prod와 같이 환경 변수를 통해 설정된 값이 반영됩니다.
- application.yml (외부): 외부 위치에서 제공되는 application.yml 파일이 우선적으로 사용됩니다. 예를 들어, JAR 파일 외부에서 /config/ 디렉터리나 동일한 디렉터리에 있는 설정 파일이 내부 파일보다 우선됩니다.
- application.yml (내부): JAR 파일 내부에 포함된 설정 파일이 가장 낮은 우선순위를 가집니다.
2.Git 서버 설정 vs. 로컬 설정: Spring Cloud Config에서 application.yml에 Git 저장소와 로컬 파일 설정을 함께 사용할 때의 우선순위는 spring.config.import 속성에서 정의한 순서에 따라 달라집니다. 예를 들어
spring:
config:
import:
- configserver:http://localhost:8888 # Git 서버
- classpath:/config/ # 로컬 파일
이 경우, Git 서버에서 가져온 설정이 먼저 적용되고, 그 후에 로컬 파일의 설정이 덮어씌워집니다. 반대로 우선순위를 변경하고 싶다면, 순서를 바꾸면 됩니다.
spring:
config:
import:
- classpath:/config/ # 로컬 파일
- configserver:http://localhost:8888 # Git 서버
위와 같은 설정일 경우 로컬 파일이 먼저 적용되고, Git 서버의 설정이 그 위에 덮어씌워집니다.
3.프로파일 우선순위: 활성화된 프로파일(spring.profiles.active)에 따라 우선순위가 달라집니다. 예를 들어, application.yml과 application-dev.yml이 함께 있을 때 dev 프로파일이 활성화되면, application-dev.yml이 기본 설정을 덮어씁니다. Git 서버에서도 동일한 방식으로, 활성화된 프로파일에 해당하는 설정 파일이 더 우선시됩니다.
4.특수 설정 (spring.config.import): spring.config.import에 여러 설정 소스를 나열했을 때, 나열한 순서대로 각 설정 소스를 적용합니다. 따라서, 첫 번째 소스가 없으면 두 번째 소스로 이동하고, 설정이 겹치면 나중에 적용된 소스가 덮어씌우게 됩니다
예시
- JVM 시스템 프로퍼티가 db.url을 jdbc:mysql://localhost:3306/prod로 설정한 경우, 이 값이 최우선으로 적용됩니다.
- 운영체제 환경변수에 db.url=jdbc:mysql://localhost:3306/staging이 설정되어 있으면, JVM 시스템 프로퍼티가 없는 경우 이 값이 사용됩니다.
- application.yml에서 db.url을 jdbc:mysql://localhost:3306/dev로 설정한 경우, 운영체제 환경변수나 JVM 프로퍼티가 적용되지 않는 상황에서 이 값이 사용됩니다.
- spring.config.import로 설정된 경우, 나열된 순서에 따라 나중에 로드된 설정의 값이 최종적으로 적용됩니다.
.
정리
따라서, 같은 키값이 여러 설정 소스에 있을 때는 후순위로 적용된 값이 최종적으로 사용되며, JVM 시스템 프로퍼티와 운영체제 환경변수가 가장 높은 우선순위를 가집니다.
Spring Cloud Config Server 설정하기
1. GitHub Repository 생성하기
2. Config Server 구성하기
3. Config Client 구성하기
1. GitHub Repository 생성하기
Private로 설정하면 ssh 설정과 토큰등 설정이 필요하기에 간단하게 Public 으로 생성하였습니다.
파일을 이름을 만드는 형식으로는 {name}-{profile}.yml 와 같이 생성한다. http://localhost:8888/application/local 이 url이 뜻하는 값이 application-local.yml 의 값을 가져와줘의 뜻처럼 나는 name= application , profile={local,dev, default} 로 만들었다.
위와같이 profile이 없는경우는 http://localhost:8888/application/default 로 호출하면 application.yml (기본 설정 파일)이 호출이 될것이다.
- application.yml (기본 설정 파일)
- application-dev.yml (개발 프로파일에 대한 설정)
- application-prod.yml (프로덕션 프로파일에 대한 설정)
- application-local.yml (로컬 프로파일에 대한 설정)
2. Config Server 구성하기
Spring Boot 3.3.3 으로 만들었고 JDK 17 을 사용하였습니다.
의존성 Actuator(Spring Cloud Refresh 사용 위함), Config Server 추가하여 만듭니다.
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/yongjooMoon/config.git # Git 저장소 URL
search-paths: "" # 설정 파일이 루트 디렉터리에 있으면 빈 문자열로 설정
default-label: main # 가져올 branch 설정
clone-on-start: true # 서버 시작 시 Git에서 파일을 가져옴
server:
port: 8888
management:
endpoints:
web:
exposure:
include: "*" # 모든 Actuator 엔드포인트 노출
Config Server 의 기본 포트는 8888으로 사용합니다.
위와 같이 git.url 정보에 생성한 repository 의 url을 작성하고 경로와 브랜치를 정해주시면 git 연결은 끝납니다.
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
다음은 application 파일을 열고 @EnableConfigServer 추가해줍니다. Config Server 라고 선언함으로서 서버 설정이 끝입니다.
서버를 가동하고
http://localhost:8888/application/local
url에 입력하면 아래와 같이 화면에 호출됩니다.
위에서 말했듯이 default로 선언된 application.yml과 profile이 local인 application-local.yml이 호출된걸 알수있습니다.
이로서 서버 설정은 끝이납니다.
#url : http://localhost:8888/application/local
{
"name": "application",
"profiles": [
"local"
],
"label": null,
"version": "b54b069930ab6ccc7a4400a076afd800ed38e316",
"state": null,
"propertySources": [
{
"name": "https://github.com/yongjooMoon/config.git/application-local.yml",
"source": {
"jwt.key": "5IVb9J0LeHpbqTQe25jUUAjtrSwFEHGJ5XIs9+1JcKI=",
"upload.path": "D:\\File",
"test": "test"
}
},
{
"name": "https://github.com/yongjooMoon/config.git/application.yml",
"source": {
"jwt.key": "5IVb9J0LeHpbqTQe25jUUAjtrSwFEHGJ5XIs9+1JcKI=",
"upload.path": "D:\\File"
}
}
]
}
3. Config Client 구성하기
Config Server와 마찬가지로 Actuator를 설정하고 Config Client를 의존성으로 생성합니다.
spring:
application:
name: user-service
profiles:
active: local
config:
import: configserver:http://localhost:8888 # Config Server URL
management:
endpoints:
web:
exposure:
include: "*" # 모든 Actuator 엔드포인트 노출
config.import 에 config server의 url 정보를 장성하여 연결을 해줍니다.
profiles.active 에 local로 설정, application-local.yml의 config 정보를 가져옵니다.
@RefreshScope
public class TestController {
@Value("${jwt.key}")
private String SECRET_KEY;
@Value 값으로 config에 설정됨 값을 가져옵니다.
config에 값이 변경된 경우 서버를 재가동해야만 config의 변경된 값을 가져옵니다.
Actuator 의존성을 생성하고 application.yml 에 설정한 endpoint include 값을 "*" 지정함으로서 refresh 명령어를 인식하여 사용할수 있습니다.
@RefreshScope를 선언 http://localhost:9002/actuator/refresh 을 postman 또는 cmd 창에서 curl -X POST http://localhost: 9002/actuator/refresh 호출해주면 config를 바라보는 scope가 refresh되면서 변경된 값으로 가져올수 있습니다.
테스트
위와 같이 test의 값은 test로 되어있습니다.
@RefreshScope
public class LoginController {
@Value("${test}")
private String test;
@PostMapping("/test")
public ResponseEntity<Map<String, Object>> test(@RequestBody test test ,HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("test == " + test );
실제로 client를 가동하여 로그를 찍었을때 test의 값은 test로 나옵니다.
config test의 값을 test1로 변경하였으나 여전히 test가 나오는 모습입니다. 위에서 언급했듯이 변경된값을 가져오려면 client 서버를 재가동하거나 curl -X POST http://localhost:9002/actuator/refresh 호출합니다.
따로 세팅을 안해놨기에 fail로 return 되었습니다. 설정해놓은 값이 없기에 위처럼 나왔지만 정상적으로 refresh가 작동한것입니다.
이렇게 config의 server와 client 설정을 알아보았습니다.
Spring Cloud Config 의 치명적인 단점이 있는데 config의 설정이 바뀌면 msa환경에서 연결된 client 모두 /actuator/refresh 를 호출을 해야한다는점!!!
이런점을 보완하고자 나온 Spring Cloud Bus가있습니다.
Spring Cloud Config Server 설정하기1(Spring Cloud Config)
Spring Cloud Config Server 설정하기2(Spring Cloud Bus)
'WEB > Spring' 카테고리의 다른 글
Spring Cloud Config Server 설정하기2(Spring Cloud Bus) (0) | 2024.09.23 |
---|---|
Spring Boot JWT(JSON Web Token) 설정하기 (1) | 2024.09.05 |
Spring Boot AOP 적용 방법(Log, Transaction) (4) | 2024.09.03 |
Spring Boot로 MSA 개발하기 (5) | 2024.08.30 |
스프링 IOC컨테이너 - DI, DL (0) | 2024.03.23 |