ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kubernetes 上手实战(4):配置管理与密钥

Kubernetes 上手实战(4):配置管理与密钥 上一篇让 Deployment 能滚动升级和回滚。本篇把环境差异从镜像中移出普通配置进入 ConfigMap敏感值通过 Secret 注入并明确更新传播、触发重启和生产密钥管理的边界。一、痛点同一镜像如何进入不同环境把 API 地址、功能开关或数据库密码写进镜像会迫使每个环境重新构建也会让秘密进入镜像层和构建日志。Kubernetes 提供 ConfigMap 保存非敏感键值Secret 保存敏感数据。二者可注入环境变量或挂载成文件应用无需调用 Kubernetes API。Secret 并非天然保险箱。清单中的data只是 Base64 编码不是加密拥有读取 Secret 权限的人仍可还原。生产要启用 etcd 静态加密、严格 RBAC、审计和外部密钥系统避免把明文 Secret 提交 Git。External Secrets Operator、Secrets Store CSI Driver 或云厂商方案可让 Git 只保存引用但选型应结合威胁模型与运维能力。环境变量简单却只在容器启动时读取更新对象不会改变已运行进程。卷挂载文件通常会被 kubelet最终同步更新但应用还要监听或定期重读通过subPath挂载单文件时不会获得自动更新。是否热加载必须由应用契约明确不能假定 Kubernetes 会替应用刷新内存。二、原理数据投影与发布语义ConfigMap 和 Secret 都受对象大小限制不适合大文件或二进制制品。键可以通过envFrom批量导入也可逐项映射以控制变量名文件投影会把每个键变成文件。逐项声明较啰嗦却能在评审中看见应用真正依赖哪些值并避免未来新增键意外进入进程环境。下面保存为config.yaml。示例 Secret 通过命令生成不把明文写进清单先创建 namespace 中的对象再应用 Deployment。学习值不是生产凭据运行后仍应删除。应用使用 Nginx通过 ConfigMap 挂载完整配置并把示例令牌作为环境变量展示注入方法但不会打印令牌。apiVersion:v1kind:ConfigMapmetadata:name:web-configdata:default.conf:|server { listen 8080; location /healthz { access_log off; return 200 ok\n; } location / { default_type text/plain; return 200 configured web\n; } }---apiVersion:apps/v1kind:Deploymentmetadata:name:webspec:replicas:2selector:matchLabels:app.kubernetes.io/name:webtemplate:metadata:labels:app.kubernetes.io/name:webspec:containers:-name:webimage:nginx:1.27.4-alpineports:-name:httpcontainerPort:8080env:-name:APP_TOKENvalueFrom:secretKeyRef:name:web-secretkey:tokenvolumeMounts:-name:configmountPath:/etc/nginx/conf.dreadOnly:truereadinessProbe:httpGet:path:/healthzport:httpvolumes:-name:configconfigMap:name:web-config三、实现创建、验证和轮换脚本从环境变量读取学习令牌使用客户端 dry-run 生成对象再 apply避免命令行采用裸字面值。注意进程环境和 shell 历史也可能泄密这种方式仅用于本地实验CI 应从受保护的密钥存储注入并禁止调试回显。#!/usr/bin/env bashset-euopipefail:${LAB_APP_TOKEN:?export LAB_APP_TOKEN with a disposable value}test$(kubectl config current-context)kind-k8s-labkubectl create secret generic web-secret\--from-literaltoken${LAB_APP_TOKEN}\--dry-runclient-oyaml|kubectl apply-f- kubectl apply-fconfig.yaml kubectl rollout status deployment/web--timeout120spod_name$(kubectl get pod-lapp.kubernetes.io/nameweb-ojsonpath{.items[0].metadata.name})kubectlexec${pod_name}-- nginx-tkubectlexec${pod_name}--wget-qO- http://127.0.0.1:8080/healthz kubectl patch configmap web-config--typemerge-p\{data:{default.conf:server { listen 8080; location /healthz { return 200 \ok\\n\; } location / { return 200 \configured-v2\\n\; } }}}kubectl rollout restart deployment/web kubectl rollout status deployment/web--timeout120s kubectl create secret generic web-secret\--from-literaltokenrotated-disposable-value\--dry-runclient-oyaml|kubectl apply-f- kubectl rollout restart deployment/web kubectl rollout status deployment/web--timeout120s脚本会让nginx -t成功并让健康端点返回ok。Secret 轮换后必须重启因为环境变量不会动态刷新。若使用卷并且应用支持热加载可选择不重启但仍应监控加载是否成功并保留旧凭据的短暂重叠窗口避免连接长时间存活时瞬间失效。GitOps 中常给 Pod template annotation 写入配置内容的哈希配置变化会改变 template从而自然触发 Deployment rollout。原生 Kubernetes 不会自动为 ConfigMap 更新重启所有引用它的 Pod。Helm 篇会实现 checksum annotation纯清单也可用 Kustomize 的 configMapGenerator 生成带哈希名称实现不可变配置引用。四、踩坑泄露通常发生在边界处不要在文章、工单、日志和截图里打印 Secret也不要用kubectl get secret -o yaml作为普通排障动作。Base64 字符串可轻易解码。RBAC 应让工作负载 ServiceAccount 只读取必要对象最好通过卷注入而不是授予应用列出整个 namespace Secret 的 API 权限。把 ConfigMap 挂在目录会遮蔽镜像中该目录原有文件因此应确认应用所需文件全部存在。文件更新采用符号链接切换长期打开文件描述符的程序可能仍读旧内容。配置语法错误也可能让新 Pod 启动失败应在流水线先运行nginx -t等专用校验再依赖 rollout 的 readiness 保护旧副本。Secretimmutable: true可防止误改并降低 API 服务器监听负担但轮换时需创建新名字并更新引用。对于证书、双密钥或数据库密码应设计新旧并存、消费者切换、验证、撤销旧值的阶段流程而不是覆盖后立即删除旧值。五、验证证明配置和密钥都按预期生效验收应覆盖配置内容可读、探针通过、秘密未出现在 PodSpec 明文字段和常规日志、更新后运行实例取得新值、旧凭据最终被撤销。可以用kubectl auth can-i get secret/web-secret --assystem:serviceaccount:lab:default检查权限但这只回答授权不代表应用必须拥有该权限。可靠配置管理的核心是把“值是什么”和“何时进入运行实例”分开记录。对象版本、Pod template 修订、应用加载结果都应可追踪。测试结束删除web-secret并从 shell 环境清除实验变量若误用真实凭据应立即在源系统撤销而不是只删 Kubernetes 对象。下一篇将处理另一种跨重建状态用 emptyDir 理解 Pod 生命周期再用 PersistentVolumeClaim 让数据独立于 Pod验证删除与重建后的持久化。为配置建立数据字典也很重要记录键名、类型、默认值、合法范围、是否敏感、拥有者、变更是否需要重启以及兼容窗口。应用启动时应校验必填值并输出不含秘密的配置摘要发现非法配置立即失败比带着半有效状态接流量更安全。删除配置键要经过“消费者不再读取、所有实例已升级、观察期结束”三个阶段不能仅凭仓库搜索不到旧代码就立刻清理。灾难演练可故意提交语法错误的配置确认新 Pod 不就绪、旧 Pod 继续服务、流水线超时并留下诊断随后恢复正确配置并验证滚动过程。另一次演练轮换一次性令牌确认新旧凭据重叠时间符合设计旧值最终在源系统失效。这里验收的是完整传播路径而不仅是接口中的资源版本已经变化。配置是否应触发发布可以用内容摘要确定而不依赖人工记版本号。下面程序对规范化后的非敏感配置计算摘要键顺序变化不会误触发值变化一定产生新摘要。真实项目把摘要写入 Pod template annotation即可让 Deployment 自动滚动。importhashlibimportjsondefconfig_digest(config:dict[str,str])-str:payloadjson.dumps(config,ensure_asciiFalse,sort_keysTrue,separators(,,:),).encode(utf-8)returnhashlib.sha256(payload).hexdigest()[:12]first{LOG_LEVEL:info,REGION:cn-north}same{REGION:cn-north,LOG_LEVEL:info}changed{LOG_LEVEL:warning,REGION:cn-north}first_hashconfig_digest(first)same_hashconfig_digest(same)changed_hashconfig_digest(changed)print(fstable_order{first_hashsame_hash})print(fchange_detected{first_hash!changed_hash})print(frollout{requirediffirst_hash!changed_hashelseskipped})运行输出stable_orderTrue change_detectedTrue rolloutrequiredSecret 的 base64 只是编码。第二个程序不打印秘密只检查必填键、值是否为空以及轮换版本是否增加这种“只输出结论、不输出内容”的模式也适用于 CI 日志。fromdataclassesimportdataclassdataclass(frozenTrue)classSecretMetadata:name:strkeys:tuple[str,...]nonempty:tuple[str,...]version:intdefvalidate(secret:SecretMetadata,previous_version:int)-list[str]:errors:list[str][]required{username,password}ifnotrequired.issubset(secret.keys):errors.append(missing required key)ifnotrequired.issubset(secret.nonempty):errors.append(empty secret value)ifsecret.versionprevious_version:errors.append(rotation version did not increase)returnerrors candidateSecretMetadata(nameweb-credentials,keys(username,password),nonempty(username,password),version4,)errorsvalidate(candidate,previous_version3)print(fsecret{candidate.name})print(fchecked_keys{len(candidate.keys)})print(validation(PASSifnoterrorselseFAIL))运行输出secretweb-credentials checked_keys2 validationPASS参考来源ConfigMapsSecretsEncrypting Confidential Data at RestSecrets Store CSI Driver 觉得有用就点个赞 收藏方便回头查阅有疑问直接在评论区留言我看到都会回。 本文属于《Kubernetes 上手实战》系列持续更新关注不迷路。 文章里的代码都能直接跑。想要可直接 clone 的完整工程 配套部署脚本 / 踩坑清单评论一声或发邮件到cj2664qq.com我免费发你。如果你正好在做类似系统、或有工程化难题想找人做也欢迎邮件聊一句——我按实际情况评估能落地的就接单或出方案。评论和邮件都能直接找到我不用跳别的平台。
返回列表