Network & Server Factory

개인 공부 기록

DevOps/Kubernetes

[Kubernetes] ConfigMap과 Secret 정리

1nfra 2026. 9. 28. 16:57
같은 이미지를 개발과 운영에서 함께 쓰려면 환경마다 달라지는 설정 값과 비밀번호를 이미지 밖에 둬야 합니다. 이 글에서는 설정을 담는 ConfigMap과 비밀 값을 담는 Secret을 Pod에 넣는 두 가지 방법, 값을 바꿨을 때의 반영 방식, 그리고 Secret을 안전하게 다루는 방법을 Redis 예제로 정리합니다.

컨테이너부터 Kubernetes까지 시리즈 9편입니다. 이전 글은 [Kubernetes] Service와 Ingress, Gateway API 정리이고, 전체 순서는 시리즈 목차에 있습니다.

1. 설정을 이미지 밖으로

DB 주소나 로그 레벨 같은 값을 이미지 안에 넣으면 환경마다 이미지를 따로 빌드해야 하고, 개발에서 확인한 이미지와 운영에 올라가는 이미지가 달라집니다. 그래서 이미지는 하나로 두고 설정은 실행할 때 넣습니다. 5편에서 Compose의 .env와 environment로 하던 일을 Kubernetes에서는 ConfigMap과 Secret이 맡습니다.

 

항목 ConfigMap Secret
담는 값 설정 파일, 환경 변수 등 공개돼도 되는 값 비밀번호, API 키, 인증서
저장 형태 평문 base64 인코딩(암호화 아님)
크기 제한 1MiB 1MiB
Pod에 넣는 방법 환경 변수, 볼륨(파일) 환경 변수, 볼륨(파일)

2. Pod에 넣는 두 가지 방법

ConfigMap과 Secret은 환경 변수로 넣거나, 볼륨으로 마운트해 키 하나를 파일 하나로 넣을 수 있습니다. 둘은 값을 바꿨을 때 동작이 다릅니다.

환경 변수는 컨테이너가 시작될 때 한 번 정해지고, 볼륨 파일은 kubelet이 주기적으로 새 값으로 바꿉니다

 

방식 값을 바꾸면 어울리는 값
환경 변수 반영되지 않음
Pod를 다시 만들어야 새 값이 들어감
DB 주소, 로그 레벨 같은 짧은 값
볼륨(파일) 1~2분 안에 파일이 새 값으로 바뀜(subPath로 마운트한 파일은 제외)
앱이 파일을 다시 읽어야 적용됨
설정 파일, 인증서

 

볼륨 파일이 바뀌어도 대부분의 앱은 시작할 때만 설정을 읽기 때문에, 실제로는 kubectl rollout restart로 Pod를 다시 만들어 적용하는 경우가 많습니다. 반대로 바뀔 일이 없는 값은 immutable: true를 주면 실수로 고치는 것을 막고, kubelet이 변경을 확인하지 않아 apiserver 부하도 줄어듭니다.

3. Secret과 base64

Secret의 data 값은 base64로 인코딩돼 있을 뿐이라, Secret을 읽을 권한이 있으면 누구나 원래 값으로 되돌릴 수 있습니다. ConfigMap과의 차이는 암호화가 아니라 관리 방식에 있습니다. kubectl describe에 값이 나오지 않고, 권한을 따로 줄 수 있으며, 필요한 노드에만 전달되고 노드에서는 디스크가 아닌 메모리(tmpfs)에 저장됩니다.

 

type 용도
Opaque 기본값, 임의의 key-value(kubectl create secret generic)
kubernetes.io/tls TLS 인증서와 키, Gateway나 Ingress의 HTTPS 설정에 사용
kubernetes.io/dockerconfigjson 사설 레지스트리에서 이미지를 받을 때의 로그인 정보(imagePullSecrets)

 

운영에서는 Secret을 YAML로 Git에 올리지 않고, etcd에 저장될 때 암호화되도록 설정하며, 원본 값은 외부 저장소에 두는 방식을 씁니다. Azure에서는 원본을 Key Vault에 두고 Pod에 파일로 넣을 수 있고, 방법은 [Azure] AKS에서 Key Vault로 Secret 관리 정리에 정리했습니다.

4. 직접 해 보기

Redis 설정 파일은 ConfigMap으로, 비밀번호는 Secret으로 넣습니다. 먼저 설정 파일을 만듭니다.

