1. 为什么Kubespray里的网络配置最容易被“跳过”又最坑这篇是Kubernetes基础系列里关于Kubespray部署过程中网络配置的实操笔记也就是标题里说的network-pro部分。Kubespray用来部署集群确实省心一句ansible-playbook就能把几十个节点拉起来很多人习惯了“装完就跑demo”的节奏对网络插件的理解停留在“选个默认的就好”。但以我这些年用Kubespray折腾各类环境的经验来说网络恰恰是出问题最多、也最容易被忽略的一环。集群装不起来、节点反复NotReady、CoreDNS解析超时、跨节点Pod互通异常大部分都能追溯到网络插件的配置和底层网络环境之间的配合出了问题。这篇内容适合正在用Kubespray搭集群、或者已经搭好但时不时被网络问题折磨的人阅读。我不会重复官方文档里那套“复制粘贴就完事”的说明而是把网络插件在Kubespray里到底扮演什么角色、选型时应该看什么、配置时哪些变量真正影响行为、部署后怎么验证、出问题怎么排一条线讲清楚。说白了network-pro不是指某个高不可攀的“专业插件”而是指让网络这套东西在部署前、部署中、部署后都可预测、可控制、可排查。1.1 网络插件不是Kubespray的“附带品”而是部署参数的输入Kubespray虽然把很多细节都封装成了Ansible角色但它并不等于“装完拉倒”。你选择的网络插件会直接影响Kubeadm初始化的参数、kubelet的网络配置、节点的路由策略以及apiserver里跟CIDR相关的参数。这些不是独立的东西而是一层层耦合的。举个例子Kubespray需要提前知道你打算用哪个Pod网段这个网段会被写进kubeadm的pod-network-cidr参数里同时网络插件比如Calico的IP池也要和它保持一致。如果你只改了某一处插件和kubeadm之间对不上轻则Pod拿不到预期网段的IP重则整个集群的网络策略直接失效。更隐蔽的问题是Kubespray的默认值不一定适配你的物理网络环境。比如它默认的Pod网段是10.233.64.0/18Service网段是10.233.0.0/18。如果你的机房、云VPC或者办公网里恰好用了这一段地址那问题就大了Pod访问集群外服务时可能撞上已有的IP路由表错乱数据包在物理网络里迷路。这类问题不是插件的bug而是“网络参数没有作为整体去规划”导致的结果。我见过一个非常典型的场景某套测试环境里团队直接用了Kubespray的默认网段部署本来一切正常后来因为业务需要和另一套老系统的内网网段打通发现两边的网段直接重叠。当时改CIDR的代价已经很大了涉及重新初始化集群、清理所有Pod和网络策略。如果在部署前就把网络规划看成和版本规划同等重要的事情这个坑完全可以避免。1.2 “默认能用”和“生产可用”之间差了多远很多人觉得Kubespray默认配置跑通了网络就“没问题”了。实际上默认配置只能证明“在这个网络环境里勉强能用”离“可控、高性能、可排障”还有不小的距离。举几个默认配置下容易埋雷的点。Calico插件默认的封装模式在不同子网间可能是IPIPIPIP协议在多数云平台的安全组里默认不放行。一旦节点跨可用区、跨VPC子网你的物理ICMP和TCP可能都通但IPIP封装的数据包全被丢在半路。这种问题用kubectl get pods -A根本看不出异常至少我最初碰到时整了半天最后才发现是安全组没放行协议号4。再比如MTU。物理网卡MTU是1500IPIP封装要多占20字节VXLAN封装要多占50字节左右。如果你没有让Calico或Flannel根据underlay网络的MTU去自动计算而是用了不匹配的值就会出现“小包通、大包不通”的诡异现象。数据库连接时好时坏、视频流卡顿排查到后面往往都是MTU在搞鬼。网络策略也是默认容易忽略的点。Kubespray里有一项enable_network_policy默认可能没开。不开的时候Calico虽然也能转发流量但不做策略控制。如果你对多租户隔离有要求这会是个大隐患。所以我在实际操作中的习惯是部署前先把网络相关参数全部梳理一遍而不是只在all.yml里改改版本号。这也是我写这篇长篇笔记的初衷——把该注意的坑提前暴露出来而不是等集群跑起来再连夜补。2. 选插件前先看清Kubespray的网络模型和变量层级Kubespray部署的网络配置分散在多个变量文件里并不是你把kube_network_plugin改成cilium就万事大吉了。同一个插件在不同版本的Kubespray里支持的变量名和默认行为还可能有变化。这一节我把变量层级和选型逻辑拆开讲搞清楚这些后面配置再复杂也不太会搞乱。2.1 网络参数都藏在哪些文件里以我常用的Kubespray版本为例和网络相关的配置主要在inventory/mycluster/group_vars/k8s_cluster/目录下其中两个文件最核心k8s-cluster.yml里面定义了kube_network_plugin、kube_pods_subnet、kube_service_addresses这些顶层参数。kube-networking.yml插件级的更细化配置比如Calico的IPIP模式、VXLAN相关参数、网络策略开关等。有非常多人在部署时会改k8s-cluster.yml但忘了看kube-networking.yml里对应插件的详细选项。其实Kubespray的设计逻辑是先把“插件类型”这个总开关定下来再靠“插件级参数”去让插件适配你的环境。总开关决定你用谁插件级参数决定它在你这里能不能活得舒服。部署的时候还要特别注意inventory里的node分组。Kubespray默认把节点分成了kube_control_plane、etcd、kube_node等组。网络插件需要部署在部分或全部节点上如果你自定义的node组名和默认角色对不上可能导致网络组件没有在所有需要的节点上调度集群虽然能起来但某些节点的Pod网络就是不通。所以我的建议是拿到一个新环境后第一件事不是去翻插件文档而是先完整看一遍group_vars里的默认值和inventory分组。先知道“Kubespray打算怎么装”再决定“我需要改成什么”。跳过这一步后面很多操作就是在猜。2.2 Calico、Cilium、Flannel在Kubespray下的真实差异Kubespray支持的CNI插件不止一种但实际生产环境里用最多的还是Calico、Cilium和Flannel这三类。它们之间的区别不能只看“功能谁多”还要看你的内核、网络环境、团队维护能力。维度FlannelCalicoCilium部署复杂度低中较高容器网络策略不支持需额外组件支持基于iptables/ipset支持基于eBPF更细粒度默认数据面VXLAN或host-gwIPIP或VXLAN配合BGPeBPF内核要求低低至中要求较高一般建议4.19以上性能上限一般较高高适合高并发低延迟场景排障门槛低中高需要理解eBPF和Hubble等先说Flannel。它在Kubespray里的优势是简单部署后基本不太需要动脑适合纯粹的“快速起一个稳定可用的集群”。但它对NetworkPolicy基本无能为力多租户隔离或者安全合规要求高的场景就不够用。如果你只是内部测试、跑跑CIFlannel够用了。Calico是Kubespray默认的插件也是我个人的首选。它同时兼顾了路由和策略BGP模式下能在大规模集群里走真正的三层路由扩展性和性能都比较稳。Kubespray对Calico的封装也比较成熟坑相对少。只要物理网络允许BGP或者IPIP/VXLANCalico都能找到合适的数据面。Cilium的功能最强eBPF带来的可观测性和安全能力很吸引人特别适合做微服务治理、零信任网络这类场景。但它的前提条件也多内核版本要够新部分云平台对eBPF程序可能有限制排障时需要的知识储备也不一样。我见过有团队兴冲冲上Cilium结果在一个老内核的节点池上起不来最后整组回滚到Calico。2.3 插件版本和Kubernetes版本是配套的别乱动Kubespray的一个设计特点是它在release时就把Kubernetes版本、插件版本和默认参数做了配对测试。你升级Kubespray版本时网络插件版本通常也会跟着变。很多人喜欢在k8s-cluster.yml里把某个插件的image tag改成自己想要的版本这在我看来风险很高。网络插件版本和Kubernetes的CRD结构、API版本、组件启动参数都有兼容性约束。比如某个Calico新版本要求Kubernetes最低版本否则CRD无法正常注册或者反过来Cilium的新版本默认启用了某个需要新版内核的功能让老节点全部异常。这些都不是改一行配置能解决的。如果你确实需要升级插件版本我的建议是先在一个测试集群上同步升级跑完网络验证清单再动生产环境而不是直接改tag重跑playbook。Kubespray社区已经帮你踩过一遍坑了默认版本组合反而是最省心的组合。3. 部署前先把网段、MTU、封装模式这三个变量定下来这一节我想重点讲部署前最关键的规划项。一个Kubespray集群的网络是否稳定很多时候在部署前就已经决定了后面只是验证和补救。网段、MTU、封装模式这三件事我每次部署都是提前确认好再动手。3.1 Pod网段和Service网段别和已有网络撞车Kubespray默认的Pod网段是10.233.64.0/18Service网段是10.233.0.0/18。这两个网段看起来不惹眼但只要你所在的物理环境、云VPC或者其他系统用到了10.233.0.0/16这个大段里的任何地址就有冲突风险。为什么冲突会带来麻烦因为K8s集群里的Pod访问外部IP时如果目标IP恰好落在集群内部路由表里数据包就会被本地的路由规则截走转发给某个不存在的Pod网关而不是发往物理网络。结果是集群内部没问题一访问某些外部服务就超时表现极其诡异。我在部署前一定会做的一件事是把所有节点的物理网段、公司内网网段、其他关联系统的网段都列出来确认和Pod网段、Service网段完全不相交。如果有交集宁可多花点时间改掉Kubespray的默认值也不要带着隐患上线。同时要考虑集群规模。/18的Pod网段有大约16000多个地址对于大多数集群够用。但如果你预期Pod密度极高、或者要跑大量StatefulSet建议提前算好需要的地址量必要时扩大到/16。注意集群一旦建好这个参数就不能随意改了。3.2 MTU和封装模式小包通、大包不通的根源MTU问题是我最想强调的一个点因为它特别容易伪装成其他问题。容器的网络数据包在跨节点通信时如果插件选择了IPIP或VXLAN会在原始报文外面再套一层。这意味着物理网络上传输的报文会比容器里看到的报文大一些。假设物理网卡MTU是1500IPIP封装会额外占用20字节那么容器网卡的MTU最多只能设为1480否则超过物理链路承载上限的报文会被静默丢弃。VXLAN的额外开销更大通常是50字节左右容器MTU建议设为1450或更低。如果插件配置没有正确适配就会出现小包比如ping默认大小能通但数据库交互、HTTP大响应体等大包直接卡死或超时。验证方法也简单在Pod里执行ping -M do -s 1400和ping -M do -s 1500对面Pod的IP小包通、大包不通基本就是MTU问题。对于封装模式的选择我一般按这个逻辑判断所有节点在同一个二层域可以关闭IPIP直接走BGP或host-gw性能最好。节点跨子网、跨可用区用IPIP的CrossSubnet模式或者直接VXLAN避免依赖底层网络的路由协议。云平台环境要确认安全组是否放行对应协议IPIP是协议号4VXLAN是UDP 4789。3.3 网络策略、NodePort范围和负载均衡模式除了网段和MTU还有几个跟网络使用体验直接相关的参数需要提前想清楚。enable_network_policy这个开关打开后Calico会为带NetworkPolicy资源的命名空间做策略编排。如果你暂时用不到网络策略可以不开能少一些iptables规则和性能损耗。但如果你有安全隔离需求就一定要开并且事先选好策略模型。kube_nodeport_range默认是30000-32767如果你的业务需要对外暴露NodePort建议提前和防火墙策略对齐。有些公司内部安全策略不允许对公网开放高位端口那你可能需要调整这个范围或者改用LoadBalancer方案。Kube-proxy的模式也值得看一眼。较新版本的Kubespray支持配置kube_proxy_mode: iptables或ipvs。iptables更经典排障也直观ipvs在节点数和Service数较多时性能更好但依赖ipvsadm和内核模块。我个人的习惯是中大规模集群优先考虑ipvs但前提是节点上相关模块已经加载。如果你不确定iptables反而是最稳的选择。4. 以Calico为例的Kubespray网络变量配置实操前面讲的都是思路这一节给出一份可以照着改的实际配置。我以Calico为例因为它是Kubespray默认也是我推荐的首选。这里给出的内容基于常见实践具体环境请以你的Kubespray版本实际变量名为准。4.1 一份可以直接参考的Calico配置模板在group_vars/k8s_cluster/kube-networking.yml里我通常这样设置# 总开关使用Calico CNI kube_network_plugin: calico # 是否启用网络策略 enable_network_policy: true # Calico IP自动分配方式eth.* 表示匹配节点上以eth开头的网卡 calico_ip_auto_method: interfaceeth.* # 容器网卡MTU物理网卡1500且使用IPIP时为1480 calico_veth_mtu: 1480 # IPIP封装模式Always / CrossSubnet / Never # 如果所有节点在同一子网不需要IPIP可以设为Never # 跨子网时建议设为CrossSubnet只在跨子网流量上做封装 calico_ipip_mode: CrossSubnet再看k8s-cluster.yml里对应的网段规划# Pod网段要注意和现有网络不冲突 kube_pods_subnet: 10.244.64.0/18 # Service网段也要避开已有网络 kube_service_addresses: 10.244.0.0/18这一个地方容易困惑很多人改了Pod网段但没改Service网段或者只改了其中一个结果DNS和Service访问对不上。所有和网段相关的变量必须一起规划、一起改。如果你的网络环境比较简单所有节点都在同一个二层域且愿意直接走主机路由可以把IPIP关掉MTU不扣封装开销性能更好。相应的配置是calico_ipip_mode: Nevercalico_veth_mtu: 1500。但如果节点跨子网这种配置就会出问题因为裸路由在三层环境下不一定能互通。4.2 修改网络参数后重跑playbook的正确姿势Kubespray部署集群后有时你会觉得网络参数不合适想重新跑一遍playbook来调整。这比全新部署风险高得多。以我的经验除非Changelog明确说支持原地修改否则必须做足准备。第一步备份inventory和当前的网络插件配置。我习惯把group_vars整个目录复制一份带时间戳的备份方便出问题时对比回滚。第二步重新运行部署命令。典型流程是ansible-playbook -i inventory/mycluster/hosts.yml cluster.yml -b -v但要注意不是所有参数都支持热更新。网段相关的参数基本没法原地改改了之后集群上已有的Pod IP不会自动迁移路由表和Calico的IP池之间会出现不一致。如果确实要改网段我建议在维护窗口内做一次全新部署或者把关键应用迁移出去后重置集群。如果只是调整MTU、切换IPIP模式这类数据面参数可以先修改配置再逐步重启节点上的calico-node服务。不过也要注意切换封装模式时Calico的IPPool配置如果还是旧的backend新配置不会自动覆盖。手动检查一下IPPool对象必要时删除并重建池再触发一轮滚动重启。我踩过最惨的一次坑是只改了calico_ipip_mode没有检查已有IPPool重启后有些节点的路由还在老模式上新旧路由混在一起跨节点通信断了大半天。所以在重跑playbook之前我的固定动作是确认inventory里没有忘记更新节点角色和分组。对比本次配置变更区分哪些参数支持热更新哪些必须重建集群。至少要有一台可回滚的“金丝雀”节点或测试集群先试一把。5. 部署完先按这份清单验证网络功能别急着上业务Kubespray运行结束不代表网络就绪。我见过太多次“集群起来了一跑业务就出事”其实很多问题在部署后一小时内用几个简单命令就能查出来。这里分享一套我每次部署后都会执行的网络功能验证清单。5.1 从CoreDNS到Pod-Pod连通性的基础检查部署完成后先看最基础的三件事CoreDNS是否正常解析、Pod之间能否互通、Pod到Service是否通。先看CoreDNS的Pod状态和日志kubectl get pods -n kube-system -l k8s-appkube-dns kubectl logs -n kube-system -l k8s-appkube-dns --tail50如果CoreDNS反复CrashLoopBackOff多半是网络插件没有正常工作DNS Pod拿不到正确IP或者节点之间无法通信。再创建一个临时Pod来测试解析和连通性kubectl run test-dns --imagebusybox:1.28 --rm -it --restartNever -- sh在Pod里执行nslookup kubernetes.default.svc.cluster.local wget -qO- http://kubernetes.default.svc.cluster.local可以解析且能访问说明CoreDNS到集群网络的链路基本没问题。然后是跨节点Pod之间的连通性。由于我们创建的临时Pod可能恰好在同一个节点为了避免假阳性我一般会用一个DaemonSet或者通过nodeSelector把测试Pod调度到多个节点上kubectl get pods -o wide在其中一个Pod里ping另一个节点的Pod IP。如果通了再看一下MTU的影响用不同包大小测一遍ping -M do -s 1400 目标Pod IP ping -M do -s 1500 目标Pod IP5.2 Service、NodePort和外部访问的验证Pod到Pod通了不代表Service就一定正常。Kube-proxy是另一层逻辑它负责把ClusterIP的流量转发到后端Pod。简单验证方式是kubectl get svc -A kubectl run test-svc --imagebusybox:1.28 --rm -it --restartNever -- sh # 在Pod里访问ClusterIP wget -qO- ClusterIP:port如果wget超时且Pod到Pod连通性是正常的那问题基本出在kube-proxy的iptables/ipvs规则或者Service的选择器上。NodePort的验证就更容易了在集群外的一台机器上访问任意节点IP:NodePort。如果只在集群内通、集群外不通优先检查节点上的防火墙端口、云安全组的入方向规则。LoadBalancer场景比较复杂取决于你的云环境和负载均衡实现。至少要到能够通过负载均衡IP访问后端Service这一步。5.3 NetworkPolicy是否真的在起作用如果你开启了enable_network_policy不要只看到有NetworkPolicy资源就以为安全了。我习惯做一次正反验证创建一个带有apptest标签的Pod再创建一个不带任何标签的Pod。配合一条只允许apptest访问的NetworkPolicy验证标签匹配的Pod访问目标通。不匹配的Pod访问目标不通。如果两条结果都符合预期说明策略生效链路是完整的。如果“不通”没有出现说明网络策略可能没被插件加载或者还有默认允许规则没有清理。这里也提醒一句NetworkPolicy的验证本身要小心别在正式业务命名空间里做。我一般会在一个临时namespace里验证完再删掉。6. 跨节点Pod不通的排查链路从路由表到防火墙逐步走前面讲了很多规划性的内容但网络问题最大的考验还是事发时的排查能力。这一节我用一个真实遇到过的场景来演示完整的排查链路方便你在自己的环境里复现同样的思路。6.1 场景现象集群正常但跨节点Pod访问时好时坏某次部署完成后的环境是三节点集群Calico网络。kubectl get nodes全部ReadyCoreDNS也起来了但业务反馈在不同节点上的Pod之间互相访问有些IP能通有些一直超时CoreDNS偶尔还会丢几个包。这种“一半通一半不通”的状态是很典型的。它不是整体网络坏了而是某种特定条件下数据包走不通。最常见的条件分两类跨子网时封装模式不对、或者底层网络对特定协议放行不一致。6.2 从数据包的路径逐段定位路由、隧道、防火墙第一步看路由表。在问题节点上用ip route查看目标Pod网段是怎么走的ip route | grep 10.244如果看到类似10.244.x.x via 10.244.y.y dev tunl0这样的记录说明Calico把跨节点流量交给了IPIP隧道设备tunl0。接下来就需要验证隧道本身是否通。第二步在源节点和目标节点各开一个tcpdumptcpdump -i any host 源Pod IP and icmp在Pod里ping目标Pod IP观察源节点是否把ICMP报文发出去了目标节点是否收到。如果源节点发出了目标节点的物理网卡完全没收到任何IPIP协议报文那问题多半发生在节点之间的网络传输层。第三步看calico-node的运行状态和日志kubectl logs -n kube-system -l k8s-appcalico-node如果BGP peer状态异常、Felix启动失败日志里会直接体现出来。但很多节点间丢包问题是发生在Kubespray部署范围之外的比如云平台安全组、机房防火墙、交换机ACL。第四步检查iptables。虽然Calico的流量管理很复杂但基础的FORWARD链如果被配置成DROP跨节点转发也会失败iptables -L FORWARD -n注意查的时候不要只盯系统默认链还要看cali-FORWARD这类Calico自定义链。如果发现流量在自定义链里被drop可以进一步用iptables -L cali-FORWARD -n -v看计数器。6.3 根因定位安全组没放行IPIP协议前面排查到“源节点发出、目标节点没收到”基本就把范围缩小到underlay网络了。在云平台上最常见的原因就是安全组规则只放行了TCP、UDP、ICMP没有放行协议号4IP-in-IP。判断方法很直接在两台节点上分别执行tcpdump -i eth0 ip proto 4然后在源节点ping目标节点上的Pod IP。如果源节点tcpdump能看到IPIP协议包目标节点tcpdump却什么都没有那就可以确定是中间网络丢包。再配合检查安全组规则中是否放行了IP-in-IP协议号4就能复现根因。修复方式是放行安全组/防火墙中协议号为4的入方向和出方向流量。如果不想放行IPIP协议另一个思路是把Calico改成VXLAN模式走UDP 4789端口这通常比IPIP更容易被传统防火墙支持。6.4 同一个场景下的变种MTU和rp_filter也常背锅排查过IPIP协议后我还想提两个容易混淆的变种问题。第一个是MTU导致的大包不通。现象和“跨节点丢包”很像但细节不同ping -s 1400通ping -s 1500不通。如果你已经把安全组放行协议4都检查完了还没找到原因一定测一下不同包大小。很多云平台上虚拟网卡的默认MTU是1500IPIP封装后容器MTU必须下调否则就会出现这种情况。第二个是rp_filter反向路径过滤。Linux内核默认在/proc/sys/net/ipv4/conf/all/rp_filter里配置了过滤规则。如果一个多网卡节点收到一个源地址来自“非最佳路径”的包可能被直接丢弃。表现也是跨节点通信丢包但你在tcpdump里能看到包到达了节点、却迟迟没有回包。遇到这种情况检查各网卡的rp_filter设置必要时改成2宽松模式或者1严格模式但配置正确。7. 最后说几句network-pro的实践心得回到标题里的network-pro。我理解的pro不是指“比别人多装了一个牛逼插件”而是指网络配置这件事要做得有章法、可预测、可维护。Kubespray虽然把部署过程自动化了但它不会替你做网络规划更不会替你避免所有环境差异带来的坑。我在自己的项目里总结了几条固定习惯。第一每次部署前把网络相关参数单独摘出来做成一份变更记录标明改了什么、为什么改、可能影响什么。第二任何网络参数的调整都要先在测试环境跑一遍验证清单再上生产。第三尽量别在一个正在业务的集群上折腾网络插件插件和数据面切换的坑远比收益更频繁。Kubespray的网络部分之所以值得单独拿出来讲是因为它的默认值确实能让你“快速跑起来”但从快速到稳定之间隔着的正是这些不起眼的规划、验证和排障习惯。如果你现在正准备部署一个集群先花半天把网段、MTU、封装模式、安全组规则这些底层细节理清楚后面会少熬很多个凌晨。