admin 管理员组

文章数量: 887019



文章目录
  • 一、概述
  • 二、Calico 架构、组件和两种模式
  • 2.1 Calico架构和组件
  • 2.2 两种模式
  • IPIP 模式
  • BGP 模式
  • 三、 Calico网络解决方案
  • 3.1 网关IP地址就是目的容器所在宿主机IP地址(三层网络架构)
  • 3.2 Calico不会在宿主机上创建任何网桥设备
  • 3.3 Calico 使用 BGP 来自动地在整个集群中分发路由信息
  • 3.4 IPIP模式在BGP模式中加上OuterIP Header
  • 3.5 生产部署
  • 四、安装Calico插件
  • 方式1:通过helm安装Calico
  • 方式2:通过yaml文件安装
  • 方式3:k8s flannel网络切换calico
  • 步骤1:卸载flannel插件
  • 步骤2:开始安装Calico插件
  • 五、Calico高级特性
  • 5.1 网络策略
  • 场景1:允许来自同一命名空间中的 Pod 的入口流量
  • 场景2:允许来自不同命名空间中的 Pod 的入口流量
  • 5.2 固定Pod IP
  • 给Pod设置固定IP
  • 给控制器设置固定IP(控制器中一个Pod)
  • 给控制器设置固定IP池(控制器中多个Pod)
  • 5.3 Calico VS Flannel
  • 六、尾声


一、概述

容器生态中,三层网络架构包括两个实现: Flannel host-gw模式、Calico 框架。

Calico 是一个联网和网络策略供应商。 Calico 支持一套灵活的网络选项,因此你可以根据自己的情况选择最有效的选项,包括非覆盖和覆盖网络,带或不带 BGP。 Calico 使用相同的引擎为主机、Pod 和(如果使用 Istio 和 Envoy)应用程序在服务网格层执行网络策略。Calico以其性能、灵活性而闻名。Calico的功能更为全面,更为复杂。它不仅提供主机和pod之间的网络连接,还涉及网络安全和管理。Calico CNI插件在CNI(container network interface)框架内封装了Calico的功能。

Calico GitHub地址: https://github/projectcalico/calico
Calico 官方文档:https://projectcalico.docs.tigera.io/about/about-calico

想了解flannel的小伙伴,可以参考我这篇文章:

其它CNI插件,可以查看k8s官网:https://kubernetes.io/docs/concepts/cluster-administration/addons/

二、Calico 架构、组件和两种模式

2.1 Calico架构和组件

Calico不使用重叠网络(比如flannel和libnetwork重叠网络驱动),它是一个纯三层的方法,使用虚拟路由代替虚拟交换,每一台虚拟路由通过BGP协议传播可达信息(路由)到剩余数据中心;Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。

Calico 的核心组件:

Calico 的 CNI 插件:这是 Calico 与 Kubernetes 对接的部分;

Felix:运行在每一台 Host 的 agent 进程,本质是一个 K8S DaemonSet 资源,主要负责在宿主机上插入路由规则,以及维护 Calico 所需的网络设备等工作,比如网络接口管理和监听、路由、ARP 管理、ACL 管理和同步、状态上报等。

Etcd:分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性,可以与kubernetes共用;

BGP Client(即BIRD):它就是 BGP 的客户端,专门负责在集群里分发路由规则信息。Calico 为每一台 Host 部署一个 BGP Client,使用 BIRD 实现,BIRD 是一个单独的持续发展的项目,实现了众多动态路由协议比如 BGP、OSPF、RIP 等。在 Calico 的角色是监听 Host 上由 Felix 注入的路由信息,然后通过 BGP 协议广播告诉剩余 Host 节点,从而实现网络互通。【因为Calico使用BGP保存路由信息,所以才有了这个组件】

BGP Route Reflector:在大型网络规模中,如果仅仅使用 BGP client 形成 mesh 全网互联的方案就会导致规模限制,因为所有节点之间俩俩互联,需要 N^2 个连接,为了解决这个规模问题,可以采用 BGP 的 Router Reflector 的方法,使所有 BGP Client 仅与特定 RR 节点互联并做路由同步,从而大大减少连接数。【因为Calico使用BGP保存路由信息,所以才有了这个组件】

2.2 两种模式

