ЁЯПл The SchoolтА║тШ╕я╕П KubernetesтА║ЁЯФС рдзрдбрд╛ 06 тАФ ConfigMaps рдЖрдгрд┐ Secrets: рд╕реВрдЪрдирд╛-рдлрд▓рдХ рд╡рд┐рд░реБрджреНрдз рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯФС рдзрдбрд╛ 06 тАФ ConfigMaps рдЖрдгрд┐ Secrets: рд╕реВрдЪрдирд╛-рдлрд▓рдХ рд╡рд┐рд░реБрджреНрдз рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 13 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдорд╛рдЧрдЪрд╛: lesson-05-namespaces ┬╖ рдкреБрдврдЪрд╛: lesson-07-health-probes


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ05, рдЖрдгрд┐: ConfigMaps (рд╕рд╛рдзреНрдпрд╛ settings) рдЖрдгрд┐ Secrets (рд╕рдВрд╡реЗрджрдирд╢реАрд▓ settings) тАФ image рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░ рд░рд╛рд╣рдгрд╛рд░реА configuration. рдЦрд▒реНрдпрд╛ files:

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рд╢рд╛рд│реЗрдд рджреЛрди рдкреНрд░рдХрд╛рд░рдЪреА рдорд╛рд╣рд┐рддреА рдЕрд╕рддреЗ:

  1. рд╕реВрдЪрдирд╛-рдлрд▓рдХ ЁЯУМ тАФ "рдЬреЗрд╡рдг 12:30 рд▓рд╛", "рд╢реБрдХреНрд░рд╡рд╛рд░реА рдХреНрд░реАрдбрд╛ рджрд┐рди". рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ! рдХреЛрдгреАрд╣реА рд╡рд╛рдЪреВ рд╢рдХрддреЗ, рдЖрдгрд┐ рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рд╢рд╛рд│рд╛ рдкреБрдиреНрд╣рд╛ рди рдмрд╛рдВрдзрддрд╛ рддреА рдмрджрд▓реВ рд╢рдХрддрд╛рдд. рд╣рд╛ ConfigMap.

  2. рддреБрдордЪреНрдпрд╛ рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА ЁЯФС тАФ рддреБрдореНрд╣реА рддреБрдордЪреА рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА рд╕реВрдЪрдирд╛-рдлрд▓рдХрд╛рд╡рд░ рд▓рд╛рд╡рдд рдирд╛рд╣реА! рддреА рдХрд╛рд│рдЬреАрдкреВрд░реНрд╡рдХ рдареЗрд╡рд▓реА рдЬрд╛рддреЗ, рдлрдХреНрдд рддреБрдореНрд╣рд╛рд▓рд╛рдЪ рджрд┐рд▓реА рдЬрд╛рддреЗ, рдЖрдгрд┐ рдХреЛрдгреА рддрд┐рдЪреА рдЭреЗрд░реЙрдХреНрд╕ рд╡рд░реНрдЧрд╛рдЪреНрдпрд╛ рдорд╛рд╕рд┐рдХрд╛рдд рдЫрд╛рдкрдд рдирд╛рд╣реА. рд╣реЗ Secret.

рдЖрдгрд┐ рд╕реЛрдиреЗрд░реА рдирд┐рдпрдо: рджреЛрдиреНрд╣реАрдкреИрдХреА рдХрд╛рд╣реАрдЪ рдбрдмреНрдпрд╛рдЪреНрдпрд╛ рдЖрдд рдЬрд╛рдд рдирд╛рд╣реА ЁЯН▒. рдЬреЗрд╡рдгрд╛рдЪрд╛ рдореЗрдиреВ рдкреНрд░рддреНрдпреЗрдХ рдбрдмреНрдпрд╛рдЪреНрдпрд╛ (image) рдЖрдд laminate рдХреЗрд▓реЗрд▓рд╛ рдЕрд╕реЗрд▓, рддрд░ рдЬреЗрд╡рдгрд╛рдЪреА рд╡реЗрд│ рдмрджрд▓рд╛рдпрд▓рд╛ 100 рдбрдмреЗ рдкреБрдиреНрд╣рд╛ рднрд░рд╛рд╡реЗ рд▓рд╛рдЧрддреАрд▓. Settings рднрд┐рдВрддреАрд╡рд░, рдЪрд╛рд╡реНрдпрд╛ рдЦрд┐рд╢рд╛рдд тАФ рдЖрдгрд┐ рддреЛрдЪ рдбрдмрд╛ dev, staging рдЖрдгрд┐ production рдордзреНрдпреЗ рдЪрд╛рд▓рддреЛ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    img["ЁЯН▒ Image school-api<br/>same everywhere<br/>NO config inside"]
    cm["ЁЯУМ ConfigMap<br/>PORT: 3000<br/>APP_VERSION: k8s"]
    sec["ЁЯФС Secret<br/>DATABASE_URL:<br/>postgres://...password..."]
    subgraph pod["ЁЯкС Pod at start-up"]
        env["env vars injected:<br/>PORT, APP_VERSION,<br/>DATABASE_URL"]
        app["school-api process<br/>reads process.env"]
        env --> app
    end
    img --> pod
    cm -- "envFrom / configMapKeyRef" --> env
    sec -- "secretKeyRef" --> env

