kubernetes网络解决方案 Calico 一、CNI方案 学习目标 这一节,我们从 基础原理、方案解读、小结 三个方面来学习 基础原理 容器访问模式 ! CNI简介 ! CNI目前被谁管理? 方…
kubernetes网络解决方案 Calico kubernetes网络解决方案 Calico 一、CNI方案 学习目标
这一节,我们从 基础原理、方案解读、小结 三个方面来学习
基础原理
容器访问模式
1 2 3 方法1 : 虚拟网桥 + 虚拟网卡对 方法2 : 多路复用 + 内核级的VLAN模块 方法3 : 硬件交换 + 硬件虚拟化
CNI简介
1 2 根据我们对于容器的基本了解,他虽然可以借助于虚拟网桥docker0实现一定程度的网络功能,但是在大范围容器访问层面,其没有最好的网络解决方案,只能借助于一些第三方的网络解决方案来实现容器级别的跨网络通信能力。 CNI的全称是Container Network Interface,Google和CoreOS联合定制的多容器通信的网络模型。在Kubernetes中通过一个CNI接口来替代docker0,它在宿主机上的默认名字叫cni0。它没有使用Docker的网络模型的原因有两个:1 不想被Docker要挟,2 自有的网络namespace设计有关。
1 2 3 4 5 CNI的设计思想即为:Kubernetes在启动Pod的pause容器之后,直接调用CNI网络插件,从而实现为Pod内部应用容器所在的Network Namespace配置符合预期的网络信息。这里面需要特别关注两个方面: - Container必须有自己的网络命名空间的环境,也就是endpoint地址。 - Container所在的网段必须能够注册网络地址信息 对容器网络的设置和操作都通过插件(Plugin)进行具体实现,CNI插件包括两种类型:CNIPlugin和IPAM(IP Address Management)Plugin。CNI Plugin负责为容器配置网络资源,IPAM Plugin负责对容器的IP地址进行分配和管理。IPAM Plugin作为CNI Plugin的一部分,与CNI Plugin一起工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 在Kubernetes中,CNI对于容器网络的设置主要是以CNI Plugin插件的方式来为容器配置网络资源,它主要有三种模式: MainPlugin - 用来创建具体的网络设备的二进制文件 - 比如bridge、ipvlan、vlan、host-device IPAM Plugin - IPAM 就是 IP Address Management - 负责对容器的IP地址进行分配和管理,作为CNI Plugin的一部分,与CNI Plugin一起工作 Meta Plugin - 由CNI社区维护的内部插件功能模块,常见的插件功能模块有以下几种 - flannel 专门为Flannel项目提供的插件 - tuning 通过sysctl调整网络设备参数的二进制文件 - portmap 通过iptables配置端口映射的二进制文件 - bandwidth 使用 Token Bucket Filter (TBF)来进行限流的二进制文件 - firewall 通过iptables或者firewalled添加规则控制容器的进出流量
1 更多详情查看:https://github.com/containernetworking/cni/blob/main/SPEC.md
CNI目前被谁管理?
1 在 Kubernetes 1.24 之前,CNI 插件也可以由 kubelet 使用命令行参数 cni-bin-dir 和 network-plugin 管理。而在Kubernetes 1.24 移除了这些命令行参数, CNI 的管理不再是 kubelet 的工作。而变成下层的容器引擎需要做的事情了,比如cri-dockerd 服务的启动文件
1 2 3 4 5 查看服务文件 /etc/systemd/system/cri-docker .service ExecStart=/usr/local/bin/cri-dockerd --network-plugin =cni --cni-conf-dir =/etc/cni/net.d --cni-bin-dir =/opt/cni/bin ... 注意: /opt/cni/bin 目录是部署kubernetes的时候,安装的cni-tools 软件包自动创建出来的,这里面包含了很多的网络命令工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 flannel的CNI配置文件 { "name" : "cbr0" , "plugins" : [ { "type" : "flannel" , "delegate" : { "hairpinMode" : true , "isDefaultGateway" : true } }, { "type" : "portmap" , "capabilities" : { "portMappings" : true } } ] }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 calico的CNI配置文件 { "name" : "k8s-pod-network" , "cniVersion" : "0.3.1" , "plugins" : [ { "type" : "calico" , "log_level" : "info" , "log_file_path" : "/var/log/calico/cni/cni.log" , "datastore_type" : "kubernetes" , "nodename" : "kubernetes-master" , "mtu" : 0 , "ipam" : { "type" : "host-local" , "subnet" : "usePodCidr" }, "policy" : { "type" : "k8s" }, "kubernetes" : { "kubeconfig" : "/etc/cni/net.d/calico-kubeconfig" } }, { "type" : "portmap" , "snat" : true , "capabilities" : {"portMappings" : true } }, { "type" : "bandwidth" , "capabilities" : {"bandwidth" : true } } ] }
方案解读
1 2 kubernetes提供了很多的网络解决方案,相关的资料如下: https://kubernetes.io/zh-cn /docs/concepts/cluster-administration /addons/
flannel方案
1 2 3 4 项目地址:https://github.com/coreos/flannel Flannel是CoreOS 开发的项目,它是容器编排系统中最成熟的网络方案之一,旨在实现更好的容器间和主机间网络,由于其稳定和配置简单,所以它是CNI最早引入的一套方案。常见的 Kubernetes 集群部署工具和许多 Kubernetes 发行版都可以默认安装 Flannel。 如果你需要一个稳定而又简单的网络功能的话,不那么在乎安全性的话,Flannel是一个很好的选择。
calico方案
1 2 3 4 项目地址:https://github.com/projectcalico/cni-plugin Calico 是 Kubernetes 生态系统中另一种流行的网络选择。虽然 Flannel 被公认为是最简单的选择,但 Calico 以其性能、灵活性而闻名。Calico 的功能更为全面,除了通用的网络连接,还涉及网络安全和网络策略管理,甚至Calico还可以在微服务的网络治理中进行整合。Calico CNI 插件在 CNI 框架内封装了 Calico 的功能。 如果对你的环境而言,支持网络策略是非常重要的一点,而且你对其他性能和功能也有需求,那么 Calico 会是一个理想的选择。
canal方案
1 2 3 4 项目地址:https://github.com/projectcalico/canal Canal 试图将 Flannel 提供的网络功能与 Calico 的网络策略功能集成在一起,只不过在研发的时候,发现Flannel 和 Calico 这两个项目的标准化和灵活性都想当标准,那集成就没必要了,所以目前这个项目“烂尾”了。由于Canal的思路很好,业界习惯性地将 Flannel 和 Calico 的功能组合实施称为“Canal”。 对于那些喜欢 Flannel 提供的网络模型,同时喜欢 Calico 的网络策略功能的人来说,Canal是一个选择。
weave方案
1 2 3 4 项目地址:https://www.weave.works/oss/net/ Weave 是由 Weaveworks 提供的一种 Kubernetes CNI 网络选项,它在集群中的每个节点上部署路由组件,从而实现主机之间创建更加灵活的网状 overlay 网络,借助于内核级别的Open vSwitch 配置,从而实现具有一定程度的智能路由功能。除此之外,weave还具有想当的网络策略功能,网络加密传输功能等。 对于那些寻求功能丰富的网络、同时希望不要增加大量复杂性或管理难度的人来说,Weave 是一个很好的选择。
1 2 3 bandwidth - 带宽、consumption - 消耗、encryption - 加密 资料来源: https://docs.google.com/spreadsheets/d/12 dQqSGI0ZcmuEy48nA0P_bPl7Yp17fNg7De47CYWzaM/edit
小结
二、 Calico环境 学习目标
这一节,我们从 基础知识、原理解读、小结 三个方面来学习
基础知识
简介
1 2 3 4 5 Calico是一个开源的虚拟化网络方案,用于为云原生应用实现互联及策略控制.相较于 Flannel 来说,Calico 的优势是对网络策略(network policy),它允许用户动态定义 ACL 规则控制进出容器的数据报文,实现为 Pod 间的通信按需施加安全策略.不仅如此,Calico 还可以整合进大多数具备编排能力的环境,可以为 虚机和容器提供多主机间通信的功能。 Calico 本身是一个三层的虚拟网络方案,它将每个节点都当作路由器,将每个节点的容器都当作是节点路由器的一个终端并为其分配一个 IP 地址,各节点路由器通过 BGP(Border Gateway Protocol)学习生成路由规则,从而将不同节点上的容器连接起来.因此,Calico 方案其实是一个纯三层的解决方案,通过每个节点协议栈的三层(网络层)确保容器之间的连通性,这摆脱了 flannel host-gw 类型的所有节点必须位于同一二层网络的限制,从而极大地扩展了网络规模和网络边界。 官方地址:https: 最新版本:v3 .24 .1 (20220827 )、 v3 .20 .6 (20220802 )、v3 .21 .6 (20220722 )、 v3 .23 .3 (20220720 )、v3 .22 .4 (20220720 )
网络模型
1 2 3 Calico为了实现更广层次的虚拟网络的应用场景,它支持多种网络模型来满足需求。 underlay network - BGP (三层虚拟网络解决方案)overlay network - IPIP (双层IP实现跨网段效果)、VXLAN (数据包标识实现大二层上的跨网段通信)
设计思想
1 Calico不使用隧道或者NAT来实现转发,而是巧妙的把所有二三层流量转换成三层流量,并通过host上路由配置完成跨host转发。
为什么用calico
原理解读
calico
1 2 Calico是一个开源的虚拟化网络方案,用于为云原生应用实现互联及策略控制.相较于 Flannel 来说,Calico 的优势是对网络策略(network policy),它允许用户动态定义 ACL 规则控制进出容器的数据报文,实现为 Pod 间的通信按需施加安全策略.不仅如此,Calico 还可以整合进大多数具备编排能力的环境,可以为 虚机和容器提供多主机间通信的功能。 我们平常使用Calico主要用到的是它的网络策略功能
软件结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Felix 每个节点都有,负责配置路由、ACL、向etcd宣告状态等 BIRD 每个节点都有,负责把 Felix 写入Kernel的路由信息 分发到整个 Calico网络,确保 workload 连通 etcd 存储calico自己的状态数据,可以结合kube-apiserver 来工作 官方推荐; < 50 节点,可以结合 kube-apiserver 来实现数据的存储 > 50 节点,推荐使用独立的ETCD集群来进行处理。 参考资料: https://projectcalico.docs.tigera.io/getting-started /kubernetes/self-managed-onprem /onpremises Route Reflector 路由反射器,用于集中式的动态生成所有主机的路由表,非必须选项 超过100 个节点推荐使用: https://projectcalico.docs.tigera.io/getting-started /kubernetes/rancher Calico编排系统插件 实现更广范围的虚拟网络解决方案。 参考资料:https://docs.projectcalico.org/reference/architecture/overview
工作模式
1 对于节点量少的情况下,我们推荐使用左侧默认的模式,当节点量多的时候,我们推荐使用右侧的反射器模式
小结
2.1 Calico部署 学习目标
这一节,我们从 环境解析、简单实践、小结 三个方面来学习
环境解析
k8s环境上的calico逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 confd - 统一管控 Calico 数据存储以及 BGP 配置的轻量级的配置管理工具。 - 当配置文件发生变化时,动态更新和生成BIRD 配置文件 Dikastes - 为 Istio 服务网格实施网络策略。作为 Istio Envoy 的 sidecar 代理在集群上运行。 CNI plugin - 为 Kubernetes 集群提供 Calico 网络,必须安装在 Kubernetes 集群中的每个节点上。 Datastore plugin - 独立使用etcd作为Calico的数据存储平台,特点在于独立扩展数据存储 - 结合K8s的apiserver实现数据存储到etcd中,特点在于使用 Kubernetes的存储、RBAC、审计功能为Calico服务 IPAM plugin - 使用 Calico 的 IP 池资源来控制 IP 地址如何分配给集群内的 Pod。 kube-controllers - 监控 Kubernetes API 并根据集群状态执行操作 - 主要是策略、命名空间、服务账号、负载、节点等通信策略的控制 Typha - 通过减少每个节点对数据存储的影响来增加规模。在数据存储和 Felix 实例之间作为守护进程运行。 参考资料: https://projectcalico.docs.tigera.io/reference/architecture/overview
基础环境支持
1 2 3 4 5 6 7 8 9 10 11 linux 主机基本要求: x86-64 、arm64、ppc64le 或 s390x 处理器 2 CPU 2 GB 内存 10 GB 可用磁盘空间 RedHat Enterprise Linux 7 .x+、CentOS 7 .x+、Ubuntu 16.04 + 或 Debian 9 .x+ 确保 Calico 可以在主机上进行管理cali和接口 其他需求: kubernetes集群配置了 --pod-network-cidr 属性 参考资料: https://projectcalico.docs.tigera.io/getting-started /kubernetes/quickstart
部署解析
1 对于calico在k8s集群上的部署来说,为了完成上面四个组件的部署,这里会涉及到两个部署组件
组件名
组件作用
calico-node
需要部署到所有集群节点上的代理守护进程,提供封装好的Felix和BIRD
calico-kube-controller
专用于k8s上对calico所有节点管理的中央控制器。负责calico与k8s集群的协同及calico核心功能实现。
部署步骤
1 2 3 4 5 6 7 1 获取资源配置文件 从calico官网获取相关的配置信息2 定制CIDR配置 定制calico自身对于pod网段的配置信息,并且清理无关的网络其他插件3 定制pod的manifest文件分配网络配置 默认的k8s集群在启动的时候,会有一个cidr的配置,有可能与calico进行冲突,那么我们需要修改一下4 应用资源配置文件
1 2 3 注意事项: 对于calico来说,它自己会生成自己的路由表,如果路由表中存在响应的记录,默认情况下会直接使用,而不是覆盖掉当前主机的路由表 所以如果我们在部署calico之前,曾经使用过flannel,尤其是flannel的host-gw 模式的话,一定要注意,在使用calico之前,将之前所有的路由表信息清空,否则无法看到calico的tunl的封装效果
简单实践
环境部署
1 2 3 4 5 1 获取资源清单文件 mkdir /data /kubernetes/network/calico -p cd /data /kubernetes/network/calico/curl https://docs.projectcalico.org/manifests/calico.yaml -O cp calico.yaml{,.bak}
1 2 3 4 5 6 7 8 9 10 11 2 配置资源清单文件---- 官网推荐的修改内容4546 - name: CALICO_IPV4POOL_CIDR4547 value: "10.244.0.0/16" ---- 方便我们的后续实验,新增调小子网段的分配4548 - name: CALICO_IPV4POOL_BLOCK_SIZE4549 value: "24" 配置解析: 开放默认注释的CALICO_IPV4POOL_CIDR变量,然后定制我们当前的pod的网段范围即可 原则上来说,我们修改官方提示的属性即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 3 定制pod的manifest文件分配网络配置---- 修改下面的内容 64 "ipam" : { 65 "type" : "calico-ipam" 66 },---- 修改后的内容 64 "ipam" : { 65 "type" : "host-local" , 66 "subnet" : "usePodCidr" 67 },---- 定制calico使用k8s集群节点的地址4551 - name: USE_POD_CIDR4552 value: "true" 配置解析: Calico默认并不会从Node.Spec.PodCIDR中分配地址,但可通过USE_POD_CIDR变量并结合host-local 这一IPAM插件以强制从PodCIDR中分配地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 4 定制默认的docker镜像 查看默认的镜像 image: docker.io/calico/cni:v3.24.1 image: docker.io/calico/node:v3.24.1 image: docker.io/calico/kube-controllers :v3.24.1 获取镜像for i in $ (grep docker.io calico.yaml | uniq | awk -F '/' '{print $NF}' )do docker pull calico/$i docker tag calico/$i kubernetes-register .superopsmsb.com/google_containers/$i docker push kubernetes-register .superopsmsb.com/google_containers/$i docker rmi calico/$i done 修改为定制的镜像 sed -i 's#docker.io/calico#kubernetes-register.superopsmsb.com/google_containers#g' calico.yaml 查看效果 image: kubernetes-register .superopsmsb.com/google_containers/cni:v3.24.1 image: kubernetes-register .superopsmsb.com/google_containers/cni:v3.24.1 image: kubernetes-register .superopsmsb.com/google_containers/node:v3.24.1 image: kubernetes-register .superopsmsb.com/google_containers/node:v3.24.1 image: kubernetes-register .superopsmsb.com/google_containers/kube-controllers :v3.24.1
1 2 3 4 5 6 7 8 9 10 11 12 5 应用资源配置文件 清理之前的flannel插件 kubectl delete -f kube-flannel .yml kubectl get pod -n kube-system | grep flannel 这个时候,先清除旧网卡,然后最好重启一下主机,直接清空所有的路由表信息 ifconfig flannel.1 reboot 重启后,查看网络效果 注意: 为了避免后续calico网络测试的异常,我们这里最好只留下一个网卡 eth0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 应用calico插件 kubectl apply -f calico.yaml 在calico-node 部署的时候,会启动多个进程 NAME READY STATUS RESTARTS AGE calico-kube-controllers-549f7748b5-xqz8j 0 /1 ContainerCreating 0 9 s calico-node-74c5w 0 /1 Init:0 /3 0 9 s ... 环境部署完毕后,查看效果 NAME READY STATUS RESTARTS AGE calico-kube-controllers-549f7748b5-xqz8j 0 /1 Running 0 39 s calico-node-74c5w 0 /1 Running 0 39 s ...
1 2 3 4 5 6 7 8 每个calico节点上都有多个进程,分别来处理不同的功能 ] root 9315 0.5 1.1 1524284 43360 ? Sl 15 :29 0 :00 calico-node -confd root 9316 0.2 0.8 1155624 32924 ? Sl 15 :29 0 :00 calico-node -monitor-token root 9317 2.8 1.0 1598528 40992 ? Sl 15 :29 0 :02 calico-node -felix root 9318 0.3 0.9 1155624 35236 ? Sl 15 :29 0 :00 calico-node -monitor-addresses root 9319 0.3 0.8 1155624 33460 ? Sl 15 :29 0 :00 calico-node -status-reporter root 9320 0.2 0.7 1155624 30364 ? Sl 15 :29 0 :00 calico-node -allocate-tunnel-addrs
测试效果
1 2 3 4 5 获取镜像 docker pull nginx docket tag nginx kubernetes-register .superopsmsb.com/superopsmsb/nginx:1.23 .1 docker push kubernetes-register .superopsmsb.com/superopsmsb/nginx:1.23 .1 docker rmi nginx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 创建一个deployment kubectl create deployment pod-deployment --image =kubernetes-register .superopsmsb.com/superopsmsb/nginx:1.23 .1 --replicas =3 查看pod NAME READY STATUS RESTARTS AGE pod-deployment-554dff674-267gq 1 /1 Running 0 48 s pod-deployment-554dff674-c8cjs 1 /1 Running 0 48 s pod-deployment-554dff674-pxrwb 1 /1 Running 0 48 s 暴露一个service kubectl expose deployment pod-deployment --port =80 --target-port =80 确认效果 kubectl get servicecurl 10.108 .138.97
小结
2.2 简单实践 学习目标
这一节,我们从 网络解析、命令完善、小结 三个方面来学习
网络解析
calico部署完毕后,会生成一系列的自定义配置属性信息
1 2 3 4 5 6 自动生成一个api版本信息 crd.projectcalico.org/v1 该api版本信息中有大量的配置属性 kubectl api-resources | grep crd.pro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 这里面的 ippools 里面包含了calico相关的网络属性信息 NAME AGE default-ipv4-ippool 37 m 查看这里配置的calico相关的信息 apiVersion: crd.projectcalico.org/v1 kind: IPPool ... spec: allowedUses: - Workload - Tunnel blockSize: 24 cidr: 10.244 .0.0 /16 ipipMode: Always natOutgoing: true nodeSelector: all() vxlanMode: Never 结果显式: 这里的calico采用的模型就是 ipip模型,分配的网段是使我们定制的 cidr网段,而且子网段也是我们定制的 24 位掩码
环境创建完毕后,会生成一个tunl0的网卡,所有的流量会走这个tunl0网卡
1 2 3 4 5 6 7 8 9 10 确认网卡和路由信息 ] ]10.244 .1.0 /24 via 10.0 .0.13 dev tunl0 proto bird onlink10.244 .2.0 /24 via 10.0 .0.14 dev tunl0 proto bird onlink10.244 .3.0 /24 via 10.0 .0.15 dev tunl0 proto bird onlink10.244 .4.0 /24 via 10.0 .0.16 dev tunl0 proto bird onlink10.244 .5.0 /24 via 10.0 .0.17 dev tunl0 proto bird onlink 结果显示: calico模型中,默认使用的是tunl0虚拟网卡实现数据包的专线转发
测试效果
1 2 3 4 5 6 7 由于在calico的默认网络模型是 IPIP,所以我们在进行数据包测试的时候,可以通过直接抓取宿主机数据包,来发现双层ip效果 kubectl get pod -o wide 在master1上采用ping的方式来测试 node2上的节点pod [root @kubernetes -master1 /data /kubernetes /network /calico ] PING 10.244 .4.3 (10.244 .4.3 ) 56 (84 ) bytes of data .64 bytes from 10.244 .4.3 : icmp_seq=1 ttl=63 time=0.794 ms
1 2 3 4 5 6 7 8 9 10 11 12 在node2上检测数据包的效果 [root @kubernetes -node2 ~] tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes15 :38 :52.231680 IP 10.0 .0.12 > 10.0 .0.16 : IP 10.244 .0.1 > 10.244 .4.3 : ICMP echo request, id 19189 , seq 1 , length 64 (ipip-proto-4 )15 :38 :52.231989 IP 10.0 .0.16 > 10.0 .0.12 : IP 10.244 .4.3 > 10.244 .0.1 : ICMP echo reply, id 19189 , seq 1 , length 64 (ipip-proto-4 )15 :38 :54.666538 IP 10.0 .0.16 .33992 > 10.0 .0.12 .179 : Flags [P. ], seq 4281052787 :4281052806 , ack 3643645463 , win 58 , length 19 : BGP15 :38 :54.666962 IP 10.0 .0.12 .179 > 10.0 .0.16 .33992 : Flags [. ], ack 19 , win 58 , length 0 结果显式: 每个数据包都是基于双层ip嵌套的方式来进行传输,而且协议是 ipip-proto-4 结合路由的分发详情,可以看到具体的操作效果。 具体效果:10.244 .0.1 -> 10.0 .0.12 -> 10.0 .0.16 -> 10.244 .6.3
命令完善
简介
1 2 3 4 calico本身是一个复杂的系统,复杂到它自己提供一个非常重要的Restful接口,结合calicoctl命令来管理自身的相关属性信息,calicoctl可以直接与etcd进行操作,也可以通过kube-apiserver 的方式与etcd来进行操作。默认情况下,它与kube-apiserver 通信的认证方式与kubectl的命令使用同一个context。但是我们还是推荐,使用手工定制的一个配置文件。 calicoctl 是运行在集群之外的,用于管理集群功能的一个重要的组件。calicoctl 的安装方式很多,常见的方式有:单主机方式、kubectl命令插件方式、pod方式、主机容器方式。我们需要自己选择一种适合自己的方式 参考资料:https://projectcalico.docs.tigera.io/getting-started /kubernetes/hardway/the-calico-datastore
1 2 3 4 5 6 7 8 9 获取专用命令cd /usr/local/bin/curl -L https://github.com/projectcalico/calico/releases/download/v3.24.1 /calicoctl-linux-amd64 -o calicoctl chmod +x calicoctl 查看帮助 Usage: calicoctl [options ] <command> [<args >... ]
命令的基本演示
1 2 3 4 5 6 7 8 9 10 查看ip的管理 calicoctl ipam --help 查看ip的信息 +---------- +--------------- +----------- +------------ +-------------- + | GROUPING | CIDR | IPS TOTAL | IPS IN USE | IPS FREE | +---------- +--------------- +----------- +------------ +-------------- + | IP Pool | 10.244 .0.0 /16 | 65536 | 0 (0 %) | 65536 (100 %) | +---------- +--------------- +----------- +------------ +-------------- +
1 2 3 4 5 6 7 8 9 10 11 12 查看信息的显式效果 calicoctl ipam show --help 显式相关的配置属性 +-------------------- +------- + | PROPERTY | VALUE | +-------------------- +------- + | StrictAffinity | false | | AutoAllocateBlocks | true | | MaxBlocksPerHost | 0 | +-------------------- +------- +
将calico整合到kubectl里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 定制kubectl 插件子命令 测试效果 Usage: kubectl-calico [options ] <command> [<args >... ] 后续的操作基本上都一样了,比如获取网络节点效果 [root @kubernetes -master1 /usr /local /bin ] Calico process is running. IPv4 BGP status +-------------- +------------------- +------- +---------- +------------- + | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +-------------- +------------------- +------- +---------- +------------- + | 10.0 .0.15 | node-to-node mesh | up | 07 :30 :48 | Established | | 10.0 .0.17 | node-to-node mesh | up | 07 :30 :48 | Established | | 10.0 .0.13 | node-to-node mesh | up | 07 :30 :48 | Established | | 10.0 .0.14 | node-to-node mesh | up | 07 :30 :51 | Established | | 10.0 .0.16 | node-to-node mesh | up | 07 :31 :41 | Established | +-------------- +------------------- +------- +---------- +------------- + IPv6 BGP status No IPv6 peers found. 注意: 这里查看的是除了自己网段之外的其他节点的路由信息
小结
2.3 BGP实践 学习目标
这一节,我们从 bgp改造、反射器实践、小结 三个方面来学习
bgp改造
简介
1 对于现有的calico环境,我们如果需要使用BGP环境,我们可以直接使用一个配置清单来进行修改calico环境即可。我们这里先来演示一下如何使用calicoctl修改配置属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 获取当前的配置属性 NAME CIDR SELECTOR default-ipv4-ippool 10.244 .0.0 /16 all() apiVersion: projectcalico.org/v3 kind: IPPool ... spec: blockSize: 24 cidr: 10.244 .0.0 /16 ipipMode: Always natOutgoing: true nodeSelector: all() vxlanMode: Never
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 定制资源配置文件 kubectl calico get ipPools default-ipv4-ippool -o yaml > default-ipv4-ippool .yaml 修改配置文件 apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: default-ipv4-ippool spec: blockSize: 24 cidr: 10.244 .0.0 /16 ipipMode: CrossSubnet natOutgoing: true nodeSelector: all() vxlanMode: Never 配置解析: 仅仅将原来的Always 更换成 CrossSubnet(跨节点子网) 模式即可 vxlanMode 的两个值可以实现所谓的 BGP with vxlan的效果 应用资源配置文件 Successfully applied 1 'IPPool' resource(s)
检查效果
1 2 3 4 5 6 7 8 9 10 11 查看路由信息 [root @kubernetes -master1 ~] default via 10.0 .0.2 dev eth010.244 .1.0 /24 via 10.0 .0.13 dev eth0 proto bird10.244 .2.0 /24 via 10.0 .0.14 dev eth0 proto bird10.244 .3.0 /24 via 10.0 .0.15 dev eth0 proto bird10.244 .4.0 /24 via 10.0 .0.16 dev eth0 proto bird10.244 .5.0 /24 via 10.0 .0.17 dev eth0 proto bird 结果显式: 更新完毕配置后,动态路由的信息就发生改变了,不再完全是 tunl0 网卡了,而是变成了通过具体的物理网卡eth0 转发出去了
1 2 3 4 5 6 7 8 9 10 11 12 13 在master1上ping在节点node2上的pod [root @kubernetes -master1 ~] PING 10.244 .4.3 (10.244 .4.3 ) 56 (84 ) bytes of data .64 bytes from 10.244 .4.3 : icmp_seq=1 ttl=63 time=0.671 ms 由于这次是直接通过节点进行转发的,所以我们在node2节点上抓包的时候,直接通过内层ip抓取即可。 [root @kubernetes -node2 ~] tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes15 :47 :32.906462 IP 10.0 .0.12 > 10.244 .4.3 : ICMP echo request, id 28248 , seq 1 , length 64 15 :47 :32.906689 IP 10.244 .4.3 > 10.0 .0.12 : ICMP echo reply, id 28248 , seq 1 , length 64 结果显示: 他们实现了直接的连通,无需进行数据包的转换了,效率更高一点
反射器实践
当前节点的网络效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 查看当前节点的网络效果 [root @kubernetes -master1 ~] Calico process is running. IPv4 BGP status +-------------- +------------------- +------- +---------- +------------- + | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +-------------- +------------------- +------- +---------- +------------- + | 10.0 .0.15 | node-to-node mesh | up | 07 :30 :48 | Established | | 10.0 .0.17 | node-to-node mesh | up | 07 :30 :48 | Established | | 10.0 .0.13 | node-to-node mesh | up | 07 :30 :48 | Established | | 10.0 .0.14 | node-to-node mesh | up | 07 :30 :51 | Established | | 10.0 .0.16 | node-to-node mesh | up | 07 :31 :41 | Established | +-------------- +------------------- +------- +---------- +------------- +
需求
1 2 当前的calico节点的网络状态是 BGP peer 的模型效果,也就是说 每个节点上都要维护 n-1 个路由配置信息,整个集群中需要维护 n*(n-1 ) 个路由效果,这在节点量非常多的场景中,不是我们想要的。 所以我们需要实现一种 BGP reflecter 的效果。
1 2 3 4 如果我们要做 BGP reflecter 效果的话,需要对反射器角色做冗余,如果我们的集群是一个多主集群的话,可以将集群的master节点作为bgp的reflecter角色,从而实现反射器的冗余。 1 定制反射器角色 2 后端节点使用反射器 3 关闭默认的网格效果
1 创建反射器角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 定制资源定义文件 01 -calico-reflector-master .yaml apiVersion: projectcalico.org/v3 kind: Node metadata: labels: route-reflector : true name: kubernetes-master1 spec: bgp: ipv4Address: 10.0 .0.12 /16 ipv4IPIPTunnelAddr: 10.244 .0.1 routeReflectorClusterID: 1.1 .1.1 属性解析; metadata.labels 是非常重要的,因为它需要被后面的节点来进行获取 metadata.name 的属性,必须是通过 calicoctl get nodes 获取到的节点名称。 spec.bgp.ipv4Address必须是 指定节点的ip地址 spec.bgp.ipv4IPIPTunnelAddr必须是 指定节点上tunl0的地址 spec.bgp.routeReflectorClusterID 是BGP网络中的唯一标识,所以这里的集群标识只要唯一就可以了 应用资源配置文件 kubectl calico apply -f 01 -calico-reflector-master .yaml
2 更改节点的网络模型为 reflecter模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 定制资源定义文件 02 -calico-reflector-bgppeer .yaml kind: BGPPeer apiVersion: projectcalico.org/v3 metadata: name: bgppeer-demo spec: nodeSelector: all() peerSelector: route-reflector =="true" 属性解析; spec.nodeSelector 指定的所有后端节点 spec.peerSelector 指定的是反射器的标签,标识所有的后端节点与这个反射器进行数据交流 应用资源配置文件 kubectl calico apply -f 02 -calico-reflector-bgppeer .yaml
3 关闭默认的网格效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 定制资源定义文件 03 -calico-reflector-defaultconfig .yaml apiVersion: projectcalico.org/v3 kind: BGPConfiguration metadata: name: default spec: logSeverityScreen: Info nodeToNodeMeshEnabled: false asNumber: 63400 属性解析; metadata.name 在这里最好是default,因为我们要对BGP默认的网络效果进行关闭 spec.nodeToNodeMeshEnabled 关闭后端节点的BGP peer默认状态 -- 即点对点通信关闭 spec.asNumber 指定的是后端节点间使用反射器的时候,我们要在一个标志号内,这里随意写一个 应用资源配置文件 kubectl calico apply -f 03 -calico-reflector-defaultconfig .yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 查看效果 [root @kubernetes -master1 ~/txt ] ... IPv4 BGP status +-------------- +--------------- +------- +---------- +------------- + | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +-------------- +--------------- +------- +---------- +------------- + | 10.0 .0.13 | node specific | up | 07 :51 :47 | Established | | 10.0 .0.14 | node specific | up | 07 :51 :49 | Established | | 10.0 .0.15 | node specific | up | 07 :51 :49 | Established | | 10.0 .0.16 | node specific | up | 07 :51 :47 | Established | | 10.0 .0.17 | node specific | up | 07 :51 :47 | Established | +-------------- +--------------- +------- +---------- +------------- + 结果显式: 默认的点对点通信方式就已经丢失了,剩下了反射器模式
小结
2.4 策略实践 学习目标
这一节,我们从 属性解读、基本控制、小结 三个方面来学习。
属性解读
策略简介
1 2 3 为了使用Network Policy,Kubernetes引入了一个新的资源对象Network Policy,供用户设置Pod间网络访问的策略。策略控制器用于监控指定区域创建对象(pod)时所生成的新API端点,并按需为其附加网络策略。 对于Pod对象来说,网络流量分为 流入(Ingress)和流出(Egress)两个方向,每个方向包含允许和禁止两种控制策略,默认情况下,所有的策略都是允许的,应用策略后,所有未经明确允许的流量都将拒绝。
1 2 3 注意: 网络策略的控制,可以是多个级别: 集群级别、namespace级别、Pod级别、ip级别、端口级别
资源对象属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name <string> namespace <string> spec: podSelector <Object> policyTypes <[]string> ingress <[]Object> - from <[]Object> - ipBlock <Object> - namespaceSelector <Object> podSelector <Object> ports <[]Object> egress <[]Object> - to <[]Object> ports <[]Object> 注意: 入栈和出栈哪个策略生效,由 policyTypes 来决定。 如果仅配置了podSelector,表明,当前限制仅限于当前的命名空间
配置示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network -policy namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Ingress - Egress ingress: - from: - ipBlock: cidr: 10.244 .0.0 /16 except: - 10.244 .1.0 /24 - namespacesSelector: matchLabels: project: develop - podSelector: matchLabels: arch: frontend ports: - protocol: TCP port: 6379 egress: - to: - ipBlock: cidr: 10.244 .0.0 /24 ports: - protocol: TCP port: 3306
准备工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 在default命名空间创建应用 [root @kubernetes -master1 ~] [root @kubernetes -master1 ~] 在superopsmsb命名空间创建应用 [root @kubernetes -master1 ~] [root @kubernetes -master1 ~] 确认效果 [root @kubernetes -master1 ~] NAME READY... AGE IP ... nginx-web-5865bb968d-759lc 1 /1 ... 10 s 10.244 .1.4 ... [root @kubernetes -master1 ~] NAME READY... AGE IP ... nginx-web-65d688fd6-h6sbpp 1 /1 ... 10 s 10.244 .1.5 ...
1 2 3 开启superopsmsb的测试容器 [root @kubernetes -master1 ~] root@nginx-web-65d688fd6-h6sbp :/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 进入到容器里面查看效果 [root @kubernetes -master1 ~] root@nginx-web-5865bb968d-759lc :/ 域名检测 root@nginx-web-5865bb968d-759lc :/ Server: 10.96 .0.10 Address: 10.96 .0.10 Name: nginx-web .default.svc.cluster.local Address: 10.101 .181.105 root@nginx-web-5865bb968d-759lc :/ Server: 10.96 .0.10 Address: 10.96 .0.10 Name: nginx-web .superopsmsb.svc.cluster.local Address: 10.105 .110.175 ping检测 root@nginx-web-5865bb968d-759lc :/ inet 10.244 .1.4 netmask 255.255 .255.255 broadcast 0.0 .0.0 RX packets 22442 bytes 20956160 (19.9 MiB) root@nginx-web-5865bb968d-759lc :/ PING 10.244 .1.5 (10.244 .1.5 ) 56 (84 ) bytes of data .64 bytes from 10.244 .1.5 : icmp_seq=1 ttl=63 time=0.357 ms
基本控制
默认拒绝规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 查看资源清单文件 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all -ingress namespace: superopsmsb spec: podSelector: {} policyTypes: ["Ingress" , "Egress" ] 应用资源清单文件 networkpolicy.networking.k8s.io/deny-all -ingress created
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 尝试default空间资源访问superopsmsb空间资源 root@nginx-web-5865bb968d-759lc :/ PING 10.244 .1.5 (10.244 .1.5 ) 56 (84 ) bytes of data .--- 10.244 .1.5 ping statistics --- 1 packets transmitted, 0 received, 100 % packet loss, time 0 ms root@nginx-web-5865bb968d-759lc :/curl : (28 ) Failed to connect to nginx-web .superopsmsb.svc.cluster.local port 80 : Connection timed out 结果显示: 访问失败 default空间资源访问非superopsmsb空间资源正常。 root@nginx-web-5865bb968d-759lc :/ Hello Nginx, nginx-web-5865bb968d-759lc-1 .23.0
默认启用规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 查看资源清单文件 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all-ingress namespace: superopsmsb spec: podSelector: {} policyTypes: ["Ingress" , "Egress" ] egress: - {} ingress: - {} 应用资源清单文件 networkpolicy.networking.k8s.io/allow-all-ingress created
1 2 3 4 5 6 7 8 9 10 11 12 在default空间访问superopsmsb空间资源 root@nginx-web-5865bb968d-759lc :/ Hello Nginx, nginx-web-65d688fd6-h6sbp-1 .23.0 root@nginx-web-5865bb968d-759lc :/ PING 10.244 .1.5 (10.244 .1.5 ) 56 (84 ) bytes of data .64 bytes from 10.244 .1.5 : icmp_seq=1 ttl=63 time=0.181 ms 结果显示: 网络策略成功了,而且多个网络策略可以叠加 注意:仅仅同名策略或者同类型策略可以覆盖 清理网络策略
当前namespace的流量限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 查看资源清单文件 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-current-ns namespace: superopsmsb spec: podSelector: {} policyTypes: ["Ingress" , "Egress" ] egress: - to: - podSelector: {} ingress: - from: - podSelector: {} 配置解析: 虽然设置了egress和ingress属性,但是下面的podSelector没有选择节点,表示只有当前命名空间所有节点不受限制 应用资源清单文件 networkpolicy.networking.k8s.io/allow-current-ns created
1 2 3 4 5 6 7 default资源访问superopsmsb资源 root@nginx-web-5865bb968d-759lc :/curl : (28 ) Failed to connect to nginx-web .superopsmsb.svc.cluster.local port 80 : Connection timed out root@nginx-web-5865bb968d-759lc :/ PING 10.244 .1.5 (10.244 .1.5 ) 56 (84 ) bytes of data . 结果显示: 访问失败
1 2 3 4 5 6 superopsmsb资源访问同命名空间的其他资源 root@nginx-web-65d688fd6-h6sbp :/ PING 10.244 .1.2 (10.244 .1.2 ) 56 (84 ) bytes of data .64 bytes from 10.244 .1.2 : icmp_seq=1 ttl=63 time=0.206 ms 结果显示: 同命名空间可以正常访问
小结
2.5 流量管控 学习目标
这一节,我们从 ip限制实践、pod限制实践、小结 三个方面来学习。
ip限制知识
准备工作
1 2 3 4 5 6 准备同名空间的两个测试pod 终端1 kubectl run superopsmsb-client1 --image =kubernetes-register .superopsmsb.com/superopsmsb/busybox -n superopsmsb --rm -it -- /bin/sh 终端2 kubectl run superopsmsb-client2 --image =kubernetes-register .superopsmsb.com/superopsmsb/busybox -n superopsmsb --rm -it -- /bin/sh
简介
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 查看资源清单文件 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-ns -pod namespace: superopsmsb spec: podSelector: {} policyTypes: ["Ingress" , "Egress" ] egress: - to: - podSelector: {} ingress: - from: - ipBlock: cidr: 10.244 .0.0 /16 except: - 10.244 .2.0 /24 ports: - protocol: TCP port: 80 配置解析: 虽然设置了egress和ingress属性,但是下面的podSelector没有选择节点,表示只有当前命名空间所有节点不受限制 应用资源对象文件 networkpolicy.networking.k8s.io/deny-ns -pod created
1 2 3 4 5 6 7 3 网段测试容器查看效果 / inet addr:10.244 .3.7 Bcast:0.0 .0.0 Mask:255.255 .255.255 / Connecting to 10.244 .1.5 (10.244 .1.5 :80 ) index.html 100 % |*****************************************************| 46 0 :00 :00 ETA /
1 2 3 4 5 6 7 8 9 2 网段测试容器查看效果 / inet addr:10.244 .2.6 Bcast:0.0 .0.0 Mask:255.255 .255.255 / Connecting to 10.244 .1.5 (10.244 .1.5 :80 )wget : can't connect to remote host (10.244.1.5): Connection timed out / 结果显示: 同namespace可以进行ip级别的访问测试
pod限制实践
实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 查看在ip限制的基础上,扩充pod限制资源清单文件 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: egress-controller namespace: superopsmsb spec: podSelector: {} policyTypes: ["Egress" ] egress: - to: ports: - protocol: UDP port: 53 - to: ports: - protocol: TCP port: 80 配置解析: 虽然设置了egress和ingress属性,但是下面的podSelector没有选择节点,表示只有当前命名空间所有节点不受限制 应用资源对象文件 networkpolicy.networking.k8s.io/egress-controller created
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 在所有pod测试容器中 / Server: 10.96 .0.10 Address 1 : 10.96 .0.10 kube-dns .kube-system .svc.cluster.local Name: nginx-web .default.svc.cluster.local Address 1 : 10.101 .181.105 nginx-web .default.svc.cluster.local / Server: 10.96 .0.10 Address 1 : 10.96 .0.10 kube-dns .kube-system .svc.cluster.local Name: nginx-web Address 1 : 10.105 .110.175 nginx-web .superopsmsb.svc.cluster.local 结果显示: 在不影响之前的策略的前提下,扩充了dns的解析功能
小结
2.6 基准测试 学习目标
这一节,我们从 软件简介、简单实践、小结 三个方面来学习
软件简介
简介
1 2 3 4 knb 全称 Kubernetes Network Benchmark,它是一个 bash 脚本,它将在目标 Kubernetes 集群上启动网络基准测试。 参考资料: https://github.com/InfraBuilder/k8s-bench-suite
1 2 3 4 5 6 7 8 9 10 11 它的主要特点如下: 依赖很少的普通 bash 脚本 完成基准测试仅需 2 分钟 能够仅选择要运行的基准测试的子集 测试TCP 和 UDP带宽 自动检测 CNI MTU 在基准报告中包括主机 cpu 和 ram 监控 能够使用 plotly/orca 基于结果数据创建静态图形图像(参见下面的示例) 无需 ssh 访问,只需通过标准 kubectl访问目标集群 不需要高权限,脚本只会在两个节点上启动非常轻量级的 Pod。 它提供了数据的图形生成镜像和配套的服务镜像
准备工作
1 2 3 4 5 6 7 master节点下载核心服务镜像 docker pull olegeech/k8s-bench-suite 特定node节点下载镜像 docker pull infrabuilder/bench-custom-monitor docker pull infrabuilder/bench-iperf3 docker pull quay.io/plotly/orca
注意事项
1 2 3 由于需要测试k8s节点间的网络通信质量并且将结果输出,所以它在操作的过程中需要提前做一些准备 1 准备k8s集群的认证config文件 2 准备数据文件的映射目录
简单实践
命令解析
1 2 3 4 5 6 对于容器内部的knb命令来说,它的基本格式如下: knb --verbose --client-node 客户端节点 --server-node 服务端节点 注意: docker run时候,可以通过NODE_AUTOSELECT从集群中自动选择几个节点来运行测试 - 如果master节点的污点无法容忍,从而导致失败
1 2 3 4 5 6 查看命令帮助 docker run -it --hostname knb --name knb --rm -v /tmp/my-graphs :/my-graphs -v /root/.kube/config:/.kube/config olegeech/k8s-bench-suite --help 注意: 如果网络效果不是很好的话,会因为镜像无法获取而导致失败,需要重试几次即可 所以,如果可以的话,提前下载到特定的工作节点上
测试效果
1 2 生成检测数据 docker run -it --hostname knb --name knb --rm -v /tmp/my-graphs :/my-graphs -v /root/.kube/config:/.kube/config olegeech/k8s-bench-suite --verbose --server-node kubernetes-node1 --client-node kubernetes-node2 -o data -f /my-graphs /mybench.knbdata
1 2 以json方式显示数据 docker run -it --hostname knb --name knb --rm -v /tmp/my-graphs :/my-graphs -v /root/.kube/config:/.kube/config olegeech/k8s-bench-suite -fd /my-graphs /mybench.knbdata -o json
1 2 根据数据进行绘图展示 docker run -it --hostname knb --name knb --rm -v /tmp/my-graphs :/my-graphs -v /root/.kube/config:/.kube/config olegeech/k8s-bench-suite -fd /my-graphs /mybench.knbdata --plot --plot-dir /my-graphs /
1 2 设定数据的图形样式 docker run -it --hostname knb --name knb --rm -v /tmp/my-graphs :/my-graphs -v /root/.kube/config:/.kube/config olegeech/k8s-bench-suite -fd /my-graphs /mybench.knbdata --plot --plot-args '--width 900 --height 600' --plot-dir /my-graphs
小结