Spring Cloud Config — 분산 환경에서 설정을 중앙 관리하는 방법
서비스가 10개인데, DB 비밀번호를 바꿔야 한다면 10개 서비스를 모두 다시 배포해야 할까요?
마이크로서비스 환경에서 각 서비스가 자체 설정을 관리하면, 설정 변경마다 모든 서비스를 재배포해야 합니다. Spring Cloud Config는 설정을 중앙 서버에서 관리하고, 재배포 없이 런타임에 설정을 변경할 수 있게 해줍니다.
Spring Cloud Config란
Spring Cloud Config는 분산 환경에서 애플리케이션 설정을 중앙에서 관리하는 서버-클라이언트 구조입니다.
- Config Server: 설정 파일을 저장하고 제공하는 서버
- Config Client: Config Server에서 설정을 가져오는 각 서비스
Config Server 구성
의존성
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
서버 설정
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
# application.yml (Config Server)
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/my-org/config-repo
default-label: main
search-paths: '{application}' # 애플리케이션별 디렉토리
clone-on-start: true # 시작 시 clone
Git 저장소 구조
config-repo/
├── application.yml # 모든 서비스 공통 설정
├── order-service/
│ ├── application.yml # order-service 기본 설정
│ └── application-prod.yml # order-service 운영 설정
├── payment-service/
│ ├── application.yml
│ └── application-prod.yml
└── user-service/
├── application.yml
└── application-prod.yml
설정 조회 API
Config Server는 REST API로 설정을 제공합니다.
GET /{application}/{profile}
GET /{application}/{profile}/{label}
예시:
GET /order-service/prod→ order-service의 prod 프로파일 설정GET /order-service/prod/main→ main 브랜치의 설정
Config Client 구성
의존성
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
클라이언트 설정
# application.yml (각 서비스)
spring:
application:
name: order-service # Config Server에서 이 이름으로 설정을 찾음
config:
import: configserver:http://localhost:8888
cloud:
config:
fail-fast: true # Config Server 연결 실패 시 즉시 종료
retry:
initial-interval: 1000
max-attempts: 5
서비스가 시작되면 Config Server에서 order-service의 설정을 가져와 로컬 설정과 병합합니다.
@RefreshScope — 재배포 없이 설정 갱신
Config Server의 설정이 변경되었을 때, 클라이언트가 재배포 없이 최신 설정을 반영하려면 @RefreshScope를 사용합니다.
@RestController
@RefreshScope // refresh 시 빈이 재생성됨
public class FeatureController {
@Value("${feature.new-ui-enabled:false}")
private boolean newUiEnabled;
@Value("${app.notification.email:admin@example.com}")
private String notificationEmail;
@GetMapping("/feature-flags")
public Map<String, Object> getFeatureFlags() {
return Map.of(
"newUiEnabled", newUiEnabled,
"notificationEmail", notificationEmail
);
}
}
설정 갱신 트리거
# Actuator의 refresh 엔드포인트 호출
curl -X POST http://order-service:8080/actuator/refresh
이 요청이 들어오면 @RefreshScope 빈이 소멸 후 재생성되며, Config Server에서 최신 설정을 다시 주입합니다.
# Actuator 설정 (클라이언트)
management:
endpoints:
web:
exposure:
include: refresh, health
Spring Cloud Bus — 전체 인스턴스 일괄 갱신
서비스 인스턴스가 여러 개라면 각각에 refresh를 호출하는 것은 번거롭습니다. Spring Cloud Bus를 사용하면 메시지 브로커를 통해 모든 인스턴스에 설정 변경을 전파할 수 있습니다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId> <!-- RabbitMQ -->
</dependency>
# 한 번의 요청으로 모든 인스턴스에 전파
curl -X POST http://any-instance:8080/actuator/busrefresh
[Config Server] → Git 변경 감지
↓
[/actuator/busrefresh 호출]
↓
[RabbitMQ] → 이벤트 전파
↓
[order-service-1] [order-service-2] [order-service-3]
(설정 갱신) (설정 갱신) (설정 갱신)
Git Webhook 자동화
Git 저장소에 Webhook을 설정하면, 설정 파일이 push될 때 자동으로 busrefresh가 트리거됩니다.
Git Push → Webhook → /monitor 엔드포인트 → Bus 이벤트 → 전체 인스턴스 갱신
암호화/복호화
DB 비밀번호, API 키 같은 민감한 설정을 암호화하여 저장할 수 있습니다.
대칭 키 설정
# Config Server
encrypt:
key: my-secret-encryption-key
암호화 API 사용
# 암호화
curl -X POST http://config-server:8888/encrypt -d "db-password-123"
# → 682bc583f4641332b5bb3e7...
# 복호화
curl -X POST http://config-server:8888/decrypt -d "682bc583f4641332b5bb3e7..."
# → db-password-123
설정 파일에 암호화된 값 사용
# Git 저장소의 설정 파일
spring:
datasource:
password: '{cipher}682bc583f4641332b5bb3e7...'
{cipher} 접두사가 있는 값은 Config Server가 클라이언트에 전달할 때 자동으로 복호화합니다.
Vault 백엔드
더 강력한 시크릿 관리가 필요하면 HashiCorp Vault를 백엔드로 사용할 수 있습니다.
spring:
cloud:
config:
server:
vault:
host: vault.example.com
port: 8200
scheme: https
authentication: TOKEN
token: s.my-vault-token
Vault는 Git과 달리 시크릿의 자동 만료, 동적 생성, 접근 감사 등 엔터프라이즈급 기능을 제공합니다.
프로파일별 설정 전략
# application.yml (기본, 모든 환경)
app:
name: order-service
log-level: INFO
# application-dev.yml (개발)
spring:
datasource:
url: jdbc:h2:mem:devdb
# application-prod.yml (운영)
spring:
datasource:
url: jdbc:mysql://prod-db:3306/orders
password: '{cipher}...'
클라이언트의 spring.profiles.active에 따라 적절한 설정이 반환됩니다.
실무 팁
- Config Server는 ** 고가용성 **을 위해 최소 2대 이상 운영하세요
fail-fast: true+retry설정으로 Config Server 장애 시 서비스 시작 실패를 방지하세요- 민감한 설정은 반드시 ** 암호화 **하거나 Vault 를 사용하세요
- 설정 변경 이력을 Git으로 관리하면 누가, 언제, 무엇을 변경했는지 추적할 수 있습니다
@RefreshScope는 ** 자주 변경되는 설정 **에만 사용하세요 (DB 커넥션 풀 등 무거운 빈에는 주의)
주의할 점
1. Config Server에 연결할 수 없으면 서비스 자체가 시작되지 않는다
fail-fast: true를 설정하면 Config Server 장애 시 서비스가 즉시 종료됩니다. 이 설정 없이도 설정값을 받아오지 못하면 빈 생성 실패로 이어질 수 있습니다. retry 설정을 함께 사용하고, Config Server의 고가용성을 반드시 확보하세요.
2. @RefreshScope 빈이 재생성될 때 일시적으로 요청 처리가 지연될 수 있다
/actuator/refresh를 호출하면 @RefreshScope 빈이 소멸 후 재생성됩니다. 이 과정에서 해당 빈을 사용하는 요청은 빈이 재생성될 때까지 대기하게 됩니다. DB 커넥션 풀이나 무거운 초기화 로직이 있는 빈에 @RefreshScope를 붙이면 갱신 시 서비스 지연이 발생할 수 있습니다.
3. Git 저장소에 평문 비밀번호를 저장하면 보안 사고로 이어진다
Config Server가 Git 기반이므로 설정 파일의 이력이 모두 남습니다. 평문 비밀번호를 커밋하면 나중에 삭제해도 Git 히스토리에 남아 있습니다. 민감한 값은 반드시 {cipher} 암호화를 사용하거나 Vault 같은 시크릿 관리 도구를 연동하세요.
정리
- Spring Cloud Config는 Git 저장소 기반의 중앙 설정 관리 서버입니다
@RefreshScope로 ** 재배포 없이** 설정을 런타임에 갱신할 수 있습니다- Spring Cloud Bus 를 사용하면 한 번의 요청으로 모든 인스턴스에 설정 변경을 전파합니다
- 민감한 설정은
{cipher}암호화 또는 Vault 로 보호합니다