多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Kubernetes核心原理与实战:容器编排、集群部署与故障排查

Kubernetes核心原理与实战:容器编排、集群部署与故障排查 Kubernetes是一套容器编排平台也是当前云原生技术栈里躲不开的核心工具。很多朋友第一次接触它是从Docker入门的感觉容器很好用但到了多机部署、服务发现、扩容缩容、故障恢复这些场景单靠Docker命令就完全不够用了。Kubernetes就是用来解决这一层问题的——它负责的事总结起来一句话让成百上千个容器按照你声明的期望状态运行并持续纠正现实中的偏差。这篇内容不是官方文档的翻译我把自己从零搭建集群、跑通业务、再到日常维护过程中沉淀下来的理解整理出来尽量讲清楚Kubernetes的底层逻辑也穿插一些实际项目里的取舍和排错经验。无论你是在备考某个知识体系、面谈中需要讲明白容器编排还是打算在自己的环境里真正落地一套集群这篇都值得花几分钟读完。1. 为什么需要Kubernetes容器化之后的下一个难题1.1 Docker带来的便利与单机瓶颈Docker把应用和依赖打包成镜像解决了在我机器上是好的这类环境一致性问题。早期的微服务改造团队普遍的做法是把若干容器通过Docker Compose跑在一台服务器上端口映射、挂载卷、网络桥接都在单机内完成。这套方案在业务量小的时候没有任何问题但一旦流量上来或者服务数量变多单机瓶颈就会非常明显。我见过某公司的早期架构一台8核16G的机器上跑着十几个Java微服务容器内存直接打满经常出现某个服务OOM后整机负载飙升。当时团队的解决办法是不断换更高配的机器从8核换到16核再换到32核成本直线上升效率却没有本质变化。这其实是走入了垂直扩展的死胡同——单机资源总有天花板而且机器一旦故障上面所有服务全部宕机坚挺的高可用自然无从谈起。1.2 多机部署真正困难的地方在哪把容器从一台机器挪到多台机器看起来只是多配几台服务器实际操作之后会发现麻烦事全藏在细节里容器调度到哪台机器如何让容器尽量均匀分布又不互相干扰容器IP是不固定的重启后IP就变了服务之间怎么找到彼此流量入口在哪里外部请求如何转发到对应的容器并且支持权重分配某个节点宕机后上面的容器由谁来重启、谁来迁移、谁保证短时间内恢复声明了5个副本实际只有3个存活谁负责补齐差值这些问题的集合就是容器编排平台要解决的范畴。Kubernetes最初源自某大型互联网公司内部的批量调度系统经验开源后逐步成为这一领域的事实标准。它提供了一套声明式API和控制器模型你描述最终想要的系统状态Kubernetes的各个组件持续工作让实际状态不断向期望状态靠近。提示可以这样理解Kubernetes与Docker的关系。Docker解决的是用什么方式跑应用容器封装Kubernetes解决的是跑在哪些机器上、怎么互相协作、坏了怎么办集群编排。两者配合但不互相替代。1.3 声明式API带来的思维转变使用Kubernetes之后你的工作方式会发生一个明显变化从执行操作变为声明状态。传统运维模式下发布一个服务的过程是登录服务器、拉取代码或镜像、停止旧进程、启动新进程、验证端口、更新负载均衡配置……每个步骤都是命令式的动作一旦操作顺序出错或者中间某一步失败回滚就非常麻烦。Kubernetes的做法完全不同——你把期望状态写在一个YAML文件里比如这个服务我需要3个副本使用某镜像的v1.2.0版本暴露80端口然后提交给集群。Kubernetes的控制器会自己去创建资源、维护副本数、执行滚动更新你不需要关心每台机器上发生了什么。这种声明式思路的好处是巨大的。首先配置文件可以进Git发布流程等同于代码变更流程有版本记录、有评审、可回滚其次控制器自带纠错能力副本少了会自动拉起节点掉线会自动在其他机器补位这是手工运维永远做不到的持续性和可靠性。2. 核心架构拆解控制面、工作节点与控制器的协作逻辑2.1 控制面组件的角色分配Kubernetes集群从物理构成看只有两类角色控制面节点和工作节点。控制面负责全局决策工作节点负责实际跑容器。控制面包括这样几个关键组件kube-apiserver所有请求的统一入口是所有组件通信的中枢。它负责认证、授权、准入控制并把状态数据写入存储层。可以把它理解为公司的前台总机任何人对集群的读写操作都经过它。etcd保存整个集群的全部状态数据包括所有资源对象定义、期望状态和实际状态。这是一个分布式键值存储数据一致性非常关键。很多Kubernetes故障牵涉etcd问题比如磁盘性能下降、空间不足、快照未清理等都会直接影响集群稳定性。kube-scheduler负责为新创建且未分配的Pod挑选合适的工作节点。它考量的是节点资源剩余量、亲和性约束、污点容忍、数据本地性等因素选出一个满足约束条件的最优节点。kube-controller-manager内部运行着多个控制器职责是监听资源变化、确保实际状态向期望状态收敛。比如deployment控制器保障副本数node控制器监控节点心跳和驱逐行为。工作节点上的核心组件相对简单一些kubelet每个节点上最核心的代理进程负责接收控制面下发的Pod定义管理Pod生命周期向控制面上报节点状态和Pod状态。它与容器运行时打交道完成容器的创建、启动、停止、删除等操作。kube-proxy负责维护节点上的网络规则实现Service到后端Pod的流量转发。常见模式包括iptables和IPVS转发规则要正确处理Pod IP的变化。容器运行时真正的容器引擎Kubernetes默认对接containerdCRI-O也是不错的选择。Docker被外部接管之后Kubernetes废弃了对Docker的直连支持改用containerd作为默认运行时。注意控制面节点通常不承担业务负载否则资源争抢会影响调度、控制器组件的运行稳定性。生产环境至少要有3个控制面节点并通过外部负载均衡对外提供apiserver入口。2.2 控制循环期望状态与现实状态的差值纠正Kubernetes最值得理解的设计是控制器模式。所有管理逻辑都围绕一个简单循环展开期望状态、当前状态、差异分析、执行纠正动作。举例来说如果你的Deployment定义了副本数replicas3现实中由于某个节点宕机少了一个副本deployment控制器就会检测到ReplicaSet里的实际Pod数量只有2于是立即调度一个新的Pod到其他可用节点。在整个过程中没有任何人去执行docker run命令一切都是控制器主动完成的。这套机制保证了系统具备自愈能力。有一次我在某环境做演练的时候故意把一个跑着核心服务的节点用断电方式测试故障转移Kubernetes在大约30秒内就把Pod重新调度到了另一台机器重新拉取镜像、启动容器整个过程无需人工介入。如果是在传统虚拟机时代这类恢复至少需要半小时而且要参与的人员按预案逐步处理。2.3 工作节点之间的资源调度策略调度器不是简单看哪台机器空闲就往哪扔。它有两阶段逻辑过滤和打分。过滤阶段会排除不满足硬性条件的节点比如资源不足、端口冲突、节点有无法容忍的污点打分阶段则根据各种优先级策略对剩余节点逐一评分选出最优目标。评分会参考CPU和内存的请求量、镜像大小差异、服务在同一节点上的亲和或反亲和部署等。一个我实际用过的场景是某系统有两个服务一个叫order-service一个叫order-cache前者对后者有高频访问需求。为了避免跨机网络延迟我给这两个服务配置了Pod亲和性让它们尽量调度到同一台节点但同时给它们的多个副本配置了反亲和性避免同一服务的所有副本堆在一台机器上。这样既保了性能又保了可用性。3. 最小可用集群从零搭建安装部署与首服务验证3.1 环境准备与组件安装讲述原理之后需要用实操验证。我在自己的模拟环境搭建过一个简化版集群整个安装部署过程比较顺利。集群规划是1台控制面节点加2台工作节点操作系统均采用某个稳定版Linux发行版内核版本保持较新因为老的kernel在一些网络特性上支持不完整。安装顺序一般情况下是三台机器设置好主机名并配置hosts解析确保互相通过主机名可以访问。加载内核模块包括overlay、br_netfilter并设置sysctl参数允许iptables转发、允许桥接流量通过iptables。安装containerd作为容器运行时配置好registry mirror加速镜像拉取。安装kubeadm、kubelet、kubectl三件套注意版本必须对齐不要混用大版本。在控制面节点执行kubeadm init初始化控制面会自动生成admin.conf等配置文件。安装CNI网络插件集群网络才真正打通。通过kubeadm join命令把工作节点加入集群。3.2 常见安装卡点与绕坑经验我在安装过程中遇到的几个坑值得特别说明。第一个坑是swap没有关闭。Kubernetes默认要求节点满足一些准入条件其中就包括交换分区必须关闭。如果你不关swapkubelet的初始化会直接报错。解决办法是swapoff -a并且把/etc/fstab里对应的swap行注释掉防止重启后自动挂载。第二个坑是CNI插件选择。网络方案的选择会直接影响之后的使用体验和排查复杂度。我先后试过两种方案最终选定calico作为默认方案。它基于BGP协议传播路由性能较好支持网络策略三层网络模式天然适配Kubernetes的Pod网段。另一种方案更偏简洁安装简单不太依赖额外组件适合快速试验但自定义网络策略支持弱一些。如果你的集群规模较大建议直接使用calico并开启IPIP模式性能与功能平衡得最好。第三个坑是镜像拉取失败。kubeadm init和后续插件安装都需要从公共镜像仓库拉取镜像但国内网络环境下经常会超时或失败。解决方式是把镜像源替换为可达的registry mirror或者提前用镜像列表把需要用到的镜像拉到本地再通过ctrlr导入到对应组件中。这方面不同网络环境的操作方式确实有差异但原理是一致的让运行环境能够顺利拉取所需镜像。提示完整执行kubeadm init后终端会输出一段加入集群的命令形如kubeadm join ...。这段命令有效期有限如果工作节点短时间内没有加入过期后需要重新生成token使用kubeadm token create --print-join-command即可重新获得。3.3 部署第一个Nginx副本验证集群可用性当集群的三个节点都处于Ready状态后我部署一个验证服务来测试整体链路。创建nginx-deployment.yaml内容大致如下apiVersion: apps/v1 kind: Deployment metadata: name: nginx-test spec: replicas: 3 selector: matchLabels: app: nginx-test template: metadata: labels: app: nginx-test spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80kubectl apply -f nginx-deployment.yaml kubectl get pods -o wide观察几个Pod的分布如果一切正常它们会分别落在不同的工作节点上状态均为Running。这说明调度成功、镜像拉取成功、网络插件工作正常。然后暴露一个ClusterIP类型的Service验证集群内部访问能力apiVersion: v1 kind: Service metadata: name: nginx-svc spec: selector: app: nginx-test ports: - protocol: TCP port: 80 targetPort: 80kubectl expose deployment nginx-test --namenginx-svc --port80 --target-port80 kubectl get svc任何一个节点上执行curl :80都能返回Nginx默认页面说明Service的转发规则正确。如果需要外部访问则改用一个NodePort类型的Service或者在生产环境使用Ingress Controller结合域名路由。我建议只在测试时用NodePort生产环境尽量用Ingress更灵活也更规范。4. 工作负载资源深入不止Deployment的流量治理与更新策略4.1 从Pod到Deployment的进阶理解很多初学者困在Pod和Deployment的概念区分上。Pod是Kubernetes最小的调度单位可以包含一个或多个容器这些容器共享网络命名空间、存储卷并作为一个整体调度。Deployment则是一层封装它管理的是Pod副本的声明周期内部使用ReplicaSet来维护副本数。日常使用中我很少直接创建Pod。原因很简单直接创建的Pod没有自愈能力节点挂了它就没了没人给你重建。而通过Deployment创建的Pod由控制器守护可随时替换。这个习惯应该在项目早期就建立起来。Deployment真正体现价值的地方是滚动更新。我可以用一条命令升级镜像版本也可以控制更新的节奏maxSurge和maxUnavailable实现蓝绿发布或金丝雀发布的效果。举个例子maxUnavailable0maxSurge1的配置意味着更新过程中始终保证副本数不少于原数量只允许多一个Pod临时超量并在新Pod就绪后才删除旧Pod。这种配置适合对可用性要求高的核心服务。4.2 StatefulSet、DaemonSet、Job三类负载各管什么Deployment适用于无状态应用但有状态场景不能这样简单处理。我列举三类特殊负载都好用但用法不同StatefulSet适合有状态应用比如数据库、消息队列、协调服务。它会给每个Pod一个稳定的网络标识如mongo-0、mongo-1Pod挂掉后重建仍然保持相同的标识和存储卷绑定。这个特性对依赖固定主机名的应用非常关键但也意味着它的部署和扩容比Deployment复杂许多。我在操作某套用StatefulSet部署的集群时调整副本数需要额外确认存储扩容和主从配置能正确联动否则新副本可能因存储不足而无法启动。DaemonSet适合在每个节点上都运行一个副本的应用典型场景是日志采集器、监控Agent、网络插件。它的特点是新增节点时自动在节点上创建Pod删除节点时对应Pod也自动清理不需要你去操心调度分布。Job适用于一次性任务比如数据迁移、批量计算。Job管理的Pod执行完成后自动进入完成状态如果失败可以配置重试次数。CronJob则在此基础上增加了定时触发能力适合周期性的批量任务夜间的数据清理和报表生成都适用。4.3 Service、Ingress、DNS三段流量路径集群内部流量依靠Service打通外部流量则靠Ingress承载。我把一个典型请求的完整路径梳理出来方便理解用户访问某个域名通过DNS解析到Ingress Controller的入口地址。Ingress Controller根据域名和路径规则将请求转发给对应Service。Service通过selector匹配到后端Pod的IP列表利用kube-proxy的转发规则把流量送到某个Pod的容器端口。Pod内的应用处理请求并返回响应。集群内部的服务发现则依赖DNS。每个Service会获得一个形如 . .svc.cluster.local的DNS名称服务之间可以通过这个名称互相访问。跨命名空间的访问会自动解析到对应服务这让微服务架构里的配置变得简单不再需要手动维护IP映射表。注意Service的selector匹配非常严格标签的key和value都必须完全一致。我曾经在一个服务上少写了一个标签值导致Service一直匹配不到后端Pod流量全部500。排查这类问题时先看清Service的selector和Pod的labels是否对得上。4.4 配置与密钥管理ConfigMap和Secret的用法应用配置不应该直接写死在镜像里否则每次改配置都要重新构建镜像。Kubernetes提供了ConfigMap来管理非敏感配置Secret管理密码、令牌等敏感信息。ConfigMap和Secret可以被环境变量引用也可以以文件形式挂载到容器内。我推荐文件挂载的方式因为环境变量只能注入一次应用进程启动后修改配置无法热加载而文件挂载后如果配置变更kubelet会更新容器内的文件应用配合监听文件变化或定期重载就能实现配置热更新。Secret的编码方式常被误解——很多人以为它加密了其实只是做了base64编码完全不等于加密。真正需要加密保护时应该使用外部密钥管理方案或Kubernetes的加密静态存储配置。不要把生产环境数据库的明文密码以明文写在YAML里安全事件发生时这是最容易被溯源的点。5. 故障排查实战链路从Pod异常到集群级问题的定位方法5.1 排查前的准备判断大概率的故障范围当Kubernetes集群出问题时第一步不是去改配置而是先判断问题出在哪个层面。我的排查顺序通常这样走先看Pod状态。如果Pod是Pending说明调度器还没找到合适节点重点看节点资源是否充足是否存在污点、亲和性导致拒绝调度。如果Pod是ImagePullBackOff或ErrImagePull说明镜像拉取有问题检查镜像地址是否写错、镜像仓库是否可达、认证凭据是否有效。如果Pod是CrashLoopBackOff说明容器启动后崩溃退出看日志是基础操作偶尔需要看上次崩溃时的输出。如果Pod是Running但不正常则需要检查Service转发、DNS解析、网络策略、安全上下文等链路。这个判断逻辑是排查效率的关键。我曾经遇到一个问题现象是服务间歇性超时一开始怀疑应用代码问题折腾了很久才发现是节点磁盘IO高导致kubelet响应慢Pod频繁被重新调度流量自然不稳定。如果早一点先看节点状态、磁盘和网络指标就不会走这么长弯路。5.2 典型场景一Pod一直Pending某次在某学习环境部署一套测试系统创建了一组Pod后状态始终是Pending。我用kubectl describe pod拿到调度器的事件信息发现只有一行0/3 nodes are available: insufficient cpu。原因是节点上预留的CPU请求总量已经超过可用值而测试环境机器配置很低没多少余量。这里的教训是节点的allocatable资源并不等于机器总资源kubelet会为系统组件预留一部分system-reserved和kube-reserved所以实际可用于Pod的CPU核心数、内存大小都会小于物理配置。计算资源申请时不要只看机器硬件参数要结合allocatable实际值来规划副本数目。解决这类问题一般是先调整replicas或资源requests或找出占用大量资源的异常Pod并清理。5.3 典型场景二CrashLoopBackOff的日志定位某模拟项目里有一个调度任务容器总是启动失败状态在CrashLoopBackOff和BackOff之间反复切换。检查日志发现应用抛出的是一个配置文件缺失的错误而配置是通过环境变量传入的。我再比对Deployment的环境变量与预期发现变量名拼错了一个字母导致应用读取不到配置直接退出。这类问题其实和容器技术关系不大更多是应用自身的启动校验。但复用Kubernetes工具链可以大大加速定位kubectl logs查看当前输出kubectl logs --previous查看上一次退出时的完整输出一般就能锁定崩溃点。还有一个好用的办法用kubectl debug临时在故障Pod里注入一个调试容器进去查看文件系统、网络状况、运行环境变量比盲猜快得多。5.4 集群级问题Node NotReady背后的原因某个节点突然显示NotReady是所有管理员最紧张的情况之一。我遇到的典型原因包括节点负载过高kubelet无法按时上报心跳控制面误判节点失联。节点磁盘空间满容器运行时无法正常工作镜像拉取、容器创建都会失败。节点内存不足触发内核OOM关键系统进程被误杀kubelet需要重启恢复。网络分区导致节点与控制面之间长时间断连控制面将节点标记为NotReady并驱逐Pod。排查时我第一步看的是节点条件Conditions和事件信息比如把kubectl describe node的具体输出拿下来看。如果是磁盘空间的问题清理镜像缓存和日志是常规手段如果是资源问题还要评估是否需要调整节点规格或减少Pod压力。更严重的节点故障可能需要先drain节点迁移Pod再隔离维修修好后再uncordon恢复调度。5.5 网络排查中的指标与命令网络在Kubernetes里是最容易出问题的层面。我总结了一套快速验证链路是否正常的命令集# 查看Service的后端端点 kubectl get endpoints service-name # 查看Pod实际IP和所在节点 kubectl get pods -o wide # 进入Pod内部测试DNS解析 kubectl exec -it pod-name -- nslookup service-name # 从Pod内部访问Service kubectl exec -it pod-name -- curl http://service-name:port这套链路逐层排下去能快速定位到是DNS解析失败、Service selector不匹配、还是后端Pod本身没有监听端口。很多时候service访问不通的原因是Pod里的应用没有绑定0.0.0.0只监听了127.0.0.1导致kube-proxy转发到容器IP后请求被拒绝。这类问题在传统服务器部署时不会遇到但在容器网络模式里很常见值得特别留意。6. 资源管理与成本治理配额、LimitRange和HPA的应用思路6.1 只写requests不写limits的风险资源配额在Kubernetes中是不可忽略的细节。很多团队上线初期图省事只给容器写requests不写limits。这种情况下如果某个Pod疯狂占用内存会直接影响同一节点上其他Pod的稳定性甚至触发整个节点OOM。更严重的情况是节点内核会把某些Pod杀掉重新调度表象就是服务莫名其妙重启。我建议的生产实践是所有长期运行的Pod都应明确设置requests和limits除非临时调试环境。requests用于调度匹配表示这个容器最低保障多少资源limits用于运行限制防止容器失控。内存超限的结果是容器被杀OOMKilledCPU超限的表现则是限流throttled不会直接杀死进程但性能会明显下降。一个常见的配置示例如下resources: requests: cpu: 250m memory: 512Mi limits: cpu: 1 memory: 1Gicpu的单位m表示千分之一核250m就是四分之一CPU核心。memory使用二进制单位Ki/Mi/Gi和十进制单位KB/MB/GB容易搞混配置时要注意区分。6.2 LimitRange约束单个容器的资源边界单靠每个开发人员自觉遵守资源限制不现实总会有人漏配或写得太离谱。LimitRange是命名空间级别的约束机制可以对命名空间内每个容器设置默认的requests和limits也可以强制最小、最大取值。例如在某个共享测试命名空间里我配置了一个LimitRange限制单个容器最大内存1Gi默认requests为128Mi。这样一来新配置的Pod即使没写资源字段也会自动套用默认值超限的配置直接创建失败。这类策略在多人共用集群的场景下非常有用直接减少了乱七八糟的资源申请。6.3 HPA实现水平弹性伸缩弹性伸缩是Kubernetes最被人称道的特性之一。HPAHorizontalPodAutoscaler可以根据监控指标自动调整副本数。最常用的指标是CPU使用率例如可以这样配置apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: order-svc-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: order-service minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60这个HPA的意思是当Pod平均CPU使用率超过60%时自动扩容副本数当长时间低于60%时自动缩容缩容下限为2个副本上限为10个。这里面有一个关键点Pod必须有requests配置HPA才能计算使用率实际使用量/requests值。好多人配置了HPA却不生效回头一看根本原因是Pod没有写requests。HPA的实际使用中扩容比缩容反应更快。默认的副本调整策略会在一分钟内以增量方式增加副本而缩容需要等待稳定周期目的是防止流量抖动导致频繁震荡。如果你对某些高峰期明显的业务有快速扩容要求可以配合ClusterAutoscaler在资源不足时自动加节点实现集群级弹性。6.4 成本治理按业务分Namespace配合配额当集群规模大了、团队多了资源混用会导致成本无法归属。我的有效做法是按业务线划分命名空间并通过ResourceQuota给每个命名空间设置总的资源上限。ResourceQuota可以限制命名空间内的CPU和内存总量、Pod数量、PVC数量等。这样某个团队不能无限创建资源超额申请会直接报错。配合查看各命名空间的资源使用情况和成本分配管理者会获得清晰的账单视图。这个思路特别适合在多团队共用一套集群的场景下落地。7. 生产化落地从学习环境到可靠系统的关键升级点7.1 高可用控制面的部署要求我身边不少团队是这样起步的一台虚机上跑控制面加几台工作节点先用起来。这适合学习和预生产验证但如果业务逐渐重要控制面单点就是最大的隐患。控制面包含apiserver、控制器、调度器等核心组件任何一个异常都可能引发整个集群的管理能力瘫痪。生产环境要做到三点奇数个控制面节点通常是3个保证多数派选举不出问题。控制面前置负载均衡kubelet和外部客户端统一访问虚拟IP。etcd与apiserver部署方式要提前规划可以选择堆叠也可以独立部署etcd集群。规模较小的集群堆叠模式更方便大型集群独立部署更安全。7.2 镜像管理与版本可追溯性镜像管理在很多团队里是薄弱环节。常见问题是所有人都有权限往同一个仓库推镜像镜像名以latest结尾结果生产环境部署时根本无法确定拉到的镜像是什么版本。我坚持的做法是镜像打版本标签至少要包含触发构建的Git提交号或流水线构建号形如order-service:20241215-3fa2b9d。禁止在生产环境使用latest标签部署。每次发布前先在预发环境用同版本镜像验证通过后再发布生产。加入镜像签名或摘要校验确保镜像内容没有被非法篡改。这样做虽然增加了一个环节但排查问题时能直接定位到具体镜像内容不用猜测。7.3 存储选型动态供给还是静态绑定对有状态应用来说存储方案决定了数据安全和性能上限。静态创建PV的方式适合固定存储后端、少量持久化需求的场景动态供给则是在PVC创建时自动从StorageClass里分配存储卷更方便也更通用。在某项目的数据库部署中我选择了通过StorageClass动态申请云盘存储每次扩容数据库副本时新副本会自动申请一块PV并挂载到特定路径。整个流程完全自动运维不用手工准备存储卷。但要注意的是不同存储后端的性能差异很大尤其是IOPS和延迟。数据库这类高要求应用一定要选择支持高IOPS的存储类型并且提前测试压力下的表现。7.4 网络策略与安全加固默认情况下Kubernetes集群内的Pod之间是互通无阻的。这对多租户或多环境共享集群来说存在较大风险——内部横向移动一旦发生影响范围非常大。NetworkPolicy可以定义Pod级的网络访问规则细化到允许哪些来源访问哪个端口的程度。在某模拟项目的多租户环境里我给每个命名空间配置了默认拒绝策略再按业务含义开放必要的入口。配置方式大致如下apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress要开启某些服务的对外访问再单独添加允许规则。这套策略让原本全通的内部网络变成有边界的可控网络安全能力明显上升。不过NetworkPolicy依赖CNI插件支持比如calico默认支持某些基础网络方案可能不支持或需要额外配置实施前要确认网络方案的能力。7.5 监控告警与日志收集的兜底方案生产集群没有监控相当于裸奔。我的推荐组合是Prometheus加GrafanaPrometheus负责收集指标、存储时序数据Grafana负责展示和告警。核心指标包括节点CPU/内存/磁盘/网络使用率、Pod数量、Pod重启次数、容器CPU/内存使用率、etcd延时、apiserver请求耗时等。日志收集方面文件日志走DaemonSet采集到中央存储再交给查询分析平台。容器标准输出让运行时统一收集应用日志则尽量写到同一目录再用边车容器或Agent采集。无论选哪种方案保留足够的检索能力和保留周期是核心指标。告警规则要结合实际业务设定阈值不要太多太吵否则告警疲劳会导致真正严重的问题被忽略。我常用的策略是分层告警严重级别影响服务的直接通知多人中等级别持续一定时间才通知低级别合并成日报。8. 学习路线与惯用技巧建立正确的Kubernetes思维方式8.1 从Deployment开始别急着碰编排细节面对Kubernetes庞大的知识点我见过不少人直接从源码阅读开始很快陷入理解泥潭。我更推荐由外到内的学习路径先会用再理解原理最后能改能查。第一步用kubectl创建和查看各种资源感受YAML声明的意义。第二步理解Service、Deployment、ConfigMap等常用对象的作用和协作方式。第三步在标准环境里部署一个带数据库的简单应用亲手把网络、存储、配置走一遍。第四步开始读官方文档关于控制器原理的部分理解控制循环、选举、调度的实现思路。第五步遇到问题再按需深入学习排查过程是最快的成长路径。8.2 kubectl使用技巧别只会get和applykubectl是操作Kubernetes的瑞士军刀多掌握几个常用命令能明显提升效率# 以表格方式查看所有命名空间的Pod kubectl get pods -A # 查看资源的详细信息和最近事件 kubectl describe pod pod-name # 实时跟踪Pod日志 kubectl logs -f pod-name # 临时进入Pod执行命令 kubectl exec -it pod-name -- /bin/sh # 查看所有资源类型 kubectl api-resources # 自动补全命令 source (kubectl completion bash)用好kubectl get -o wide、-o yaml等输出选项对排查问题非常有帮助。如果集群数量多更换上下文时要注意线上和预发环境别搞混这是非常基础但至关重要的一点。8.3 避免常见的认知误区在实战中最常见的误区有这几个认为容器里可以放心使用root权限。容器内root与宿主机的root边界并没有想象中那么清晰配置securityContext限制用户权限是必要的安全习惯。认为Pod可以像虚拟机一样随意手动登录操作。Pod是短暂的重启后变化极大。应将管理能力接入控制器和配置系统而不是靠人工登录救火。认为集群越大越好。Kubernetes虽然能管理大规模集群但集群太大时控制面负担、网络复杂度、资源碎片化都会增加。合理的做法是控制单集群规模按业务或环境拆分集群。认为Kubernetes能解决所有部署问题。它擅长的是无状态应用的编排和标准化有状态应用、高性能计算、强一致分布式存储等场景仍需要专门的架构设计。8.4 最后分享一个日常操作体会这些年在多个集群环境里反复实验我最深的体会是Kubernetes最大的价值不在于消灭运维动作而在于把运维动作变成可评审的声明配置、可回放的版本记录、可自动化的纠错循环。真正理解这套机制后你会发现在它上面搭建任何层级的工作流都有明确的地基。如果你正处在刚接触Kubernetes的阶段不必急着把所有组件原理都背熟先把一个最简单的应用完整跑通从Deployment创建Pod到Service暴露访问再到看监控指标、修改配置完成一次滚动更新这个过程会给你建立非常好的直觉。等这套流程熟练了再逐步深入控制面、调度器、网络策略这些底层的细节自然就会顺畅很多。
返回列表