тЭУ рдХрд╛рдп

ЁЯФР security рдЪреЗ рдПрдХ рд╡рд╛рдХреНрдп

Kubernetes Secret рд▓рд╛ Secret рдореНрд╣рдгрддрд╛рдд рдореНрд╣рдгреВрди рддреЗ рдЖрдкреЛрдЖрдк рд╕реБрд░рдХреНрд╖рд┐рдд рддрд┐рдЬреЛрд░реА рд╣реЛрдд рдирд╛рд╣реА. Default рдиреЗ рддреЗ etcd рдордзреНрдпреЗ base64 рдЕрд╕рддреЗ тАФ encryption at rest рдЪрд╛рд▓реВ рдХрд░рд╛, get secrets рдХреЛрдг рдХрд░реВ рд╢рдХрддреЗ рддреЗ рдорд░реНрдпрд╛рджрд┐рдд рдХрд░рд╛ (RBAC, L17), рдЖрдгрд┐ рддреЗ рдХрдзреАрдЪ commit рдХрд░реВ рдирдХрд╛. рдпрд╛ repo рдордзрд▓реА git-ignored secret.yaml рд╣реА рдлрдХреНрдд рд╢рд┐рдХрдгреНрдпрд╛рд╕рд╛рдареАрдЪреА secret рд╣рд╛рддрд╛рд│рдгреА рдЖрд╣реЗ тАФ production рдордзреНрдпреЗ рдЦрд╛рд╕ secret manager рд╡рд╛рдкрд░рддрд╛рдд (External Secrets рдХрд┐рдВрд╡рд╛ Sealed Secrets тАФ ArgoCD рд╢рд╛рд│рд╛ L12; AWS Secrets Manager тАФ AWS рд╢рд╛рд│рд╛).

ЁЯдФ рдХрд╛

рддреАрдЪ image рддреБрдордЪреНрдпрд╛ laptop рд╡рд░ (рдирдХрд▓реА DB), staging рдордзреНрдпреЗ, рдЖрдгрд┐ prod рдордзреНрдпреЗ (рдЦрд░реЗ RDS) рдЪрд╛рд▓рд▓реА рдкрд╛рд╣рд┐рдЬреЗ тАФ рдлрдХреНрдд settings рд╡реЗрдЧрд│реНрдпрд╛ рдЕрд╕рддрд╛рдд. Config рд▓рд╛ code рдкрд╛рд╕реВрди рд╡реЗрдЧрд│реЗ рдареЗрд╡рдгреЗ рд╣рд╛ twelve-factor apps рдЪрд╛ рдирд┐рдпрдо #1 рдЖрд╣реЗ. рдЖрдгрд┐ secrets рдирд╛ config рдкреЗрдХреНрд╖рд╛ рд╡реЗрдЧрд│реЗ рджрд╛рд░ рд▓рд╛рдЧрддреЗ: port number рддреБрдореНрд╣реА рдЖрдирдВрджрд╛рдиреЗ git commit рдХрд░рддрд╛; database password рдХрдзреАрдЪ commit рдХрд░рдд рдирд╛рд╣реА. рдореНрд╣рдгреВрдирдЪ рдЗрдереЗ secret.yaml git-ignored рдЖрд╣реЗ рдЖрдгрд┐ repo рдордзреНрдпреЗ рдлрдХреНрдд secret.example.yaml (CHANGE_ME рд╕рд╣) рдЖрд╣реЗ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

k8s/configmap.yaml рдордзреНрдпреЗ рд╕рд╛рдзреНрдпрд╛ values рдЖрд╣реЗрдд. рдордЧ k8s/deployment.yaml рджреЛрдиреНрд╣реА pod рдордзреНрдпреЗ рдЬреЛрдбрддреЗ:

