Lab 17 - ConfigMaps and Secrets

Lab 17 - ConfigMaps and Secrets

Goal: same image, different configuration - and learn which changes need a restart. Chapter: ConfigMaps and Secrets

# 1 - from literals and from a file
cd ~
printf 'color=blue\nretries=3\n' > app.properties
kubectl create cm app-cfg \
  --from-literal=DATACENTER=dc01 \
  --from-file=app.properties
kubectl get cm app-cfg -o yaml

--from-literal makes one key; --from-file makes a key named after the file whose value is the whole file. Both live in the same data map.

# 2 - consume it both ways at once
cat > cfgpod.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
  name: cfgpod
spec:
  containers:
    - name: box
      image: busybox
      command: ["sh", "-c", "env | sort; sleep 3600"]
      env:
        - name: DATACENTER
          valueFrom:
            configMapKeyRef:
              name: app-cfg
              key: DATACENTER
      volumeMounts:
        - name: cfg
          mountPath: /etc/appcfg
  volumes:
    - name: cfg
      configMap:
        name: app-cfg
YAML
kubectl apply -f cfgpod.yaml
kubectl logs cfgpod | grep DATACENTER
kubectl exec cfgpod -- ls /etc/appcfg
kubectl exec cfgpod -- cat /etc/appcfg/app.properties

Every key became a file in /etc/appcfg, and one key also became an environment variable.

# 3 - change the ConfigMap and wait
printf 'color=green\nretries=5\n' > app.properties
kubectl create cm app-cfg --from-literal=DATACENTER=dc02 \
  --from-file=app.properties --dry-run=client -o yaml | kubectl apply -f -
sleep 70
kubectl exec cfgpod -- cat /etc/appcfg/app.properties   # green - updated
kubectl exec cfgpod -- printenv DATACENTER              # dc01 - NOT updated

This is the single most useful fact in the chapter. Mounted files are refreshed by the kubelet; environment variables are frozen at container start. An application that reads config from env vars needs a restart to see a change.

The kubectl create ... --dry-run=client -o yaml | kubectl apply -f - pattern is how you update an object that has no kubectl set command.

Secrets

# 4 -
kubectl create secret generic db-cred \
  --from-literal=username=app \
  --from-literal=password=S3cret
kubectl get secret db-cred -o yaml
kubectl get secret db-cred -o jsonpath='{.data.password}' | base64 -d; echo

Base64 is encoding, not encryption. Anyone who can read Secrets in this namespace can read the password - protection comes from RBAC and encryption at rest.

# 5 - inject the whole Secret as environment variables
cat > secpod.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
  name: secpod
spec:
  containers:
    - name: box
      image: busybox
      command: ["sh", "-c", "sleep 3600"]
      envFrom:
        - secretRef:
            name: db-cred
YAML
kubectl apply -f secpod.yaml
kubectl exec secpod -- sh -c 'echo $username / $password'

envFrom takes every key at once; the key names become the variable names.

# 6 - the restart that picks up a change
kubectl create deploy web --image nginx:1.27
kubectl set env deploy/web --from=configmap/app-cfg
kubectl rollout status deploy/web
kubectl exec deploy/web -- printenv DATACENTER      # dc02

kubectl create cm app-cfg --from-literal=DATACENTER=dc03 \
  --from-file=app.properties --dry-run=client -o yaml | kubectl apply -f -
kubectl exec deploy/web -- printenv DATACENTER      # still dc02
kubectl rollout restart deploy/web
kubectl rollout status deploy/web
kubectl exec deploy/web -- printenv DATACENTER      # dc03

kubectl rollout restart after a config change is a habit worth forming.

Clean up

kubectl delete -f cfgpod.yaml -f secpod.yaml
kubectl delete deploy web
kubectl delete cm app-cfg
kubectl delete secret db-cred