IPIP 模式
  • 从字面来理解,就是把一个IP数据包又套在一个IP包里(所以成为IPIP, 名称里两个IP, 一个套一个),即把 IP 层封装到 IP 层的一个 tunnel,看起来似乎是浪费,实则不然。
  • 它的作用其实基本上就相当于一个基于IP层的网桥!
  • 一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。
  • ipip 的源代码在内核 net/ipv4/ipip.c 中可以找到。

Calico的IPIP模式工作原理如下图:

Calico使用的这个tunl0设备,是一个IP隧道(IP tunnel)设备

在上面的例子中,IP包进入IP隧道设备之后,就会被Linux内核的IPIP驱动接管。IPIP驱动会将这个IP包直接封装在一个宿主机网络的IP包中,如下所示:

架构中的 Router1 Router2 就是 Linux 之间数据包网络传送,所以多了一层 OuterIPHeader .

BGP 模式

定义:边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议,本质是一个协议。

  • 它通过维护IP路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。
  • BGP不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。
  • BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单IP,BGP 机房的优点:服务器只需要设置一个IP地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。

最大特点:BGP网络相比较IPIP网络,最大的不同之处就是没有了隧道设备 tunl0。 前面介绍过IPIP网络pod之间的流量发送tunl0,然后tunl0发送对端设备。BGP网络中,pod之间的流量直接从网卡发送目的地,减少了tunl0这个环节。

BGP模式架构如下(下图相对于IPIP架构图,最大的区别是没有了 tunl0 网卡,就是架构图中的 Route1 Router2):

三、 Calico网络解决方案

Calico项目
相同点:Calico项目和Flannel host-gw模式一样,都是纯三层网络方案,route路由规则中的 网关的 IP 地址 正是目的容器所在宿主机的 IP 地址,可以通过路由表为每个容器的 IP 地址,找到它所对应的、“下一跳”的网关。
不同点:
(1) Calico不会在宿主机上创建任何网桥设备,取而代之的是每个使用虚拟IP的Pod都会有一个calixxx网卡,都会有一条路由规则。
(2) Flannel 通过 Etcd 和宿主机上的 flanneld 来存储路由信息,Calico 项目使用 BGP 来自动地在整个集群中分发路由信息。
(3) Calico可以在默认BGP模式下加上IPIP配置,用来实现不同网段之间Node的Pod之间通信。

三层网络方案的核心就是可以为为每个容器的 IP 地址,找到它所对应的、“下一跳”的网关。

Calico网络解决方案包括三个知识点:
(1) 是纯三层网络方案,route路由规则中的 网关的 IP 地址 正是目的容器所在宿主机的 IP 地址,和 Flannel host-gw模式一样;
(2) Calico不会在宿主机上创建任何网桥设备,取而代之的是每个使用虚拟IP的Pod都会有一个calixxx网卡,都会有一条路由规则。
(3) Calico 项目使用 BGP 协议,用来自动地在整个集群中分发路由信息。
(4) Calico可以在默认BGP模式下加上IPIP配置,用来实现不同网段之间Node的Pod之间通信。

3.1 网关IP地址就是目的容器所在宿主机IP地址(三层网络架构)

对于不同Node上的Pod通信,Calico 项目提供的网络解决方案,与 Flannel 的 host-gw 模式,几乎是完全一样的。也就是说,Calico 也会在每台宿主机上,添加一个格式如下所示的路由规则:

# 任何一个宿主机上执行 ip route (这个未使用ipip的bgp模式)
<目的容器IP地址段> via <网关的IP地址> dev eth0
  • 1.
  • 2.

