ConfigMap과 Secret이란?
Kubernetes에서 애플리케이션 설정을 컨테이너 이미지와 분리하는 두 가지 리소스입니다. ConfigMap은 일반 설정(환경변수, 설정 파일), Secret은 민감한 데이터(비밀번호, API 키, TLS 인증서)를 저장합니다. 설정과 코드를 분리하는 12-Factor App 원칙의 핵심 구현체입니다.
ConfigMap 생성과 사용
YAML 선언
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
# 단일 키-값
DATABASE_HOST: "db.internal.svc.cluster.local"
DATABASE_PORT: "5432"
LOG_LEVEL: "info"
# 파일 형태 (멀티라인)
nginx.conf: |
server {
listen 80;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
}
}
application.yml: |
spring:
datasource:
url: jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/mydb
cache:
type: redis
CLI로 빠르게 생성
# 리터럴 값으로
kubectl create configmap app-config
--from-literal=DATABASE_HOST=db.internal
--from-literal=LOG_LEVEL=info
# 파일에서
kubectl create configmap nginx-config
--from-file=nginx.conf=./nginx.conf
# 디렉토리 전체
kubectl create configmap config-dir
--from-file=./config/
# .env 파일에서
kubectl create configmap env-config
--from-env-file=.env
Pod에서 ConfigMap 사용: 3가지 방법
방법 1: 환경변수로 주입
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: my-app:latest
env:
# 개별 키 선택
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_HOST
# 모든 키를 환경변수로
envFrom:
- configMapRef:
name: app-config
prefix: APP_ # APP_DATABASE_HOST, APP_LOG_LEVEL 등
방법 2: 볼륨 마운트 (파일로)
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d # 디렉토리에 파일로 마운트
readOnly: true
volumes:
- name: config-volume
configMap:
name: nginx-config
items: # 특정 키만 선택
- key: nginx.conf
path: default.conf # 파일명 변경 가능
defaultMode: 0644
방법 3: 특정 파일만 subPath로
volumeMounts:
- name: config-volume
mountPath: /app/config/application.yml # 파일 하나만
subPath: application.yml # 기존 디렉토리 내용 보존
주의: subPath를 사용하면 ConfigMap 업데이트 시 자동 갱신이 되지 않습니다. subPath 없이 디렉토리로 마운트해야 kubelet이 주기적으로 갱신합니다.
Secret 타입과 생성
| 타입 | 용도 | 자동 검증 |
|---|---|---|
Opaque |
일반 시크릿 (기본값) | 없음 |
kubernetes.io/tls |
TLS 인증서 | tls.crt, tls.key 필수 |
kubernetes.io/dockerconfigjson |
컨테이너 레지스트리 인증 | JSON 형식 검증 |
kubernetes.io/basic-auth |
Basic 인증 | username, password 필수 |
# Opaque Secret (base64 인코딩 필수)
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: production
type: Opaque
data:
username: cG9zdGdyZXM= # echo -n "postgres" | base64
password: c3VwZXJzZWNyZXQ= # echo -n "supersecret" | base64
# stringData로 평문 입력 (적용 시 자동 base64 인코딩)
apiVersion: v1
kind: Secret
metadata:
name: api-keys
type: Opaque
stringData:
STRIPE_KEY: "sk_live_xxxxxxxxxxxx"
JWT_SECRET: "my-jwt-secret-key"
# CLI로 생성
kubectl create secret generic db-credentials
--from-literal=username=postgres
--from-literal=password=supersecret
# TLS Secret
kubectl create secret tls my-tls
--cert=server.crt
--key=server.key
# Docker Registry Secret
kubectl create secret docker-registry regcred
--docker-server=ghcr.io
--docker-username=user
--docker-password=token
Secret 사용 패턴
spec:
containers:
- name: app
env:
# 개별 키
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# 전체 키
envFrom:
- secretRef:
name: api-keys
# 파일로 마운트 (TLS 인증서 등)
volumeMounts:
- name: tls-certs
mountPath: /etc/tls
readOnly: true
# Docker Registry 인증
imagePullSecrets:
- name: regcred
volumes:
- name: tls-certs
secret:
secretName: my-tls
defaultMode: 0400 # 읽기 전용, owner만
Immutable ConfigMap/Secret
Kubernetes 1.21+에서는 immutable: true를 설정할 수 있습니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v3
immutable: true # 한 번 생성 후 수정 불가
data:
DATABASE_HOST: "db.internal"
장점:
- 실수로 운영 설정을 변경하는 사고 방지
- kubelet의 watch 부하 감소 (대규모 클러스터에서 성능 향상)
- 변경 시 새 ConfigMap 생성 + Deployment 롤링 업데이트 → 변경 이력 추적 가능
설정 변경 시 Pod 재시작 전략
ConfigMap/Secret을 변경해도 기존 Pod는 자동으로 재시작되지 않습니다 (볼륨 마운트 갱신은 되지만 앱이 다시 읽지 않으면 무의미). 3가지 해결책이 있습니다.
전략 1: Reloader (자동 롤링 업데이트)
# Stakater Reloader 설치
helm install reloader stakater/reloader -n kube-system
# Deployment에 어노테이션 추가
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
annotations:
reloader.stakater.com/auto: "true" # 연관 ConfigMap/Secret 변경 시 자동 재시작
# 또는 특정 ConfigMap만
configmap.reloader.stakater.com/reload: "app-config"
secret.reloader.stakater.com/reload: "db-credentials"
전략 2: 해시 어노테이션 (Helm/Kustomize)
# Helm 템플릿에서
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
전략 3: Immutable + 버전 관리
# 설정 변경 시 새 ConfigMap 생성
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v4 # 버전 업
data:
LOG_LEVEL: "debug"
# Deployment에서 참조 변경
spec:
template:
spec:
containers:
- envFrom:
- configMapRef:
name: app-config-v4 # v3 → v4
보안 베스트 프랙티스
Secret은 기본적으로 안전하지 않습니다. etcd에 base64로 저장될 뿐, 암호화되지 않습니다.
# 1. etcd 암호화 활성화 (EncryptionConfiguration)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {} # fallback: 암호화 없이 읽기 (마이그레이션용)
# 2. RBAC로 Secret 접근 제한
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["db-credentials"] # 특정 Secret만
verbs: ["get"] # list 불가 → 다른 Secret 열람 방지
# 3. Pod가 불필요한 Secret 접근 차단
spec:
automountServiceAccountToken: false # SA 토큰 자동 마운트 비활성
운영 환경에서는 Sealed Secrets이나 External Secrets를 사용하여 Git에 암호화된 Secret을 저장하고, K8s RBAC로 접근 권한을 최소화하세요.
Kustomize로 ConfigMap 자동 생성
# kustomization.yaml
configMapGenerator:
- name: app-config
literals:
- DATABASE_HOST=db.internal
- LOG_LEVEL=info
files:
- configs/nginx.conf
secretGenerator:
- name: db-credentials
literals:
- username=postgres
- password=supersecret
options:
disableNameSuffixHash: false # 해시 접미사 → 변경 시 자동 롤링 업데이트
Kustomize의 configMapGenerator는 내용이 변경되면 자동으로 해시 접미사가 바뀌어(app-config-abc123), Deployment가 자동으로 롤링 업데이트됩니다.
정리
ConfigMap과 Secret 관리의 핵심은 “설정과 코드를 분리하고, 민감 데이터를 보호하라”입니다. 환경변수와 볼륨 마운트로 유연하게 주입하되, subPath의 갱신 제한을 이해하고, Reloader나 Immutable + 버전 관리로 설정 변경 시 Pod 재시작을 보장하세요. Secret은 etcd 암호화, RBAC 제한, External Secrets 연동까지 반드시 보안 계층을 추가해야 합니다.