实验基线:Kubernetes v1.37.0、kubectl v1.37.0。先在测试环境执行,记录变更前状态与回滚点;生产集群不得直接照抄节点地址、网段、存储类或资源额度。
配置、秘密与身份是三件事
ConfigMap 保存非敏感配置;Secret 的 base64 只是编码,不等于加密;ServiceAccount 为 Pod 提供集群身份。生产环境还需要 etcd 静态加密、外部密钥系统、访问审计与轮换流程。
创建并消费配置
kubectl create configmap app-config -n lab --from-literal=LOG_LEVEL=info
kubectl create secret generic db-credential -n lab \
--from-literal=username=app --from-literal=password='replace-me'
kubectl create serviceaccount app -n lab
kubectl get configmap app-config -n lab -o yaml
kubectl get secret db-credential -n lab -o jsonpath='{.data.username}' | base64 -d命令历史可能泄漏密码,真实环境应从受控文件或外部秘密管理系统导入,并及时清理。不要把 Secret 明文提交到 Git。
挂载与轮换规则
spec:
serviceAccountName: app
automountServiceAccountToken: false
containers:
- name: app
image: nginx:1.27-alpine
envFrom:
- configMapRef: {name: app-config}
volumeMounts:
- name: credential
mountPath: /run/secrets/app
readOnly: true
volumes:
- name: credential
secret:
secretName: db-credential
defaultMode: 0400环境变量不会自动刷新;卷投射最终会更新,但应用是否重载取决于自身实现。推荐对配置内容计算哈希并放入 Pod 模板注解,以触发可审计的滚动发布。只有确实调用 Kubernetes API 的工作负载才开启令牌自动挂载。
从文件生成配置,避免手工转义
kubectl create configmap app-config -n lab \
--from-file=application.yaml=./application.yaml \
--dry-run=client -o yaml > app-config.yaml
kubectl diff -f app-config.yaml
kubectl apply -f app-config.yaml将生成的 YAML 审阅后提交版本库。ConfigMap 单个对象不适合存放大文件;二进制与大型配置应放对象存储或镜像,并记录不可变版本。
环境变量与卷更新差异
| 方式 | 变更后 | 适用 |
|---|---|---|
| env/envFrom | 已运行进程不会更新 | 启动期固定配置 |
| volume | kubelet 最终更新投射文件 | 应用支持文件重载 |
| subPath | 不会收到自动更新 | 明确接受重启生效 |
发布流水线可计算配置哈希并写入 Pod template annotation,从而触发受控滚动更新。
Secret 安全操作
umask 077
kubectl create secret generic db-credential -n lab \
--from-env-file=.secret.env --dry-run=client -o yaml > /tmp/db-secret.yaml
kubectl apply -f /tmp/db-secret.yaml
shred -u /tmp/db-secret.yamlmacOS 不一定提供 shred,应改用受控临时目录并安全清理。生产更推荐 External Secrets/CSI 驱动等外部密钥集成。轮换时采用“双凭据窗口”:先让服务接受新旧凭据,再更新消费者,确认旧凭据无流量后撤销。
ServiceAccount 最小化
spec:
serviceAccountName: app
automountServiceAccountToken: false若应用确需访问 API,可显式投射短期令牌并设置 audience 与 expirationSeconds;再用 Role/RoleBinding 限制资源、动词、命名空间和 resourceNames。执行:
kubectl auth can-i get configmap/app-config -n lab --as=system:serviceaccount:lab:app
kubectl auth can-i list secrets -n lab --as=system:serviceaccount:lab:app第一条应按设计允许,第二条必须拒绝。把正向和反向权限测试加入发布门禁。
完整工作负载示例与配置发布
apiVersion: apps/v1
kind: Deployment
metadata: {name: app, namespace: lab}
spec:
replicas: 2
selector: {matchLabels: {app: app}}
template:
metadata:
labels: {app: app}
annotations: {config.checksum: "replace-with-real-sha256"}
spec:
serviceAccountName: app
automountServiceAccountToken: false
containers:
- name: app
image: nginx:1.27-alpine
env: [{name: LOG_LEVEL, valueFrom: {configMapKeyRef: {name: app-config, key: LOG_LEVEL}}}]
volumeMounts: [{name: credential, mountPath: /run/secrets/app, readOnly: true}]
volumes: [{name: credential, secret: {secretName: db-credential, defaultMode: 0400}}]HASH=$(kubectl get configmap app-config -n lab -o json | sha256sum | cut -d' ' -f1)
kubectl patch deployment app -n lab --type=merge \
-p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"config.checksum\":\"$HASH\"}}}}}"
kubectl rollout status deployment/app -n labGitOps/Helm 环境应在渲染阶段生成哈希,而不是由终端临时 patch;这里用于解释触发原理。
短期 API 令牌
确需访问 API 时,显式投射有 audience 与过期时间的令牌,避免长期 Secret 令牌:
volumes:
- name: api-token
projected:
sources:
- serviceAccountToken:
path: token
audience: my-api
expirationSeconds: 3600服务端必须校验 audience。轮换演练应验证旧令牌过期、新令牌自动刷新以及 API 暂时不可用时应用的容错行为。
可复现记录模板
每次实验记录:集群版本、容器运行时、CNI/CSI 版本、命名空间、使用的 YAML Git 提交、开始与结束时间。命令输出至少保留对象状态、事件、关键日志和回滚结果。文中的占位符必须替换成自己的值,生产执行前应由第二人复核。
故障处理原则
- 先缩小影响面,不删除现场。
- 按对象状态—事件—日志—依赖顺序收集证据。
- 提出可证伪假设,一次只改变一个变量。
- 验证恢复后清理临时权限、调试 Pod、端口转发和测试数据。
完成检查
- 命令退出码为 0,目标对象状态与预期一致。
- 保存执行前后 YAML、事件与关键日志,确认没有把测试命名空间以外的对象改动。
- 故障演练完成后执行清理或回滚,再进行下一章。