☁️ 클라우드

ConfigMap

Kubernetes ConfigMap

설정 데이터를 저장하는 Kubernetes 리소스. 환경변수, 설정 파일을 Pod에 주입. Secret과 함께 12 Factor App 구현.

📖 상세 설명

ConfigMap은 Kubernetes에서 설정 데이터를 키-값 쌍으로 저장하는 API 오브젝트입니다. 애플리케이션 코드와 설정을 분리하여 동일한 컨테이너 이미지를 개발, 스테이징, 프로덕션 등 다양한 환경에서 다른 설정으로 실행할 수 있게 합니다.

ConfigMap은 12 Factor App의 세 번째 원칙인 "설정을 환경에 저장"을 구현하는 핵심 메커니즘입니다. 비밀이 아닌 설정 데이터(DB 호스트, 기능 플래그, 로그 레벨 등)를 ConfigMap에 저장하고, 민감한 정보(패스워드, API 키)는 Secret에 저장합니다.

ConfigMap 데이터를 Pod에 주입하는 방법:

ConfigMap 크기는 1MiB로 제한되며, 더 큰 설정이 필요하면 별도의 볼륨이나 외부 설정 서버를 사용해야 합니다. 또한 ConfigMap 변경 시 기존 Pod에는 자동 반영되지 않으므로, 롤링 업데이트 전략이 필요합니다.

💻 코드 예제

# app-config.yaml - 다양한 형태의 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
  labels:
    app: backend
    environment: production
data:
  # 단순 키-값 쌍 (환경변수용)
  DATABASE_HOST: "postgres.production.svc.cluster.local"
  DATABASE_PORT: "5432"
  DATABASE_NAME: "app_production"
  LOG_LEVEL: "info"
  FEATURE_NEW_UI: "true"
  MAX_CONNECTIONS: "100"

  # 설정 파일 전체 (볼륨 마운트용)
  application.yml: |
    spring:
      profiles:
        active: production
      datasource:
        hikari:
          maximum-pool-size: 20
          minimum-idle: 5
          connection-timeout: 30000
      cache:
        type: redis
        redis:
          time-to-live: 3600000

    logging:
      level:
        root: INFO
        com.company.app: DEBUG

    app:
      cors:
        allowed-origins:
          - https://app.company.com
          - https://admin.company.com

  nginx.conf: |
    upstream backend {
        server backend-service:8080;
        keepalive 32;
    }

    server {
        listen 80;
        server_name app.company.com;

        location /api/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_connect_timeout 30s;
            proxy_read_timeout 60s;
        }

        location /health {
            access_log off;
            return 200 "healthy\n";
        }
    }
---
# 환경별 ConfigMap 분리 예시
apiVersion: v1
kind: ConfigMap
metadata:
  name: feature-flags
  namespace: production
data:
  ENABLE_DARK_MODE: "true"
  ENABLE_BETA_FEATURES: "false"
  MAINTENANCE_MODE: "false"
  A_B_TEST_VARIANT: "control"
# deployment.yaml - ConfigMap 사용 예시
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
      annotations:
        # ConfigMap 변경 시 자동 롤링 업데이트를 위한 해시
        checksum/config: "{{ include (print $.Template.BasePath \"/configmap.yaml\") . | sha256sum }}"
    spec:
      containers:
      - name: app
        image: company/backend:v1.2.3
        ports:
        - containerPort: 8080

        # 방법 1: 전체 ConfigMap을 환경변수로 주입
        envFrom:
        - configMapRef:
            name: app-config
        - configMapRef:
            name: feature-flags

        # 방법 2: 특정 키만 환경변수로 주입
        env:
        - name: DB_HOST
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: DATABASE_HOST
        - name: DB_PORT
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: DATABASE_PORT
              optional: true  # 키가 없어도 Pod 시작

        # 방법 3: 볼륨 마운트로 설정 파일 주입
        volumeMounts:
        - name: config-volume
          mountPath: /app/config
          readOnly: true
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
          readOnly: true

        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"

        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5

      volumes:
      # ConfigMap을 볼륨으로 마운트
      - name: config-volume
        configMap:
          name: app-config
          items:
          - key: application.yml
            path: application.yml
            mode: 0644  # 파일 권한 설정

      - name: nginx-config
        configMap:
          name: app-config
          items:
          - key: nginx.conf
            path: default.conf