envFrom:
  - configMapRef:                 # ЁЯУМ the whole notice board at once
      name: school-api-config     #    (every key becomes an env var)
env:
  - name: DATABASE_URL
    valueFrom:
      secretKeyRef:               # ЁЯФС one key from the locker
        name: school-api-secrets
        key: DATABASE_URL
        optional: true            # no secret? app falls back to in-memory mode

App рд╕реНрд╡рддрдГ рдлрдХреНрдд process.env.PORT рд╡рд╛рдЪрддреЗ тАФ Kubernetes рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЖрд╣реЗ рдпрд╛рдЪреА рддрд┐рд▓рд╛ рдХрд▓реНрдкрдирд╛рд╣реА рдирд╛рд╣реА.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

kubectl apply -f k8s/configmap.yaml

# Make your real (git-ignored) secret from the example:
cp k8s/secret.example.yaml k8s/secret.yaml   # edit the password inside
kubectl apply -f k8s/secret.yaml

kubectl -n school get configmap school-api-config -o yaml   # readable ЁЯУМ
kubectl -n school get secret school-api-secrets -o yaml     # base64 gibberish ЁЯФС

# Prove base64 is NOT encryption:
kubectl -n school get secret school-api-secrets \
  -o jsonpath='{.data.DATABASE_URL}' | base64 -d; echo

# Change config тЖТ roll pods тЖТ same image, new settings:
kubectl -n school rollout restart deployment school-api

ЁЯФз рдпрд╛ рдзрдбреНрдпрд╛рд╕рд╛рдареА kubectl

kubectl get cm,secret ┬╖ kubectl describe cm ┬╖ kubectl create secret generic

ЁЯФЧ рдпрд╛рд╡рд░ рдЖрдзрд╛рд░рд┐рдд: ЁЯкк AWS L05 (machines рдирд╛ keys рдирд╛рд╣реА, roles рдорд┐рд│рддрд╛рдд) ┬╖ ЁЯН▒ Docker L08 (secrets рдХрдзреАрдЪ image рдордзреНрдпреЗ рднрд╛рдЬреВ рдирдХрд╛)

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

kubectl exec POD -- env | grep PORT ConfigMap рдЪреА value рджрд╛рдЦрд╡рддреЗ; Secret рдЪреА value рдкрдг рджрд┐рд╕рддреЗ тАФ рдХрд╛рд░рдг default рдиреЗ Secret рд╕рд╛рдард╡рд▓реЗрд▓реЗ рдЕрд╕рддрд╛рдирд╛ рдлрдХреНрдд base64 рдЕрд╕рддреЗ.

ЁЯз╣ рд╕рд╛рдлрд╕рдлрд╛рдИ

kubectl delete secret school-db тАФ рдЖрдгрд┐ secret.yaml рдХрдзреАрдЪ commit рдХрд░реВ рдирдХрд╛

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

тПня╕П рдкреБрдвреЗ

Pods рдЪрд╛рд▓рддрд╛рдд тАФ рдкрдг рддреЗ рдирд┐рд░реЛрдЧреА рдЖрд╣реЗрдд рдХрд╛? Pod рдЧреЛрдард▓рд╛ рдЖрд╣реЗ, рдХрд┐рдВрд╡рд╛ рдЕрдЬреВрди рддрдпрд╛рд░ рдирд╛рд╣реА, рд╣реЗ Kubernetes рд▓рд╛ рдХрд╕реЗ рдХрд│рддреЗ? Probes тАФ рд╢рд┐рдХреНрд╖рд┐рдХрд╛рдВрдЪреЗ рджреЛрди рдкреНрд░рд╢реНрди.

git checkout lesson-07-health-probes

ЁЯФС Lesson 06 тАФ ConfigMaps & Secrets: notice board vs locker key

ЁЯУН You are here: Lesson 06 of 13 ┬╖ Previous: lesson-05-namespaces ┬╖ Next: lesson-07-health-probes


ЁЯУж What's in this branch

Lessons 01тАУ05, plus: ConfigMaps (plain settings) and Secrets (sensitive settings) тАФ configuration that lives outside the image. Real files:

ЁЯзТ Explain like I'm 5

