HashiCorp Consul 마스터 노트 시리즈 4편. KV Store의 CLI·HTTP API·UI 3가지 접근, prefix 계층 구조와 권한 관리, get/put/delete 기본 + recurse·json 출력, watch로 실시간 변경 감지, envconsul·consul-template으로 설정 자동 주입까지 — Objective 4 완전 정리.
이 글은 HashiCorp Consul 마스터 노트 시리즈의 네 번째 편입니다. 3편(Service Discovery)에서 서비스 등록·조회를 잡았다면, 이번엔 동적 설정·기능 플래그를 저장하는 Key/Value Store — Objective 4.
KV는 단순해 보여도 활용 폭이 매우 넓어요. 서비스 설정·기능 플래그·분산 락·리더 선거까지.
KV Store 기초
Consul KV는 계층적 키-값 저장소. 키는 /로 구분된 경로 형식.
/myapp/database/host
/myapp/database/port
/myapp/feature-flags/new-checkout
/myapp/feature-flags/dark-mode
용도:
- 동적 애플리케이션 설정
- 기능 플래그 (Feature Flags)
- 분산 락·리더 선거
- 서비스 디스커버리 메타데이터
여기서 시험 함정이 하나 있어요. 값(Value)은 최대 512KB. 큰 데이터(이미지·파일)는 다른 저장소(S3 등)에 두고 KV에는 참조만.
3가지 접근 방법
1. CLI
# 쓰기
consul kv put myapp/db/host "localhost"
consul kv put myapp/db/port "5432"
consul kv put myapp/feature/dark-mode "true"
# 읽기
consul kv get myapp/db/host
# localhost
# 메타데이터 포함
consul kv get -detailed myapp/db/host
# 재귀 조회 (prefix 하위 모두)
consul kv get -recurse myapp/
# JSON 출력
consul kv get -recurse -keys myapp/
# 삭제
consul kv delete myapp/feature/dark-mode
# Prefix 모두 삭제
consul kv delete -recurse myapp/feature/
2. HTTP API
# 쓰기
curl --request PUT --data 'localhost' http://localhost:8500/v1/kv/myapp/db/host
# 읽기 (Base64 인코딩된 응답)
curl http://localhost:8500/v1/kv/myapp/db/host
# [{"LockIndex":0,"Key":"myapp/db/host","Flags":0,"Value":"bG9jYWxob3N0",...}]
# 디코딩 후 보기
curl http://localhost:8500/v1/kv/myapp/db/host?raw
# localhost
# Prefix 재귀
curl http://localhost:8500/v1/kv/myapp/?recurse
# 삭제
curl --request DELETE http://localhost:8500/v1/kv/myapp/db/host
여기서 시험 함정이 하나 있어요. HTTP API 응답의 Value는 Base64 인코딩. 그대로 사용 X — ?raw 옵션이나 디코딩 필요.
3. UI
http://<consul-server>:8500/ui/<dc>/kv — 브라우저에서 트리 뷰.
Prefix 계층 구조 활용
/myapp/
├── /myapp/database/
│ ├── /myapp/database/host
│ └── /myapp/database/port
├── /myapp/feature-flags/
│ ├── /myapp/feature-flags/new-checkout
│ └── /myapp/feature-flags/dark-mode
└── /myapp/secrets/
└── /myapp/secrets/api-key
/anotherapp/
└── ...
여기서 정말 중요한 시험 함정 — prefix 단위 ACL 권한 부여가 KV의 강점입니다. myapp/secrets/ 하위 prefix만 admin에 권한 줌, 나머지는 모든 팀에 read 허용 같은 패턴. 7편(보안)에서 자세히.
원자적 연산 — CAS
Check-And-Set — 조건부 쓰기. 동시성 문제 해결.
# 1. 현재 ModifyIndex 확인
consul kv get -detailed myapp/counter
# ModifyIndex 142
# 2. ModifyIndex 일치할 때만 쓰기
consul kv put -cas -modify-index=142 myapp/counter "new-value"
# 다른 사람이 그 사이 변경했으면 142가 아닌 다른 값 → 실패
용도:
- 분산 락
- 리더 선거
- 동시 수정 충돌 방지
HTTP API CAS
curl --request PUT \
--data 'new-value' \
"http://localhost:8500/v1/kv/myapp/counter?cas=142"
응답 — true (성공) / false (실패).
Session — 분산 락
# 세션 생성 (TTL 30초)
SESSION_ID=$(curl --request PUT \
--data '{"Name":"my-lock","TTL":"30s"}' \
http://localhost:8500/v1/session/create | jq -r .ID)
# 세션으로 락 획득
curl --request PUT \
--data 'locked-by-process-1' \
"http://localhost:8500/v1/kv/locks/my-resource?acquire=$SESSION_ID"
# true (성공) / false (이미 잠김)
# 해제
curl --request PUT \
"http://localhost:8500/v1/kv/locks/my-resource?release=$SESSION_ID"
여기서 시험 함정이 하나 있어요. 세션 TTL 만료 = 자동 락 해제. 프로세스 죽어도 락이 영원히 안 잡힘. 분산 시스템의 표준 패턴.
Watch — 실시간 변경 감지
KV·서비스·노드 변경을 감지해 명령 실행.
# Long Polling으로 변경 대기
consul watch -type=key -key=myapp/feature/dark-mode \
/usr/local/bin/reload_app.sh
# 또는 prefix 단위
consul watch -type=keyprefix -prefix=myapp/feature/ \
/usr/local/bin/reload_features.sh
Watch 종류
| Type | 감지 대상 |
|---|---|
key |
단일 키 |
keyprefix |
prefix 하위 |
services |
등록된 서비스 목록 |
service |
특정 서비스의 인스턴스 |
nodes |
노드 목록 |
node |
특정 노드 |
checks |
헬스 체크 |
event |
사용자 이벤트 |
Long Polling
HTTP API에서 직접:
# index 142 이후 변경 대기 (최대 5분)
curl "http://localhost:8500/v1/kv/myapp/feature/dark-mode?index=142&wait=5m"
새 값 도착하면 즉시 응답. 없으면 5분 후 timeout.
envconsul — 환경 변수로 주입
# KV에 저장
consul kv put myapp/db/host "db.internal"
consul kv put myapp/db/password "secret123"
# envconsul로 앱 실행
envconsul -prefix=myapp/db -- /usr/local/bin/myapp
# 앱 안에서 환경 변수로 보임:
# DB_HOST=db.internal
# DB_PASSWORD=secret123
KV 변경 시 앱 자동 재시작 옵션도 있음.
consul-template — 파일 자동 생성
설정 파일·인증서를 KV·서비스 정보 기반으로 자동 생성.
# nginx.conf.tpl
upstream backend {
{{ range service "backend|passing" }}
server {{ .Address }}:{{ .Port }} max_fails={{ key "myapp/lb/max_fails" }};
{{ end }}
}
consul-template \
-template "nginx.conf.tpl:nginx.conf:nginx -s reload" \
-consul-addr=localhost:8500
서비스·KV 변경 시 자동으로 nginx.conf 갱신 + nginx -s reload 실행.
트랜잭션 (Transactions)
여러 KV 연산을 원자적으로.
curl --request PUT \
--data @transaction.json \
http://localhost:8500/v1/txn
[
{ "KV": { "Verb": "set", "Key": "key1", "Value": "value1-base64" } },
{ "KV": { "Verb": "set", "Key": "key2", "Value": "value2-base64" } },
{ "KV": { "Verb": "delete", "Key": "key3" } }
]
모두 성공 OR 모두 실패. 일부 성공 X.
백업·복원
KV 데이터는 5편(백업·복구)에서 다루는 consul snapshot save에 포함.
consul snapshot save backup.snap
consul snapshot restore backup.snap
KV·서비스·ACL·세션 모두 한 스냅샷.
일반적 활용 패턴
기능 플래그 (Feature Flag)
consul kv put myapp/feature/new-checkout "true"
# 앱 코드
import consul
c = consul.Consul()
def is_feature_enabled(name):
_, data = c.kv.get(f'myapp/feature/{name}')
return data and data['Value'] == b'true'
if is_feature_enabled('new-checkout'):
# 새 체크아웃 사용
pass
동적 환경 변수
# 운영자가 KV 업데이트
consul kv put myapp/db/max_connections "200"
# 앱이 watch로 자동 적용
consul watch -type=key -key=myapp/db/max_connections \
/usr/local/bin/apply_db_config.sh
리더 선거
# 모든 후보 노드가 같은 키에 락 시도
SESSION_ID=$(curl ... session/create)
# 한 명만 성공 = 그 노드가 리더
ACQUIRED=$(curl --request PUT \
--data 'leader' \
"http://localhost:8500/v1/kv/myapp/leader?acquire=$SESSION_ID")
if [ "$ACQUIRED" = "true" ]; then
echo "I am the leader"
fi
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 4편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.
- KV = 계층적 key/value,
/로 prefix 구분 - 값 최대 512KB — 큰 데이터는 외부 + 참조
- 3가지 접근 — CLI / HTTP API / UI
- CLI —
consul kv put / get / delete -recurse= prefix 하위 모두-detailed= 메타데이터 포함- HTTP API 응답
Value는 Base64 —?raw로 평문 - Prefix 단위 ACL = KV의 강점
- CAS (Check-And-Set) = 조건부 쓰기, 동시성
?cas=142또는-cas -modify-index=142- 응답 true (성공) / false (실패)
- Session = 분산 락 표준
- TTL 만료 = 자동 락 해제 (프로세스 죽어도)
- Watch = 실시간 변경 감지 → 명령 실행
- 종류 — key / keyprefix / services / service / node / checks / event
- Long Polling =
?index=N&wait=5m envconsul= KV → 환경 변수 주입consul-template= 설정 파일·인증서 자동 생성- nginx config + reload 자동
- Transaction = 여러 KV 연산 원자적
- 백업 =
consul snapshot save(KV·서비스·ACL 모두) - 활용 — Feature Flag / 동적 설정 / 분산 락 / 리더 선거
시리즈 다른 편
- 1편 — Consul 입문
- 2편 — 단일 DC 배포
- 3편 — Service Discovery
- 4편 — KV Store (현재 글)
- 5편 — 백업 & 복구
- 6편 — Service Mesh (Connect)
- 7편 — 보안 운영
공식 문서: Consul KV Store에서 더 깊이.
다음 글(5편)에서는 백업·복구 — consul snapshot save/restore, 자동 백업 스케줄, 비활성 ACL 활성화 시 토큰까지 — Objective 5 정리.