/엔지니어/Docker / 컨테이너/Kubernetes ConfigMap·Secret
Docker / 컨테이너중급linuxkubernetesconfigmapsecret

Kubernetes ConfigMap·Secret — 설정과 민감정보 관리 완전 가이드

ConfigMap과 Secret으로 설정·민감정보를 컨테이너 이미지에서 분리하고, 환경변수/볼륨 주입, 자동 리로드, 암호화 등 실전 패턴을 정리합니다.

ConfigMap·Secret 이란?

12-factor 원칙의 핵심은 "설정을 코드(이미지)에서 분리"하는 것입니다. 쿠버네티스는 두 리소스로 이를 구현합니다.

  • ConfigMap: 비민감 설정(앱 옵션, URL, 기능 플래그 등)을 키-값으로 저장
  • Secret: 비밀번호, 토큰, 인증서 등 민감정보를 저장 (base64 인코딩 + 접근 제어)

둘 다 환경변수나 볼륨 파일로 컨테이너에 주입할 수 있어, 같은 이미지를 dev/stage/prod에서 서로 다른 설정으로 재사용할 수 있습니다.

Secret의 기본 인코딩은 암호화가 아니라 base64입니다. 누구나 디코딩할 수 있으므로 "Secret이니까 안전하다"는 착각은 금물입니다. 진짜 보호는 RBAC + etcd 암호화 + 외부 비밀 관리 도구로 완성됩니다.


ConfigMap 만들기

명령형(리터럴/파일)

Bash
# 키-값 직접
kubectl create configmap app-config \
  --from-literal=LOG_LEVEL=info \
  --from-literal=MAX_CONN=100

# 파일 통째로 (--from-file)
kubectl create configmap nginx-conf --from-file=./nginx.conf

# .env 형식 일괄 (--from-env-file)
kubectl create configmap app-env --from-env-file=./app.env

선언형(YAML) — 권장

YAML
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "info"
  MAX_CONN: "100"
  # 파일 형태 설정도 통째로 넣을 수 있음
  application.yaml: |
    server:
      port: 8080
    feature:
      newUI: true
Bash
kubectl apply -f configmap.yaml
kubectl get cm app-config -o yaml

Secret 만들기

Bash
# 일반 비밀값
kubectl create secret generic db-secret \
  --from-literal=DB_USER=admin \
  --from-literal=DB_PASS='S3cr3t!23'

# TLS 인증서
kubectl create secret tls web-tls --cert=tls.crt --key=tls.key

# 프라이빗 레지스트리 인증
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=ci --docker-password='token'

YAML로 쓸 때는 값이 base64여야 합니다. 평문을 그대로 쓰려면 stringData를 사용하세요.

YAML
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:           # 평문 입력 → 저장 시 자동 base64
  DB_USER: admin
  DB_PASS: "S3cr3t!23"

Secret의 주요 타입은 다음과 같습니다.

type용도
Opaque임의 키-값 (기본)
kubernetes.io/tlsTLS 인증서/키
kubernetes.io/dockerconfigjson레지스트리 인증
kubernetes.io/service-account-tokenSA 토큰

컨테이너에 주입하기 — 환경변수

개별 키 주입

YAML
spec:
  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: LOG_LEVEL
    - name: DB_PASS
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASS

전체 일괄 주입 (envFrom)

YAML
    envFrom:
    - configMapRef: { name: app-config }
    - secretRef: { name: db-secret }

환경변수로 주입한 값은 Pod가 만들어질 때 한 번 박힙니다. ConfigMap을 수정해도 이미 떠 있는 Pod의 환경변수는 갱신되지 않습니다. 반영하려면 롤링 재시작이 필요합니다.


컨테이너에 주입하기 — 볼륨 마운트

ConfigMap/Secret을 파일로 마운트하면, 환경변수와 달리 ConfigMap 변경 시 마운트된 파일이 자동 갱신됩니다(수십 초 지연).