Calico为每个Pod生成了虚拟IP和路由规则:calico没有安装之前(kubectl apply -f https://docs.projectcalico/v3.9/manifests/calico.yaml),这些虚拟IP就无法生成,就算是 coredns 也无法 Running . (kubedns是过时,coredns是当前最新)

步骤1:ip route 可以看到 虚拟IP 和 calico 网卡名称的一一对应关系;
步骤2:执行 kubectl get pod -o wide -A 可以看到所有的 虚拟 IP;
步骤3:然后 ip a 可以看到所有的网卡名称 (当然包括calico的所有网卡名称) 。

3.2 Calico不会在宿主机上创建任何网桥设备

Calico 项目与 Flannel 的 host-gw 模式的一个不同之处,在于它不会在宿主机上创建任何网桥设备。这时候,Calico 的工作方式,可以用一幅示意图来描述,如下所示(在接下来的讲述中,我会统一用“BGP 示意图”来指代它):

其中的绿色实线标出的路径,就是一个 IP 包从 Node 1 上的 Container 1,到达 Node 2 上的 Container 4 的完整路径。可以看到,Calico 的 CNI 插件会为每个容器设置一个 Veth Pair 设备,然后把其中的一端放置在宿主机上(它的名字以 cali 前缀开头)。

此外,由于 Calico 没有使用 CNI 的网桥模式,Calico 的 CNI 插件还需要在宿主机上为每个容器的 Veth Pair 设备配置一条路由规则,用于接收传入的 IP 包。比如,宿主机 Node 2 上的 Container 4 对应的路由规则,如下所示:

10.233.2.3 dev cali5863f3 scope link
  • 1.

即:发往 10.233.2.3 的 IP 包,应该进入 cali5863f3 设备,就是每个带有IP的Pod运行在宿主机上,都会有一张calixxx网卡,用来完成宿主机与容器的veth-pair网络直连。

基于上述原因,Calico 项目在宿主机上设置的路由规则,肯定要比 Flannel 项目多得多。不过,Flannel host-gw 模式使用 CNI 网桥的主要原因,其实是为了跟 VXLAN 模式保持一致。否则的话,Flannel 就需要维护两套 CNI 插件了。

有了这样的 Veth Pair 设备之后,Calico不同宿主机之间Container网络通信为:
(1) 容器发出的 IP 包就会经过 Veth Pair 设备出现在宿主机上。
(2) 宿主机网络栈就会根据路由规则的下一跳 IP 地址,把它们转发给正确的网关/宿主机。
(3) 目的宿主机发出的 IP 包就会经过 Veth Pair 设备出现在目的容器上。

以上三个步骤中,最核心是第二步,这里的“下一跳”路由规则,就是由 Calico 的 Felix 进程负责维护的。这些路由规则信息,则是通过 BGP Client 也就是 BIRD 组件,使用 BGP 协议传输而来的。

而这些通过 BGP 协议传输的消息,你可以简单地理解为如下格式:

[BGP消息]
我是宿主机192.168.1.3
10.233.2.0/24网段的容器都在我这里
这些容器的下一跳地址是我
  • 1.
  • 2.
  • 3.
  • 4.

不难发现,Calico 项目实际上将集群里的所有节点,都当作是边界路由器来处理,它们一起组成了一个全连通的网络,互相之间通过 BGP 协议交换路由规则。这些节点,我们称为 BGP Peer。

需要注意的是,Calico 维护的网络在默认配置下,是一个被称为“Node-to-Node Mesh”的模式.这时候,每台宿主机上的 BGP Client 都需要跟其他所有节点的 BGP Client 进行通信以便交换路由信息。但是,随着节点数量 N 的增加,这些连接的数量就会以 N²的规模快速增长,从而给集群本身的网络带来巨大的压力。

所以,Node-to-Node Mesh 模式一般推荐用在少于 100 个节点的集群里。而在更大规模的集群中,你需要用到的是一个叫作 Route Reflector 的模式。在这种模式下,Calico 会指定一个或者几个专门的节点,来负责跟所有节点建立 BGP 连接从而学习到全局的路由规则。而其他节点,只需要跟这几个专门的节点交换路由信息,就可以获得整个集群的路由规则信息了。这些专门的节点,就是所谓的 Route Reflector 节点,它们实际上扮演了“中间代理”的角色,从而把 BGP 连接的规模控制在 N 的数量级上。

3.3 Calico 使用 BGP 来自动地在整个集群中分发路由信息

BGP 的全称是 Border Gateway Protocol,即:边界网关协议。它是一个 Linux 内核原生就支持的、专门用在大规模数据中心里维护不同的“自治系统”之间路由信息的、无中心的路由协议。这个概念可能听起来有点儿“吓人”,但实际上,我可以用一个非常简单的例子来为你讲清楚计算机网络中的基本概念——BGP协议。

在这个图中,我们有两个自治系统(Autonomous System,简称为 AS):AS 1 和 AS 2。而所谓的一个自治系统,指的是一个组织管辖下的所有 IP 网络和路由器的全体。你可以把它想象成一个小公司里的所有主机和路由器。在正常情况下,自治系统之间不会有任何“来往”。但是,如果这样两个自治系统里的主机,要通过 IP 地址直接进行通信,我们就必须使用路由器把这两个自治系统连接起来。

比如,AS 1 里面的主机 10.10.0.2,要访问 AS 2 里面的主机 172.17.0.3 的话。它发出的 IP 包,就会先到达自治系统 AS 1 上的路由器 Router 1。而在此时,Router 1 的路由表里,有这样一条规则,即:目的地址是 172.17.0.2 包,应该经过 Router 1 的 C 接口,发往网关 Router 2(即:自治系统 AS 2 上的路由器)。所以 IP 包就会到达 Router 2 上,然后经过 Router 2 的路由表,从 B 接口出来到达目的主机 172.17.0.3。

但是反过来,如果主机 172.17.0.3 要访问 10.10.0.2,那么这个 IP 包,在到达 Router 2 之后,就不知道该去哪儿了。因为在 Router 2 的路由表里,并没有关于 AS 1 自治系统的任何路由规则。解决方案:网络管理员就应该给 Router 2 也添加一条路由规则,比如:目标地址是 10.10.0.2 的 IP 包,应该经过 Router 2 的 C 接口,发往网关 Router 1。

像上面这样负责把自治系统连接在一起的路由器,我们就把它形象地称为:边界网关。它跟普通路由器的不同之处在于,它的路由表里拥有其他自治系统里的主机路由信息。

上面的这部分原理,相信你理解起来应该很容易。毕竟,路由器这个设备本身的主要作用,就是连通不同的网络。但是,你可以想象一下,假设我们现在的网络拓扑结构非常复杂,每个自治系统都有成千上万个主机、无数个路由器,甚至是由多个公司、多个网络提供商、多个自治系统组成的复合自治系统呢?这时候,如果还要依靠人工来对边界网关的路由表进行配置和维护,那是绝对不现实的。而这种情况下,BGP 大显身手的时刻就到了。

在使用了 BGP 之后,你可以认为,在每个边界网关上都会运行着一个小程序,它们会将各自的路由表信息,通过 TCP 传输给其他的边界网关,即程序取代网络管理员来自动更新每个 AS 的路由表信息。而其他边界网关上的这个小程序,则会对收到的这些数据进行分析,然后将需要的信息添加到自己的路由表里。这样,图 2 中 Router 2 的路由表里,就会自动出现 10.10.0.2 和 10.10.0.3 对应的路由规则了。

所以说,所谓 BGP,就是在大规模网络中实现节点路由信息共享的一种协议。

BGP 的程序自动更新每个自治系统AS的能力,正好可以取代 Flannel 维护主机上路由表的功能。而且,BGP 这种原生就是为大规模网络环境而实现的协议,其可靠性和可扩展性,远非 Flannel 自己的方案可比。

注意:BGP 协议实际上是最复杂的一种路由协议。我在这里的讲述和所举的例子,仅是为了能够帮助你建立对 BGP 的感性认识,并不代表BGP 真正的实现方式。

小结:对于BGP这种纯理论的知识,记住两点即可
(1) 分为不同多个独立的自治系统AS; 【calico项目中,每个k8s node就是一个AS】
(2) 程序取代网络管理员来自动更新每个 AS 的路由表信息。【calico项目中,通过 Felix 和 bird 来维护】
这两点就是BGP与实用相关的最显著的两个特点

3.4 IPIP模式在BGP模式中加上OuterIP Header

Calico要求集群宿主机之间是二层连通的:我们知道,Flannel host-gw 模式最主要的限制,就是要求集群宿主机之间是二层连通的。而这个限制对于 Calico 来说,也同样存在。

举个例子,假如我们有两台处于不同子网的宿主机 Node 1 和 Node 2,对应的 IP 地址分别是 192.168.1.2 和 192.168.2.2。需要注意的是,这两台机器通过路由器实现了三层转发,所以这两个 IP 地址之间是可以相互通信的。而我们现在的需求,还是 Container 1 要访问 Container 4。按照我们前面的讲述,Calico 会尝试在 Node 1 上添加如下所示的一条路由规则:

10.233.2.0/16 via 192.168.2.2 eth0
  • 1.

但是,这时候问题就来了。上面这条规则里的下一跳地址是 192.168.2.2,可是它对应的 Node 2 跟 Node 1 却根本不在一个子网里,没办法通过二层网络把 IP 包发送到下一跳地址。

在这种情况下,你就需要为 Calico 打开 IPIP 模式。

我把这个模式下容器通信的原理,总结成了一张图片,如下所示(接下来我会称之为:IPIP 示意图):

在 Calico 的 IPIP 模式下,Felix 进程在 Node 1 上添加的路由规则,会稍微不同,如下所示:

10.233.2.0/24 via 192.168.2.2 tunl0
  • 1.

可以看到,尽管这条规则的下一跳地址仍然是 Node 2 的 IP 地址,但这一次,要负责将 IP 包发出去的设备,变成了 tunl0。注意,是 T-U-N-L-0,而不是 Flannel UDP 模式使用的 T-U-N-0(tun0),这两种设备的功能是完全不一样的。

Calico 使用的这个 tunl0 设备,是一个 IP 隧道(IP tunnel)设备。

在上面的例子中,IP 包进入 IP 隧道设备之后,就会被 Linux 内核的 IPIP 驱动接管。IPIP 驱动会将这个 IP 包直接封装在一个宿主机网络的 IP 包中,如下所示:

其中,经过封装后的新的 IP 包的目的地址(图 5 中的 Outer IP Header 部分),正是原 IP 包的下一跳地址,即 Node 2 的 IP 地址:192.168.2.2。

而原 IP 包本身,则会被直接封装成新 IP 包的 Payload。这样,原先从容器到 Node 2 的 IP 包,就被伪装成了一个从 Node 1 到 Node 2 的 IP 包。

由于宿主机之间已经使用路由器配置了三层转发,也就是设置了宿主机之间的“下一跳”。所以这个 IP 包在离开 Node 1 之后,就可以经过路由器,最终“跳”到 Node 2 上。这时,Node 2 的网络内核栈会使用 IPIP 驱动进行解包,从而拿到原始的 IP 包。然后,原始 IP 包就会经过路由规则和 Veth Pair 设备到达目的容器内部。

以上,就是 Calico 项目主要的工作原理了。

不难看到,当 Calico 使用 IPIP 模式的时候,集群的网络性能会因为额外的封包和解包工作而下降。在实际测试中,Calico IPIP 模式与 Flannel VXLAN 模式的性能大致相当。所以,在实际使用时,如非硬性需求,我建议你将所有宿主机节点放在一个子网里,避免使用 IPIP。

3.5 生产部署

不过,通过上面对 Calico 工作原理的讲述,你应该能发现这样一个事实:如果 Calico 项目能够让宿主机之间的路由设备(也就是网关),也通过 BGP 协议“学习”到 Calico 网络里的路由规则,那么从容器发出的 IP 包,不就可以通过这些设备路由到目的宿主机了么?

比如,只要在上面“IPIP 示意图”中的 Node 1 上,添加如下所示的一条路由规则:

10.233.2.0/24 via 192.168.1.1 eth0
  • 1.

然后,在 Router 1 上(192.168.1.1),添加如下所示的一条路由规则:

10.233.2.0/24 via 192.168.2.1 eth0
  • 1.

那么 Container 1 发出的 IP 包,就可以通过两次“下一跳”,到达 Router 2(192.168.2.1)了。以此类推,我们可以继续在 Router 2 上添加“下一条”路由,最终把 IP 包转发到 Node 2 上。遗憾的是,上述流程虽然简单明了,但是在 Kubernetes 被广泛使用的公有云场景里,却完全不可行。

这里的原因在于:公有云环境下,宿主机之间的网关,肯定不会允许用户进行干预和设置。当然,在大多数公有云环境下,宿主机(公有云提供的虚拟机)本身往往就是二层连通的,所以这个需求也不强烈。

不过,在私有部署的环境下,宿主机属于不同子网(VLAN)反而是更加常见的部署状态。这时候,想办法将宿主机网关也加入到 BGP Mesh 里从而避免使用 IPIP,就成了一个非常迫切的需求。而在 Calico 项目中,它已经为你提供了两种将宿主机网关设置成 BGP Peer 的解决方案。

第一种方案,就是所有宿主机都跟宿主机网关建立 BGP Peer 关系。

这种方案下,Node 1 和 Node 2 就需要主动跟宿主机网关 Router 1 和 Router 2 建立 BGP 连接。从而将类似于 10.233.2.0/24 这样的路由信息同步到网关上去。需要注意的是,这种方式下,Calico 要求宿主机网关必须支持一种叫作 Dynamic Neighbors 的 BGP 配置方式。这是因为,在常规的路由器 BGP 配置里,运维人员必须明确给出所有 BGP Peer 的 IP 地址。考虑到 Kubernetes 集群可能会有成百上千个宿主机,而且还会动态地添加和删除节点,这时候再手动管理路由器的 BGP 配置就非常麻烦了。而 Dynamic Neighbors 则允许你给路由器配置一个网段,然后路由器就会自动跟该网段里的主机建立起 BGP Peer 关系。

不过,相比之下,我更愿意推荐第二种方案。
这种方案,**是使用一个或多个独立组件负责搜集整个集群里的所有路由信息,然后通过 BGP 协议同步给网关。**而我们前面提到,在大规模集群中,Calico 本身就推荐使用 Route Reflector 节点的方式进行组网。所以,这里负责跟宿主机网关进行沟通的独立组件,直接由 Route Reflector 兼任即可。更重要的是,这种情况下网关的 BGP Peer 个数是有限并且固定的。所以我们就可以直接把这些独立组件配置成路由器的 BGP Peer,而无需 Dynamic Neighbors 的支持。

当然,这些独立组件的工作原理也很简单:它们只需要 WATCH Etcd 里的宿主机和对应网段的变化信息,然后把这些信息通过 BGP 协议分发给网关即可。

纯三层网络方案包括两种:Fannel host-gw 模式和 Calico 。需要注意的是,在大规模集群里,三层网络方案在宿主机上的路由规则可能会非常多,这会导致错误排查变得困难。此外,在系统故障的时候,路由规则出现重叠冲突的概率也会变大。基于上述原因,如果是在公有云上,由于宿主机网络本身比较“直白”,一般会推荐更加简单的 Flannel host-gw 模式。但不难看到,在私有部署环境里,Calico 项目才能够覆盖更多的场景,并为你提供更加可靠的组网方案和架构思路。
小结:CNI插件选用:公有云 Flannel host-gw 模式;私有云 Calico 项目

四、安装Calico插件

方式1:通过helm安装Calico

官方文档:https://projectcalico.docs.tigera.io/getting-started/kubernetes/helm

# 添加源
helm repo add projectcalico https://projectcalico.docs.tigera.io/charts

# helm repo update  

# 下载
helm pull  projectcalico/tigera-operator --version v3.24.5
# 解压
tar -xf tigera-operator-v3.24.5.tgz

# 安装,默认命名空间:calico-system
helm install calico ./tigera-operator  --namespace tigera-operator --create-namespace

# 检查tigera-operator所有资源
kubectl get all -n tigera-operator
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

方式2:通过yaml文件安装

wget https://docs.projectcalico/manifests/calico.yaml
kubectl apply -f calico.yaml

# 查看
kubectl get all -n kube-system|grep calico
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

方式3:k8s flannel网络切换calico

步骤1:卸载flannel插件
### 1、查看已安装flannel信息
cat /etc/cni/net.d/10-flannel.conflist

### 2、删除flannel布署资源
kubectl delete -f kube-flannel.yml

### 3、清除flannel遗留信息,在集群各节点清理flannel网络的残留文件
ifconfig cni0 down
ip link delete cni0
ifconfig flannel.1 down
ip link delete flannel.1
rm -rf /var/lib/cni
rm -rf /etc/cni/net.d
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
步骤2:开始安装Calico插件
# 下载
wget https://docs.projectcalico/manifests/calico.yaml

# 安装
kubectl apply -f calico.yaml

# 查看
kubectl get all -n kube-system|grep calico

# 如果节点NotReady,重启以下容器或者kubelet试试
systemctl restart containerd docker
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.


无论使用哪种方式,最后安装的calico包括一个 deployment 和 一个deamonset

五、Calico高级特性

官方文档:https://projectcalico.docs.tigera.io/security/kubernetes-policy

calico相对于flannel,在完成作为一个cni插件实现Pod之间(同一Node和不同Node)通信的基本功能之后,还有两个额外特性,一个是网络策略Network Policy,一个是固定IP/固定IP组

关于网络策略,可以参考我这篇文章:【云原生】k8s 中的 hostNetwork 和 NetworkPolicy(网络策略)讲解与实战操作

5.1 网络策略

场景1:允许来自同一命名空间中的 Pod 的入口流量

允许来自同一命名空间中的 Pod 的入口流量,

在以下示例中,传入带有标签的 Pod 的 label color: red,仅当它们来自 pod 带有label color: red,才被允许转到80端口。

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-same-namespace
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: blue
  # 新增:允许来自同一命名空间中的 Pod 的入口流量 
  ingress:
  - from:
    - podSelector:
        matchLabels:
          color: red
    ports:
      - port: 80
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
场景2:允许来自不同命名空间中的 Pod 的入口流量

允许来自不同命名空间中的 Pod 的入口流量,

在以下示例中,仅当传入流量来自带有标签 color: red的 Pod 时,才允许传入流量,在带有标签的命名空间中带有标签shape: square,在端口上 80.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-same-namespace
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: blue
      
  ingress:
  - from:
    - podSelector:
        matchLabels:
          color: red
      namespaceSelector:
        matchLabels:
          shape: square
    ports:
    - port: 80
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

小结:两个场景的不同在于第二个场景多了一个

namespaceSelector:
    matchLabels:
      shape: square
  • 1.
  • 2.
  • 3.

就是允许来自不同命名空间的Pod的入口流量

5.2 固定Pod IP

给Pod设置固定IP

利用注解 cni.projectcalico/ipAddrs

# vi fixed-ip-test-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
  annotations:
    cni.projectcalico/ipAddrs: "[\"192.168.55.66\"]"
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

测试,看到固定IP,就说明成功了

首先,查看集群的默认 ippool ,这个 ippool 资源类型是 calico crd自定义的资源,在k8s官网找不到的

kubectl get ippool -A
kubectl get ippool default-ipv4-ippool -o yaml
  • 1.
  • 2.


对于 annotations: cni.projectcalico/ipAddrs: “[“192.168.55.66”]” ,无论是给Pod指定IP,还是给控制器Deployment中的一个Pod指定IP,都需要注意:
第一,yaml文件前面的空格使用键盘的 space 键敲击,而不是 tab 键,使用 tab 键,执行 kubectl apply -f xxx.yaml 会报格式错误;
第二,只能有一个指定的IP,指定多个IP报错,关键性日志查看可通过 kubectl describe pod pod-name 查看报错信息最后一行,为 more than one IP;
第三,这个指定的IP必须在已经存在的 ippool 192.168.0.0/16 的范围内,否则报错,关键性日志查看可通过 kubectl describe pod pod-name 查看报错信息最后一行。

给控制器设置固定IP(控制器中一个Pod)

利用注解 cni.projectcalico/ipAddrs

# vi fixed-ip-test-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fixed-ip-test
  namespace: default
  labels:
    k8s-app: cloudnativer-test
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: cloudnativer-test
  template:
    metadata:
      labels:
        k8s-app: cloudnativer-test
      annotations:
        cni.projectcalico/ipAddrs: "[\"10.244.1.220\"]"
    spec:
      containers:
      - name: fixed-ip-test
        image: nginx:1.7.9
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
  • 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.

测试,看到固定IP,就说明成功了

给控制器设置固定IP池(控制器中多个Pod)

需要创建额外IP池(除了默认IP池),利用注解cni.projectcalico/ipv4pools。

这里先安装一个客户端工具calicoctl

wget https://github/projectcalico/calico/releases/download/v3.24.5/calicoctl-linux-amd64
mv calicoctl-linux-amd64 /usr/local/bin/calicoctl 
chmod +x /usr/local/bin/calicoctl
  • 1.
  • 2.
  • 3.

编排

# vi fixed-ip-test-deployment2.yaml
# apiVersion: projectcalico/v3
apiVersion: crd.projectcalico/v1
kind: IPPool
metadata:
  name: new-pool1
spec:
  blockSize: 31
  cidr: 10.244.3.220/24
  ipipMode: Never
  natOutgoing: true
---
# apiVersion: projectcalico/v3
apiVersion: crd.projectcalico/v1
kind: IPPool
metadata:
  name: new-pool2
spec:
  blockSize: 31
  cidr: 10.244.4.221/24
  ipipMode: Never
  natOutgoing: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fixed-ip-test2
  namespace: default
  labels:
    k8s-app: cloudnativer-test
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      k8s-app: cloudnativer-test
  template:
    metadata:
      labels:
        k8s-app: cloudnativer-test
      annotations:
        # 【注意】不能使用单引号
        "cni.projectcalico/ipv4pools": "[\"new-pool1\",\"new-pool2\"]"
    spec:
      containers:
      - name: fixed-ip-test
        image: nginx:1.7.9
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
  • 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.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.

测试,看到固定IP,就说明成功了

# 查看ip池
calicoctl get ippool
kubectl get pods -owide
  • 1.
  • 2.
  • 3.

【温馨提示】要更改用于Pod的默认IP范围,请修改calico.yaml清单文件中CALICO_IPV4POOL_CIDR部分。

5.3 Calico VS Flannel

目前比较常用的是flannel和calico,flannel的功能比较简单,不具备复杂网络的配置能力,不支持网络策略;calico是比较出色的网络管理插件,单具备复杂网络配置能力的同时,往往意味着本身的配置比较复杂,所以相对而言,比较小而简单的集群使用flannel,考虑到日后扩容,未来网络可能需要加入更多设备,配置更多策略,则使用calico更好。

1)Flannel
优势:部署简单,性能一般。
劣势:没办法实现固定 IP 的容器漂移,没法做子网隔离,对上层设计依赖程度高,没有 IPAM , IP 地址浪费,对 Docker 启动方法有绑定。

