학습 예시 안내: 본문의 상황과 출력은 개념 설명을 위한 예시로 정리했습니다. 당시 실행 여부는 확인되지 않았으며, 현재 환경에서의 클러스터 실습도 별도 검증이 필요합니다.
🎯 학습 목표
이 글을 통해 다음을 학습할 수 있습니다:
- 하드코딩된 설정값의 문제점과 해결책
- ConfigMap을 이용한 설정 데이터 외부화
- Secret을 이용한 민감 정보 보안 관리
- 환경변수와 볼륨 마운트를 통한 데이터 주입 방법
- CKA 준비 과정에서 연습할 구성 관리 패턴
📝 앞선 개념과 이번 예제
앞선 글에서는 Pod, Deployment, Service의 구성을 다뤘습니다. 이번에는 같은 애플리케이션을 개발·스테이징·운영 환경에 배포할 때 설정을 분리하는 상황을 가정합니다.
예제에서 가정한 환경
# 기존 리소스들 확인
kubectl get deployments
kubectl get services
kubectl get pods
문제 상황 시뮬레이션
예를 들어, 웹 애플리케이션에 데이터베이스 연결 설정이 필요하다고 가정해봅시다:
# 기존 방식의 발췌: 환경변수가 매니페스트에 하드코딩됨 (selector 등 생략)
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
template:
spec:
containers:
- name: web
image: nginx
env:
- name: DB_HOST
value: "mysql.prod.example.com" # 하드코딩!
- name: DB_PORT
value: "3306" # 하드코딩!
- name: DB_USER
value: "admin" # 하드코딩!
- name: DB_PASSWORD
value: "super-secret-password" # 보안 위험!
문제점들:
- 환경별 설정 어려움: 개발/스테이징/운영 환경마다 다른 값 필요
- 보안 위험: 비밀번호가 YAML 파일에 평문으로 노출
- 재사용성 부족: 환경별 매니페스트를 반복 수정해야 함 (위처럼 환경변수로 전달하면 이미지 재빌드는 필요 없음)
- 관리의 복잡성: 설정값이 여러 곳에 분산
이런 설정 데이터를 분리하는 ConfigMap과 Secret을 살펴보겠습니다.
🗃 ConfigMap 완전 이해하기
ConfigMap이란?
ConfigMap은 설정 데이터를 저장하는 쿠버네티스 오브젝트입니다. 컨테이너 이미지와 설정을 분리하여 관리할 수 있게 해줍니다.
첫 번째 ConfigMap 만들기
1. 명령어로 생성
# key-value 형태로 직접 생성
kubectl create configmap app-config \
--from-literal=DB_HOST=mysql.dev.example.com \
--from-literal=DB_PORT=3306 \
--from-literal=APP_ENV=development
# 생성 확인
kubectl get configmaps
kubectl describe configmap app-config
2. 파일에서 생성
먼저 설정 파일들을 만들어봅시다:
# 설정 파일 생성
echo "mysql.dev.example.com" > db-host.txt
echo "3306" > db-port.txt
# 애플리케이션 설정 파일 생성
cat > app.properties << EOF
app.name=MyWebApp
app.version=1.0.0
app.debug=true
max.connections=100
EOF
# 파일에서 ConfigMap 생성
kubectl create configmap file-config --from-file=app.properties
kubectl create configmap host-config --from-file=db-host.txt
# 확인
kubectl get configmap file-config -o yaml
3. YAML 매니페스트로 생성
# app-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: web-app-config
data:
# key-value 형태
DB_HOST: "mysql.dev.example.com"
DB_PORT: "3306"
DB_NAME: "webapp"
# 파일 형태 (멀티라인)
app.properties: |
app.name=MyWebApp
app.version=1.0.0
app.debug=true
logging.level=INFO
nginx.conf: |
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
}
# ConfigMap 생성
kubectl apply -f app-configmap.yaml
# 상세 확인
kubectl describe configmap web-app-config
🔐 Secret 완전 이해하기
Secret이란?
Secret은 민감한 정보를 별도로 관리하는 쿠버네티스 오브젝트입니다. data 필드는 Base64로 표현되지만, 이는 암호화가 아니며 누구나 디코딩할 수 있습니다. 기본 설정의 etcd 저장 암호화는 보장되지 않으므로 저장 시 암호화와 RBAC 접근 제한을 별도로 구성해야 합니다. Secret 보안 권장 사항
이 글의 비밀번호·토큰은 설명용 값입니다. 실제 비밀값을 글이나 저장소에 넣지 않고 별도로 관리합니다.
첫 번째 Secret 만들기
1. 명령어로 생성
# Generic Secret 생성
kubectl create secret generic db-credentials \
--from-literal=DB_USER=admin \
--from-literal=DB_PASSWORD=super-secret-password
# 생성 확인
kubectl get secrets
kubectl describe secret db-credentials
2. 파일에서 생성
# 민감한 정보를 파일로 저장
echo -n "admin" > username.txt
echo -n "super-secret-password" > password.txt
# 파일에서 Secret 생성
kubectl create secret generic file-credentials \
--from-file=username.txt \
--from-file=password.txt
# 확인 (데이터가 Base64로 인코딩됨)
kubectl get secret file-credentials -o yaml
3. YAML 매니페스트로 생성
# Base64 인코딩 (수동)
echo -n "admin" | base64
# YWRtaW4=
echo -n "super-secret-password" | base64
# c3VwZXItc2VjcmV0LXBhc3N3b3Jk
# db-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: database-secret
type: Opaque
data:
DB_USER: YWRtaW4= # admin (Base64)
DB_PASSWORD: c3VwZXItc2VjcmV0LXBhc3N3b3Jk # super-secret-password (Base64)
# Secret 생성
kubectl apply -f db-secret.yaml
# 데이터 확인 (디코딩)
kubectl get secret database-secret -o jsonpath='{.data.DB_USER}' | base64 --decode
Secret 타입별 이해
Docker Registry Secret
# Docker Hub 로그인 정보 저장
kubectl create secret docker-registry my-registry-secret \
--docker-server=docker.io \
--docker-username=myusername \
--docker-password=mypassword \
--docker-email=my@email.com
TLS Secret
# TLS 인증서 Secret 생성
kubectl create secret tls tls-secret \
--cert=path/to/cert.crt \
--key=path/to/cert.key
🔄 Pod에서 ConfigMap과 Secret 사용하기
1. 환경변수로 주입
# pod-with-config.yaml
apiVersion: v1
kind: Pod
metadata:
name: config-test-pod
spec:
containers:
- name: web
image: nginx
env:
# ConfigMap에서 환경변수 가져오기
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: web-app-config
key: DB_HOST
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: web-app-config
key: DB_PORT
# Secret에서 환경변수 가져오기
- name: DB_USER
valueFrom:
secretKeyRef:
name: database-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: database-secret
key: DB_PASSWORD
# Pod 생성 및 환경변수 확인
kubectl apply -f pod-with-config.yaml
kubectl exec config-test-pod -- env | grep DB_
2. 전체 ConfigMap/Secret을 환경변수로 주입
# pod-env-from.yaml
apiVersion: v1
kind: Pod
metadata:
name: env-from-pod
spec:
containers:
- name: web
image: nginx
envFrom:
# ConfigMap의 모든 key-value를 환경변수로
- configMapRef:
name: web-app-config
# Secret의 모든 key-value를 환경변수로
- secretRef:
name: database-secret
3. 볼륨 마운트로 파일 형태로 주입
# pod-volume-mount.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-mount-pod
spec:
containers:
- name: web
image: nginx
volumeMounts:
# ConfigMap을 파일로 마운트
- name: config-volume
mountPath: /etc/config
# Secret을 파일로 마운트
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: web-app-config
- name: secret-volume
secret:
secretName: database-secret
# Pod 생성 및 마운트된 파일 확인
kubectl apply -f pod-volume-mount.yaml
# ConfigMap 파일들 확인
kubectl exec volume-mount-pod -- ls -la /etc/config
kubectl exec volume-mount-pod -- cat /etc/config/app.properties
# Secret 파일들 확인
kubectl exec volume-mount-pod -- ls -la /etc/secrets
kubectl exec volume-mount-pod -- cat /etc/secrets/DB_USER
4. 특정 키만 선택적으로 마운트
# selective-mount.yaml
apiVersion: v1
kind: Pod
metadata:
name: selective-mount-pod
spec:
containers:
- name: web
image: nginx
volumeMounts:
- name: selective-config
mountPath: /etc/app
volumes:
- name: selective-config
configMap:
name: web-app-config
items:
- key: app.properties
path: application.properties
- key: nginx.conf
path: nginx/nginx.conf
💡 실전 예제: 환경별 설정 관리
환경별로 다른 설정값을 전달하는 학습용 시나리오입니다. 실제 운영 환경에 적용한 결과를 기록한 것은 아닙니다.
개발 환경 ConfigMap
# dev-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: development
data:
DB_HOST: "mysql.dev.local"
DB_PORT: "3306"
REDIS_HOST: "redis.dev.local"
LOG_LEVEL: "DEBUG"
API_ENDPOINT: "https://api-dev.example.com"
운영 환경 ConfigMap
# prod-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
DB_HOST: "mysql.prod.local"
DB_PORT: "3306"
REDIS_HOST: "redis.prod.local"
LOG_LEVEL: "WARN"
API_ENDPOINT: "https://api.example.com"
환경마다 생성할 Secret 템플릿 (Base64 표현)
<base64-encoded-…>는 실제 값으로 바꿔야 하는 자리표시자입니다. Secret·ConfigMap·Deployment는 같은 네임스페이스에 생성해야 하며, 운영 비밀값을 개발 환경과 공유하지 않습니다.
# common-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
DB_PASSWORD: <base64-encoded-password>
API_KEY: <base64-encoded-api-key>
JWT_SECRET: <base64-encoded-jwt-secret>
애플리케이션 Deployment
# web-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web
image: myapp:latest
ports:
- containerPort: 8080
# ConfigMap에서 환경변수 주입
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
# 설정 파일 마운트
volumeMounts:
- name: app-config-volume
mountPath: /app/config
readOnly: true
volumes:
- name: app-config-volume
configMap:
name: app-config
🔄 ConfigMap과 Secret 업데이트
데이터 업데이트 방법
# ConfigMap 데이터 업데이트
kubectl patch configmap web-app-config -p '{"data":{"DB_HOST":"new-mysql.example.com"}}'
# Secret 데이터 업데이트 (Base64 인코딩 필요)
kubectl patch secret database-secret -p '{"data":{"DB_PASSWORD":"'$(echo -n "new-password" | base64)'"}}'
# 또는 파일에서 업데이트
kubectl create configmap web-app-config --from-file=new-config.properties --dry-run=client -o yaml | kubectl replace -f -
Pod에서 업데이트 반영
주의할 점: ConfigMap이나 Secret을 업데이트해도 기존 Pod의 환경변수는 자동으로 업데이트되지 않습니다!
# Pod 재시작이 필요
kubectl rollout restart deployment web-app
# 또는 Pod를 직접 삭제 (Deployment가 자동으로 새 Pod 생성)
kubectl delete pods -l app=web-app
볼륨 마운트의 경우: 일반적인 ConfigMap·Secret 볼륨은 지연 후 갱신되며, 애플리케이션도 변경을 다시 읽어야 합니다. subPath로 마운트한 파일은 자동 갱신되지 않습니다. ConfigMap 공식 문서
🚨 문제 해결과 디버깅
ConfigMap/Secret이 Pod에 반영되지 않을 때
1. 존재 여부 확인
# ConfigMap/Secret 존재 확인
kubectl get configmap <name>
kubectl get secret <name>
# 네임스페이스 확인
kubectl get configmap <name> -n <namespace>
2. 키 이름 확인
# 정확한 키 이름 확인
kubectl describe configmap <name>
kubectl get configmap <name> -o yaml
3. Pod 이벤트 확인
# Pod 생성 실패 원인 확인
kubectl describe pod <pod-name>
kubectl get events --sort-by=.metadata.creationTimestamp
일반적인 실수들
1. Base64 인코딩 누락
# ❌ 잘못된 예 (Secret에서 평문 사용)
data:
password: "my-password"
---
# ✅ 올바른 예
data:
password: "bXktcGFzc3dvcmQ=" # Base64 인코딩된 값
2. 존재하지 않는 키 참조
# ❌ ConfigMap에 없는 키 참조
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: my-config
key: DATABASE_HOST # 실제로는 DB_HOST
---
# ✅ 올바른 키 사용
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: my-config
key: DB_HOST
3. 네임스페이스 불일치
# Pod는 default 네임스페이스, ConfigMap은 다른 네임스페이스에 있는 경우
# ConfigMap을 같은 네임스페이스로 이동하거나 Pod 네임스페이스 변경 필요
🎯 CKA 대비 연습 패턴
연습할 문제 유형
1. ConfigMap 생성과 사용
# 문제: key-value로 ConfigMap 생성하고 Pod에서 환경변수로 사용
kubectl create configmap app-config --from-literal=APP_ENV=production
2. Secret 생성과 사용
# 문제: Secret 생성하고 Pod에서 볼륨으로 마운트
kubectl create secret generic db-secret --from-literal=password=secret123
3. 파일에서 ConfigMap/Secret 생성
# 문제: 기존 파일에서 ConfigMap 생성
kubectl create configmap nginx-config --from-file=nginx.conf
4. 기존 Pod에 ConfigMap 적용
- 기존 Deployment를 수정해서 ConfigMap 사용하도록 변경
- 환경변수와 볼륨 마운트 방식 선택
시간 단축 팁
# 빠른 생성
kubectl create cm <name> --from-literal=key=value # cm = configmap
kubectl create secret generic <name> --from-literal=key=value
# 기존 리소스를 YAML로 출력 후 수정
kubectl get configmap <name> -o yaml > config.yaml
# 즉시 적용 및 확인
kubectl apply -f config.yaml && kubectl describe configmap <name>
📊 ConfigMap vs Secret 비교 정리
기능 비교표
| 항목 | ConfigMap | Secret |
|---|---|---|
| 용도 | 일반 설정 데이터 | 민감한 정보 |
| 데이터 표현 | data 문자열 / binaryData Base64 |
data Base64 (암호화 아님) |
| 크기 제한 | 1 MiB | 1 MiB |
| 환경변수 주입 | ✅ | ✅ |
| 볼륨 마운트 | ✅ | ✅ |
| 변경 반영 | 일반 볼륨은 지연 갱신, 환경변수·subPath는 자동 갱신 안 됨 | 일반 볼륨은 지연 갱신, 환경변수·subPath는 자동 갱신 안 됨 |
사용 가이드라인
ConfigMap 사용하는 경우:
- 데이터베이스 호스트명, 포트 번호
- API 엔드포인트 URL
- 애플리케이션 설정 파일
- 로그 레벨, 디버그 모드 설정
Secret 사용하는 경우:
- 데이터베이스 비밀번호
- API 키, 토큰
- TLS 인증서와 개인키
- OAuth 클라이언트 시크릿
📚 필수 명령어 정리
ConfigMap 관리
# 생성
kubectl create configmap <name> --from-literal=key=value
kubectl create configmap <name> --from-file=<file>
kubectl apply -f configmap.yaml
# 조회
kubectl get configmaps # 또는 kubectl get cm
kubectl describe configmap <name>
kubectl get configmap <name> -o yaml
# 수정
kubectl edit configmap <name>
kubectl patch configmap <name> -p '{"data":{"key":"new-value"}}'
# 삭제
kubectl delete configmap <name>
Secret 관리
# 생성
kubectl create secret generic <name> --from-literal=key=value
kubectl create secret generic <name> --from-file=<file>
kubectl create secret docker-registry <name> --docker-server=<server>
# 조회
kubectl get secrets
kubectl describe secret <name>
kubectl get secret <name> -o yaml
# 데이터 확인 (Base64 디코딩)
kubectl get secret <name> -o jsonpath='{.data.key}' | base64 --decode
# 삭제
kubectl delete secret <name>
🚀 다음 학습 계획
다음에는 애플리케이션의 CPU·메모리 요청량과 제한을 설정하는 방법을 살펴볼 계획입니다.
다음 주제들
- Pod 리소스 제한과 요청 설정 - 리소스 최적화와 안정성
- Liveness와 Readiness Probe 구성 - 헬스체크와 자동 복구
- 네임스페이스를 통한 리소스 격리
- Ingress를 통한 외부 트래픽 관리
- RBAC과 보안 설정
개인 학습 목표
- 실제 운영 환경에서의 설정 관리 패턴 이해
- 보안을 고려한 민감 정보 관리 방법 숙달
- 다양한 주입 방식(환경변수 vs 볼륨)의 적절한 선택
ConfigMap과 Secret은 설정을 코드와 분리하는 수단입니다. 환경변수와 볼륨은 갱신 방식이 다르므로, 설정을 바꾼 뒤 애플리케이션이 실제로 읽는 값까지 확인해야 합니다.
다음 글에서는 Pod의 리소스 요청과 제한을 다룹니다.
🔗 참고 자료:
yellow.log · 2025.08.06에 작성 · 2026.09.29에 수정
CKA 준비 전체 8편
- 1.Pod 생성과 관리 - 쿠버네티스의 기본 단위 이해하기
- 2.ReplicaSet과 Deployment로 Pod 관리하기 - 확장성과 가용성 확보
- 3.Service를 통한 Pod 네트워킹 - 안정적인 접근 경로 만들기
- 4.ConfigMap과 Secret으로 설정 관리하기 - 환경별 설정 분리읽는 중
- 5.Pod 리소스 제한과 요청 설정 - 안정적인 클러스터 운영을 위한 리소스 관리
- 6.Liveness와 Readiness Probe 구성 - 헬스체크와 자동 복구
- 7.네임스페이스를 통한 리소스 격리와 다중 테넌시 - 팀별, 환경별 격리
- 8.Ingress를 통한 외부 트래픽 관리와 라우팅 - 클러스터의 똑똑한 관문 구축