K8s 기초 #6 ConfigMap과 Secret — 설정 분리
#5 Service에서 매니페스트 안에 설정값과 비밀값이 직접 적혀 있으면 운영이 불편하다는 점을 확인했습니다. 이번 글에서는 그 값을 매니페스트 본체에서 분리하는 방법, 즉 ConfigMap과 Secret을 다루겠습니다. 설정은 어떻게 주입하는지, 비밀값은 어떻게 다른지, 그리고 값이 바뀌었을 때 Pod를 어떻게 다시 반영하는지까지 정리하겠습니다.
이번 시리즈는 K8s 기초 7편입니다.
- #1 쿠버네티스란 — 왜 컨테이너 오케스트레이터가 필요한가
- #2 로컬 환경 — minikube / kind / Docker Desktop k8s
- #3 kubectl과 첫 Pod
- #4 Deployment와 ReplicaSet — 선언형 배포와 롤링 업데이트
- #5 Service — ClusterIP / NodePort / LoadBalancer
- #6 ConfigMap과 Secret — 설정 분리 ← 이번 글
- #7 Namespace와 라벨
이번 글의 끝에서는 같은 Deployment 매니페스트 한 장을 dev / staging / prod 어디에든 그대로 적용할 수 있는 모양을 정리하겠습니다. 환경별로 달라지는 값은 ConfigMap,Secret 쪽에만 갈라져 있으면 되고, 워크로드 정의는 한 벌로 충분합니다.
12-factor의 한 줄 — 설정은 환경에 둔다 #
ConfigMap,Secret이 풀려고 하는 문제는 K8s가 처음 만들어 낸 게 아닙니다. 컨테이너가 보편화되기 한참 전부터 웹 앱 운영의 정설로 굳어진 패턴입니다. 가장 자주 인용되는 출처가 12-factor app의 III번 항목, 한 줄로 표현하면 이렇습니다.
Store config in the environment.
설정은 환경에 둔다.
여기서 “설정(config)“은 환경마다 달라지는 값들을 가리킵니다 — DB 호스트, 외부 API 키, 로그 레벨, 비밀번호. 컨테이너 시대 이전에는 이걸 환경변수, /etc/의 설정 파일, .env 파일 같은 형태로 풀었습니다. K8s 시대에 와서는 그 역할을 ConfigMap(평범한 설정값)과 Secret(비밀값)이 맡습니다.
왜 굳이 분리해야 하는지 한 줄씩 짚어 두면 다음 셋입니다.
- 이미지,코드 변경 없이 설정만 바꾸기 — 같은 컨테이너 이미지를 그대로 두고 환경변수만 다르게 줘서 동작을 바꿀 수 있습니다. 새 빌드도, 새 이미지 태그도 필요 없습니다.
- 환경별 다중 배포 — dev / staging / prod의 매니페스트가 거의 같고, 다른 부분은 ConfigMap,Secret으로 떨어져 있습니다. 워크로드 정의를 환경마다 통째로 복제하지 않아도 됩니다.
- 비밀값을 git에 안 올리기 — DB 비밀번호, API 토큰 같은 값이 매니페스트 본체에 평문으로 적혀 있으면 그게 곧 git 저장소에 올라가게 됩니다. Secret 객체로 분리하면 매니페스트는 “그 Secret을 참조한다"라는 한 줄만 적고, 실제 값은 별도 경로로 클러스터에 들어갑니다.
이 셋이 운영의 거의 모든 결정을 좌우합니다. 그럼 ConfigMap부터 보겠습니다.
ConfigMap — 설정의 키-값 묶음 #
ConfigMap은 이름 그대로 설정값의 키-값 모음을 들고 있는 K8s 객체입니다. 매니페스트 한 장으로 만듭니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
data:
LOG_LEVEL: "info"
APP_GREETING: "hello from k8s"
app.conf: |
server {
listen 80;
location / {
return 200 "ok\n";
}
}apiVersion은 Service와 마찬가지로 코어 그룹의 v1 입니다. ConfigMap은 워크로드 컨트롤러가 아니라서 apps/v1이 아닙니다.
핵심 필드는 data 한 곳입니다. 그 안의 모양이 두 갈래입니다.
- 짧은 키-값 (스칼라) —
LOG_LEVEL: "info",APP_GREETING: "hello from k8s"처럼 한 줄짜리 값. 환경변수에 그대로 부어 쓰기 좋은 형태입니다. - 멀티라인 파일 — YAML의 블록 스칼라(
|)로 적은 긴 텍스트. 위 예시의app.conf처럼 nginx 설정 파일, 앱의config.yaml, 작은 SQL 스크립트 같은 것들을 그대로 넣을 수 있습니다.
명령형 생성도 한 번 짚어 두면 #
매니페스트로 적는 길 외에 명령형으로 만드는 길도 있습니다.
kubectl create configmap web-config \
--from-literal=LOG_LEVEL=info \
--from-literal=APP_GREETING="hello from k8s" \
--from-file=app.conf--from-literal은 인라인 키-값을, --from-file은 디스크의 파일을 그대로 가져와 키로 등록합니다. 빠르긴 하지만 분명한 단점이 있습니다 — 만들어진 ConfigMap이 매니페스트로 안 남습니다. 다음 사람이 클러스터의 ConfigMap을 봐도, 이 값이 어디서 왔는지 git 저장소에서 추적할 길이 없습니다. 운영에서는 거의 항상 kubectl apply -f 흐름으로 가고, 명령형은 디버깅,실험 중에만 잠깐 씁니다.
크기 한도 — 1 MiB #
ConfigMap이 들고 있는 값의 총합은 **1 MiB(메비바이트)**를 넘을 수 없습니다. 이건 K8s의 임의 결정이 아니라 그 아래의 etcd가 객체 한 개당 들 수 있는 크기 상한입니다. 작은 설정 파일,환경변수 묶음은 이 한도 안에 충분히 들어가지만, 큰 정적 자산(예: 모델 가중치, 큰 SQL 스키마, 브라우저용 번들 파일)을 ConfigMap에 욱여넣는 것은 패턴에 안 맞습니다. 그런 자산은 별도 스토리지(S3,GCS, PV)에 두고 컨테이너에서 받아 가는 모양이 정공법입니다.
만들어 두고 한 번 봐 봅시다.
kubectl apply -f web-config.yamlconfigmap/web-config createdkubectl get cmNAME DATA AGE
kube-root-ca.crt 1 2d
web-config 3 10s컬럼명을 한 줄로 짚어 두면 — NAME / DATA / AGE. DATA 컬럼의 숫자는 data 아래의 키 개수입니다. 위 예시에서 3개 키(LOG_LEVEL, APP_GREETING, app.conf)를 넣었으니 3으로 찍혀요. kube-root-ca.crt는 K8s가 자체적으로 들고 있는 ConfigMap이라 신경 안 써도 됩니다.
ConfigMap을 Pod에 주입하는 세 가지 방법 #
ConfigMap을 만들기만 해서는 Pod가 그 값을 알아채지 못합니다. Pod가 그 값을 어떻게 받아 가는지를 매니페스트에 적어 줘야 합니다. 방법이 셋 있고, 이 셋의 차이를 잡아 두는 게 이번 글의 가장 실용적인 부분입니다.
1. 단일 키 → 환경변수 (env.valueFrom.configMapKeyRef)
#
ConfigMap의 키 한 개를 컨테이너의 환경변수 하나로 매핑하는 가장 명시적인 모양입니다.
spec:
containers:
- name: web
image: nginx:1.27
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: web-config
key: LOG_LEVELenv는 #3에서 짧게 본 적이 있는 그 필드입니다. 보통 인라인으로 value: "info"처럼 적지만, valueFrom을 쓰면 다른 객체에서 값을 끌어다 쓴다는 뜻이 됩니다. configMapKeyRef의 name이 ConfigMap 이름, key가 그 안의 키 이름입니다.
장점은 명시성입니다 — 어떤 환경변수가 어느 ConfigMap의 어느 키에서 왔는지가 매니페스트에 그대로 드러나요. 단점은 길이입니다. 환경변수가 여러 개라면 그만큼 줄이 길어집니다.
2. 전체 키 → 환경변수 한꺼번에 (envFrom.configMapRef)
#
ConfigMap 안의 키 전부를 한 번에 환경변수로 부어 넣고 싶을 때 쓰는 모양입니다.
spec:
containers:
- name: web
image: nginx:1.27
envFrom:
- configMapRef:
name: web-config이렇게 적으면 web-config의 모든 키가 컨테이너의 환경변수로 자동 주입됩니다. LOG_LEVEL, APP_GREETING, app.conf 셋이 모두 같은 이름의 환경변수가 됩니다. 짧고 편하지만 한 가지 주의할 점이 있습니다 — ConfigMap의 키 이름이 그대로 환경변수명이 됩니다. 그래서 ConfigMap을 envFrom으로 쓸 의도라면 키 이름을 UPPER_SNAKE_CASE로 두는 게 무난합니다. app.conf처럼 점이 들어간 키는 환경변수로 쓰기에 안 어울립니다(셸에서 점이 들어간 환경변수는 다루기 까다로움). 그런 키는 다음 절의 볼륨 마운트로 가는 게 맞습니다.
3. 파일로 마운트 (volumes.configMap + volumeMounts)
#
app.conf처럼 그 자체가 파일이어야 의미가 있는 값은 컨테이너 안에 파일로 넣어 줘야 합니다. ConfigMap을 볼륨처럼 마운트하면 키마다 한 개의 파일이 만들어져요.
spec:
containers:
- name: web
image: nginx:1.27
volumeMounts:
- name: app-conf
mountPath: /etc/myapp
volumes:
- name: app-conf
configMap:
name: web-config
items:
- key: app.conf
path: app.conf읽는 법은 두 단계입니다.
volumes— Pod 단위로 정의하는 볼륨. 위에서는app-conf라는 이름의 볼륨을 만들었고, 그 내용물이web-configConfigMap의app.conf키로 정해져 있습니다.items를 적으면 ConfigMap 안에서 일부 키만 골라 마운트할 수 있습니다.items를 생략하면 ConfigMap의 모든 키가 각각 파일로 마운트됩니다.volumeMounts— 컨테이너 단위로, 위 볼륨을 컨테이너 파일시스템의 어느 경로에 끼워 넣을지.mountPath: /etc/myapp이면 컨테이너 안에서/etc/myapp/app.conf경로로 그 내용이 보입니다.
언제 어떤 걸 쓸까 #
세 갈래의 용도를 한 표로 정리해 두면 결정이 한결 빠릅니다.
| 주입 모양 | 적합한 경우 | 설명 |
|---|---|---|
env.valueFrom.configMapKeyRef | 환경변수 한두 개 | 명시적이지만 길다 |
envFrom.configMapRef | 환경변수 묶음 전체 | 짧지만 키 이름 규칙이 필요 |
volumes.configMap | 설정 파일 전체를 파일로 | 앱이 파일에서 읽도록 만들어졌을 때 |
머릿속 단순한 결정 규칙은 — 값이 한두 개면 env, 키-값 묶음이 통째로 환경변수가 돼야 하면 envFrom, 파일이어야 의미가 있으면 volume 입니다.
전체 합쳐 보기 — Deployment + ConfigMap 한 사이클 #
위 세 모양을 한 매니페스트에 모아 봅니다. #4의 web Deployment를 가져와서, 환경변수 한 개는 env로, 나머지는 envFrom으로, 그리고 app.conf는 볼륨으로 마운트하는 구성입니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: web-config
key: LOG_LEVEL
envFrom:
- configMapRef:
name: web-config
volumeMounts:
- name: app-conf
mountPath: /etc/myapp
volumes:
- name: app-conf
configMap:
name: web-config
items:
- key: app.conf
path: app.conf(예시상 env와 envFrom을 둘 다 적었습니다 — 실무에서는 한쪽만 쓰는 게 보통입니다. 같은 ConfigMap에서 동일한 키를 두 번 끌어오면 마지막에 정의된 쪽이 우선합니다.)
적용하고 결과를 확인합니다.
kubectl apply -f web-config.yaml -f web.yamlconfigmap/web-config unchanged
deployment.apps/web createdPod 안에 들어가서 환경변수와 파일이 실제로 들어왔는지 봅니다.
kubectl exec -it deploy/web -- env | grep -E "LOG_LEVEL|APP_GREETING"LOG_LEVEL=info
APP_GREETING=hello from k8skubectl exec -it deploy/web -- cat /etc/myapp/app.confserver {
listen 80;
location / {
return 200 "ok\n";
}
}ConfigMap에 적은 그대로가 컨테이너 안에서 환경변수와 파일로 보이는 게 확인됩니다. 이게 한 사이클의 끝입니다. 매니페스트의 본체에는 값 자체가 적혀 있지 않고, “ConfigMap에서 가져온다"라는 참조만 적혀 있습니다.
Secret — 비밀값 분리 #
ConfigMap이 평범한 설정값을 위한 객체라면, Secret은 비밀번호,토큰,인증서처럼 매니페스트 본체에 평문으로 두면 안 되는 값을 위한 객체입니다. 매니페스트 모양은 ConfigMap과 거의 같습니다.
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
DB_USER: "myapp"
DB_PASSWORD: "s3cret-do-not-commit"apiVersion은 동일하게 v1. ConfigMap과 다른 부분이 둘 있습니다.
type— Secret은 종류가 여러 가지여서type필드가 있습니다. 평범한 키-값 묶음이면Opaque(기본값).stringDatavsdata— Secret 본체에서 값을 적는 두 길.
data vs stringData — 그리고 base64 라는 한 줄 #
이번 글의 가장 중요한 한 줄이 여기입니다.
Secret이라는 이름이 붙어 있지만, 기본 동작은 base64 인코딩일 뿐입니다. 암호화가 아닙니다.
kubectl get secret db-secret -o yaml로 보면 매니페스트의 stringData가 사라지고 data 아래에 base64 인코딩된 문자열만 보입니다.
kubectl apply -f db-secret.yaml
kubectl get secret db-secret -o yamlapiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
DB_USER: bXlhcHA=
DB_PASSWORD: czNjcmV0LWRvLW5vdC1jb21taXQ=bXlhcHA=나 czNjcmV0LWRvLW5vdC1jb21taXQ=는 어렵게 보이지만, base64는 보안 장치가 아니라 바이너리를 텍스트로 옮기기 위한 인코딩입니다. 한 줄로 풀어 볼 수 있습니다.
kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -ds3cret-do-not-commit원래 값이 그대로 나옵니다. 그러니 Secret 객체를 다루는 일은 본질적으로 평문 비밀값을 다루는 일과 같다고 봐야 합니다. 진짜 보호는 다른 층에서 와야 합니다 — 뒤에서 짧게 짚어 두겠습니다.
data와 stringData의 차이는 사람이 적기 편한지뿐입니다.
data— base64로 미리 인코딩한 값을 적는다. 사람이 직접 적기는 번거롭다.stringData— 평문을 적으면 K8s가 받아서 base64로 알아서 인코딩합니다. 사람이 매니페스트로 Secret을 만들 때 거의 항상 이쪽을 씁니다.
명령형 생성도 ConfigMap과 같은 결입니다.
kubectl create secret generic db-secret \
--from-literal=DB_USER=myapp \
--from-literal=DB_PASSWORD=s3cret-do-not-commitSecret type 한 줄씩 #
Secret은 용도에 따라 몇 가지 정해진 type이 있습니다. 자주 만나는 넷을 한 줄씩 짚어 둡니다.
| type | 용도 |
|---|---|
Opaque | 기본. 임의의 키-값 묶음 |
kubernetes.io/dockerconfigjson | 사설 컨테이너 레지스트리 자격증명. imagePullSecrets에서 참조 |
kubernetes.io/tls | TLS 인증서,키 쌍. Ingress의 HTTPS 종단점에서 참조 |
kubernetes.io/service-account-token | ServiceAccount 토큰. RBAC와 함께 등장 |
이 중 사람이 직접 매니페스트로 만지는 건 보통 Opaque와 kubernetes.io/tls 정도입니다. dockerconfigjson은 kubectl create secret docker-registry라는 전용 명령으로 만드는 게 보편적이고, service-account-token은 K8s가 거의 알아서 다룹니다.
get secret 출력 컬럼 #
kubectl get secretNAME TYPE DATA AGE
db-secret Opaque 2 1mConfigMap과 다른 점은 TYPE 컬럼이 추가됐다는 것뿐입니다 — NAME / TYPE / DATA / AGE. DATA의 숫자는 키 개수입니다.
Secret을 Pod에 주입 #
Secret을 Pod에 주입하는 모양은 ConfigMap과 동일합니다 — 키 이름만 살짝 다를 뿐입니다. 셋을 한 번에 정리하겠습니다.
1. 단일 키 → 환경변수 (env.valueFrom.secretKeyRef)
#
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORDConfigMap의 configMapKeyRef가 secretKeyRef로 바뀌는 게 전부입니다.
2. 전체 키 → 환경변수 한꺼번에 (envFrom.secretRef)
#
envFrom:
- secretRef:
name: db-secretconfigMapRef가 secretRef로. 같은 마음가짐으로 키 이름은 UPPER_SNAKE_CASE로 두는 게 무난합니다.
3. 파일로 마운트 (volume.secret)
#
volumes:
- name: db-creds
secret:
secretName: db-secret
volumeMounts:
- name: db-creds
mountPath: /etc/db
readOnly: trueConfigMap 볼륨은 configMap 키 아래 name을 적었지만, Secret 볼륨은 secret 키 아래 **secretName**으로 이름이 살짝 다릅니다. 또 한 가지 차이는 디스크 위치 — 볼륨 마운트로 풀린 Secret 파일은 노드의 디스크에 평문으로 떨어지지 않습니다. K8s가 tmpfs(메모리 기반 파일시스템)에 둬서 노드를 재부팅하면 사라지도록 만들어 뒀습니다. ConfigMap에는 이런 보호가 없습니다.
진짜 비밀값을 안전하게 다루려면 #
Secret이 base64일 뿐이라는 한 줄을 짚었으니, 실제 운영에서 비밀값을 어떻게 다루는지도 짧게 정리해 둡니다. 깊은 설치는 이번 시리즈 범위 밖이고, 이름만 알아두는 게 목적입니다.
- etcd 단계의 암호화 — apiserver의
EncryptionConfiguration을 설정하고 KMS(AWS KMS, GCP KMS 등)와 연동하면 etcd에 들어가는 Secret 값이 암호화된 채 저장됩니다. 클러스터를 직접 운영할 때 가장 먼저 켜는 항목입니다. - Sealed Secrets (Bitnami) — Secret 매니페스트를 클러스터의 공개키로 암호화한
SealedSecret이라는 객체로 변환해 둡니다. 이 암호화된 매니페스트는 git에 안전하게 올려도 되고, 클러스터에 들어가면 컨트롤러가 풀어서 일반 Secret으로 바꿔 줍니다. - External Secrets Operator — Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault 같은 외부 비밀 저장소가 진짜 비밀값을 들고 있고, 이 오퍼레이터가 그 값을 K8s Secret으로 동기화해 줍니다. 운영의 일반적인 답입니다.
운영 클러스터에서는 위 셋 중 하나 이상을 거의 항상 함께 씁니다. 이번 시리즈에서는 매니페스트의 모양과 주입 방식까지만 다루고, 비밀값 운영의 깊은 부분은 K8s 중급에서 한 편으로 따로 묶어 다루겠습니다.
설정이 바뀌면 어떻게 적용되나 #
ConfigMap,Secret을 만들었으니 자연스럽게 다음 질문이 떠오릅니다 — 값을 바꿨을 때 그 변경이 Pod에 자동으로 반영되는가? 답은 주입 방식에 따라 갈라집니다. 운영에서 자주 헷갈리는 부분이라 한 번 정리해 둘 가치가 있습니다.
환경변수로 주입한 경우 — 시작 시점에 한 번 #
env나 envFrom으로 환경변수에 부어 넣은 값은 Pod가 시작할 때 한 번만 채워지고 끝입니다. 그 뒤에 ConfigMap을 수정해도 이미 떠 있는 Pod의 환경변수는 변하지 않습니다. 프로세스의 환경 블록은 시작 시점에 한 번 만들어지면 OS 차원에서 그 모양 그대로 굳기 때문입니다 — K8s만의 한계가 아니라 프로세스 모델의 본성입니다.
새 값으로 환경변수를 다시 채우려면 Pod가 새로 떠야 합니다. 의도된 점진 교체를 강제하는 표준 명령이 다음 한 줄입니다.
kubectl rollout restart deployment/web이 명령은 새 ReplicaSet을 만드는 #4의 롤링 업데이트와 같은 메커니즘으로 작동합니다 — 다만 spec은 그대로 두고 Pod만 점진적으로 교체합니다. 새로 떠오른 Pod가 ConfigMap의 최신 값을 환경변수로 가지고 시작합니다.
(kubectl rollout restart는 1.15+부터 도입된 표준 명령입니다. 그 이전에는 Pod 라벨에 임의의 어노테이션을 더해 spec을 살짝 바꾸는 우회 방법을 썼지만, 이제는 거의 안 만집니다.)
볼륨으로 마운트한 경우 — 자동 갱신 #
볼륨으로 마운트한 ConfigMap,Secret은 K8s가 주기적으로 동기화해서 파일이 자동으로 갱신됩니다. ConfigMap을 수정하면 보통 분 단위 지연 안에 컨테이너 안의 파일 내용이 바뀌어 있습니다. 이 지연은 kubelet의 동기화 주기(기본 1분)와 맞물려 있어서, 즉시는 아닙니다.
다만 한 가지 단서가 붙습니다 — 앱이 그 파일을 다시 읽는 코드를 가지고 있어야 변경이 의미가 있습니다. nginx처럼 SIGHUP을 받으면 설정을 다시 읽는 프로세스라면 동작하지만, 시작할 때 한 번만 설정을 읽고 끝인 앱은 파일이 바뀐들 행동이 달라지지 않습니다. 설정 파일 변경을 감지해 자동 reload를 거는 사이드카(예: configmap-reload)를 두는 패턴도 흔하게 보입니다.
한 표로 정리 #
| 주입 모양 | 변경 반영 | 강제 갱신 |
|---|---|---|
env / envFrom | 자동 반영 안 됨 (시작 시 1회) | kubectl rollout restart |
volume | 자동 반영 (분 단위 지연) | 앱 자체의 reload 또는 kubectl rollout restart |
운영의 단순한 기본기는 — 설정을 바꿨으면 일단 kubectl rollout restart로 의도된 점진 교체를 한 번 돌린다입니다. 환경변수든 볼륨이든 그 시점에는 확실히 반영됩니다.
정리,치우기 #
오늘 만든 객체를 정리하겠습니다.
kubectl delete -f web.yaml
kubectl delete -f web-config.yaml
kubectl delete -f db-secret.yamldeployment.apps "web" deleted
configmap "web-config" deleted
secret "db-secret" deletedkubectl get deploy,cm,secret으로 비어 있는지 확인하면 출발점으로 돌아옵니다. kube-root-ca.crt ConfigMap과 default-token-... Secret은 K8s가 자체적으로 들고 있는 객체라 한 줄씩 남아 있어도 정상입니다.
정리 #
이번 글에서 잡은 흐름을 정리합니다.
- 환경마다 달라지는 값과 비밀값을 매니페스트 본체에서 떼어 내는 패턴이 12-factor의 “설정은 환경에 둔다”. K8s에서 이 역할을 맡는 객체가 ConfigMap과 Secret.
- ConfigMap 매니페스트의 척추는
apiVersion: v1/kind: ConfigMap/data.data아래는 짧은 키-값(스칼라)과 멀티라인 파일(|) 둘 다 적을 수 있습니다. 크기 한도는 1 MiB. - Pod에 주입하는 길은 셋 —
env.valueFrom.configMapKeyRef(단일 키),envFrom.configMapRef(전체),volumes.configMap(파일). 단순 결정 규칙은 한두 개면env, 묶음 전체면envFrom, 파일이어야 하면volume. - Secret은 ConfigMap과 거의 같은 모양에
type필드가 더 붙는 객체. 이름은 Secret이지만 기본 동작은 base64 인코딩일 뿐, 암호화가 아닙니다. 진짜 보호는 etcd 암호화,Sealed Secrets,External Secrets Operator 같은 별도 층에서 옵니다. - Secret 주입은 ConfigMap과 같은 셋 —
secretKeyRef/envFrom.secretRef/volume.secret. 평문은 매니페스트에stringData로 적는 게 사람이 다루기 편하다. - 환경변수는 Pod 시작 시 1회 채워진다 — 값 변경 후 반영하려면
kubectl rollout restart. 볼륨 마운트는 분 단위로 자동 갱신되지만 앱이 파일을 다시 읽도록 만들어져 있어야 의미가 있습니다.
다음 — Namespace와 라벨 #
여기까지 와도 한 가지가 여전히 어색한 채 남아 있습니다 — 지금까지 만든 모든 객체(Pod, Deployment, Service, ConfigMap, Secret)가 전부 default 네임스페이스에 들어갔다는 점. 한 클러스터 안에 여러 환경(개발/스테이징)이나 여러 팀의 워크로드가 같이 떠 있어야 한다면 이 단일 공간이 곧 좁아집니다. 그리고 #4 selector부터 계속 만나 온 라벨도, 이쯤에서 한 번 정리해 둘 만한 양이 쌓였습니다.
#7 Namespace와 라벨에서는 (1) 네임스페이스가 클러스터를 어떻게 논리적으로 갈라 주는지, (2) 라벨,셀렉터의 문법과 자주 쓰는 라벨 컨벤션, (3) kubectl을 네임스페이스 단위로 다루는 운영 팁까지 따라가면서, 이 시리즈가 다룬 매니페스트 7종을 한 클러스터 안에서 깨끗이 갈라 두는 모양으로 마무리합니다.