2)Calico
Calico还以其先进的网络功能而闻名。网络策略是其最受追捧的功能之一。支持固定 IP 的配置。此外,Calico还可以与服务网格Istio集成,以便在服务网格层和网络基础架构层中解释和实施集群内工作负载的策略。这意味着用户可以配置强大的规则,描述Pod应如何发送和接受流量,提高安全性并控制网络环境。

两个插件使用的都比较广泛,如果需要设置网络策略NetworkPolicy,给Pod分配固定IP等,就建议使用Calico;如果只是简单的使用网络插件的通讯功能就选择Flannel。

六、尾声

本文中学到两个部分的内容:

第一,Flannel host-gw模式和 Calico 项目都是常用的CNI插件,都完成了 cni 插件实现 Pod之间 网络通信的功能(包括同一Node和不同Node)
(1) 是纯三层网络方案,route路由规则中的 网关的 IP 地址 正是目的容器所在宿主机的 IP 地址,和 Flannel host-gw模式一样;
(2) Calico不会在宿主机上创建任何网桥设备,取而代之的是每个使用虚拟IP的Pod都会有一个calixxx网卡,都会有一条路由规则。
(3) Calico 项目使用 BGP 来自动地在整个集群中分发路由信息。
(4) Calico可以在默认BGP模式下加上IPIP配置,用来实现不同网段之间Node的Pod之间通信。

第二,Calico除了完成基本的Pod之间网络通信的功能,还提供两个额外功能:给Pod提供NetworkPolicy网络策略、给Pod提供固定IP

问题1:Flannel host-gw模式和Calico项目都是使用纯三层网络架构,这个纯三层网络架构是什么意思?
回答:纯三层网络架构就是 Pure Layer 3, 其特点就是下一跳地址对应的正是我们的目的宿主机IP地址,即 <目的容器IP地址段> via <网关的IP地址> dev eth0 ,无论是Flannel host-gw模式 还是 Calico项目,说的就是这个意思。

问题2:calico两种模式:IPIP模式和BGP模式有什么区别?
回答:核心就是不同Node之间的Pod交互的时候,IPIP模式,在IP的基础上再套了一层IP, 就是在包含 源Pod IP - 目的Pod IP 的 IP Header 上再套一层 源机器IP-目的机器IP 的 Outer IP Header. 多出来的这一层是因为 Linux 在不同子网里面,要负责将 IP 包发出去的设备,由 eth0 变成了 tunl0。


原创作者: u_15287666 转载于: https://blog.51cto/u_15287666/11443750

本文标签: 网络 容器 特性 解决方案 高级