YAML
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: config-vol
      mountPath: /etc/app          # /etc/app/application.yaml 로 생성됨
      readOnly: true
    - name: secret-vol
      mountPath: /etc/secret
      readOnly: true
  volumes:
  - name: config-vol
    configMap:
      name: app-config
      items:                        # 특정 키만 선택 마운트
      - key: application.yaml
        path: application.yaml
  - name: secret-vol
    secret:
      secretName: db-secret
      defaultMode: 0400             # 권한 제한
방식자동 갱신적합한 경우
환경변수 (env/envFrom)아니오단순 값, 12-factor 앱
볼륨 마운트예(파일 갱신)설정 파일, 인증서, 핫리로드 앱

설정 변경 시 자동 롤링 재시작

환경변수 주입은 자동 반영이 안 되므로, 설정 변경 시 Deployment를 다시 굴려야 합니다. 흔한 패턴은 ConfigMap 내용의 해시를 어노테이션에 박는 것입니다.

YAML
spec:
  template:
    metadata:
      annotations:
        # 내용이 바뀌면 이 값을 갱신 → Pod 템플릿 변경 → 롤링 재시작
        checksum/config: "a1b2c3..."

수동으로는 다음 명령으로 즉시 롤링합니다.

Bash
kubectl rollout restart deployment/myapp

kubectl edit 또는 apply로 불변(immutable) ConfigMap을 만들면(immutable: true) 실수 변경을 막고 API 서버 부하도 줄일 수 있습니다. 단, 변경하려면 삭제 후 재생성해야 합니다.


보안 강화 — Secret 진짜로 보호하기

1) etcd 저장 시 암호화

YAML
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <base64-32byte-key>
  - identity: {}

API 서버 기동 옵션에 --encryption-provider-config를 추가하면 Secret이 etcd에 암호문으로 저장됩니다.

2) RBAC로 접근 제한

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: prod
rules:
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["db-secret"]   # 특정 Secret만
  verbs: ["get"]

3) 외부 비밀 관리 연동

운영에서는 평문 Secret을 git에 두지 않고 다음을 권장합니다.

  • External Secrets Operator: AWS Secrets Manager, Vault 등에서 동기화
  • Sealed Secrets: 암호문 형태로 git 커밋 가능, 클러스터 내에서만 복호화
  • SOPS: 키만 KMS로 관리하며 파일 암호화

검증과 디버깅

Bash
# Secret 값 디코딩 확인
kubectl get secret db-secret -o jsonpath='{.data.DB_PASS}' | base64 -d; echo

# Pod 안에서 실제 주입된 환경변수 확인
kubectl exec deploy/myapp -- env | grep -E 'LOG_LEVEL|DB_'

# 마운트된 설정 파일 확인
kubectl exec deploy/myapp -- cat /etc/app/application.yaml
증상원인
CreateContainerConfigError참조한 ConfigMap/Secret/key가 존재하지 않음
값이 빈 문자열key 이름 오타 또는 대소문자 불일치
파일이 안 보임mountPath가 기존 디렉터리를 덮어씀(전체 교체됨)

정리

항목ConfigMapSecret
대상비민감 설정비밀번호/토큰/인증서
저장평문base64 (암호화 아님)
주입env / envFrom / volume동일
자동 갱신volume 마운트만volume 마운트만
보안RBACRBAC + etcd 암호화 + 외부도구
변경 반영rollout restart동일

설정과 코드의 분리가 ConfigMap/Secret의 본질입니다. 핫리로드가 필요하면 볼륨 마운트, 단순 값은 환경변수를 쓰고, Secret은 base64일 뿐임을 잊지 말고 etcd 암호화·RBAC·외부 비밀관리로 실질적 보호를 갖추세요.

#kubernetes#configmap#secret#configuration
편집 안내 · Editorial Note

이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.

질문 & 답변 (Q&A)

이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.