apiVersion: v1
kind: ConfigMap
metadata: { name: app-config }
data:
LOG_LEVEL: "info"
application.yml: |
server:
port: 8080
# 환경변수로
envFrom:
- configMapRef: { name: app-config }
# 파일로 마운트
volumeMounts:
- { name: config, mountPath: /etc/app }
volumes:
- { name: config, configMap: { name: app-config } }
갱신 반영 방식이 다르다
- 환경변수로 넣은 것 — 파드를 다시 만들어야 반영된다 (절대 안 바뀐다)
- 파일로 마운트한 것 — kubelet 이 주기적으로 갱신한다 (수십 초~1분)
- 단 애플리케이션이 파일을 다시 읽어야 의미가 있다
- subPath 로 마운트한 것 — 갱신되지 않는다 ← 자주 놓치는 예외
실무 기본형 — 설정을 바꾸면 파드를 새로 띄운다 kubectl rollout restart deploy/web
또는 ConfigMap 이름에 해시를 붙여 바뀔 때마다 새 이름을 쓴다
- (Kustomize 의 configMapGenerator 가 이것을 해 준다)
- 롤아웃이 자동으로 일어나고 롤백도 함께 된다
Secret 은 이름만 비밀이다
기본적으로 base64 인코딩일 뿐 암호화가 아니다
- kubectl get secret db-cred -o jsonpath='{.data.password}' | base64 -d
etcd 에도 평문으로 저장된다 — 별도로 켜야 암호화된다
- EncryptionConfiguration 으로 저장 시 암호화(at rest)
- KMS 프로바이더를 쓰면 키를 외부에서 관리한다
즉 "Secret 에 넣었으니 안전하다" 는 틀렸다
안전하게 만들려면
- ① etcd 저장 시 암호화를 켠다
- ② RBAC 으로 secret 읽기 권한을 좁힌다
- (secret 을 읽을 수 있으면 그 네임스페이스의 모든 비밀을 본다)
- ③ 외부 시크릿 매니저와 연동한다
- External Secrets Operator · CSI Secret Store
- ④ 환경변수보다 파일 마운트를 쓴다
- 환경변수는 프로세스 목록·크래시 덤프·로그에 새기 쉽고
- 자식 프로세스에 그대로 상속된다
크기 제한
ConfigMap·Secret 은 1MiB 를 넘을 수 없다 (etcd 제약)
- 큰 설정 파일·인증서 번들에서 걸린다
- 볼륨이나 외부 저장소로 옮긴다
그리고 이 객체들은 etcd 에 저장돼 모든 API 서버가 들고 있다
- 개수가 많아지면 API 서버 메모리에 영향을 준다
불변 ConfigMap·Secret
immutable: true
수정할 수 없게 만든다 (지우고 다시 만들어야 한다)
얻는 것
- 실수로 바꾸는 사고를 막는다
- kubelet 이 변경 감시를 안 해도 되므로 API 서버 부하가 준다
- (대규모 클러스터에서 의미 있는 차이가 난다)
이름에 해시를 붙이는 방식과 잘 맞는다
- app-config-a1b2c3 → 바뀌면 새 이름 → 롤아웃이 자동으로 일어난다
설정을 어디에 둘 것인가
- 이미지에 — 절대 안 바뀌는 것 (기본값)
- ConfigMap — 환경마다 다른 것 (엔드포인트 · 기능 플래그)
- Secret — 비밀 (자격증명 · 키)
- 외부 설정 서버 — 런타임에 바뀌어야 하는 것
경계가 흐려지면 "이 값이 어디서 오는지" 를 아무도 모르게 된다 우선순위를 문서화하고, 애플리케이션이 실제 사용 값을 로그로 남기게 한다 (비밀은 마스킹해서)
면접 함정
- ❌ "ConfigMap을 바꾸면 자동 반영된다" → 환경변수는 안 되고, subPath도 안 된다.
- ❌ "Secret은 암호화된다" → base64다. etcd 암호화를 따로 켜야 한다.