Kubernetes 설정과 스토리지: ConfigMap·Secret·PV/PVC·StorageClass

개요

컨테이너 이미지는 불변(immutable)이어야 한다. 환경마다 달라지는 설정값·비밀번호를 이미지에 굽는 순간 재사용성과 보안이 무너진다. Kubernetes는 설정을 ConfigMap, 민감 정보를 Secret으로 분리해 런타임에 주입하고, 데이터는 VolumePersistentVolume/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로 이어진다.