Calico OpenShift

一、Calico 是什么

calico 是容器网络的一种解决方案,也是当前最流行的方案之一。和其他虚拟网络最大的不同是,它没有采用 overlay 网络做报文的转发,提供了纯 3 层的网络模型。三层通信模型表示每个容器都通过 IP 直接通信,中间通过路由转发找到对方。在这个过程中,容器所在的节点类似于传统的路由器,提供了路由查找的功能。

要想路由工作能够正常,每个虚拟路由器(容器所在的主机节点)必须有某种方法知道整个集群的路由信息,calico 采用的是BGP 路由协议,全称是 Border Gateway Protocol。

除了能用于 docker 这样的容器外,它还能集成到容器集群平台 OpenShift/kubernetes、公有云平台 AWS、GCE 等, 而且也能很容易地集成到 openstack 等 Iaas 平台。

二、Calico网络方式

2.1 IPIP模式

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

2.2 BGP模式

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

根据路由规则的同步方式,BGP模式也有两种方式,mesh模式与RR模式。

2.2.1 mesh 模式

mesh 模式又称为全互联模式,就是一个 BGP Speaker 需要与其它所有的 BGP Speaker 建立 bgp 连接(形成一个bgp mesh)。BGP Speaker越多,将会消耗越多的连接。所以它只能支持小规模集群,一般50-100为上限。

2.2.2 RR模式

RR模式,就是在网络中指定一个或多个 BGP Speaker 作为反射路由(Router Reflector),RR与所有的 BGP Speaker 建立 bgp 连接。每个BGP Speaker只与RR建立连接,交换路由信息就能获得全网的路由信息。Calico 中通过Global Peer来实现RR模式。

默认情况下,每个 calico 节点会和集群中其他所有节点建立 BGP peer 连接,也就是说这是一个 O(n^2) 的增长趋势。在集群规模比较小的情况下,这种模式是可以接受的,但是当集群规模扩展到百个节点、甚至更多的时候,这样的连接数无疑会带来很大的负担。为了解决集群规模较大情况下 BGP client 连接数膨胀的问题,calico 引入了 RR(Router Reflector) 的功能。

RR 的基本思想是选择一部分节点(一个或者多个)作为 Global BGP Peer,它们和所有的其他节点互联来交换路由信息,其他的节点只需要和 Global BGP Peer 相连就行,不需要之间再两两连接。更多的组网模式也是支持的,不管怎么组网,最核心的思想就是所有的节点能获取到整个集群的路由信息。

三、Calico组件和架构

calico 的工作有:

  • 分配和管理 IP
  • 配置上容器的 veth pair 和容器内默认路由
  • 根据集群网络情况实时更新节点上路由表

完成以上所有的功能,除了 etcd 保存了数据外,还在每个节点运行 了calico-node 容器。calico/node 这个容器运行了多个组件:

  • libnetwork plugin
  • BIRD
  • confd
  • felix

下图为Calico各组件之间的相互关系图。
Calico BGP

3.1 libnetwork plugin

libnetwork-plugin 是 calico 提供的 docker 网络插件,主要提供的是 IP 管理和网络管理的功能。

默认情况下,当网络中出现第一个容器时,calico 会为容器所在的节点分配一段子网(子网掩码为 /26,比如192.168.196.128/26),后续出现在该节点上的容器都从这个子网中分配 IP 地址。这样做的好处是能够缩减节点上的路由表的规模,按照这种方式节点上 2^6 = 64 个 IP 地址只需要一个路由表项就行,而不是为每个 IP 单独创建一个路由表项。节点上创建的子网段可以在etcd 中 /calico/ipam/v2/host//ipv4/block/ 看到。

calico 还允许创建容器的时候指定 IP 地址,如果用户指定的 IP 地址不在节点分配的子网段中,calico 会专门为该地址添加一个 /32 的网段。

3.2 BIRD

BIRD(BIRD Internet Routing Daemon) 是一个常用的网络路由软件,支持很多路由协议(BGP、RIP、OSPF等)。它会在每台宿主机上运行,calico 用它在实现主机间传播路由信息。

BIRD 对应的配置文件在 /etc/calico/confd/config/ 目录。

3.3 confd