# redis.conf
appendonly yes
maxmemory 64mb
kubectl create configmap redis-config --from-file=redis.conf
kubectl create secret generic redis-auth --from-literal=password='S3cret!pass'
kubectl get secret redis-auth -o jsonpath='{.data.password}' | base64 -d

--from-file은 파일 이름을 키로, 파일 내용을 값으로 저장합니다. 마지막 명령은 Secret에 저장된 UzNjcmV0IXBhc3M=를 디코딩해 S3cret!pass를 그대로 보여 줍니다. base64가 암호화가 아니라는 것을 확인하는 명령입니다.

 

Redis Deployment에서 ConfigMap은 /etc/redis에 파일로, Secret은 환경 변수로 넣습니다. args의 $(REDIS_PASSWORD)는 Kubernetes가 컨테이너를 시작할 때 같은 컨테이너의 환경 변수 값으로 바꿔 줍니다.

# redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:8-alpine
        args: ["redis-server", "/etc/redis/redis.conf", "--requirepass", "$(REDIS_PASSWORD)"]
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: redis-auth
              key: password
        volumeMounts:
        - name: config
          mountPath: /etc/redis
      volumes:
      - name: config
        configMap:
          name: redis-config
kubectl apply -f redis.yaml
kubectl exec deploy/redis -- redis-cli ping
kubectl exec deploy/redis -- sh -c 'redis-cli -a "$REDIS_PASSWORD" --no-auth-warning config get maxmemory'

비밀번호 없이 보낸 ping은 NOAUTH 오류로 거절되고, 비밀번호를 준 명령은 maxmemory 값으로 64MB를 바이트로 바꾼 67108864를 돌려줍니다. Secret과 ConfigMap이 모두 적용된 것입니다. kubectl describe pod로 보면 REDIS_PASSWORD는 값 대신 어느 Secret의 어떤 키에서 왔는지만 나옵니다.

 

이제 redis.conf의 maxmemory를 128mb로 고치고 ConfigMap을 바꿉니다. create 명령에 --dry-run=client -o yaml을 붙여 만든 YAML을 apply에 넘기는 방식입니다. 처음 한 번은 last-applied-configuration 어노테이션이 없다는 경고가 나오는데, 자동으로 추가되므로 무시해도 됩니다.

kubectl create configmap redis-config --from-file=redis.conf --dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deployment/redis

rollout restart 없이 1~2분 기다리면 컨테이너 안의 /etc/redis/redis.conf 파일은 128mb로 바뀌지만, Redis는 시작할 때만 설정 파일을 읽어서 config get maxmemory 값은 그대로입니다. Pod를 다시 만들어야 134217728이 나옵니다. 이 Redis Deployment는 10편에서 데이터를 남기는 볼륨을 붙일 때 이어서 씁니다.

5. 운영 시 주의점

항목 조치
Secret YAML과 Git base64는 누구나 디코딩 가능
Git에는 올리지 않고 Key Vault, External Secrets 같은 외부 저장소 사용
etcd 저장 별도 설정이 없으면 etcd에 암호화되지 않은 채 저장
직접 구성한 클러스터는 EncryptionConfiguration으로 암호화
권한 Secret 조회 권한뿐 아니라 Pod 생성 권한만 있어도 Secret을 마운트해 읽을 수 있음
RBAC로 네임스페이스별 권한을 최소화
환경 변수 노출 앱이 환경 변수를 로그나 오류 화면에 출력하면 값이 새어 나감
민감한 값은 파일로 마운트하는 쪽이 안전
설정 변경 반영 환경 변수는 자동 반영되지 않음
ConfigMap을 바꾼 뒤 kubectl rollout restart로 적용

6. 정리

  • ConfigMap과 Secret은 환경마다 달라지는 값을 이미지 밖에 두고, 환경 변수나 파일로 Pod에 넣습니다.
  • 환경 변수는 Pod를 다시 만들어야 바뀌고, 볼륨 파일은 1~2분 안에 바뀌지만 앱이 다시 읽어야 적용됩니다.
  • Secret은 base64 인코딩일 뿐이므로 Git에 올리지 않고, etcd 암호화와 외부 저장소, RBAC로 보호합니다.

다음 글 10편에서는 Pod가 다시 만들어져도 데이터가 남도록 하는 Volume, PV, PVC, StorageClass를 다룹니다.

참고

728x90
서울
--:--:--
-전체 글
-카테고리
오늘 방문