Spring Cloud Config란
Spring Cloud Config는 마이크로서비스 환경에서 설정을 중앙 집중 관리하는 서버-클라이언트 구조의 프로젝트입니다. 각 서비스에 분산된 application.yml을 Git 리포지토리, Vault, JDBC 등 외부 저장소에서 통합 관리하고, 서비스 재시작 없이 런타임에 설정을 갱신할 수 있습니다.
환경별(dev, staging, prod) 설정 분리, 민감 정보 암호화, 설정 변경 이력 추적이 기본 제공되어, 12-Factor App의 “Config” 원칙을 완벽히 구현합니다.
Config Server 구축
// build.gradle.kts
dependencies {
implementation("org.springframework.cloud:spring-cloud-config-server")
implementation("org.springframework.boot:spring-boot-starter-security")
}
@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/myorg/config-repo
default-label: main
search-paths:
- '{application}' # 서비스별 디렉토리
clone-on-start: true # 시작 시 클론
timeout: 10
# 프라이빗 리포 인증
username: ${GIT_USERNAME}
password: ${GIT_TOKEN}
# 다중 리포지토리
# repos:
# payment:
# pattern: payment-*
# uri: https://github.com/myorg/payment-config
Git 리포지토리 구조:
config-repo/
├── application.yml # 모든 서비스 공통 설정
├── application-prod.yml # 프로덕션 공통
├── order-service/
│ ├── order-service.yml # order-service 기본 설정
│ ├── order-service-dev.yml # 개발 환경
│ └── order-service-prod.yml # 프로덕션
├── payment-service/
│ ├── payment-service.yml
│ └── payment-service-prod.yml
└── user-service/
└── user-service.yml
Config Client 연동
// build.gradle.kts (각 마이크로서비스)
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-config")
implementation("org.springframework.boot:spring-boot-starter-actuator")
}
# application.yml (order-service)
spring:
application:
name: order-service # Config Server에서 이 이름으로 설정 조회
config:
import: "configserver:http://config-server:8888"
cloud:
config:
fail-fast: true # Config Server 연결 실패 시 앱 시작 중단
retry:
initial-interval: 1000
max-interval: 10000
max-attempts: 6
multiplier: 1.5
management:
endpoints:
web:
exposure:
include: refresh, health, info
설정 우선순위 (높은 것이 우선):
| 순위 | 소스 | 예시 |
|---|---|---|
| 1 | 서비스별+프로파일 | order-service-prod.yml |
| 2 | 서비스별 기본 | order-service.yml |
| 3 | 공통+프로파일 | application-prod.yml |
| 4 | 공통 기본 | application.yml |
런타임 설정 갱신: @RefreshScope
서비스 재시작 없이 설정을 변경하는 핵심 기능입니다:
@RestController
@RefreshScope // 이 빈은 /actuator/refresh 호출 시 재생성됨
public class FeatureFlagController {
@Value("${feature.new-checkout:false}")
private boolean newCheckoutEnabled;
@Value("${rate-limit.max-requests:100}")
private int maxRequests;
@GetMapping("/features")
public Map<String, Object> getFeatures() {
return Map.of(
"newCheckout", newCheckoutEnabled,
"maxRequests", maxRequests
);
}
}
# Git에서 설정 변경 후, 개별 서비스에 갱신 요청
curl -X POST http://order-service:8080/actuator/refresh
# 응답: 변경된 프로퍼티 키 목록
["feature.new-checkout", "rate-limit.max-requests"]
Spring Cloud Bus: 전체 서비스 일괄 갱신
서비스 인스턴스가 수십 개일 때 개별 /refresh는 비효율적입니다. Spring Cloud Bus는 메시지 브로커를 통해 모든 인스턴스에 갱신 이벤트를 브로드캐스트합니다:
// build.gradle.kts
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-bus-kafka")
// 또는 spring-cloud-starter-bus-amqp (RabbitMQ)
}
# application.yml
spring:
cloud:
bus:
enabled: true
kafka:
bootstrap-servers: kafka:9092
# Config Server에 한 번만 요청하면 전체 서비스가 갱신됨
curl -X POST http://config-server:8888/actuator/busrefresh
# 특정 서비스만 갱신
curl -X POST http://config-server:8888/actuator/busrefresh/order-service
동작 흐름:
- 1단계: Git에서 설정 파일 수정 → 커밋/푸시
- 2단계:
/actuator/busrefresh호출 (또는 Git Webhook 연동) - 3단계: Config Server가 Kafka/RabbitMQ에 RefreshRemoteApplicationEvent 발행
- 4단계: 모든 서비스 인스턴스가 이벤트 수신 → @RefreshScope 빈 재생성
민감 정보 암호화
Config Server는 대칭키/비대칭키 암호화를 지원합니다:
# Config Server — 대칭키 설정
encrypt:
key: ${ENCRYPT_KEY} # 환경 변수로 주입
# 암호화 API
curl http://config-server:8888/encrypt -d "my-db-password"
# → AQA1b2c3d4e5f6...
# 복호화 API
curl http://config-server:8888/decrypt -d "AQA1b2c3d4e5f6..."
# → my-db-password
Git 리포지토리에 암호화된 값을 저장합니다:
# order-service-prod.yml (Git에 저장)
spring:
datasource:
url: jdbc:postgresql://db-prod:5432/orders
username: order_app
password: '{cipher}AQA1b2c3d4e5f6...' # 암호화된 값
payment:
api-key: '{cipher}AQBx7y8z9...'
클라이언트가 설정을 조회하면 Config Server가 자동으로 복호화하여 평문으로 전달합니다. Git에는 암호문만 저장되므로 리포 유출 시에도 안전합니다.
Vault 백엔드
민감 정보를 더 안전하게 관리하려면 HashiCorp Vault를 백엔드로 사용합니다:
# Config Server — Vault + Git 복합 백엔드
spring:
profiles:
active: git, vault
cloud:
config:
server:
git:
uri: https://github.com/myorg/config-repo
vault:
host: vault.infra
port: 8200
scheme: https
backend: secret
default-key: application
kv-version: 2
authentication: TOKEN
token: ${VAULT_TOKEN}
비밀번호·API 키는 Vault에, 나머지 설정은 Git에 저장하는 하이브리드 구성이 권장됩니다.
JDBC 백엔드
Git이나 Vault 대신 데이터베이스에 설정을 저장할 수도 있습니다:
-- 설정 테이블
CREATE TABLE properties (
id BIGSERIAL PRIMARY KEY,
application VARCHAR(128) NOT NULL,
profile VARCHAR(128) NOT NULL,
label VARCHAR(128) NOT NULL,
key VARCHAR(256) NOT NULL,
value TEXT NOT NULL,
UNIQUE(application, profile, label, key)
);
-- 데이터 예시
INSERT INTO properties VALUES
(1, 'order-service', 'prod', 'main', 'server.port', '8080'),
(2, 'order-service', 'prod', 'main', 'feature.new-checkout', 'true');
# Config Server — JDBC 백엔드
spring:
profiles:
active: jdbc
cloud:
config:
server:
jdbc:
sql: "SELECT key, value FROM properties WHERE application=? AND profile=? AND label=?"
datasource:
url: jdbc:postgresql://config-db:5432/config
username: config_user
password: ${DB_PASSWORD}
Config Server 고가용성
프로덕션에서는 Config Server를 다중 인스턴스로 운영합니다:
# K8s Deployment — Config Server 2 replicas
apiVersion: apps/v1
kind: Deployment
metadata:
name: config-server
spec:
replicas: 2
template:
spec:
containers:
- name: config-server
image: config-server:latest
ports:
- containerPort: 8888
readinessProbe:
httpGet:
path: /actuator/health
port: 8888
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: config-server
spec:
selector:
app: config-server
ports:
- port: 8888
클라이언트에서는 서비스 디스커버리 또는 K8s Service를 통해 접근하므로, 어떤 인스턴스에 연결되든 동일한 설정을 받습니다.
보안 설정
Config Server는 모든 서비스의 설정을 보유하므로 반드시 인증을 적용합니다:
# Config Server — Basic Auth
spring:
security:
user:
name: ${CONFIG_USER}
password: ${CONFIG_PASSWORD}
# 클라이언트
spring:
cloud:
config:
username: ${CONFIG_USER}
password: ${CONFIG_PASSWORD}
모니터링과 로깅
# Config Server 엔드포인트
GET /order-service/prod # order-service 프로덕션 설정 조회
GET /order-service/prod/main # label(branch) 지정
GET /encrypt # 암호화
GET /decrypt # 복호화
POST /actuator/busrefresh # 전체 갱신
# 설정 조회 로그 (Config Server)
logging:
level:
org.springframework.cloud.config: DEBUG
정리
Spring Cloud Config는 마이크로서비스의 설정을 Git/Vault/JDBC에서 중앙 관리하고, @RefreshScope + Cloud Bus로 런타임 갱신을 실현합니다. 핵심은 민감 정보 암호화, 환경별 설정 분리, 재시작 없는 설정 변경의 세 가지입니다. K8s ConfigMap/Secret과 병행하면 인프라 설정은 K8s에, 애플리케이션 비즈니스 설정은 Config Server에 분리하는 것이 운영상 가장 효율적입니다.