confd是一个简单的配置管理工具。bird 的配置文件会根据用户设置的变化而变化,因此需要一种动态的机制来实时维护配置文件并通知 bird 使用最新的配置,这就是 confd 的工作。它会监听 etcd 的数据,用来更新 bird 的配置文件,并重新启动 bird 进程让它加载最新的配置文件。confd 的工作目录是 /etc/calico/confd,里面有三个目录:

  • conf.d:confd 需要读取的配置文件,每个配置文件告诉 confd 模板文件在什么,最终生成的文件应该放在什么地方,更新时要执行哪些操作等
  • config:生成的配置文件最终放的目录
  • templates:模板文件,里面包括了很多变量占位符,最终会替换成 etcd 中具体的数据
    具体的配置文件很多,以下是一个例子:
    1
    2
    3
    4
    5
    6
    7
    8
    / # cat /etc/calico/confd/conf.d/bird.toml
    [template]
    src = "bird.cfg.mesh.template"
    dest = "/etc/calico/confd/config/bird.cfg"
    prefix = "/calico/bgp/v1"
    keys = ["/host","/global"]
    check_cmd = "bird -p -c {{.src}}"
    reload_cmd = "pkill -HUP bird || true"
    它会监听 etcd 的 /calico/bgp/v1 路径,一旦发现更新,就用其中的内容更新模板文件 bird.cfg.mesh.template,把新生成的文件放在 /etc/calico/confd/config/bird.cfg,文件改变之后还会运行 reload_cmd 指定的命令重启 bird 程序。

3.4 felix

felix 负责最终网络相关的配置,也就是容器网络在 linux 上的配置工作,比如:

  • 更新节点上的路由表项
  • 更新节点上的 iptables 表项

它的主要工作是从 etcd 中读取网络的配置,然后根据配置更新节点的路由和 iptables,felix 的代码在 http://github.com/calico/felix

四、部署Calico BGP RR模式

4.1 安装Calico BGP网络插件

在之前的文章中已经分享过Calico BGP网络插件的部署过程。Openshift开启Calico BGP 与 OVS性能PK
安装完成后,Calico BGP默认使用的是Mesh模式。

4.2 开启RR模式

4.2.1 开启单RR部署(单个主机节点作为RR)

  1. 关闭当前Calico Mesh模式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@master calico]# cat << EOF | calicoctl create -f -
    apiVersion: projectcalico.org/v3
    kind: BGPConfiguration
    metadata:
    name: default
    spec:
    logSeverityScreen: Info
    nodeToNodeMeshEnabled: false
    asNumber: 63400
  2. 设置指定Node为RR,比如选择infra01_node为RR,“添加router-reflector标签,设置routeReflectorClusterID”。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@master calico]# calicoctl get node infra01_node  --export -o yaml  > infra01_node.yaml
    [root@master calico]# cat infra01_node.yaml
    apiVersion: projectcalico.org/v3
    kind: Node
    metadata:
    labels:
    i-am-a-route-reflector: "true"
    name: infra01_node
    spec:
    bgp:
    ipv4Address: 192.168.0.3/16
    routeReflectorClusterID: 224.0.0.1
    [root@master calico]# calico apply -f infra01_node.yaml
  3. 配置BGPPeer资源,告诉Node节点路由反射器。
    1
    2
    3
    4
    5
    6
    7
    8
    [root@master calico]# cat << EOF | calicoctl create -f -
    apiVersion: projectcalico.org/v3
    kind: BGPPeer
    metadata:
    name: peer-to-rrs
    spec:
    nodeSelector: !has(i-am-a-route-reflector)
    peerSelector: has(i-am-a-route-reflector)
  4. 查看bgppeer
    1
    2
    3
    [root@master1 calico]# calicoctl get bgppeers
    NAME PEERIP NODE ASN
    peer-to-rrs (global) 0
  5. 通过netstat命令查看节点间calico-node的连接
    1
    [root@master1 calico]# netstat -natp | grep bird
    可以看到非RR节点只与RR节点建立连接,而RR节点与所有节点建立连接。

4.2.2 多RR节点部署(多个主机节点作为RR)

当只有一个RR节点时,会有一定的风险。当该节点出现异常时,所有节点将无法获取路由,这将会影响到整个OpenShift集群的网络。所以需要考虑RR节点的高可用,一种最简单的方式就是设置多个RR节点。下面演示如何添加一个新RR节点。

  1. 参考4.2.1,选择infra02_node作为新的RR节点。与infra01_node设置同样的routeReflectorClusterID值。
  2. 额外添加一条新的BGPPeer资源
    1
    2
    3
    4
    5
    6
    7
    8
    [root@master calico]# cat << EOF | calicoctl create -f -
    apiVersion: projectcalico.org/v3
    kind: BGPPeer
    metadata:
    name: rr-mesh
    spec:
    nodeSelector: has(i-am-a-route-reflector)
    peerSelector: has(i-am-a-route-reflector)
  3. 查看bgppeer
    1
    2
    3
    4
    [root@master1 calico]# calicoctl get bgppeers
    NAME PEERIP NODE ASN
    peer-to-rrs (global) 0
    rr-mesh has(i-am-a-route-reflector) 0
    以上配置后,每个非RR节点会与所有RR节点建立连接,同时RR节点之间建立连接,RR节点间是一个双活的配置。

4.2.3 硬件设备RR节点部署(硬件交换机作为RR节点)