# ConfigMap 생성 방법들

# 1. 리터럴 값으로 생성
kubectl create configmap app-settings \
  --from-literal=DATABASE_HOST=postgres.svc \
  --from-literal=DATABASE_PORT=5432 \
  --from-literal=LOG_LEVEL=info \
  -n production

# 2. 파일에서 생성 (파일 이름이 키가 됨)
kubectl create configmap nginx-config \
  --from-file=nginx.conf \
  --from-file=mime.types \
  -n production

# 3. 디렉토리 전체에서 생성
kubectl create configmap app-configs \
  --from-file=./config-dir/ \
  -n production

# 4. env 파일에서 생성
# .env 파일 내용: KEY1=value1\nKEY2=value2
kubectl create configmap env-config \
  --from-env-file=.env \
  -n production

# ConfigMap 조회
kubectl get configmap app-config -n production -o yaml
kubectl describe configmap app-config -n production

# ConfigMap 수정 (에디터로 열기)
kubectl edit configmap app-config -n production

# ConfigMap 업데이트 (파일에서)
kubectl apply -f app-config.yaml

# 특정 키 값만 조회
kubectl get configmap app-config -n production \
  -o jsonpath='{.data.DATABASE_HOST}'

# ConfigMap 삭제
kubectl delete configmap app-config -n production

# Pod에서 ConfigMap 사용 현황 확인
kubectl get pods -n production -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.volumes[*].configMap.name}{"\n"}{end}'

# ConfigMap 변경 후 Deployment 재시작 (롤링 업데이트)
kubectl rollout restart deployment/backend -n production

# Kustomize로 ConfigMap 생성 (권장)
# kustomization.yaml
# configMapGenerator:
# - name: app-config
#   files:
#   - application.yml
#   literals:
#   - LOG_LEVEL=info

🗣️ 실무에서 이렇게 말하세요

배포 파이프라인 논의에서
"환경별 설정은 ConfigMap으로 관리하고 있어요. 개발/스테이징/프로덕션 각각 다른 ConfigMap을 만들어서 DB 호스트, 로그 레벨, 기능 플래그를 분리했습니다. 이미지는 동일하게 쓰고 ConfigMap만 바꿔서 배포하니까 설정 실수가 많이 줄었어요."
면접에서 Kubernetes 경험 질문에
"ConfigMap과 Secret을 분리해서 사용합니다. 기능 플래그나 외부 서비스 URL은 ConfigMap에, API 키나 DB 패스워드는 Secret에 저장해요. ConfigMap은 etcd에 평문으로 저장되기 때문에 민감한 정보는 절대 넣지 않습니다. Sealed Secrets나 External Secrets로 GitOps도 구현했습니다."
설정 변경 배포 중
"ConfigMap 수정했는데 기존 Pod에는 바로 반영 안 됩니다. 볼륨 마운트 방식은 kubelet이 주기적으로 동기화하지만 환경변수 방식은 Pod 재시작이 필요해요. Deployment에 ConfigMap 해시를 annotation으로 넣어서 ConfigMap 변경 시 자동으로 롤링 업데이트되도록 설정했습니다."

⚠️ 흔한 실수 & 주의사항

ConfigMap에 민감한 정보 저장

ConfigMap은 etcd에 평문으로 저장되어 kubectl로 누구나 조회 가능합니다. 패스워드, API 키, 인증서 등은 반드시 Secret을 사용하세요. RBAC으로 접근 제어를 해도 ConfigMap은 민감 정보용이 아닙니다.

환경변수 방식에서 핫 리로드 기대

envFrom이나 env.valueFrom으로 주입된 환경변수는 ConfigMap을 수정해도 기존 Pod에 반영되지 않습니다. 볼륨 마운트 방식만 kubelet 동기화(기본 1분)로 업데이트됩니다. 완전한 반영을 위해선 Pod 재시작이 필요합니다.

올바른 방법: Immutable ConfigMap 사용

immutable: true로 설정하면 ConfigMap 수정이 불가능해집니다. 설정 변경 시 새 ConfigMap을 만들고 Deployment를 업데이트하는 방식이 더 안전합니다. Kustomize의 configMapGenerator는 자동으로 해시 suffix를 붙여줍니다.

🔗 관련 용어

📚 더 배우기