운영 DB 비밀번호를 교체했는데 애플리케이션 파드는 여전히 예전 값으로 접속하고 있습니다. ConfigMap과 Secret이 파드에 환경변수 또는 볼륨으로 주입되는 방식을 모르면 재시작 필요 여부를 놓치게 됩니다. 설정과 민감정보를 안전하게 분리하는 습관이 운영 사고를 줄입니다.
ConfigMap과 Secret — 설정과 민감 정보 분리
배포 자동화를 처음 구성할 때 가장 많이 저지르는 실수가 있습니다. 데이터베이스 비밀번호, API 키, 접속 URL을 Docker 이미지 안에 하드코딩하거나 Deployment YAML에 직접 씁니다. 이렇게 하면 개발/스테이징/운영 환경마다 다른 이미지를 빌드해야 하고, 비밀번호가 Git 이력에 남아 보안 감사에서 지적을 받습니다. Kubernetes는 이 문제를 ConfigMap과 Secret으로 해결합니다. 설정은 코드와 분리하고, 동일한 이미지를 환경별로 다른 설정으로 실행합니다. 비밀번호는 Secret으로 격리하고 RBAC으로 접근을 제어합니다. 이 패턴이 12-Factor App의 세 번째 원칙(Config)이며, 쿠버네티스 기반 운영 환경의 표준 방식입니다.
ConfigMap과 Secret으로 설정과 민감 정보를 이미지에서 분리하고, 두 가지 주입 방식의 차이를 실습합니다.
- 1ConfigMap으로 일반 설정 데이터를 환경변수와 볼륨에 주입할 수 있다
- 2Secret의 Base64 인코딩과 실제 보안 메커니즘을 설명할 수 있다
- 3환경변수 방식과 볼륨 마운트 방식을 비교해 선택할 수 있다
- 4Secret 변경 후 파드에 반영되는 타이밍을 파악할 수 있다
- 5etcd 암호화와 RBAC 등 실무 보안 주의사항을 적용할 수 있다
기본적인 kubectl 사용법(kubectl-basics)과 Deployment 개념(deployment-basics)을 익혔다면 바로 시작할 수 있습니다.
kubectl cluster-infokubectl create namespace config-labkubectl config set-context --current --namespace=config-labConfigMap — 환경변수와 볼륨 마운트 두 방식
개발 환경과 운영 환경의 데이터베이스 접속 URL이 다를 때, 이미지를 환경마다 따로 빌드하면 배포 실수가 생기고 이미지 관리가 복잡해집니다. Docker 이미지에 설정값을 하드코딩하면 "코드는 맞는데 설정이 달라서 장애"가 생기고 어느 환경에 어떤 값이 들어갔는지 추적이 어렵습니다. ConfigMap은 이 설정 데이터를 이미지 밖으로 꺼내 Kubernetes 오브젝트로 독립 관리하는 방법입니다. 주입 방식이 환경변수냐 볼륨 마운트냐에 따라 변경 반영 시점이 달라지기 때문에, 두 방식의 차이를 알아야 설정 변경 후 재시작 없이 반영됐다고 잘못 판단하는 실수를 막을 수 있습니다.
확대
ConfigMap 생성
# 명령어로 직접 생성
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=APP_PORT=8080 \
--from-literal=LOG_LEVEL=info \
-n config-lab
# 파일에서 생성 (설정 파일을 통째로 ConfigMap에 저장)
kubectl create configmap nginx-config \
--from-file=nginx.conf \
-n config-lab
# ConfigMap 확인
kubectl get configmap app-config -n config-lab -o yaml
# configmap.yaml — YAML로 직접 정의
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: config-lab
data:
APP_ENV: "production"
APP_PORT: "8080"
LOG_LEVEL: "info"
# 여러 줄 설정 파일도 저장 가능
app.properties: |
server.port=8080
spring.datasource.url=jdbc:postgresql://postgres:5432/mydb
logging.level.root=INFO
ConfigMap의 값을 컨테이너 환경변수로 넣는 두 방법(envFrom 전체 주입 / configMapKeyRef 선택 주입)을 deployment에 작성하고, 적용 후 파드 안에서 env로 실제 주입됐는지 확인합니다.
# deployment-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: config-lab
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env && sleep 3600"]
# 방법 A: ConfigMap의 모든 key-value를 환경변수로 주입
envFrom:
- configMapRef:
name: app-config
# 방법 B: 특정 키만 선택하여 다른 이름으로 주입
env:
- name: PORT # 컨테이너 환경변수 이름
valueFrom:
configMapKeyRef:
name: app-config
key: APP_PORT # ConfigMap의 key
kubectl apply -f deployment-env.yaml
# 파드에서 환경변수 확인
kubectl exec -it $(kubectl get pod -n config-lab -l app=my-app -o name) \
-n config-lab -- env | grep -E "APP_ENV|APP_PORT|LOG_LEVEL"
# APP_ENV=production
# APP_PORT=8080
# LOG_LEVEL=info
kubectl apply -f deployment-env.yaml- env 출력에 APP_ENV·APP_PORT·LOG_LEVEL이 모두 보이는지 본다 — 안 보이면 ConfigMap 이름 오타이거나 파드가 ConfigMap 생성 전에 떠서 반영 안 된 것(파드 재생성 필요)
- envFrom은 ConfigMap의 키 이름 그대로(APP_PORT), env+configMapKeyRef는 지정한 이름(PORT)으로 들어온다 — 둘의 키 이름 차이를 확인
- 환경변수 주입은 파드 시작 시점에 고정된다 — ConfigMap을 수정해도 기존 파드의 env는 안 바뀐다(볼륨 마운트와의 핵심 차이). 갱신하려면 롤아웃 재시작이 필요
- 값이 비어 들어오면 ConfigMap의 해당 key가 실제로 있는지 kubectl get configmap app-config -o yaml로 교차 확인
방식 2: 볼륨으로 마운트 (자동 갱신 가능)
# deployment-volume.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-vol
namespace: config-lab
spec:
replicas: 1
selector:
matchLabels:
app: my-app-vol
template:
metadata:
labels:
app: my-app-vol
spec:
volumes:
- name: config-volume
configMap:
name: app-config # ConfigMap을 볼륨으로 변환
containers:
- name: app
image: busybox
command: ["sh", "-c", "ls /etc/config && cat /etc/config/APP_ENV && sleep 3600"]
volumeMounts:
- name: config-volume
mountPath: /etc/config # 이 경로에 ConfigMap key가 파일로 생성됨
kubectl apply -f deployment-volume.yaml
# 마운트된 파일 확인
kubectl exec -it $(kubectl get pod -n config-lab -l app=my-app-vol -o name) \
-n config-lab -- ls /etc/config
# APP_ENV APP_PORT LOG_LEVEL app.properties
# ↑ 각 key가 파일로 생성됨
kubectl exec -it $(kubectl get pod -n config-lab -l app=my-app-vol -o name) \
-n config-lab -- cat /etc/config/APP_ENV
# production
두 방식 비교
| 항목 | 환경변수 (envFrom) | 볼륨 마운트 |
|---|---|---|
| 설정 변경 반영 | 파드 재시작 필요 | kubelet이 자동 갱신 (~1-2분) |
| 대용량 파일 | 어려움 | 가능 (nginx.conf 등) |
| 프로세스 접근 | os.getenv() | 파일 읽기 (open()) |
| 민감도 | 프로세스 메모리에 노출 | 파일로 격리 |
| 적합한 용도 | 짧은 key-value 설정 | 설정 파일, 자주 갱신되는 설정 |
Secret — Base64 인코딩과 실제 보안 메커니즘
보안 감사에서 "Git 이력에 DB 비밀번호가 평문으로 남아있습니다"라는 지적을 받는 경우, 대부분 Deployment YAML에 직접 환경변수를 넣었거나 ConfigMap에 민감값을 저장했기 때문입니다. Secret은 ConfigMap과 구조는 비슷하지만 RBAC으로 접근 제어를 분리하고, etcd 암호화 at rest로 저장 시 보호할 수 있는 전용 오브젝트입니다. Base64가 "암호화"처럼 보이지만 누구나 디코딩할 수 있다는 사실을 모르면 잘못된 보안 의식이 생깁니다. Secret의 실제 보안은 RBAC과 etcd 암호화에서 나오며, 이 두 가지가 갖춰지지 않으면 Secret이라도 안전하지 않습니다.
확대
Secret 생성 — Base64 이해
# Base64 인코딩 (암호화 아님, 인코딩임)
echo -n 'mypassword123' | base64
# bXlwYXNzd29yZDEyMw==
# Base64 디코딩 (누구나 가능)
echo 'bXlwYXNzd29yZDEyMw==' | base64 -d
# mypassword123
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: config-lab
type: Opaque
data:
# 값은 반드시 Base64 인코딩된 문자열
DB_PASSWORD: bXlwYXNzd29yZDEyMw== # 'mypassword123'
DB_USER: YWRtaW4= # 'admin'
# stringData를 쓰면 평문으로 작성 가능 (kubectl이 자동으로 인코딩)
stringData:
DB_HOST: "postgres-service:5432" # 평문 작성 가능
# 명령어로 Secret 생성 (더 안전한 방법 — 터미널 이력에 평문이 남지 않음)
kubectl create secret generic db-secret \
--from-literal=DB_PASSWORD=mypassword123 \
--from-literal=DB_USER=admin \
-n config-lab
# Secret 확인 (값은 Base64로 표시됨)
kubectl get secret db-secret -n config-lab -o yaml
# data:
# DB_PASSWORD: bXlwYXNzd29yZDEyMw==
# DB_USER: YWRtaW4=
# 값 디코딩 확인
kubectl get secret db-secret -n config-lab \
-o jsonpath='{.data.DB_PASSWORD}' | base64 -d
# mypassword123
Secret을 파드에 주입
환경변수와 볼륨 방식 모두 ConfigMap과 동일합니다. 단 볼륨 마운트 시 파일 권한을 0400(소유자만 읽기)으로 제한하는 것이 보안 베스트 프랙티스입니다.
# deployment-secret.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: db-app
namespace: config-lab
spec:
replicas: 1
selector:
matchLabels:
app: db-app
template:
metadata:
labels:
app: db-app
spec:
volumes:
- name: secret-volume
secret:
secretName: db-secret
defaultMode: 0400 # 소유자만 읽기 가능 (보안 강화)
containers:
- name: app
image: busybox
command: ["sh", "-c", "sleep 3600"]
# 환경변수 방식
envFrom:
- secretRef:
name: db-secret
# 볼륨 방식 (환경변수와 동시 사용 가능)
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true # 컨테이너가 Secret 파일 수정 불가
kubectl apply -f deployment-secret.yaml
# Secret이 환경변수로 주입됐는지 확인
kubectl exec -it $(kubectl get pod -n config-lab -l app=db-app -o name) \
-n config-lab -- env | grep DB
# DB_PASSWORD=mypassword123
# DB_USER=admin
# DB_HOST=postgres-service:5432
# 볼륨으로 마운트된 Secret 파일 확인
kubectl exec -it $(kubectl get pod -n config-lab -l app=db-app -o name) \
-n config-lab -- ls -la /etc/secrets
# -r-------- 1 root root 13 May 16 05:00 DB_PASSWORD
# -r-------- 1 root root 5 May 16 05:00 DB_USER
실제 보안 주의사항
# ❌ 금지: Secret을 Git에 커밋하지 말 것
git add secret.yaml && git commit -m "add db secret"
# → 이력에 평문(또는 Base64) 값이 영원히 남음
# ✅ 권장: .gitignore에 추가
echo "*-secret.yaml" >> .gitignore
echo "*.secret.yaml" >> .gitignore
# ✅ 권장: kubectl create secret으로 터미널에서 직접 생성
# 또는 HashiCorp Vault, AWS Secrets Manager + external-secrets-operator 사용
# etcd 암호화 at rest 설정 확인 (클러스터 관리자용)
kubectl get encryptionconfigurations -A 2>/dev/null || \
echo "EncryptionConfiguration 확인: 클러스터 설정 필요"
ConfigMap·Secret 값이 컨테이너 안까지 들어가는 법 — 5단계
kubectl apply로 ConfigMap이나 Secret을 만들었다고 값이 바로 앱에 들어가는 것은 아닙니다. 값은 etcd에 저장됐다가, 파드가 그것을 참조하고, kubelet이 읽어와, 환경변수로 주입되거나 파일로 마운트된 다음, 마지막으로 앱이 읽어야 비로소 쓰입니다. 이 경로를 알면 "설정을 바꿨는데 왜 파드는 옛 값이지"의 답이 어느 단계에 있는지 — 재시작이 필요한 env 방식(④a)인지, 자동 갱신되는 volume 방식(④b)인지, 아니면 앱이 파일을 다시 안 읽는 것(⑤)인지 — 를 정확히 짚을 수 있습니다.
kubectl apply -f configmap.yaml / secret.yaml
│
① 리소스 생성 → etcd 저장 (ConfigMap=평문 · Secret=Base64, 암호화 아님)
│
② 파드 스펙이 참조 (env/envFrom · 또는 volumes + volumeMounts)
│
③ kubelet이 값 조회 (API 서버에서 해당 ConfigMap/Secret 읽음)
│
├─④a env 방식: 시작 시 환경변수 주입 (프로세스에 고정 → 이후 변경 반영 안 됨)
├─④b volume 방식: 파일로 마운트 (..data 심링크 → 값 바뀌면 파일 자동 갱신)
│
⑤ 앱이 읽음 (os.getenv() · 또는 파일 open())
▼
env=재시작해야 갱신 · volume=지연 후 자동 갱신(단, 앱이 다시 읽어야 실제 적용)
각 단계에서 무슨 일이 일어나고, 막히면 어떤 증상인가:
| 단계 | 하는 일 | 여기서 막히면 |
|---|---|---|
| ① 생성·저장 | ConfigMap/Secret이 etcd에 저장. Secret은 Base64 인코딩일 뿐 암호화 아님 | 잘못된 네임스페이스에 생성 → 파드가 못 찾음 |
| ② 참조 | 파드 스펙이 configMapRef·secretRef(env) 또는 volumes(파일)로 가리킴 | 이름 오타·미존재 → 파드가 CreateContainerConfigError로 안 뜸 |
| ③ 조회 | kubelet이 파드 기동 시 API 서버에서 값을 읽어 옴 | 파드가 리소스 생성 전에 이미 떠 있었다면 옛 상태 그대로(재생성 필요) |
| ④a env 주입 | 시작 시 환경변수로 넣고 프로세스에 고정 | ConfigMap/Secret을 바꿔도 기존 파드는 옛 값 → rollout restart 필요 |
| ④b volume 마운트 | ..data 심링크로 파일 제공, 값이 바뀌면 원자적 교체로 자동 갱신 | subPath로 단일 파일만 마운트하면 갱신 대상에서 빠져 옛 값 고정 |
| ⑤ 앱이 읽음 | 앱이 os.getenv()로 환경변수를, 또는 파일을 읽어 실제 사용 | 파일은 새 값인데 앱이 다시 안 읽으면 프로세스 안 값은 그대로(리로드 필요) |
정리하면 "변경이 반영 안 됨"의 원인은 거의 항상 ④와 ⑤에 있습니다. env 방식(④a)은 원래 재시작해야 바뀌는 것이 정상이고, volume 방식인데도 안 바뀌면 ④b의 subPath를 의심하며, 파일까지 새 값인데 동작이 옛날 그대로면 ⑤(앱이 파일을 다시 읽지 않음)입니다. 반대로 파드가 아예 안 뜨면 ②(참조 이름 오타·미존재)를 먼저 봅니다.
문제 상황
# Secret 값을 업데이트
kubectl create secret generic db-secret \
--from-literal=DB_PASSWORD=newpassword456 \
-n config-lab \
--dry-run=client -o yaml | kubectl apply -f -
# Secret 확인 — 변경됨
kubectl get secret db-secret -n config-lab \
-o jsonpath='{.data.DB_PASSWORD}' | base64 -d
# newpassword456 ← 새 값으로 변경됨
# 파드에서 확인 — 아직 이전 값!
kubectl exec -it $(kubectl get pod -n config-lab -l app=db-app -o name) \
-n config-lab -- env | grep DB_PASSWORD
# DB_PASSWORD=mypassword123 ← 여전히 이전 값
원인 분석
환경변수는 파드 시작 시 프로세스에 주입된 후 고정됩니다. 부모 프로세스 환경변수가 바뀌지 않듯, 실행 중인 파드의 환경변수는 Secret이 바뀌어도 자동으로 갱신되지 않습니다.
Secret 업데이트
↓
kubelet이 감지 (약 수십 초)
↓
볼륨 마운트 방식: 파일 자동 갱신 ✅
환경변수 방식: 파드 재시작 필요 ❌
해결: 파드 재시작
# Deployment의 모든 파드를 롤링 재시작
kubectl rollout restart deployment/db-app -n config-lab
# 재시작 진행 상태 확인
kubectl rollout status deployment/db-app -n config-lab
# Waiting for deployment "db-app" rollout to finish: 1 old replicas are pending termination...
# deployment "db-app" successfully rolled out
# 새 파드에서 Secret 값 확인
kubectl exec -it $(kubectl get pod -n config-lab -l app=db-app -o name) \
-n config-lab -- env | grep DB_PASSWORD
# DB_PASSWORD=newpassword456 ← 새 값 반영됨!
볼륨 마운트는 자동 갱신 확인
# 볼륨 방식은 파드 재시작 없이 자동 반영 (1~2분 대기)
kubectl exec -it $(kubectl get pod -n config-lab -l app=db-app -o name) \
-n config-lab -- cat /etc/secrets/DB_PASSWORD
# newpassword456 ← kubelet이 자동으로 갱신
# 갱신 시간 확인 (파일 수정 시간이 변경됨)
kubectl exec -it $(kubectl get pod -n config-lab -l app=db-app -o name) \
-n config-lab -- ls -la /etc/secrets/
예방 패턴: Secret 변경 시 자동 재시작 트리거
# Deployment의 annotation에 Secret 체크섬을 추가하는 패턴
# Helm 차트에서 많이 사용
spec:
template:
metadata:
annotations:
# Secret 내용의 해시값 — Secret이 바뀌면 이 값도 바뀌어 파드 재시작됨
checksum/secret: "{{ include (print $.Template.BasePath \"/secret.yaml\") . | sha256sum }}"
심화 — 볼륨 자동 갱신의 예외
심화: subPath로 마운트하면 자동 갱신이 깨진다
볼륨으로 마운트하면 ConfigMap/Secret이 자동 갱신된다는 것까지는 배웠습니다. 그런데 자동 갱신을 믿고 배포했는데 파일이 옛 값 그대로인 사고가 실무에서 반복됩니다. 그 대부분은 subPath 때문입니다.
- 자동 갱신의 원리: kubelet은 ConfigMap/Secret 볼륨을 마운트할 때 실제 데이터를
..data같은 타임스탬프 디렉터리에 쓰고, 마운트 경로에는 그 디렉터리를 가리키는 심볼릭 링크를 둡니다. 값이 바뀌면 새 타임스탬프 디렉터리를 만든 뒤 심링크를 원자적으로 교체해 파일이 통째로 갱신됩니다. - subPath의 함정:
volumeMount에subPath를 지정하면 kubelet은 마운트 시점의 그 파일 하나만 컨테이너에 바인드 마운트합니다. 심링크 교체의 대상이 아니므로, ConfigMap이 바뀌어도 그 파일은 파드가 재생성될 때까지 옛 값 그대로입니다. 볼륨은 자동 갱신된다는 규칙이 subPath에서는 깨집니다. - 타이밍도 알아야 합니다: 자동 갱신은 즉시가 아니라 kubelet sync 주기 + 캐시 전파만큼(합쳐 최대 1분 안팎) 늦습니다. 게다가 파일이 갱신돼도 앱이 그 파일을 다시 읽지 않으면 프로세스 안의 값은 그대로입니다 — inotify로 리로드하거나 롤아웃이 필요합니다.
정리하면, 자동 갱신이 필요한 설정은 subPath 없이 디렉터리째 마운트하고, 특정 파일만 넣어야 하면 subPath 대신 볼륨의 items로 필요한 키만 파일로 노출합니다. subPath가 불가피하면 값 변경 시 롤아웃으로 파드를 새로 띄웁니다.
상황: nginx.conf를 ConfigMap 볼륨으로 마운트하고 값을 수정한 뒤 kubelet의 자동 갱신을 기대했습니다. 그런데 5분, 10분이 지나도 컨테이너 안 /etc/nginx/nginx.conf는 옛 내용 그대로입니다. 환경변수 주입 문제도 아니고 분명 볼륨 마운트인데 바뀌지 않습니다.
원인: volumeMount에 subPath: nginx.conf를 써서 디렉터리가 아니라 단일 파일만 바인드 마운트했습니다. subPath로 마운트한 파일은 kubelet의 심링크 원자 교체 대상에서 빠지므로 ConfigMap이 바뀌어도 갱신되지 않습니다. /etc/nginx에 다른 파일이 이미 있어 디렉터리째 덮으면 곤란해서 subPath를 쓴 것이 원인이었습니다.
진단: 파드 spec에서 volumeMounts의 subPath가 설정돼 있는지 확인합니다. subPath가 있으면 자동 갱신은 기대할 수 없습니다. 컨테이너 안에서 ls -la로 마운트 경로를 보면, 자동 갱신되는 마운트는 ..data를 가리키는 심링크 구조가 보이지만 subPath는 평범한 일반 파일만 있어 바로 구분됩니다.
해결: 자동 갱신이 필요하면 subPath를 빼고 디렉터리째 마운트하거나, 특정 파일만 넣어야 하면 볼륨의 items로 필요한 키만 파일로 노출합니다(이 방식은 갱신됩니다). subPath가 불가피하면 ConfigMap을 새 이름/버전으로 만들고 Deployment를 롤아웃해 파드를 새로 뜨게 합니다(checksum annotation 패턴).
환경별 설정 분리 패턴
실무에서 개발/스테이징/프로덕션 환경마다 ConfigMap 이름을 동일하게 유지하고 내용만 다르게 관리합니다.
# 각 환경의 ConfigMap — 이름은 동일, 네임스페이스로 구분
# 개발 환경
kubectl create configmap app-config \
--from-literal=APP_ENV=development \
--from-literal=LOG_LEVEL=debug \
-n development
# 프로덕션 환경
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=LOG_LEVEL=warn \
-n production
# Deployment YAML은 동일하게 사용 — namespace만 다름
Secret 관리 도구 연동 (실무 권장)
# external-secrets-operator를 사용하면 AWS Secrets Manager의 값을
# 자동으로 Kubernetes Secret으로 동기화
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-secret
spec:
refreshInterval: 1h # 1시간마다 동기화
secretStoreRef:
name: aws-secretsmanager
kind: ClusterSecretStore
target:
name: db-secret # 생성될 Kubernetes Secret 이름
data:
- secretKey: DB_PASSWORD
remoteRef:
key: production/myapp/db # AWS Secrets Manager의 경로
property: password
불변 ConfigMap으로 의도치 않은 변경 방지
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v1
immutable: true # 생성 후 수정 불가 (변경 시 새 ConfigMap 생성 필요)
data:
APP_VERSION: "1.0.0"
대규모 클러스터에서 immutable: true를 사용하면 kubelet이 변경 감시를 중단해 API 서버 부하가 줄어드는 장점도 있습니다.
실무 체크리스트
- Secret 값을
kubectl describe로 확인하면Data: X bytes형태로 마스킹됨 (기본 보안) - 파드의 서비스어카운트에 최소 권한 원칙 적용 — Secret 읽기 권한만 부여
- 로그에 Secret 값이 출력되지 않도록 애플리케이션 수준에서도 주의
- Deployment 롤링 업데이트 중에는 이전 파드와 새 파드가 동시에 다른 Secret 값을 사용할 수 있음
정리
# ConfigMap 관련 명령어
kubectl create configmap <name> --from-literal=KEY=VALUE
kubectl create configmap <name> --from-file=config.yaml
kubectl get configmap -n <namespace>
kubectl describe configmap <name> -n <namespace>
kubectl edit configmap <name> -n <namespace>
kubectl delete configmap <name> -n <namespace>
# Secret 관련 명령어
kubectl create secret generic <name> --from-literal=KEY=VALUE
kubectl create secret tls <name> --cert=tls.crt --key=tls.key
kubectl get secret -n <namespace>
kubectl describe secret <name> -n <namespace> # 값은 마스킹됨
# 적용된 값 확인
kubectl get secret <name> -o jsonpath='{.data.KEY}' | base64 -d
# Secret 변경 후 파드 재시작
kubectl rollout restart deployment/<name> -n <namespace>
kubectl rollout status deployment/<name> -n <namespace>
- kubectl get configmap -o yaml 에서 data 섹션을 먼저 확인 — 키-값이 의도한 대로 있는지 검증. 키가 없으면 --from-literal 옵션이 누락된 것
- Pod에서 환경변수로 주입된 경우: kubectl exec 후 printenv KEY_NAME 으로 실제 값 확인. 출력 없으면 envFrom/env 설정 오류 또는 ConfigMap 이름 불일치
- Secret은 base64 인코딩: kubectl get secret -o jsonpath='{.data.KEY}' | base64 -d 로 확인 시 원본값과 다르면 인코딩 오류 — stringData 필드 사용으로 해결
- 볼륨 마운트 방식 갱신 확인: kubectl exec 후 ls -la /etc/config 에서 파일 수정 시간을 보고 ConfigMap 수정 후 1~2분 내에 갱신됐는지 확인. 갱신 안 됐으면 kubelet sync 주기 대기
- 환경변수 방식 미반영 확인: kubectl rollout restart 후 kubectl rollout status 에서 "successfully rolled out" 출력 → 새 파드에서 printenv 로 재확인. rollout 중이면 이전 파드와 새 파드가 동시에 다른 값 사용 중일 수 있음
- RBAC 문제 확인: kubectl get secret 에서 Error from server (Forbidden) 이 나오면 현재 사용자 또는 ServiceAccount에 secret get 권한 없음 — kubectl auth can-i get secret 으로 확인
명령어·단축키 빠른 참조
이 모듈에서 ConfigMap·Secret을 만들고 주입·갱신할 때 쓴 kubectl 명령을 모았습니다. "변경 후 반영"과 "Secret 디코딩" 조합이 특히 자주 쓰입니다.
| 명령어/단축키 | 용도 | 자주 쓰는 예 |
|---|---|---|
kubectl create configmap | 설정값으로 ConfigMap 생성 | ... app-config --from-literal=LOG_LEVEL=info |
kubectl create configmap --from-file | 설정 파일 통째로 저장 | ... nginx-config --from-file=nginx.conf |
kubectl create secret generic | 민감값으로 Secret 생성 | ... db-secret --from-literal=DB_PASSWORD=... |
kubectl create secret tls | TLS 인증서 Secret 생성 | ... --cert=tls.crt --key=tls.key |
kubectl get configmap -o yaml | data 섹션 키-값 검증 | kubectl get cm app-config -o yaml (cm 축약) |
kubectl get secret -o jsonpath | Secret 값 디코딩 확인 | ... -o jsonpath='{.data.DB_PASSWORD}' | base64 -d |
base64 / base64 -d | Base64 인코딩·디코딩(암호화 아님) | echo -n 'pw' | base64 / echo '...' | base64 -d |
kubectl describe secret | 값 노출 없이 키·크기 확인 | Data: X bytes로 마스킹됨 |
kubectl exec ... -- env | 파드에 주입된 환경변수 확인 | ... -- env | grep DB / printenv DB_PASSWORD |
kubectl exec ... -- ls -la | 볼륨 마운트 파일·권한 확인 | ... -- ls -la /etc/secrets (0400 확인) |
kubectl apply --dry-run=client | 적용 전 매니페스트 생성 | ... --dry-run=client -o yaml | kubectl apply -f - |
kubectl rollout restart | 환경변수 갱신 위해 파드 재시작 | kubectl rollout restart deployment/db-app |
kubectl rollout status | 롤아웃 완료 확인 | kubectl rollout status deployment/db-app |
kubectl auth can-i | Secret 접근 권한(RBAC) 확인 | kubectl auth can-i get secret |
kubectl edit configmap | ConfigMap 즉시 수정 | kubectl edit cm app-config -n config-lab |
관련 모듈로 더 깊이:
- Deployment를 이용한 안정적인 서비스 배포와 롤백 전략 — ConfigMap/Secret을 주입받는 파드를 선언적으로 관리하는 법
- PV와 PVC를 활용한 영구 볼륨 스토리지 바인딩 — 설정이 아닌 데이터를 파드 재시작에도 유지하는 영구 스토리지
- RBAC(Role-based Access Control) 기반 다중 사용자 보안 — Secret에 누가 접근할 수 있는지 권한으로 통제하는 법
다음 챕터에서는 PersistentVolume과 PersistentVolumeClaim으로 파드 재시작에도 데이터가 유지되는 영구 스토리지를 구성합니다.