ЁЯФС рдзрдбрд╛ 06 тАФ ConfigMaps рдЖрдгрд┐ Secrets: рд╕реВрдЪрдирд╛-рдлрд▓рдХ рд╡рд┐рд░реБрджреНрдз рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 13 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдорд╛рдЧрдЪрд╛: lesson-05-namespaces ┬╖ рдкреБрдврдЪрд╛: lesson-07-health-probes
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ05, рдЖрдгрд┐: ConfigMaps (рд╕рд╛рдзреНрдпрд╛ settings) рдЖрдгрд┐ Secrets (рд╕рдВрд╡реЗрджрдирд╢реАрд▓ settings) тАФ image рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░ рд░рд╛рд╣рдгрд╛рд░реА configuration. рдЦрд▒реНрдпрд╛ files:
- k8s/configmap.yaml тАФ PORT, APP_VERSION
- k8s/secret.example.yaml тАФ DATABASE_URL рдЪрд╛ рд╕рд╛рдЪрд╛ (copy тЖТ
secret.yaml, git-ignored) - k8s/deployment.yaml тАФ рдЬрд┐рдереЗ pod рджреЛрдиреНрд╣реА рд╡рд╛рдЪрддреЛ
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рд╢рд╛рд│реЗрдд рджреЛрди рдкреНрд░рдХрд╛рд░рдЪреА рдорд╛рд╣рд┐рддреА рдЕрд╕рддреЗ:
рд╕реВрдЪрдирд╛-рдлрд▓рдХ ЁЯУМ тАФ "рдЬреЗрд╡рдг 12:30 рд▓рд╛", "рд╢реБрдХреНрд░рд╡рд╛рд░реА рдХреНрд░реАрдбрд╛ рджрд┐рди". рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ! рдХреЛрдгреАрд╣реА рд╡рд╛рдЪреВ рд╢рдХрддреЗ, рдЖрдгрд┐ рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рд╢рд╛рд│рд╛ рдкреБрдиреНрд╣рд╛ рди рдмрд╛рдВрдзрддрд╛ рддреА рдмрджрд▓реВ рд╢рдХрддрд╛рдд. рд╣рд╛ ConfigMap.
рддреБрдордЪреНрдпрд╛ рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА ЁЯФС тАФ рддреБрдореНрд╣реА рддреБрдордЪреА рд▓реЙрдХрд░рдЪреА рдЪрд╛рд╡реА рд╕реВрдЪрдирд╛-рдлрд▓рдХрд╛рд╡рд░ рд▓рд╛рд╡рдд рдирд╛рд╣реА! рддреА рдХрд╛рд│рдЬреАрдкреВрд░реНрд╡рдХ рдареЗрд╡рд▓реА рдЬрд╛рддреЗ, рдлрдХреНрдд рддреБрдореНрд╣рд╛рд▓рд╛рдЪ рджрд┐рд▓реА рдЬрд╛рддреЗ, рдЖрдгрд┐ рдХреЛрдгреА рддрд┐рдЪреА рдЭреЗрд░реЙрдХреНрд╕ рд╡рд░реНрдЧрд╛рдЪреНрдпрд╛ рдорд╛рд╕рд┐рдХрд╛рдд рдЫрд╛рдкрдд рдирд╛рд╣реА. рд╣реЗ 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
тЭУ рдХрд╛рдп
- ConfigMap = рдЧреБрдкреНрдд рдирд╕рд▓реЗрд▓реНрдпрд╛ config рдЪреНрдпрд╛ keyтЖТvalue рдЬреЛрдбреНрдпрд╛, рдЬреНрдпрд╛ pods рдордзреНрдпреЗ env vars рдореНрд╣рдгреВрди рдЯрд╛рдХрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд (рдХрд┐рдВрд╡рд╛ files рдореНрд╣рдгреВрди mount рдХреЗрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд).
- Secret = рд╕рдВрд╡реЗрджрдирд╢реАрд▓ values рд╕рд╛рдареА рддреАрдЪ рдХрд▓реНрдкрдирд╛. base64-encoded рд╕реНрд╡рд░реВрдкрд╛рдд рд╕рд╛рдард╡рд▓реЗ рдЬрд╛рддреЗ (рддреЗ encoding рдЖрд╣реЗ, encryption рдирд╛рд╣реА!) рдЖрдгрд┐ рддреНрдпрд╛рд╡рд░ access рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддрд╛ рдпреЗрддреЛ; рдЦрд▒реНрдпрд╛ production рдордзреНрдпреЗ рддреБрдореНрд╣реА encryption-at-rest рдХрд┐рдВрд╡рд╛ AWS Secrets Manager рд╕рд╛рд░рдЦрд╛ manager рдЬреЛрдбрддрд╛.
- Pods рддреНрдпрд╛рдВрдирд╛ рдирд╛рд╡рд╛рдиреЗ рд╕рдВрджрд░реНрдн рджреЗрддрд╛рдд тАФ config рдмрджрд▓рд╛, pods restart рдХрд░рд╛, image рддреАрдЪ.
ЁЯФР security рдЪреЗ рдПрдХ рд╡рд╛рдХреНрдп
Kubernetes Secret рд▓рд╛ Secret рдореНрд╣рдгрддрд╛рдд рдореНрд╣рдгреВрди рддреЗ рдЖрдкреЛрдЖрдк рд╕реБрд░рдХреНрд╖рд┐рдд рддрд┐рдЬреЛрд░реА рд╣реЛрдд рдирд╛рд╣реА. Default рдиреЗ рддреЗ etcd рдордзреНрдпреЗ base64 рдЕрд╕рддреЗ тАФ encryption at rest рдЪрд╛рд▓реВ рдХрд░рд╛,
get secretsрдХреЛрдг рдХрд░реВ рд╢рдХрддреЗ рддреЗ рдорд░реНрдпрд╛рджрд┐рдд рдХрд░рд╛ (RBAC, L17), рдЖрдгрд┐ рддреЗ рдХрдзреАрдЪ commit рдХрд░реВ рдирдХрд╛. рдпрд╛ repo рдордзрд▓реА git-ignoredsecret.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 рдХрд░реВ рдирдХрд╛
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рдирд╛рд╡рд╛рдореБрд│реЗ Secret encrypted рдЖрд╣реЗ рдЕрд╕реЗ рдорд╛рдирдгреЗ тАФ encryption at rest + RBAC рдЪрд╛рд▓реВ рдХрд░рд╛
- password inject рдХрд░рдгреНрдпрд╛рдРрд╡рдЬреА image рдордзреНрдпреЗ рднрд╛рдЬреВрди рдЯрд╛рдХрдгреЗ (Docker L08)
тПня╕П рдкреБрдвреЗ
Pods рдЪрд╛рд▓рддрд╛рдд тАФ рдкрдг рддреЗ рдирд┐рд░реЛрдЧреА рдЖрд╣реЗрдд рдХрд╛? Pod рдЧреЛрдард▓рд╛ рдЖрд╣реЗ, рдХрд┐рдВрд╡рд╛ рдЕрдЬреВрди рддрдпрд╛рд░ рдирд╛рд╣реА, рд╣реЗ Kubernetes рд▓рд╛ рдХрд╕реЗ рдХрд│рддреЗ? Probes тАФ рд╢рд┐рдХреНрд╖рд┐рдХрд╛рдВрдЪреЗ рджреЛрди рдкреНрд░рд╢реНрди.
git checkout lesson-07-health-probes