이번 글에서는 Spring Cloud Config Client를 사용하여 Config Server로부터 설정 값을 가져오고, 동적으로 반영하는 방법을 다룹니다.
해당 글에는 Spring Cloud Config Server 세팅을 전제로 진행합니다.
Spring Cloud Config Server를 활용하여 HashiCorp Vault와 연동 과정은 이전 블로그 내용에서 확인 가능합니다.
1. Spring Cloud Config Client 구성
Spring Cloud Config Client는 Config Server에서 중앙 집중식으로 관리되는 설정 값을 가져오는 역할을 합니다.
즉, Client Application은 직접 Vault에 접근하는 것이 아니라 Config Server를 통해 보안 설정을 받아오게 되는 것! 입니다.
Client 구성 및 Client에서 Vault KV 값을 가져오는 워크플로우는 다음과 같습니다.
- Client 프로젝트에 spring.config.import 설정을 추가하여 Config Server에서 값을 가져오도록 설정합니다.
- Client 프로젝트는 Config Server를 통해 Vault에 저장된 KV 값을 가져오게 됩니다.
- 클라이언트에서 다음과 같은 테스트 진행합니다.
- @ConfigurationProperties를 활용하여 바인딩하여 사용하도록 코드 작성
- ContextRefresher.refresh()를 활용하여 Vault에서 설정 값이 변경되면 자동으로 반영될 수 있도록 코드 작성
1-1) Gradle 의존성 (dependencies 설정)
Gradle 기반의 Spring Boot 프로젝트를 생성하고, build.gradle.kts에 아래와 같이 의존성을 추가합니다.
dependencies {
// Spring Cloud Config Client
implementation("org.springframework.cloud:spring-cloud-starter-config")
// Kotlin 필수 설정
implementation("org.jetbrains.kotlin:kotlin-reflect")
// TEST
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
- implementation("org.springframework.cloud:spring-cloud-starter-config")
- Spring Cloud Config Client를 사용하기 위한 필수 라이브러리
- 클라이언트가 spring.config.import 설정을 통해 Config Server에서 설정을 가져올 수 있도록 지원
2-2) Client 애플리케이션 코드 작성
(1) 애플리케이션 시작 파일을 작성합니다.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.scheduling.annotation.EnableScheduling
@SpringBootApplication
@EnableScheduling
class KotlinGradleVaultApplication
fun main(args: Array<String>) {
runApplication<KotlinGradleVaultApplication>(*args)
}
- Spring Boot 애플리케이션을 실행하는 main 클래스로 @EnableScheduling을 추가하여 Config Server로 부터 받은 Vault 값 변경을 주기적으로 감지할 수 있도록 설정합니다.
(2) Spring Cloud Config Server를 통해 가져온 Vault의 KV 값을 Spring에서 사용하기 위한 코드를 작성합니다.
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.cloud.context.config.annotation.RefreshScope
import org.springframework.stereotype.Component
@RefreshScope
@Component
@ConfigurationProperties(prefix = "")
data class VaultConfigProperties(
var db_url: String = "",
var username: String = "",
var password: String = ""
)
- @ConfigurationProperties(prefix = "")
- Config Server에서 가져온 속성 값을 매핑하는데 사용됩니다.
- Prefix를 비워둠으로써 ("") 모든 속성을 자동으로 바인딩할 수 있도록 설정합니다.
- 예를 들어, db_url, username, password 등의 키를 따로 설정할 필요 없이 Config Server에서 내려주는 모든 값을 객체에 매핑됩니다.
- @Component
- Spring에서 빈(Bean)으로 등록하여 다른 클래스에서 VaultConfigProperties를 주입받아 사용 가능하도록 설정합니다.
- @RefreshScope
- Vault에서 값이 변경될 경우, Spring Context가 자동으로 갱신되도록 설정합니다.
- 이를 통해 ContextRefresher.refresh()를 호출하면, 최신 설정 값이 자동으로 반영됩니다. 예를 들어, Vault에서 새로운 db_url 값이 업데이트되면, 해당 변경 사항이 반영됨
- Vault에서 값이 변경될 경우, Spring Context가 자동으로 갱신되도록 설정합니다.
즉, 위와 같이 코드를 짜면 VaultConfigProperties의 필드명이 Config Server에서 내려오는 키와 동일하다면, 자동으로 매핑되어 애플리케이션에서 사용할 수 있게 됩니다.
VaultConfigProperties는 @Component로 등록된 Bean이기 때문에, 다른 클래스에서 의존성 주입(@Autowired) 을 통해 쉽게 사용할 수 있습니다.
(3) Spring Boot 애플리케이션이 시작될 때 Config Server에서 정보를 가져온 변수(Vault KV값)를 출력할 수 있는 테스트 코드를 작성합니다.
import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component
@Component
class VaultConfigRunner(private val vaultConfigProperties: VaultConfigProperties) : CommandLineRunner {
override fun run(vararg args: String?) {
println("🔥🔥🔥 VaultConfigRunner : 최초 Vault KV 확인!!!")
println("🔹 최초 db_url: ${vaultConfigProperties.db_url}")
println("🔹 최초 username: ${vaultConfigProperties.username}")
println("🔹 최초 password: ${vaultConfigProperties.password}")
}
}
- class VaultConfigRunner(private val vaultConfigProperties: VaultConfigProperties) : CommandLineRunner
- CommandLineRunner는 Spring Boot 애플리케이션이 실행될 때 자동으로 실행되는 기능을 제공하는 인터페이스로 이 코드에서는 Config Server에서 가져온 환경 변수(VaultConfigProperties)를 출력하는 코드입니다.
- CommandLineRunner를 구현하면 run() 메서드 내부의 코드가 애플리케이션이 실행될 때 한 번 실행됩니다.
- VaultConfigProperties는 위에서 미리 작성한 클래스로 Config Server에서 가져온 Vault의 값이 자동으로 매핑됩니다.
- VaultConfigProperties를 생성자 주입하여, run() 메서드에서 사용 가능하도록 작성합니다.
- 즉, Config Server에서 가져온 Vault의 설정 값인 db_url, username, password 값을 vaultConfigProperties를 통해 접근할 수 있습니다.
(4) 클라이언트 애플리케이션이 Vault에서 변경된 설정 값을 자동으로 반영하는 테스트 코드를 작성합니다.
Spring Cloud Context의 ContextRefresher 기능을 활용하여 일정 시간마다 설정 값을 새로고침(refresh) 하도록 구성하였습니다.
Vault 내 KV 값이 변경되면 자동으로 반영되는 구조를 구현하는 것을 테스트하기 위한 목적입니다.
import org.springframework.cloud.context.refresh.ContextRefresher
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
@Component
class VaultConfigRefresher(
private val contextRefresher: ContextRefresher,
private val vaultConfigProperties: VaultConfigProperties
) {
@Scheduled(fixedRate = 60000)
fun refreshVaultConfig() {
println("🔄 [Vault Config] Refreshing...")
println("🔄 Vault의 KV의 내용이 변했는지 확인 중...")
try {
val updatedKeys = contextRefresher.refresh()
println("✅ [Vault Config] Refreshed! 변경된 키: $updatedKeys")
} catch (e: Exception) {
println("❌ [Vault Config] Refresh failed. Config Server might be down.")
e.printStackTrace()
}
// 최신 값 출력
printCurrentConfig("📌 [Updated Vault Config]")
}
private fun printCurrentConfig(header: String) {
println(header)
println("🔹 db_url: ${vaultConfigProperties.db_url}")
println("🔹 username: ${vaultConfigProperties.username}")
println("🔹 password: ${vaultConfigProperties.password}")
}
}
- ContextRefresher
- Spring Cloud에서 제공하는 기능으로, Config Server에서 최신 설정 값을 다시 불러와 애플리케이션 컨텍스트를 갱신(refresh)할 수 있도록 지원합니다.
- 이를 활용하면 수동으로 서버를 재시작하지 않아도 변경된 값을 반영할 수 있습니다.
- @Scheduled(fixedRate = 60000)
- 애플리케이션이 실행된 후 60초마다 해당 메서드가 실행되며 설정 값을 확인합니다.
- contextRefresher.refresh()
- Config Server에서 최신 설정 값을 다시 불러오고, Vault에서 변경된 내용이 있으면 자동으로 업데이트 합니다.
- updatedKeys는 실제로 변경된 속성 키 목록을 반환합니다.
- 변경된 값이 있으면 updatedKeys 리스트에 해당 키들이 출력됩니다.
- 변경 사항이 없으면 빈 리스트 []가 반환됩니다.
- 예외 발생 시, "❌ Refresh failed." 메시지와 함께 오류 내용을 출력하여 Config Server 연결 상태를 확인할 수 있도록 처리했습니다.
2-3) application.yml 설정
server:
port: 8081
spring:
application:
name: spring
config:
import: "optional:configserver:http://localhost:8888"
cloud:
config:
profile: dev
- server.port: 8081
- Spring Cloud Config Client가 포트 8081에서 실행됩니다.
- spring.application.name: spring
- spring.application.name은 Config Server에서 설정 값을 가져올 때 사용되는 식별자입니다.
- Config Server의 Vault에서 spring/dev 경로에 있는 설정을 가져오게 됩니다. (profile: dev 설정과 함께 사용됨)
- spring.config.import: "optional:configserver:http://localhost:8888"
- Config Server에서 설정 값을 가져오도록 Config Server 정보를 기입합니다.
- "configserver:http://localhost:8888"를 지정하면, 클라이언트는 http://localhost:8888에서 설정 값을 가져옵니다.
- optional을 사용하여 Config Server가 응답하지 않으면 Client 애플리케이션 실행이 중단되지 않도록 설정합니다.
- Config Server가 일시적으로 다운되거나 사용 불가능한 경우에도 애플리케이션이 정상적으로 실행되도록 설정
- Config Server에서 설정 값을 가져오도록 Config Server 정보를 기입합니다.
- spring.cloud.config.profile: dev
- Config Server에서 dev 프로필을 가져오도록 지정합니다.
- Config Server의 Vault에서 spring/dev 경로의 값을 불러오게 됩니다.
- 예를 들어, Vault의 KV 엔진에서 spring-config-kv/spring/dev에 저장된 설정 값을 가져옵니다.
- Config Server에서 dev 프로필을 가져오도록 지정합니다.
2. 코드 실행 결과 확인
- ./gredlew clean bootRun 명령어를 통해 Config Client를 실행합니다.
- 초기 실행 시점에서 Vault에 저장된 값이 정상적으로 출력을 확인할 수 있습니다.

