Kubernetes(简称K8s)是目前最热门的容器编排平台已经成为云原生的事实标准越来越多的公司开始在生产环境使用K8s来编排和管理容器。
但是K8s架构复杂概念多组件多在生产环境使用会遇到很多坑从集群搭建到应用部署到运维监控每个环节都可能出问题,而且很多问题排查起来非常费劲需要对K8s的架构和原理有深入的理解。
我最近在生产环境使用K8s踩了不少坑熬了好几个通宵才把问题一个个解决今天想记录一下这些让我熬夜的问题以及,排查过程和解决方案希望能帮大家少走弯路。
一、网络问题:最常见也最头疼
K8s的网络是最复杂也最容易出问题的部分K8s的网络模型比较特殊有Pod网络Service网络Ingress等等多层网络叠加出了问题排查起来非常费劲。
问题1:Pod之间,网络不通:
刚搭建好集群的时候,遇到了Pod之间,网络不通的问题同一个Node上的Pod能互通,但是跨Node的Pod不通排查了很久。
排查过程:
- 先在两个Node上分别起测试Podping对方Pod的IP不通。
- 检查Node之间,网络是否通ping对方Node的IP通说明Node之间,网络没问题。
- 检查CNI插件(我们用的Calico)是否正常看Calico的Pod日志发现有,错误提示BGP邻居建立失败。
- 检查Node的防火墙发现Node之间,的BGP端口(179)被防火墙挡了导致Calico的BGP邻居建立失败跨Node的Pod网络不通。
解决方案:打开Node之间,的BGP端口(179)以及Calico需要的其他端口问题解决。
经验:K8s的网络插件(CNI)需要特定的端口通信搭建集群前一定要先检查防火墙配置打开所有需要的端口包括K8s组件的端口和CNI插件的端口,否则会遇到各种网络问题。
问题2:Service访问不通:
还有一个常见的问题是Service访问不通Pod能通,但是通过Service的ClusterIP或者NodePort访问不通。
排查过程:
- 先检查Service的selector是否正确能不能匹配到后端Pod用kubectl describe service看Endpoints是否有内容,如果Endpoints为空说明selector不匹配,或者Pod没Ready。
- 检查Pod的readinessProbe是否通过,如果readinessProbe失败Pod不会被加入Service的EndpointsService访问就会失败。
- 检查kube-proxy是否正常kube-proxy负责Service的负载均衡和转发,如果kube-proxy出问题Service就会访问不通看kube-proxy的日志是否有错误。
- 检查iptables或者IPVS规则是否正确kube-proxy通过iptables或者IPVS来实现Service的转发,如果规则有问题Service就会访问不通。
解决方案:根据排查结果针对性解决,比如修正selector修复readinessProbe重启kube-proxy等等。
经验:Service访问不通最常见的原因是Endpoints为空也就是selector不匹配,或者Pod没Ready排查Service问题第一步就是看Endpoints是否正常这能解决大部分问题。
问题3:Ingress访问不通:
Ingress是K8s中暴露HTTP/HTTPS服务的方式,但是Ingress也容易出问题访问不通。
排查过程:
- 检查Ingress Controller是否正常部署Pod是否Running日志是否有错误。
- 检查Ingress规则是否正确hostpathbackend是,否配置正确用kubectl describe ingress查看。
- 检查Ingress对应的Service是否正常Endpoints是否有内容。
- 检查DNS解析是否正常Ingress的host是否能解析到Ingress Controller的IP。
- 检查TLS证书是否正确,如果是HTTPS证书过期,或者配置错误会导致访问失败。
经验:Ingress问题一般出在Ingress Controller本身,或者Ingress规则配置错误排查的时候,先看Ingress Controller的日志一般能找到问题原因。
二、存储问题:数据安全是底线
K8s的存储也是容易出问题的部分特别是有状态的应用(数据库消息队列等等)存储出问题可能导致数据丢失后果严重。
问题1:PV/PVC绑定失败:
刚用K8s部署有状态应用的时候,遇到了PVC一直Pending绑定不上PV的问题。
排查过程:
- 用kubectl describe pvc看事件提示no persistent volumes available for this claim说明没有匹配的PV。
- 检查PV的配置accessModesstorageClassNamecapacity是否和PVC匹配发现PV的storageClassName是manual而PVC没有指定storageClassName默认是""不匹配。
- 或者用了StorageClass动态供给,但是StorageClass配置错误,或者没有默认StorageClass导致PVC无法动态创建PV。
解决方案:修正PV/PVC的配置确保storageClassNameaccessModescapacity匹配,或者配置正确的StorageClass设置默认StorageClass。
经验:PV/PVC绑定失败最常见的原因是storageClassName不匹配,或者accessModes不匹配排查的时候,要仔细对比PV和PVC的配置。
问题2:数据丢失:
有一次误删了一个PVC导致PV也被回收数据丢失差点出大事,幸好有备份。
原因:PV的persistentVolumeReclaimPolicy配置为DeletePVC被删除后PV也会被自动删除数据也就丢了。
解决方案:
- 重要数据的PV配置persistentVolumeReclaimPolicy为Retain这样PVC被删除后PV不会被删除数据还在可以手动恢复。
- 定期备份数据,不管用什么存储都要定期备份有备无患。
- 做好权限控制不要随便给删除PV/PVC的权限避免误删。
经验:生产环境重要数据的PV一定要用Retain策略,并且定期备份数据不要用Delete策略,否则误删PVC就会丢数据后果严重。
问题3:存储性能问题:
还有一个问题是存储性能不够数据库跑在K8s里IO性能差响应慢。
原因:用了网络存储(NFS或者云存储)IO延迟高吞吐量低不适合数据库这种对IO要求高的应用。
解决方案:
- 数据库等对IO要求高的应用用本地存储(Local PV)或者,高性能的块存储不要用NFS这种网络文件存储。
- 配置存储的IO参数,比如块存储的IOPS吞吐量等等。
- 对数据库做读写分离分库分表减轻单个节点的IO压力。
经验:不是所有应用都适合跑在K8s里特别是对IO要求高的数据库要谨慎选择存储方案必要时数据库还是跑在物理机,或者虚拟机上更稳定性能更好。
三、资源调度问题:合理分配资源
K8s的资源调度也是容易出问题的部分资源配置不合理会导致Pod调度不上去,或者Node资源耗尽影响应用稳定性。
问题1:Pod一直Pending调度不上去:
常见的问题是Pod一直Pending调度不上去。
排查过程:
- 用kubectl describe pod看事件一般会提示调度失败的原因,比如Insufficient cpuInsufficient memorynode(s) had taints that the pod didn't tolerate等等。
- 如果是资源不足检查Pod的resources.requests是,否配置过大超过了Node的剩余资源。
- 如果是污点容忍问题检查Node的taints和,Pod的tolerations是否匹配。
- 如果是节点选择问题检查nodeSelectornodeAffinity是,否配置正确有没有匹配的Node。
解决方案:根据原因针对性解决,比如调小resources.requests增加Node资源配置tolerations修正nodeSelector等等。
经验:PodPending调度不上去用kubectl describe pod看事件一般就能找到原因K8s的事件信息很详细能帮我们快速定位问题。
问题2:OOMKilledPod被杀死:
还有一个常见的问题是Pod被OOMKilled(内存溢出杀死)。
原因:Pod的内存使用量超过了resources.limits.memoryK8s会杀死Pod重启。
解决方案:
- 检查应用是否有内存泄漏导致内存使用量持续增长。
- 合理配置resources.limits.memory不要设置太小也不要太大根据应用的实际内存使用量配置。
- 配置resources.requests.memory和limits保持一致,或者略小避免资源超卖。
经验:OOMKilled一般是应用有内存泄漏,或者limits设置太小要先排查应用是否有内存泄漏再调整limits不要盲目调大limits否则可能导致Node内存耗尽影响其他Pod。
问题3:CPU throttling应用响应慢:
还有一个隐蔽的问题是CPU throttling(CPU节流)Pod的CPU使用量没到limits但是,应用响应慢排查发现是CPU throttling导致的。
原因:K8s的CPU limits是用CFS(Completely Fair Scheduler)来限制的是按时间片来限制的,比如limits.cpu = 1就是100ms内最多用100ms的CPU时间,如果应用在某个时间片内用完了CPU时间就会被节流等到下一个时间片才能继续运行导致应用响应延迟增加,即使平均CPU使用率不高。
解决方案:
- 合理配置CPU limits不要设置太小给应用足够的CPU时间。
- 对延迟敏感的应用可以考虑不设置CPU limits只设置requests避免CPU throttling但是要注意资源超卖的问题。
- 用CPU manager或者静态CPU管理策略给延迟敏感的应用分配独占的CPU核心避免throttling。
经验:CPU throttling是一个很隐蔽的问题不容易发现应用响应慢,但是CPU使用率不高就要考虑是不是CPU throttling导致的可以看Pod的CPU throttling指标来确认。
四、配置管理问题:ConfigMap和Secret
K8s用ConfigMap和Secret来管理配置,但是也有一些坑。
问题1:ConfigMap更新应用不生效:
常见的问题是更新了ConfigMap但是应用里的配置没更新不生效。
原因:ConfigMap更新后已经挂载到Pod里的ConfigMap会自动更新(大概1-2分钟延迟)但是应用是否重新加载配置取决于应用本身很多应用启动时读取配置之后,就不重新读取了,所以ConfigMap更新了应用也不生效。
解决方案:
- 应用支持配置热加载监听配置文件变化自动重新加载。
- 用滚动更新重启Pod让应用重新读取配置可以用kubectl rollout restart或者,更新Pod的annotation触发滚动更新。
- 用Reloader之类的工具自动监听ConfigMap/Secret变化触发Deployment滚动更新。
经验:ConfigMap更新不生效一般是应用没有重新加载配置不是K8s的问题要根据应用的情况选择合适的方案要么应用支持热加载要么重启Pod。
问题2:Secret不安全:
Secret是用来管理敏感信息的(密码密钥证书等等)但是K8s的Secret默认只是,Base64编码不是加密的不安全。
原因:K8s的Secret默认存储在etcd里是明文(Base64编码等于明文)任何能访问etcd的人都能看到Secret的内容,而且RBAC权限配置不当也可能导致未授权访问Secret。
解决方案:
- 开启etcd加密(Encryption at Rest)让Secret在,etcd里是加密存储的。
- 配置严格的RBAC权限只给需要的人和服务访问Secret的权限。
- 用外部密钥管理系统(VaultSealed Secrets等等)来管理敏感信息不直接存在K8s的Secret里。
- 不要把Secret提交到代码仓库用GitOps的时候,要注意加密Secret。
经验:生产环境一定要开启etcd加密,并且配置严格的RBAC权限重要的密钥建议用外部密钥管理系统不要只依赖K8s的Secret毕竟默认的Secret安全性有限。
五、监控和日志问题:可观测性很重要
K8s的监控和日志也是生产环境必须做好的出了问题需要靠监控和日志来排查。
问题1:监控缺失出问题不知道:
刚上K8s的时候,监控没做好出了问题都不知道等用户反馈才发现很被动。
解决方案:
- 部署Prometheus + Grafana监控集群资源(NodePod容器的CPU内存磁盘网络等等)以及应用指标。
- 部署metrics-server支持kubectl top查看资源使用情况。
- 配置告警规则(Alertmanager)重要指标异常及时告警通知相关人员。
- 监控K8s组件本身(etcdapiserverschedulercontroller-managerkubeletkube-proxy等等)确保集群本身健康。
经验:生产环境监控一定要先做好再上应用不要等出了问题才想起来做监控监控是,生产环境的基础没有监控就像盲人摸象出了问题都不知道。
问题2:日志收集日志丢失:
还有一个问题是日志收集日志丢失,或者收集不及时排查问题找不到日志。
解决方案:
- 部署EFK(Elasticsearch + Fluentd/Filebeat + Kibana)或者,Loki来收集和查询日志。
- 应用日志输出到stdout/stderr不要写到文件里K8s会自动收集stdout/stderr的日志。
- 配置日志轮转避免日志文件太大占满磁盘。
- 对重要的日志配置告警错误日志异常及时告警。
经验:K8s的日志最佳实践是应用输出到stdout/stderr然后用日志收集工具统一收集不要让应用写日志文件,否则日志文件管理麻烦还容易丢失。
六、安全问题:不能忽视
K8s的安全也是生产环境必须重视的K8s组件多攻击面大安全配置不当容易被攻击。
常见安全问题:
- API Server未授权访问:API Server暴露在公网没有,认证授权任何人都能访问控制集群非常危险。
- RBAC权限过大:给Service Account或者用户分配了过大的权限,比如cluster-admin被攻陷后能控制整个集群。
- 容器以root运行:容器以root用户运行被攻陷后能获取宿主机root权限危险。
- 特权容器:容器配置了privileged: true能访问宿主机的所有设备被攻陷后非常危险。
- etcd未加密:etcd未加密存储Secret等敏感信息泄露风险。
- 镜像漏洞:使用了有漏洞的镜像被攻击风险。
解决方案:
- API Server不要暴露在公网放在内网通过VPN或者,堡垒机访问配置认证授权。
- 配置最小权限的RBAC只给需要的权限不要随便给cluster-admin。
- 容器以非root用户运行配置securityContext.runAsNonRoot: truerunAsUser指定非root用户。
- 不要用特权容器除非确实需要,并且做好安全隔离。
- 开启etcd加密(Encryption at Rest)。
- 用镜像扫描工具(TrivyClair等等)扫描镜像漏洞及时修复。
- 用NetworkPolicy限制Pod之间,的网络访问最小化攻击面。
- 定期做安全审计和漏洞扫描及时发现和修复安全问题。
经验:K8s的安全是一个系统工程需要从多个层面做好防护不要等被攻击了才重视安全生产环境一定要做好基础的安全配置最小权限非root加密等等。
七、写在最后
以上就是我在K8s生产实践中遇到的那些让我熬夜的问题以及排查过程和,解决方案包括网络存储资源调度配置管理监控日志安全等等方面。
K8s是一个强大,但是复杂的系统生产环境使用会遇到很多坑需要我们不断学习和积累经验,但是,只要我们理解K8s的架构和原理做好基础的配置和监控遇到问题耐心排查大部分问题都能解决。
希望我的踩坑经历能帮大家少走弯路更快地上手K8s在生产环境稳定运行。
最后用一句话结束这篇文章:"K8s生产实践没有银弹,只有不断踩坑不断积累不断优化才能稳定运行。"
愿大家的K8s集群都能稳定运行少出问题少熬夜。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录