ARTICLE DETAIL

资讯详情

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

用Guardon守护Kubernetes:20个关键配置错误自查清单

用Guardon守护Kubernetes:20个关键配置错误自查清单 做运维的人都知道Kubernetes集群的故障大多数时候不是“轰”地一下崩掉的而是像温水煮青蛙一样配置里的小隐患一点点累积等到某次发版、某个流量高峰、某次节点重启才集中爆发出来。真正让人头疼的不是排障那几个小时而是你根本不知道问题出在哪一个配置项上。我在生产环境维护多个K8s集群之后逐步把Guardon当作一个默认的“配置守门员”让它在故障发生之前就把可疑的配置错误标记出来。这篇文章就把我在这套方案里筛选出的20个最关键配置错误完整拆开讲每个错误都会说明它会造成什么后果、Guardon如何识别它以及应该怎么修。不论你是平台工程师还是业务团队的K8s使用者这20个错误都能帮你少踩几个坑。1. 为什么是Guardon核心思路与方案选型1.1 配置错误才是生产事故的头号来源Kubernetes本身不会拦你你给它什么配置它就跑什么配置。这个特性在企业环境里其实是一个隐患集群是共享的应用是多团队部署的人员流动也快一个服务以root账号跑了两周可能没人注意等到某次安全事件复盘才有人想起来查当时的配置。配置错误不像代码报错那样直接让CI失败它一般在线上环境里“半静默”地潜伏只在特定条件下被触发——比如流量突增导致Pod被驱逐、节点重启导致调度重建、发版时副本数缩容触发亲和性冲突。我把这类问题总结为“延迟爆炸”型故障配置本身不报错但会在某次变更或某个节点事件中被引爆。最典型的例子是Pod没有设置resources.limits平时跑得挺正常一旦同节点其他Pod把CPU打满这个Pod就会被内核OOM杀死业务方第一反应是“是不是你们平台出问题了”查半天才发现是自己的配置压根没限制资源使用。这类排障成本非常高因为它把平台问题、业务问题、配置问题混在一起很难定位。1.2 Guardon为什么能提前发现问题Guardon的核心是一套基于OPAOpen Policy Agent的持续配置审计机制。它从Kubernetes API Server拉取资源数据再把内置的几十条策略逐条比对任何一条不满足都会生成告警报告。这件事的独特价值在于它不是等故障出现再做告警而是从配置落地那一刻就开始做约束。你可以把Guardon理解成给集群请了一位不知疲倦的配置审计员24小时盯着所有Deployment、StatefulSet、Service、Ingress、NetworkPolicy、RBAC等资源。策略不满足就给出报告完全不依赖业务流量是否异常也不依赖监控曲线是否告警。这意味着很多配置错误可以在上线后几分钟内被识别出来而不是等几个月后故障爆发了才被追查。从团队协作角度看Guardon还提供了一个中性审查视角。很多时候配置问题是业务团队和平台团队互相扯皮的重灾区业务说自己按文档配的平台说你们配错了。Guardon的策略是公开、透明、可查的它不会偏袒任何一方谁违反了策略规则报告里写得很清楚。把Guardon的扫描报告直接丢到群里比口头解释一百遍都管用。2. 20个关键配置错误全解析你的集群中了几条这一部分是我在多个集群里跑了Guardon之后积累的真实观察。它的内置策略覆盖了配置安全、资源管理、存储、网络、容器生命周期等多个维度。我按故障影响面和出现频率把它们整理成5个组别每组下面拆开讲解。2.1 权限安全组5个最容易让集群裸奔的配置错误1容器以root账号运行。这是Guardon默认策略里面最常命中、影响也最直接的一条。容器内的进程如果以UID 0运行一旦应用本身存在漏洞比如RCE、文件上传绕过攻击者拿到shell之后就直接拥有了容器内的最高权限。配合错误的capabilities配置和宿主机内核漏洞很容易把容器逃逸变成现实。修复方式是在Deployment的securityContext里设置runAsNonRoot: true并显式指定runAsUser为一个非0的UID比如10001。如果你的基础镜像里某些进程必须bind到低端口小于1024还需要配合NET_BIND_SERVICE capability做精确放行而不是直接放弃非root校验。错误2privileged: true特权容器。这个配置一开容器基本上就是宿主机上的一个普通进程了它可以访问所有设备、加载内核模块、操作cgroups。有段时间很多中间件容器在裸机时代习惯了特权运行迁移到K8s就直接带上了这个配置风险极大。Guardon对privileged的检测是直接看spec.containers[].securityContext.privileged字段只要等于true就报。修复标准是移除privileged字段改用更细粒度的capabilities。比如需要抓网络包就加NET_ADMIN需要操作iptables就加NET_RAW不要图省事一刀切开特权。错误3RBAC权限过大。比如把cluster-admin的ClusterRoleBinding直接绑到一个业务ServiceAccount上或者为某个命名空间的普通应用授予了集群级别的list secret权限。这类错误在“业务需要访问另一个命名空间资源”的场景里特别常见为了快速解决临时需求直接给了大权限。Guardon的策略会检查ClusterRole和RoleBinding里是否有过于宽泛的资源权限定义比如resources: []、verbs: []之类。修复思路是遵循最小权限原则只授予当前业务真实需要的资源类型和操作动词。权限设计上要有“按场景按角色拆分”意识比如把只读权限和读写权限拆成不同Role给不同的ServiceAccount用。错误4Secret在环境变量中明文暴露或使用弱编码方式存储。很多Deployment会把数据库密码、API Key直接写成env.value而不是引用secretKeyRef一旦YAML被提交到Git仓库、截图发到群里、导出到日志里敏感信息就直接泄露了。Guardon的检查点在于secret对象是否被定义为stringData而不做加密、Deployment的env是否直接引用普通ConfigMap中的敏感字段。修复方式是把所有敏感信息收敛到Kubernetes Secret在Deployment里通过secretKeyRef方式引用。如果企业有Vault、KMS等外部密钥管理服务可以接入External Secrets Operator统一管理不要在YAML里写任何明文密码。错误5hostPath挂载宿主机目录。hostPath允许Pod直接读写Node上的目录这在单机测试环境确实方便但生产环境一旦误用Pod可以访问宿主机的/var/lib/kubelet、/etc/kubernetes等敏感目录等于把节点安全完全交给了一个业务容器。Guardon会对hostPath类型的volume直接告警。修复方式是用PersistentVolumeClaim代替hostPath让存储生命周期和节点解耦。如果业务确实需要访问节点上的某些文件比如日志目录优先考虑使用emptyDir配合sidecar收集或者用DaemonSet配合hostPath并做好白名单尽量缩小暴露面。2.2 资源与稳定性组5个容易引发雪崩的配置错误6Deployment没有设置resources.requests和resources.limits。这是我在生产环境见过最多的配置错误也是最容易引发雪崩的。Pod没有requests时调度器不知道它需要多少资源节点上超卖严重没有limits时单个容器可以把节点CPU吃满拖垮同节点所有Pod。Guardon对每个container检查spec.containers[].resources.limits.cpu、limits.memory、requests.cpu、requests.memory是否都有值缺一个就报。修复建议是limits和requests都写requests给实际使用基线limits给允许的上限。比如一个Java服务经验值是requests 1C2Gi、limits 2C4Gi起步再压测调整。错误7缺少readinessProbe或livenessProbe。没有readinessProbePod一启动就会被Service纳入Endpoints哪怕进程还没就绪流量已经打过来了老用户会看到502/503。没有livenessProbe进程死锁或陷入死循环后Kubelet不会重启它服务就那么挂死着占用资源。Guardon会检查每一个container是否定义了readinessProbe和livenessProbe。修复时注意区分两个探针的职责readinessProbe控制流量接入livenessProbe控制进程恢复。探针参数也要根据业务实际调initialDelaySeconds太短会导致启动慢的应用频繁被杀timeoutSeconds太短容易误报。错误8Namespace没有配置ResourceQuota和LimitRange。这个问题在多人共享集群时特别突出。某个业务团队创建了一堆Pod每个都没有资源限制加起来把整个集群的可用内存吃光了其他团队部署Pod时一直pending排查半天才发现是某个命名空间没有配额约束。Guardon会检查namespace下是否存在resourcequota类型资源和limitrange类型资源。修复方式是为每个业务namespace创建ResourceQuota限制总量比如max memory、max pods和LimitRange给单个容器一个默认requests和limits。这样即使开发者在YAML里没写resources字段LimitRange也能兜底填一个默认值。错误9关键服务副本数只有1。数据库、Redis、核心API服务如果replicas: 1一旦节点故障或Pod被驱逐整个服务就是不可用的。很多团队吐槽“K8s不稳定”很多时候不是K8s的问题是业务自身没做多副本。Guardon策略会检查Deployment的replicas是否大于1StatefulSet的副本数是否匹配该有的一致性要求。修复方式是至少设置3个副本并配合PodAntiAffinity把副本尽量打散到不同节点。如果应用本身不支持多实例比如部分单机任务那也应该用StatefulSet管理而不是裸奔一个Deployment。错误10没有配置PodDisruptionBudgetPDB。这个错误在大集群运维操作时才会显现。当我们需要对节点做维护、升级内核、迁移实例时如果应用没有PDB节点排水会直接把所有副本同时摘掉服务瞬间不可用。Guardon会检查Deployment/StatefulSet是否有对应的poddisruptionbudget对象关联。修复方式是为关键服务创建PDB设置minAvailable或者maxUnavailable策略。比如一个3副本服务设置minAvailable: 2那节点维护时最多只有一个副本被同时摘掉其余副本可以正常服务。2.3 存储与数据持久化组4个会让数据“消失”的配置错误11StatefulSet使用本地存储而非PV/PVC。有状态服务数据库、消息队列如果用本地磁盘或hostPath存储数据Pod一旦被重新调度到另一台节点数据就“丢”了——准确说还在旧节点上但已经无法被新Pod访问。Guardon会检测StatefulSet的volume是否直接使用emptyDir或hostPath而非PersistentVolumeClaim。修复方式是为StatefulSet创建带storageClassName的PVC模板让每个副本有一个独立的持久卷。要特别注意StatefulSet的volumeClaimTemplates会在创建Pod时自动生成PVC千万不要手动一个个创建PVC然后去绑那样Pod重建后PVC不会自动匹配。错误12PersistentVolume的reclaimPolicy设置不当。PersistentVolume的reclaimPolicy有三个值Retain、Delete、Recycle已废弃。如果设置成DeletePVC删除时PV和底层存储数据会被直接清掉。在一些需要“保留数据、后续手工恢复”的运维场景里这个策略可能造成数据永久丢失。Guardon会检查PV的spec.persistentVolumeReclaimPolicy字段。修复建议是对数据库等有状态服务reclaimPolicy设置RetainPVC删除后管理员还能找到PV并手工恢复数据对临时性数据或者有完整备份机制的存储可以用Delete减少存储清理工作量。错误13Deployment没有显式指定storageClassName。集群里如果存在多个StorageClass比如本地盘SSD、云盘、网络存储不指定storageClassName的话默认使用default class。一旦默认class选错比如给了网络存储但应用需要高IO本地盘性能问题会立刻凸显而且这类问题是性能问题不是功能问题很难排查。Guardon会检查PVC是否指定了storageClassName。修复方式是根据业务性能要求显式指定合适的StorageClass。另外要确认集群中哪个class被标记为default尽量让默认class符合大多数通用业务的需求。错误14PVC容量规划错误。容量规划错误分两种情况一是申请容量过小业务增长后频繁触达容量告警只能删除PVC重建很痛二是申请容量过大云上块存储是按容量计费的超配造成巨大浪费。Guardon的存储容量策略会对照PV的capacity和PVC的requests检查是否存在明显不合理的分派。修复建议是对数据库类应用先压测估算出真实的增长曲线再申请至少3个月以上冗余的容量对文件存储类应用优先考虑支持动态扩容的StorageClass后期可以在线扩容。2.4 网络与流量接入组3个让流量“兜圈子”的配置错误15Service类型选择错误。常见误区包括外部访问需求为0的纯内部服务用了LoadBalancer白白占用云负载均衡的月费内部服务因为“图方便”把Service直接暴露成NodePort让业务端口暴露在集群所有节点上需要客户端源IP保持的场景却没设置externalTrafficPolicy: Local导致源IP被SNAT掉。Guardon策略会检查LoadBalancer类型的Service有没有对应的annotation说明用途以及是否合理使用了type字段。修复方式是理清访问链路集群内访问用ClusterIP跨命名空间用Headless Service配合DNS节点调试用临时NodePort只有真正面向外部流量才用LoadBalancer或Ingress。错误16Ingress没有启用TLS。K8s集群内部默认的流量是明文HTTP一旦Ingress没有配置TLS证书用户请求的Cookie、Token、敏感参数都会明文传输。很多内网系统在跑的时候没人注意等公司安全扫描或等第三方渗透测试报告出来才紧急整改。Guardon会检查Ingress资源的spec.tls字段是否存在。修复方式是为Ingress绑定合适的证书生产环境使用企业CA签发的证书或ACME自动签发的Lets Encrypt证书并配置强制跳转HTTP到HTTPS。现在很多集群已经接入了cert-manager自动签发和维护证书周期不用等证书到期前手工换。错误17没有配置NetworkPolicy。默认情况下Kubernetes集群里所有Pod之间都是网络全通的。这个默认行为意味着只要有一个Pod被攻破攻击者就能横向访问同集群内所有其他Pod的服务端口。Guardon的network策略会检查每个namespace下是否定义了networkpolicy资源。修复方式是用默认拒绝策略兜底再按业务实际需要放行特定来源的流量。最简单的方式是创建一个默认拒绝所有入口流量的NetworkPolicy然后再逐条添加允许规则。注意NetworkPolicy通常是namespace隔离的它只对Pod之间的流量生效不控制Pod访问外部互联网的流量。2.5 容器生命周期与镜像组3个影响发布和调度的配置错误18镜像Tag使用latest。使用latest作为镜像Tag发布时无法确定线上跑的到底是哪个commit构建的版本。同一个latest在不同节点上可能拉到了不同镜像回滚时也无从下手因为历史版本被覆盖了。Guardon的image tag策略会检查镜像Tag是否为latest或空。修复方式是使用不可变的版本Tag比如git commit的短SHA或者语义化版本号my-app:1.4.2、my-app:7f3a2c1。配合CI/CD流水线在每次代码合并后自动构建并推送带新Tag的镜像不要覆盖旧Tag保证可追溯、可回滚。错误19容器缺少优雅停机配置。默认情况下Pod被删除时Kubelet会同时向容器发送SIGTERM信号如果应用没有处理SIGTERM完成存量请求收尾和连接清理就直接被SIGKILL强杀。在高并发场景下这个行为会导致大量在途请求失败。Guardon会检查容器是否配置了lifecycle.preStop和terminationGracePeriodSeconds是否合理。修复方式是两步走一是为Spring Boot、Node.js等应用处理SIGTERM信号做优雅退出逻辑二是在Deployment里设置terminationGracePeriodSeconds为30~60秒同时用preStop hook加一个sleep几秒的缓冲时间确保Kubelet删除Endpoint后流量已经不再路由到该Pod。错误20imagePullPolicy设置不当。imagePullPolicy有三个值Always、IfNotPresent、Never。如果设置成Always每次Pod启动都会触发一次镜像拉取即使本地已有相同Tag的镜像。镜像仓库的限流策略会拖慢Pod启动速度在企业内网环境还会加大镜像仓库压力。而如果设置成IfNotPresent且使用latest无Tag变更新版本镜像根本不会被拉取就会出现改了代码但线上跑的还是旧版本的情况。Guardon的image策略会检查imagePullPolicy配置是否与Tag策略匹配。我的建议是生产环境统一用不可变Tag配上IfNotPresent既保证速度又保证版本准确性。3. Guardon落地实操部署、扫描、接入CI3.1 前置条件与快速部署Guardon本身就是一个运行在Kubernetes集群内的应用所以部署它没什么特殊要求只需要一个正常工作的K8s集群1.20和一个有权限创建自定义资源的账号。我习惯在一个单独的guardon命名空间里部署方便后续统一管理和清理。部署流程大致分为四步创建命名空间和应用RBAC、写入OPA策略ConfigMap、部署Guardon实例、验证策略加载。如果你用的是Helm方式一条helm install就能完成大部分工作。如果是从仓库的kustomize目录直接用kubectl apply也建议按照官方文档的目录顺序来因为RBAC对象如果没有先创建后面的Deployment启动时会因为权限不足而疯狂报403。部署完成之后先不要急着看报告。先确认Guardon的Pod是Running状态然后查看它的日志确保能正常从API Server拉取资源数据。我遇到过几次明明部署成功但没有任何报告输出的情况最后定位都是ServiceAccount权限缺失——Guardon本身也是K8s应用它的RBAC需要至少具备get/list各个核心资源的权限否则扫描就是空转。3.2 执行首次扫描并看懂报告Guardon的扫描结果有两种常见的阅读方式一是直接看Pod日志每次扫描完成后会输出一个汇总报告二是通过API接口拉取JSON格式的结果适合自己写脚本做告警或者推送到监控平台。首次扫描的结果通常比较“难看”几十条甚至上百条告警都很正常特别是老集群。第一次看到扫描报告时先不要慌也不要急着把里面的每一条都修掉。Guardon的默认策略相对严格有些告警在特定业务场景里其实是合理的。我的处理建议是分三个阶段第一个阶段只处理高危项。比如privileged特权容器、root运行、RBAC绑定过宽、hostPath挂载这些这些属于“出事就是大事”的配置必须立刻修。第二个阶段处理中危项。像缺少readinessProbe、缺少资源限制、latest镜像Tag这类属于潜在风险可以排期在迭代里修。第三个阶段低危项和业务特殊项比如某个状态检查周期过长、某些探针参数偏保守这类可以做例外标注不用强行改。查看报告的时候重点看两个字段Policy和Resource。Policy告诉你违反了哪条策略规则Resource告诉你具体是哪个Deployment/StatefulSet/Service。把这个对应关系记到排期表里修复起来就有明确目标了。3.3 把Guardon接入CI/CD流水线Guardon最有价值的使用方式不是等它扫描告警而是把它的检查接入CI/CD流水线在应用部署到集群之前就做一次配置预检。具体做法是在流水线里加一个步骤生成待部署的YAML清单后先跑一次Guardon scan把YAML里的每个对象用Guardon的OPA策略做静态检查检查不通过就卡住发布。这个流程的好处是开发者在写Deployment的时候系统会直接提示“你这里缺了一个readinessProbe”“你的镜像Tag不能是latest”而不是等到应用上线一个月后Guardon扫描出来了再修。等于把配置评审从“事后审计”前移到了“发布准入”。实际接入时要注意Guardon静态扫描YAML和在线扫描实时集群是两个模式。静态扫描时一些依赖集群上下文的信息比如StorageClass是否存在、PVC是否会绑定成功它检查不了只能检查能看得到的那部分字段。所以更稳妥的方式是静态扫描作为发布卡点在线扫描作为持续巡检两者互补而不是二选一。4. 常见问题与排查技巧实录4.1 误报与例外管理Guardon默认策略在部分场景下会有误报这是OPA策略引擎的固有权衡策略越严格误报率越高。比如它默认会把privileged容器的告警定义为Critical但如果是DaemonSet里跑的网络插件、监控Agent、备份Agent这些组件确实需要privileged模式直接按报告去“修复”反而会搞坏功能。我的处理方式是不要试图一次性把所有例外都加进去而是分类处理。对于确实需要特权的系统组件DaemonSet把它们单独放在kube-system或专用的系统命名空间里然后在Guardon的例外规则里按namespace维度排除。这样业务Pod的违规还是会被正常报告不会被系统组件的例外掩盖掉。另外Guardon的ConfigMap里可以自定义策略的白名单或者调整策略的严重级别。如果某个策略在你当前的架构下完全不适用比如集群根本没有LoadBalancer类型Service可以直接把这条策略的severity调低甚至关闭不要让它在报告列表里持续产生噪音。需要提醒的是例外和关闭都要写清楚原因和负责人不然过几个月之后没人知道这条例外是谁加的、为什么加。4.2 策略自定义让检查贴合实际场景Guardon内置策略覆盖了大部分通用场景但每个团队都有自己的架构规范和特殊约束。比如有些团队强制要求所有Pod必须带有team和应用名Label便于成本核算和监控聚合有些团队要求所有Deployment必须设置podManagementPolicy: Parallel。这些规则Guardon默认策略里没有但可以通过编写自定义OPA策略轻松实现。写自定义OPA策略时建议从浅到深先写简单的字段存在性校验比如“Deployment必须包含spec.selector.matchLabels.app”再写稍微复杂的关联性校验证比如“如果Pod绑定了PVC那么该PVC必须声明storageClassName”。写完之后放到Guardon的policy目录下加载后就能立刻生效。我自己写自定义策略时最大的体会是每一条策略都要有对应的业务含义不要为了“检查而检查”。一条策略落地到生产环境之前先拿历史数据跑一遍测试确认不会误伤正常业务再正式启用。4.3 团队落地经验让开发接受修复Guardon部署很容易落地很“难”难的不是技术是让人接受“你的配置有问题”这件事。很多开发同学看到Guardon报告时的第一反应是这工具是不是误报了我这么配跑得好好的为什么要改我的落地经验是先从一个有故障痛点的团队开始用他们之前真实发生过的事故做对比。比如某团队上次线上故障就是因为Pod没有设置memory limits导致OOM重启那就把这个案例和Guardon的memory策略对应起来用事实说话。等这个团队修复完配置后再把Guardon报告分享给其他团队让大家看到“这份检查是能提前发现真实问题的”接受程度会高很多。还有一个细节是不要在周五下午推送一大批Guardon告警给所有团队没有人会在周末前有心情改配置。更好的方式是每周固定一个时间发送扫描摘要按团队和优先级分组让开发直接看到自己负责的服务有哪些配置需要修复。修复闭环之后再庆祝一次“这个月Guardon告警清零”的成果比任何KPI都有效。最后分享一个技巧我在实际使用中还发现一个很实用的组合把Guardon的扫描结果同时输出到企业微信机器人或者Slack频道每天定时推送“昨日新增配置错误”和“待关闭的错误清单”。这样配置错误不再是一堆躺在报告里的死数据而是一个有闭环的日常运维动作。团队里无论谁新建了Deployment或改了Service配置只要违反了策略当天就能被发现。如果Guardon连续一周都是零新增告警那就说明团队的配置规范已经内化了这时候可以开始检查一些更深层的策略比如镜像安全扫描、权限周期性复核把集群治理再做深一层。
返回列表