Two kinds of information at school:

  1. The notice board ЁЯУМ тАФ "Lunch at 12:30", "Sports day Friday". Public! Anyone may read it, and the teacher can change it without rebuilding the school. That's a ConfigMap.

  2. Your locker key ЁЯФС тАФ you do NOT pin your locker key to the notice board! It's kept carefully, given only to you, and nobody photocopies it into the class magazine. That's a Secret.

And the golden rule: neither goes inside the lunchbox ЁЯН▒. If the lunch menu were laminated inside every lunchbox (image), changing lunch time would mean re-packing 100 boxes. Keep settings on the wall, keys in pockets тАФ and the same lunchbox works in dev, staging and production.

ЁЯЧ║я╕П Diagram

flowchart LR
    img["ЁЯН▒ Image school-api<br/>same everywhere<br/>NO config inside"]
    cm["ЁЯУМ ConfigMap<br/>PORT: 3000<br/>APP_VERSION: k8s"]
    sec["ЁЯФС Secret<br/>DATABASE_URL:<br/>postgres://...password..."]
    subgraph pod["ЁЯкС Pod at start-up"]
        env["env vars injected:<br/>PORT, APP_VERSION,<br/>DATABASE_URL"]
        app["school-api process<br/>reads process.env"]
        env --> app
    end
    img --> pod
    cm -- "envFrom / configMapKeyRef" --> env
    sec -- "secretKeyRef" --> env

тЭУ What

ЁЯФР One security sentence

A Kubernetes Secret is not automatically a secure vault because it is called a Secret. By default it is base64 in etcd тАФ turn on encryption at rest, restrict who may get secrets (RBAC, L17), and never commit it. The git-ignored secret.yaml in this repo is learning-only secret handling тАФ production uses a dedicated secret manager (External Secrets or Sealed Secrets тАФ ArgoCD school L12; AWS Secrets Manager тАФ AWS school).

ЁЯдФ Why

The same image must run on your laptop (fake DB), in staging, and in prod (real RDS) тАФ only the settings differ. Separating config from code is rule #1 of twelve-factor apps. And secrets need a different door than config: you happily git commit a port number; you never commit a database password. That's exactly why secret.yaml is git-ignored here and only secret.example.yaml (with CHANGE_ME) is in the repo.

ЁЯФз How (in this repo)

k8s/configmap.yaml holds the plain values. Then k8s/deployment.yaml wires both into the pod:

envFrom:
  - configMapRef:                 # ЁЯУМ the whole notice board at once
      name: school-api-config     #    (every key becomes an env var)
env:
  - name: DATABASE_URL
    valueFrom:
      secretKeyRef:               # ЁЯФС one key from the locker
        name: school-api-secrets
        key: DATABASE_URL
        optional: true            # no secret? app falls back to in-memory mode

The app itself just reads process.env.PORT тАФ it has no idea Kubernetes exists.

ЁЯзк Try it

kubectl apply -f k8s/configmap.yaml

# Make your real (git-ignored) secret from the example:
cp k8s/secret.example.yaml k8s/secret.yaml   # edit the password inside
kubectl apply -f k8s/secret.yaml

kubectl -n school get configmap school-api-config -o yaml   # readable ЁЯУМ
kubectl -n school get secret school-api-secrets -o yaml     # base64 gibberish ЁЯФС

# Prove base64 is NOT encryption:
kubectl -n school get secret school-api-secrets \
  -o jsonpath='{.data.DATABASE_URL}' | base64 -d; echo

# Change config тЖТ roll pods тЖТ same image, new settings:
kubectl -n school rollout restart deployment school-api

ЁЯФз kubectl for this lesson

kubectl get cm,secret ┬╖ kubectl describe cm ┬╖ kubectl create secret generic

ЁЯФЧ Builds on: ЁЯкк AWS L05 (machines get roles, not keys) ┬╖ ЁЯН▒ Docker L08 (never bake secrets)

тЬЕ Verify тАФ what you should see

kubectl exec POD -- env | grep PORT shows the ConfigMap value; the Secret value appears too тАФ because a Secret is only base64 at rest by default.

ЁЯз╣ Clean up

kubectl delete secret school-db тАФ and never commit secret.yaml

тЪая╕П Common mistakes

тПня╕П Next

Pods run тАФ but are they healthy? How does Kubernetes know a pod is frozen, or not ready yet? Probes тАФ the teacher's two questions.

git checkout lesson-07-health-probes
тЖР PreviousnamespacesNext тЖТhealth probes

This page is the lesson's README from the lesson-06-configmaps-secrets branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.