当前位置: 首页 > 科技观察

如何保护你的Kubernetes集群

时间:2023-03-20 12:53:45 科技观察

随着Kubernetes的不断发展和技术的不断成熟,越来越多的公司选择将自己的应用部署到Kubernetes上。但是将应用程序部署到Kubernetes就完事了吗?很明显不是。应用容器化只是万里长征的第一步。如何让应用程序安全、稳定地运行,就是后续的全部工作。这里主要从以下几个方面来整理,对于大部分公司来说已经足够了。NodeNode可以是物理主机,也可以是云主机,是Kubernetes的载体。很多时候,我们不太关心Node发生了什么,除非它出现了异常。但是作为运维人员,我们最不想要的就是异常,Node也是如此。Node节点不需要做太多复杂的操作,主要有以下几点:>内核升级对于大多数企业来说,CentOS系统仍然是首选。默认情况下,7系系统默认版本为3.10。这个版本的内核在Kubernetes社区中有很多已知的bug,所以对于节点来说,升级内核是必须的,或者企业可以选择Ubuntu作为底层操作系统。升级内核的步骤如下(简单升级方法):wgethttps://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-lt-5.4.86-1.el7.elrepo.x86_64.rpmrpm-ivhkernel-lt-5.4.86-1.el7.elrepo.x86_64.rpmcat/boot/grub2/grub.cfg|grepmenuentrygrub2-set-default'CentOSLinux(5.4.86-1.el7.elrepo.x86_64)7(核心)'grub2-editenvlistgrub2-mkconfig-o/boot/grub2/grub.cfgreboot>软件更新对于大多数人来说,很多时候都不会更新软件,因为他们害怕兼容性问题。但是在实际生产中,我们需要对已知存在高危漏洞的软件进行更新,可以进行相应的处理。>优化Docker配置文件对于Docker配置文件,主要优化日志驱动、保留日志大小、镜像加速等,其他配置视情况而定,如下:cat>/etc/docker/daemon.json<优化kubelet参数对于K8S,kubelet是领队负责Node的“饮食起居”。这里其参数配置主要如下:cat>/etc/systemd/system/kubelet.service<日志配置管理这里的日志配置管理是针对系统的日志,不是自研应用日志。默认情况下,系统日志不需要特殊配置。我在这里提出主要是为了保证日志的可追溯性。当系统因为某种原因被入侵,系统被删除时,仍然有日志供我们分析。因此,在条件允许的情况下,需要远程备份Node节点的系统日志。可以使用rsyslog进行配置管理,日志可以保存到远程日志中心或者oss。>安全配置这里涉及的安全配置不多,主要是加强一些已知的安全问题。主要有以下五种(当然还有更多,看自己情况):ssh密码过期策略密码复杂度策略ssh登录次数限制系统超时配置历史配置PodPod是K8S的最小调度单元,是应用程序的载体.应用程序的稳定性直接关系到应用程序本身。部署应用程序时,需要考虑几个方面。>ResourceLimitationPod使用主机的资源。合理的资源限制可以有效避免资源超卖或资源抢占。配置资源限制时,需要根据实际应用情况确定Pod的QoS。不同的QoS配置是不同的。如果应用级别比较高,建议配置Guaranteedlevel配置,如下:resources:limits:memory:"200Mi"cpu:"700m"requests:memory:"200Mi"cpu:"700m"如果应用level一般,建议配置Burstablelevel,如下:resources:limits:memory:"200Mi"cpu:"500m"requests:memory:"100Mi"cpu:"100m"强烈不建议使用BestEffort类型豆荚。>调度策略调度策略也是根据情况决定的。如果您的应用程序需要指定调度到某些节点,您可以使用亲和力调度,如下所示:一个节点只允许某个应用被调度,那么就需要使用污点调度,即先对节点进行污点,然后需要调度到该节点的Pod需要容忍污点。最安全的方法是标签+污渍的组合。如下:tolerations:-key:"key1"#可以容忍的taintkeyoperator:"Equal"#Equal等于key=value,Exists不等于,表示value不等于后面的值正常value:"value1"#Valueeffect:"NoExecute"#effectstrategytolerationSeconds:3600#原来的pod被驱逐需要多长时间?注意只有effect:"NoExecute"可以设置,否则会报错。当然除了Pod和Node的关联之外,还有Pod和Pod之间的关联。在某些情况下,为了实现真正的高可用,我们不建议将同一个应用的Pod调度到同一个节点上,所以我们需要对Pod进行反亲和调度,如下:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchExpressions:-key:appoperator:Invalues:-storetopologyKey:"kubernetes.io/hostname"如果一个应用与其他应用有affinity,可以使用affinity,可以在一定程度上减少网络延迟,如下:affinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchExpressions:-key:securityoperator:Invalues:-S1topologyKey:failure-domain.beta.kubernetes.io/zone>Gracefulpod升级默认采用滚动更新策略,我们主要关注新的Pod,旧的Pod如何优雅地处理流量,外界无动于衷。最简单的方法是“睡几秒钟”。此方法不保证100%优雅的流量处理。方法如下:lifecycle:preStop:exec:command:-/bin/sh--c-sleep15如果有注册中心,退出前可以先从注册中心注销原来的服务。比如这里使用的nacos作为注册中心,如下:lifecycle:preStop:exec:command:-/bin/sh--c-"curl-XDELETEyour_nacos_ip:8848/nacos/v1/ns/instance?serviceName=nacos.test.1&ip=${POD_IP}&port=8880&clusterName=DEFAULT"&&sleep15>probe配置重要吗?重要的!是kubelet判断Pod是否健康的重要依据。Pod的主要探针有:livenessProbereadinessProbestartupProbe其中,startupProbe是v1.16之后新增的探针。它主要针对启动时间较长的应用程序。大多数情况下只需要配置livenessProbe和readinessProbe即可。通常一个Pod代表一个应用,所以配置探针时最好直接反映应用是否正常。很多框架都有健康检测功能。我们可以考虑在配置探针的时候使用这些健康检测功能,如果框架没有,也可以考虑让开发者开发统一的健康检测接口,方便健康检测标准化。如下:readinessProbe:failureThreshold:3httpGet:path:/healthport:httpscheme:HTTPInitialDelaySeconds:40periodSeconds:10successThreshold:1timeoutSeconds:3livenessProbe:failureThreshold:3httpGet:path:/healthport:httpGet:path:/healthport:httpscheme:HTTPInitialDelaySeconds:60periodSeconds:60需要配置,start可以配置如下:startupProbe:httpGet:path:/healthprot:80failureThreshold:10initialDelay:10periodSeconds:10>保护策略这里的保护策略主要是指我们在运行时通过保护策略来控制Pod的运行数量主动销毁Pod。该功能在K8S中通过PodDisruptionBudget(PDB)实现。对于一些重要的应用,我们需要为其配置PDB,如下:apiVersion:policy/v1beta1kind:PodDisruptionBudgetmetadata:name:pdb-demospec:minAvailable:2selector:matchLables:app:nginx在PDB中,Pod的数量主要由控制两个参数:minAvailable:表示可用Pod的最小数量,表示Pod集群中处于运行状态的Pod的最小数量或者处于运行状态的Pod数量占总数的百分比;maxUnavailable:表示不可用Pod的最大数量,表示Pod集群中不可用Pod的最大数量或占不可用Pod总数的百分比;注意:minAvailable和maxUnavailable是互斥的,也就是说同一时间只能有一个出现。日志会贯穿应用的整个生命周期,在排查问题或分析数据时,日志是必不可少的。对于日志,这里主要从以下几个方面进行分析。>日志标准日志一般分为业务日志和异常日志。对于日志,我们不希望它们太复杂或太简单。我们希望通过日志达到以下目的:记录和监控程序的运行状态;必要时,可以详细了解程序内部运行情况;对系统性能的影响尽可能小;如何定义日志标准?这里我简单梳理一下几点:日志分类的合理使用统一的输出格式代码编码规范统一的日志输出路径统一的日志输出命名规范这个规定的主要目的是为了方便日志的收集和查看。>采集不同的日志输出有不同的日志采集方案。日志采集主要有两种方式:在Node上部署LoggingAgent进行采集,以Sidecar的形式采集到Pod中,在Node上部署LoggingAgent进行采集。这种日志收集方案主要针对已经标准输出的日志,架构如下:没有办法收集非标准输出的日志。在Pod中以Sidecar的形式收集。该采集方案主要针对非标准输出日志。您可以在Pod中运行Sidecar形式的日志采集客户端,将日志采集到日志中心。架构如下:但是这种方式比较浪费资源,所以比较理想的情况是把所有的应用日志都输出到标准输出,收集起来比较简单。>分析业务正常时,我们很少查看日志内容。只有出现问题的时候,我们才用日志来分析问题(大部分情况都是这样),为什么要在这里提出分析呢??日志实际上携带了很多信息。如果能够对日志进行有效的分析,可以帮助我们识别和排查很多问题。比如阿里云的日志中心,在日志分析方面做的很好。>告警日志告警可以让我们快速了解问题所在,缩小排查范围。但是做日志告警,需要对日志“关键词”进行管理,即要保证某个关键词能够准确的代表一个问题,最好不要有笼统的引用。这样做的好处是可以让报警更有准备,而不是一些报警风暴或者无效报警,久而久之就会麻木。监控集群和应用的生命周期都离不开监控系统。一个有效的监控系统可以为我们提供更高的可观察性,便于我们线性分析问题、排查问题、定位问题,并提供有效的告警通知,也方便我们快速知道问题所在。对于监控,主要从以下几个方面进行介绍。>集群监控对于K8S集群以及运行在K8S上的应用,一般会使用Prometheus进行监控。整个集群的稳定性关系到应用的稳定性,所以集群的监控非常重要。下面简单列举一些监控项目,实际工作中应酌情处理。>应用监控在很多企业中,没有接入应用监控。主要原因是应用中没有集成监控指标,导致无法监控。因此,强烈建议在应用开发时加入应用监控,指标按照prometheus标准格式暴露。除了开发者主动暴露指标外,我们还可以通过javaagent配置一些exporter来抓取一些指标,比如jvm监控指标。应用层面的监控可以细化监控粒度,更容易发现问题。这里我简单梳理了一些应用监控项,如下:这些监控项都是由相应的exporter完成的,比如redis中间件的redis-exporter,api监控的blcakbox-exporter等>事件监控在Kubernetes中,事件分为两种,一种是Warning事件,表示产生该事件的状态转换是在非预期状态之间产生的;另一个是Normal事件,表示预期状态,与当前状态一致。在大多数情况下,事件表示正在发生或已经发生的事情。这种信息在实际工作中很容易被忽略,所以我们有必要使用事件监控来避免此类问题。在K8S中,常用的事件监控是kube-eventer,它可以收集pod/node/kubelet等资源对象的事件,也可以收集自定义资源对象的事件,然后将这些信息发送给相关人员。通过事件,我们主要关注的监控项目有:>链路监控通常情况下,K8S中的应用都是作为独立的个体存在的,它们之间没有显式的联系。这时候就需要一种手段,把链接的关系展现出来,方便我们跟踪分析整个链接的问题。目前流行的链路监控工具有很多。我主要用skywalking做链路监控。它的主代理端比较丰富,同时也提供了很高的自扩展性。有兴趣的朋友可以了解一下。通过链路监控,主要实现以下目的。>警告通知很多人会忽略警告通知,认为警告就够了。但是在做告警通知的时候还是需要慎重考虑的。将兴趣点简单整理如下。我个人认为难点在于需要提醒哪些指标。选择指标时,必须遵循以下规则:警示指标具有唯一性。警告指标可以正确反映问题。暴露的问题亟待解决。综合考虑这些规则,方便我们选择需要的指标。二是紧迫性分级,主要根据该预警指标暴露出的问题是否需要及时解决,以及影响范围来综合衡量。故障升级主要是针对需要解决的未解决问题的策略。提高故障级别相当于提高紧急程度。通知渠道的分类主要是为了方便我们区分不同的告警,是否可以快速接收到告警信息。最后写的是一些基本的操作。对于YAML工程师来说,是必备的技能储备。这套适用于大多数公司。