Kubernetes 설정과 스토리지: ConfigMap·Secret·PV/PVC·StorageClass
개요
컨테이너 이미지는 불변(immutable)이어야 한다. 환경마다 달라지는 설정값·비밀번호를 이미지에 굽는 순간 재사용성과 보안이 무너진다. Kubernetes는 설정을 ConfigMap, 민감 정보를 Secret으로 분리해 런타임에 주입하고, 데이터는 Volume과 PersistentVolume/PVC 추상화로 파드 수명과 분리해 보존한다. 여기에 StorageClass가 스토리지를 동적으로 프로비저닝한다. 이 분리가 12-factor 앱 원칙(“설정은 환경에”)을 Kubernetes에서 구현하는 방법이다. 상태 워크로드와의 관계는 Kubernetes - Pod와 워크로드의 StatefulSet과 함께 본다.
핵심 개념과 원리
ConfigMap: 설정의 외부화
ConfigMap은 비밀이 아닌 설정값을 key-value 또는 파일 형태로 담는다. 파드에 주입하는 방법은 두 가지다.
| 주입 방식 | 특징 | 런타임 반영 |
|---|---|---|
환경 변수(env/envFrom) | 간단, 앱에서 바로 읽음 | Pod 재시작해야 반영 |
| 볼륨 마운트 | 파일로 마운트, 대용량·구조적 설정 | 마운트된 파일은 자동 갱신(수십 초 지연) |
환경 변수로 주입한 값은 Pod가 시작할 때 고정되므로, ConfigMap을 바꿔도 Pod를 재시작해야 반영된다. 반면 볼륨으로 마운트한 파일은 kubelet이 주기적으로 갱신하지만, 애플리케이션이 파일 변경을 감지해 리로드하도록 만들어야 실제로 반영된다.
Secret: 민감 정보 처리
Secret은 비밀번호·토큰·인증서 등 민감 데이터를 담는 리소스로, 사용법은 ConfigMap과 거의 같다. 다만 몇 가지 차이와 주의점이 있다.
- base64 인코딩 ≠ 암호화: Secret 값은
etcd에 base64로 저장될 뿐, 기본적으로 암호화되지 않는다. 진짜 보호를 위해 etcd encryption at rest를 활성화하거나 외부 KMS를 연동해야 한다. - 타입:
Opaque(일반),kubernetes.io/tls(인증서),kubernetes.io/dockerconfigjson(레지스트리 인증) 등. - 외부 비밀 관리: 프로덕션에서는 External Secrets Operator, Vault, 클라우드 Secrets Manager와 연동해 Secret을 클러스터 밖에서 관리하는 것이 안전하다.
Volume: 파드 수명 주기 내 저장
Kubernetes Volume은 파드 스펙에 정의되어 파드의 컨테이너들이 공유하는 디렉터리다. 대표 종류는 다음과 같다.
emptyDir: 파드 생성 시 비어 있고 파드 삭제 시 사라지는 임시 볼륨. 컨테이너 간 파일 공유·캐시에 사용.configMap/secret: ConfigMap·Secret을 파일로 마운트.hostPath: 노드의 파일시스템 경로를 마운트(보안·이식성 문제로 프로덕션 지양).persistentVolumeClaim: 아래의 영속 스토리지에 연결.
emptyDir을 포함한 대부분의 볼륨은 파드와 수명을 같이한다. 파드가 다른 노드로 재스케줄되면 데이터가 사라지므로, 진짜 영속 데이터는 PV/PVC가 필요하다.
PersistentVolume과 PersistentVolumeClaim
영속 스토리지는 관심사 분리 모델로 설계됐다.
- PersistentVolume(PV): 클러스터 관리자가 제공하는 실제 스토리지 조각(EBS 볼륨, NFS 등). 인프라 관점.
- PersistentVolumeClaim(PVC): 사용자(개발자)가 “20Gi, ReadWriteOnce가 필요하다”고 요청하는 신청서. 애플리케이션 관점.
파드는 PVC를 참조하고, PVC는 조건에 맞는 PV에 바인딩된다. 이 간접 계층 덕분에 개발자는 백엔드 스토리지의 구체적 종류를 몰라도 되고, 관리자는 스토리지 구현을 바꿔도 애플리케이션을 건드리지 않는다.
접근 모드(access mode)는 중요하다.
| 모드 | 의미 |
|---|---|
ReadWriteOnce(RWO) | 단일 노드에서 읽기·쓰기(블록 스토리지 대부분) |
ReadOnlyMany(ROX) | 여러 노드에서 읽기 전용 |
ReadWriteMany(RWX) | 여러 노드에서 읽기·쓰기(NFS·CephFS 등 파일 스토리지) |
StorageClass: 동적 프로비저닝
관리자가 PV를 일일이 미리 만들어 두는 것(정적 프로비저닝)은 번거롭다. StorageClass는 스토리지의 “종류”(SSD/HDD, IOPS 등)를 정의하는 템플릿으로, PVC가 특정 StorageClass를 지정하면 프로비저너(CSI 드라이버)가 그 순간 PV를 동적 생성해 바인딩한다. 이것이 클라우드 환경의 표준 방식이다.
reclaimPolicy는 PVC 삭제 후 PV·실제 데이터의 운명을 결정한다. Delete(기본, 볼륨까지 삭제)와 Retain(데이터 보존, 수동 정리)이 있으며, 중요한 데이터에는 Retain을 권장한다.
StatefulSet과의 관계
StatefulSet은 volumeClaimTemplates를 통해 각 복제본(db-0, db-1…)마다 전용 PVC를 자동 생성한다. Pod가 재생성돼도 같은 이름의 PVC에 다시 바인딩되므로 데이터 정체성이 유지된다. 이 메커니즘이 데이터베이스를 Kubernetes에서 안전하게 운영하는 기반이다.
실전
ConfigMap과 Secret 주입
apiVersion: v1
kind: ConfigMap
metadata: { name: app-config }
data:
LOG_LEVEL: "info"
config.yaml: |
server:
timeout: 30s
---
apiVersion: v1
kind: Secret
metadata: { name: db-secret }
type: Opaque
stringData: # 평문으로 작성하면 자동 base64 인코딩
DB_PASSWORD: "s3cr3t"
---
apiVersion: v1
kind: Pod
metadata: { name: app }
spec:
containers:
- name: app
image: myorg/app:1.0
envFrom:
- configMapRef: { name: app-config } # ConfigMap 전체를 env로
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef: { name: db-secret, key: DB_PASSWORD }
volumeMounts:
- name: cfg
mountPath: /etc/app # config.yaml을 파일로 마운트
volumes:
- name: cfg
configMap: { name: app-config }PVC + StorageClass 동적 프로비저닝
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: { name: fast-ssd }
provisioner: ebs.csi.aws.com # CSI 드라이버가 볼륨 동적 생성
parameters: { type: gp3 }
reclaimPolicy: Retain # PVC 삭제해도 데이터 보존
allowVolumeExpansion: true # 온라인 용량 확장 허용
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: data }
spec:
accessModes: [ReadWriteOnce]
storageClassName: fast-ssd
resources:
requests: { storage: 20Gi }kubectl get pvc,pv # 바인딩 상태 확인(STATUS: Bound)
kubectl describe pvc data # 이벤트로 프로비저닝 실패 원인 추적함정과 베스트 프랙티스
- Secret을 Git에 평문 커밋 금지: SealedSecrets·External Secrets·SOPS로 암호화해 관리한다.
- base64는 보안이 아니다: etcd encryption at rest를 반드시 켠다.
- env 주입은 자동 갱신 안 됨: ConfigMap 변경 후 롤아웃(재시작)이 필요하다. 자동 반영이 필요하면 볼륨 마운트 + 앱 리로드.
- RWO 볼륨을 여러 파드가 공유하려 하지 말 것: 다중 쓰기가 필요하면 RWX(NFS/CephFS)를 쓴다.
reclaimPolicy: Delete의 위험: 실수로 PVC를 지우면 데이터까지 삭제된다. 중요 데이터는Retain.- 볼륨 확장 전
allowVolumeExpansion확인: StorageClass가 허용하지 않으면 온라인 확장 불가.
정리
설정은 ConfigMap, 비밀은 Secret으로 이미지에서 분리해 런타임에 주입하고(env 또는 볼륨), 데이터는 PV/PVC 추상화로 파드 수명과 분리해 보존한다. StorageClass는 CSI 프로비저너로 PV를 동적 생성해 클라우드 스토리지 운영을 단순화한다. StatefulSet은 이 스토리지 모델 위에서 상태 워크로드의 데이터 정체성을 보장한다. 워크로드 종류는 Kubernetes - Pod와 워크로드, 패키징·자동화는 Kubernetes - Helm과 Operator로 이어진다.