2-1) Vault에서 KV 값 변경 후 자동 갱신 확인
- 먼저 저장된 KV값을 변경합니다.
- 필자의 경우 Vault UI를 통해 변경했지만, Vault CLI 명령어를 통해 변경도 가능합니다.

- 변경된 값이 자동으로 반영됨을 확인

- ContextRefresher.refresh()가 실행되면서 변경된 설정 값이 자동 반영됨을 확인할 수 있습니다.
- [Updated Vault Config]에서 변경된 값이 출력됩니다.
개인 정리
Spring Cloud Config Client가 Config Server를 통해 Vault의 KV 값을 가져오는 테스트 과정 요약을 하자면...
- Spring Cloud Config Client가 실행되면서 Config Server에서 값을 가져옴
- @ConfigurationProperties를 활용하여 값 매핑
- ContextRefresher.refresh()를 통해 변경 사항을 자동 감지 및 반영
이번 Spring Cloud Config Server와 Vault 연동을 진행하면서 스프링을 비교적 많이 다룰 일이 없었음에도 불구하고, Vault의 유즈케이스 테스트를 통해 자연스럽게 Spring Cloud Config의 구조와 동작 원리를 간단하게나마 경험함.
특히, Vault에 저장된 환경별(dev, prod 등) 설정을 어떻게 구성할지 먼저 설계하는 것이 중요할 것 같고...만약 운영 단에서 해당 구조로 사용을 한다면 Vault의 KV 마운트 경로, 키 경로 설정을 보다 체계적으로 구성하는 것이 장기적인 유지보수와 확장성 면에서 굉장히 중요할 것으로 판단됨
또한, ContextRefresher.refresh()를 활용하여 변경 사항을 실시간으로 반영할 수 있도록 구성하는 방식이 꽤 유용 한듯
애플리케이션이 실행될 때 Config Server를 통해 Vault의 KV 값을 전달받고, 이후에는 그 당시의 값을 계속 유지한다는 점이 존재하고, Vault의 KV 값이 변경되더라도 실행 중인 애플리케이션에서는 초기 실행 시점의 값이 바뀌지 않는 문제가 존재...
하지만 애플리케이션의 재기동 없이 해당 값만 바꾸어 바로 서비스를 유지해야 애플리케이션의 경우 ContextRefresher.refresh() 기능을 활용해도 괜찮을 것 같다... 물론 나는 전문적인 개발자가 아니여서... 장담은 no....
'Vault > Spring' 카테고리의 다른 글
[Vault] (Spring Cloud Config - 3 ) Client에서 Config 변경 사항 반영 방안 정리 (1) | 2025.03.16 |
---|---|
[Vault] (Spring Cloud Config - 1 ) Server + Vault 연동하기 (2) | 2025.03.12 |
[Spring boot] Visual Studio Code JVM Target 설정 오류 해결하기 (0) | 2025.03.10 |