前提:硬件交换机支持BGP协议。

  1. 查看硬件交换机对应vlan IP。
    1
    2
    3
    4
    5
    6
    7
    8
    / Display current-configuration interface vlan 16
    interface Vlanif16
    ip address 192.168.16.251 255.255.255.0
    vrrp vrid 84 virtual-ip 192.168.16.253
    vrrp vrid 84 priority 150
    vrrp vrid 84 preempt-mode timer delay 20
    vrrp vrid 84 track interface XGigabitEthernet0/0/1 reduced 30
    vrrp vrid 84 track interface XGigabitEthernet0/0/2 reduced 30
  2. 在OpenShift集群关闭Calico mesh模式,并设置ASNumber。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@master calico]# cat << EOF | calicoctl create -f -
    apiVersion: projectcalico.org/v3
    kind: BGPConfiguration
    metadata:
    name: default
    spec:
    logSeverityScreen: Info
    nodeToNodeMeshEnabled: false
    asNumber: 63400
  3. 在OpenShift集群创建与硬件交换机的BGPPeer配置。
    1
    2
    3
    4
    5
    6
    7
    8
    [root@master calico]# cat << EOF | calicoctl create -f -
    apiVersion: projectcalico.org/v3
    kind: BGPPeer
    metadata:
    name: bgppeer-global
    spec:
    peerIP: 192.168.16.251
    asNumber: 63400
  4. 硬件交换机和NODE 在AS号63400 中,通过IBGP建立了对等体
    1
    2
    3
    4
    5
    / bgp 63400
    router-id 192.168.16.11
    peer 192.168.16.1 as-number 63400
    peer 192.168.16.2 as-number 63400
    peer 192.168.16.3 as-number 63400
  5. 硬件交换机的192.168.16.251 作为RR和NODE建立了BGP
    1
    2
    3
    4
    5
    6
    7
    8
    /  ipv4-family unicast
    undo synchronization
    peer 192.168.16.1 enable
    peer 192.168.16.1 reflect-client
    peer 192.168.16.2 enable
    peer 192.168.16.2 reflect-client
    peer 192.168.16.3 enable
    peer 192.168.16.3 reflect-client
  6. 在硬件交换机上查看bgp peer信息
    1
    2
    3
    4
    5
    6
    7
    8
    /  display  bgp peer 
    BGP local router ID : 192.168.16.11
    Local AS number : 63400
    Total number of peers : 3 Peers in established state : 3
    Peer V AS MsgRcvd MsgSent OutQ Up/Down State PrefRcv
    192.168.16.1 4 63400 26 29 0 00:19:34 Established 1
    192.168.16.2 4 63400 26 29 0 00:19:34 Established 1
    192.168.16.3 4 63400 22 22 0 00:16:27 Established 1
    BGP状态为established 表示已建立状态。
  7. 在硬件交换机上查看路由信息
    1
    2
    3
    4
    5
    6
    7
    /  display  bgp routing-table 
    BGP Local router ID is 192.168.16.11
    Total Number of Routes: 3
    Network NextHop MED LocPrf PrefVal Path/Ogn
    *>i 10.200.0.0/24 192.168.16.3 100 0 i
    *>i 10.200.1.0/24 192.168.16.2 100 0 i
    *>i 10.200.2.0/24 192.168.16.1 100 0 i
    并能通过NODE学到POD的地址段,从192.168.16.1学到10.200.2.0/24的路由,192.168.16.2学到10.200.1.0/24的路由,192.168.16.3学到10.200.0.0/24的路由。

五、Calico BGP管理工具calicoctl

管理calico网络需要使用calicoctl工具,该工具的配置可参考OpenShift/Kubernetes集群 Calico BGP管理工具calicoctl配置

  1. 查看calico节点状态
    1
    $ calicoctl node status
  2. 查看ip池
    1
    $ calicoctl get ipPool
  3. 查看node信息
    1
    2
    $ calicoctl get node -o wide
    $ calicoctl get node infra01_node -o yaml
  4. 创建新的资源
    1
    $ calicoctl create -f resource.yaml

补充

OpenShift Calico BGP网络模式下默认使用的是etcd存储,同时访问etcd的证书保存secret calico-etcd-secrets中。

1
2
$ oc get secret | grep calico-etcd-secrets
calico-etcd-secrets Opaque 3 205d

如果calico的存储etcd使用的正是OpenShift集群的etcd集群,那么当etcd的证书有更新时,请务必更新calico证书的内容,也就是更新该secret的内容,否则集群网络将无法为新的POD分配网络。

1
2
3
4
5
6
$ oc project kube-system
$ oc create secret generic calico-etcd-secrets \
--from-file=etcd-ca=/etc/etcd/ca.crt \
--from-file=etcd-cert=/etc/etcd/server.crt \
--from-file=etcd-key=/etc/etcd/server.key -o yaml \
--dry-run | oc apply -f -

参考文章

calico官方部署文档
calico官方配置案例
Calico官方架构文档
docker 容器网络方案:calico 网络模型
在私有云上运行Calico:IP互连网络结构
k8s使用calico网络
calico网络原理、组网方式和使用
Calico配置双RR架构