how to config calico BGP

2020-08-22 17:50:33

默认为读者已经有一个运行正常的 Kubernetes 集群,并且采用 Calico 作为 CNI 组件,且 Calico 工作正常;同时应当在某个节点完成了 calicoctl 命令行工具的配置

BGP基本概念

动态路由协议可以按照工作范围分为IGP以及EGP。
IGP工作在同一个AS内,主要用来发现和计算路由,为AS内提供路由信息的交换;而EGP工作在AS与AS之间,在AS间提供无环路的路由信息交换。

BGP则是EGP的一种。边界网关协议BGP(Border Gateway Protocol)是一种实现自治系统AS(Autonomous System)之间的路由可达,并选择最佳路由的距离矢量路由协议。

AS(Autonomous system):自治系统,在一个实体管辖下的拥有相同选路策略的IP网络。BGP网络中的每个AS都被分配一个唯一的AS号,用于区分不同的AS。AS号分为2字节AS号和4字节AS号,其中2字节AS号的范围为1至65535,4字节AS号的范围为1至4294967295。支持4字节AS号的设备能够与支持2字节AS号的设备兼容

IGP(Interior Gateway Protocol):内部网关协议,在一个AS内部所使用的一种路由协议。一个AS内部也可以有多个路由器管理多个网络。各个路由器之间需要路由信息以知道子网络的可达信息。IGP就是用来管理这些路由。代表的实现有RIP和OSPF。

EGP(Exterior Gateway Protocol):外部网关协议,在多个AS之间使用的一种路由协议,但是EGP设计得比较简单,只发布网络可达的路由信息,而不对路由信息进行优选,同时也没有考虑环路避免等问题,很快就无法满足网络管理的要求。现在已经淘汰,被BGP取而代之

BGP按照运行方式分为EBGP(External/Exterior BGP)和IBGP(Internal/Interior BGP)
EBGP:运行于不同AS之间的BGP称为EBGP。为了防止AS间产生环路,当BGP设备接收EBGP对等体发送的路由时,会将带有本地AS号的路由丢弃。

IBGP:运行于同一AS内部的BGP称为IBGP。为了防止AS内产生环路,BGP设备不将从IBGP对等体学到的路由通告给其他IBGP对等体,并与所有IBGP对等体建立全连接。为了解决IBGP对等体的连接数量太多的问题,BGP设计了路由反射器(RR)和BGP联盟

BGP报文交互中的角色分为 Speaker 和 Peer 两种角色
Speaker:发送BGP报文的设备称为BGP发言者(Speaker),它接收或产生新的报文信息,并发布(Advertise)给其它BGP Speaker。

Peer:相互交换报文的Speaker之间互称对等体(Peer)。

BGP的Router ID是一个用于标识BGP设备的32位值,通常是IPv4地址的形式,在BGP会话建立时发送的Open报文中携带。对等体之间建立BGP会话时,每个BGP设备都必须有唯一的Router ID,否则对等体之间不能建立BGP连接。BGP的Router ID在BGP网络中必须是唯一的,可以采用手工配置,也可以让设备自动选取。缺省情况下,BGP选择设备上的Loopback接口的IPv4地址作为BGP的Router ID。如果设备上没有配置Loopback接口,系统会选择接口中最大的IPv4地址作为BGP的Router ID。一旦选出Router ID,除非发生接口地址删除等事件,否则即使配置了更大的地址,也保持原来的Router ID

在一个AS内部关于路由反射器有以下几种角色:

  • 路由反射器RR(Route Reflector):允许把从IBGP对等体学到的路由反射到其他IBGP对等体的BGP设备,类似OSPF网络中的DR。
  • 客户机(Client):与RR形成反射邻居关系的IBGP设备。在AS内部客户机只需要与RR直连。
  • 非客户机(Non-Client):既不是RR也不是客户机的IBGP设备。在AS内部非客户机与RR之间,以及所有的非客户机之间仍然必须建立全连接关系。
  • 始发者(Originator):在AS内部始发路由的设备。Originator_ID属性用于防止集群内产生路由环路。
  • 集群(Cluster):路由反射器及其客户机的集合。Cluster_List属性用于防止集群间产生路由环路。

路由反射器原理
同一集群内的客户机只需要与该集群的RR直接交换路由信息,因此客户机只需要与RR之间建立IBGP连接,不需要与其他客户机建立IBGP连接,从而减少了IBGP连接数量。

RR突破了“从IBGP对等体获得的BGP路由,BGP设备只发布给它的EBGP对等体。”的限制,并采用独有的Cluster_List属性和Originator_ID属性防止路由环路。RR向IBGP邻居发布路由规则如下:

  • 从非客户机学到的路由,发布给所有客户机。
  • 从客户机学到的路由,发布给所有非客户机和客户机(发起此路由的客户机除外)。
  • 从EBGP对等体学到的路由,发布给所有的非客户机和客户机

BGP联盟是解决AS内部的IBGP网络连接激增问题,除了使用路由反射器之外,还可以使用联盟(Confederation)。联盟将一个AS划分为若干个子AS。每个子AS内部建立IBGP全连接关系,子AS之间建立联盟EBGP连接关系,但联盟外部AS仍认为联盟是一个AS。配置联盟后,原AS号将作为每个路由器的联盟ID

Calico策略实践
  • BGP
  • RR (Route Reflector模式)
  • IPIP

BGP模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@node01 ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+----------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+----------------+-------------------+-------+----------+-------------+
| 172.17.207.194 | node-to-node mesh | up | 02:10:25 | Established |
| 172.17.207.195 | node-to-node mesh | up | 02:10:25 | Established |
+----------------+-------------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.

node-to-node mesh是BGP的全互连模式

[root@node01 ~]# ss -tan | grep 179
LISTEN 0 8 *:179 *:*
ESTAB 0 0 172.17.207.193:179 172.17.207.195:61815
ESTAB 0 0 172.17.207.193:179 172.17.207.194:28190

这种情况下节点数量越多,网络中的连接数就会成倍增加,而且在100个节点左右会遇到性能瓶颈
解决办法就是把其中的几个calico节点当做路由反射器(route reflector), 然后其他节点只需要把这几个节点当做对等体建立连接就可以。
路由器反射器会把传递过来的路由,在传递给其他节点,来实现路由交换

IPIP模式
calico默认为IPIP模式,如果有安全组策略需要开放TCP179端口;官方推荐使用在Node小于100的集群,IPIP模式能支撑了100-200规模的集群稳定运行

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@node01 ~]# calicoctl get ippool -o yaml
apiVersion: projectcalico.org/v3
items:
- apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
creationTimestamp: "2020-08-19T08:32:03Z"
name: default-ipv4-ippool
resourceVersion: "170581"
uid: c4d037b3-2542-4628-a18f-7c1636a039bb
spec:
blockSize: 26
cidr: 10.20.0.0/16
ipipMode: Always
natOutgoing: true
nodeSelector: all()
vxlanMode: Never
kind: IPPoolList
metadata:
resourceVersion: "972246"

[root@node01 ~]# calicoctl get ippool -o wide
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED SELECTOR
default-ipv4-ippool 10.20.0.0/16 true Always Never false all()

Route Reflector 模式

  • 关键配置

    1
    2
    3
    # 设置 CALICO_IPV4POOL_IPIP=“Never”,可以提高网络性能
    CALICO_IPV4POOL_IPIP: "Never"
    安装完成后会发现,网卡并未像开启IPIP那样生成tunl0网卡,而是通过物理网卡获取到各节点POD网段的路由,说明配置成功
  • 关闭 node-to-node BGP网格
    禁用node-to-node mesh的时候,网络立马就会断,因此断的话要提早作好影响的范围,也就是切换这个网络是须要断网的,使用node-to-node BGP这种也是建议100个节点如下,当超过100台节点必定要使用路由反射RR模式

    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

    查询默认节点ASN
    [root@node01 ~]# calicoctl get nodes -o wide
    NAME ASN IPV4 IPV6
    node01 (64512) 172.17.207.193/24
    node02 (64512) 172.17.207.194/24
    node03 (64512) 172.17.207.195/24

    #首先执行以下命令查看是否存在默认的 BGP 配置
    calicoctl get bgpconfig default
    #如果存在则将其保存为配置文件
    calicoctl get bgpconfig default -o yaml > bgp.yaml
    #修改其中的 spec.nodeToNodeMeshEnabled 为 false,然后进行替换
    calicoctl apply -f bgp.yaml

    #如果不存在则手动创建一个配置,然后应用
    cat << EOF | calicoctl create -f -
    apiVersion: projectcalico.org/v3
    kind: BGPConfiguration
    metadata:
    name: default
    spec:
    logSeverityScreen: Info
    nodeToNodeMeshEnabled: false
    asNumber: 64512
    EOF

    BGPConfiguration: BGPConfiguration是全局的配置资源。
    nodeToNodeMeshEnabled: 就是是否开启全互连模式。
    asNumber: as表示自治系统,asN自治系统编号。 默认是64512。 这里必须提供,不然asNumber好像就变成空了。
    64512-65535也是私有的ASN,不能出现在公网。ASN在外网是唯一的,由IANA 地址授权委员会统一分配, 不过在内网就无所谓了。官网的例子是63400,同样没问题


    [root@node01 calico]# calicoctl node status
    Calico process is running.

    IPv4 BGP status
    No IPv4 peers found.

    IPv6 BGP status
    No IPv6 peers found.
    应用以后, bgp之间的连接就断了,然后路由也没了,网络也断了
    如果把nodeToNodeMeshEnabled改为true再次应用,就会再次启用全互连模式,网络也会恢复
  • 创建对等规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [root@node01 calico]# cat rr.yml 
    kind: BGPPeer
    apiVersion: projectcalico.org/v3
    metadata:
    name: peer-to-rrs
    spec:
    nodeSelector: "!has(i-am-a-route-reflector)"
    peerSelector: has(i-am-a-route-reflector)
    ---
    kind: BGPPeer
    apiVersion: projectcalico.org/v3
    metadata:
    name: rr-mesh
    spec:
    nodeSelector: has(i-am-a-route-reflector)
    peerSelector: has(i-am-a-route-reflector)

    calicoctl create -f rr.yaml
  • 配置对等体
    为方便让BGPPeer轻松选择节点,经过标签选择器匹配,也就是能够去调用k8s里面的标签进行关联,给那个节点打个标签,我这将node1打上标签

    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
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    导出node02 node03配置
    [root@node01 calico]# calicoctl get node node03 --export -oyaml > node03.yml
    [root@node01 calico]# cat node03.yml
    apiVersion: projectcalico.org/v3
    kind: Node
    metadata:
    annotations:
    projectcalico.org/kube-labels: '{"beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/os":"linux","kubernetes.io/arch":"amd64","kubernetes.io/hostname":"node03","kubernetes.io/os":"linux"}'
    creationTimestamp: null
    labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/arch: amd64
    kubernetes.io/hostname: node03
    kubernetes.io/os: linux
    name: node03
    spec:
    bgp:
    ipv4Address: 172.17.207.195/24
    ipv4IPIPTunnelAddr: 10.20.186.192
    orchRefs:
    - nodeName: node03
    orchestrator: k8s
    status: {}

    # 增加标签,将rr标签置为true,也可以通过命令行添加kubectl label node  node03 i-am-a-route-reflector=true,标签名自己确定,前后一致就可以,
    # 增加标签,确保同一个反射簇配置ID一致,即node01与node02一致,用于冗余和防环
    [root@node01 calico]# cat node03.yml
    apiVersion: projectcalico.org/v3
    kind: Node
    metadata:
    annotations:
    projectcalico.org/kube-labels: '{"beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/os":"linux","kubernetes.io/arch":"amd64","kubernetes.io/hostname":"node03","kubernetes.io/os":"linux"}'
    creationTimestamp: null
    labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/arch: amd64
    kubernetes.io/hostname: node03
    kubernetes.io/os: linux
    i-am-a-route-reflector: true
    name: node03
    spec:
    bgp:
    ipv4Address: 172.17.207.195/24
    ipv4IPIPTunnelAddr: 10.20.186.192
    routeReflectorClusterID: 224.0.0.1
    orchRefs:
    - nodeName: node03
    orchestrator: k8s
    status: {}

    calicoctl apply -f node03.yml

    [root@node01 calico]# calicoctl apply -f rr.yml
    Successfully applied 2 'BGPPeer' resource(s)
    [root@node01 calico]# calicoctl node status
    Calico process is running.

    IPv4 BGP status
    +----------------+---------------+-------+----------+-------------+
    | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
    +----------------+---------------+-------+----------+-------------+
    | 172.17.207.195 | node specific | up | 16:21:43 | Established |
    +----------------+---------------+-------+----------+-------------+

    IPv6 BGP status
    No IPv6 peers found.


    calicoctl apply -f node02.yml
    [root@node01 calico]# calicoctl node status
    Calico process is running.

    IPv4 BGP status
    +----------------+---------------+-------+----------+-------------+
    | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
    +----------------+---------------+-------+----------+-------------+
    | 172.17.207.195 | node specific | up | 16:21:43 | Established |
    | 172.17.207.194 | node specific | up | 16:29:48 | Established |
    +----------------+---------------+-------+----------+-------------+

    IPv6 BGP status
    No IPv6 peers found.

    同时在非 RR 节点上使用 calicoctl node status 应该能看到以下输出
    [root@node02 bin]# calicoctl node status
    Calico process is running.

    IPv4 BGP status
    +----------------+---------------+-------+----------+-------------+
    | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
    +----------------+---------------+-------+----------+-------------+
    | 172.17.207.190 | node specific | up | 09:44:19 | Established |
    | 172.17.207.193 | node specific | up | 09:44:22 | Established |
    | 172.17.207.195 | node specific | up | 09:28:19 | Established |
    +----------------+---------------+-------+----------+-------------+

    IPv6 BGP status
    No IPv6 peers found.
  • 调整 IPIP 规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Calico IPIP 模式的三个可选项:
    Always: 永远进行 IPIP 封装(默认)
    CrossSubnet: 只在跨网段时才进行 IPIP 封装,适合有 Kubernetes 节点在其他网段的情况,属于中肯友好方案
    Never: 从不进行 IPIP 封装,适合确认所有 Kubernetes 节点都在同一个网段下的情况

    [root@node01 calico]#calicoctl get ippool default-ipv4-ippool -o yaml > ippool.yaml

    [root@node01 calico]# calicoctl get ippool default-ipv4-ippool -o yaml
    apiVersion: projectcalico.org/v3
    kind: IPPool
    metadata:
    creationTimestamp: "2020-08-19T08:32:03Z"
    name: default-ipv4-ippool
    resourceVersion: "170581"
    uid: c4d037b3-2542-4628-a18f-7c1636a039bb
    spec:
    blockSize: 26
    cidr: 10.20.0.0/16
    ipipMode: Always
    natOutgoing: true
    nodeSelector: all()
    vxlanMode: Never

修改 ipipMode 值为 CrossSubnet
重新使用 calicoctl apply -f ippool.yaml 应用既可

  • 增加路由联通网络
    1
    2
    3
    4
    5
    6
    在开发机器添加路由既可,将 Pod IP 10.20.0.0/16 和 Service IP 10.254.0.0/16 路由到 RR 节点 172.16.0.13
    # Pod IP
    ip route add 10.20.0.0/16 via 172.16.0.13
    # Service IP
    ip route add 10.254.0.0/16 via 172.16.0.13
    最省事的方法是在开发网络的路由上做,设置完成后就可以直连集群内的 Pod IP 和 Service IP,至于想直接访问 Service Name 只需要调整上游 DNS 解析
办公网络与k8s网络方案

网络环境假定如下:pod的ip是10.244.0.0/16这个网段,那么service是10.0.0.10/24,宿主机是172.17.0.0/24,那么办公网络是192.168.1.0/24

第一种状况,k8s集群测试环境在办公网络的子网里面,那么这个实现就比较简单了,只须要在子网中上层的路由器添加一个规则就好了,ip route add,目的IP为10.244.0.0/16,到达的下一跳via为其中的k8s节点,好比k8s-node1 dev 接口A
ip route add 10.244.0.0/16 via dev A
添加这么一个规则,办公网络就能直接访问k8s的节点,直接就能访问pod IP,也就是下一跳地址以后,就能直接访问都podIP了

第二种状况,k8s集群与办公网络在不一样VLAN中,不一样机房 前提是k8s集群与办公网络是互通的,三层可达

  • 方案1 在路由器上添加路由表,10.244.0.0/16
  • 方案2 采用BGP,若是三层的路由支持BGP协议的话,直接就可让路由器BGP与路由反射器BGP创建链接,这样的话路由器上的BGP就能获取到了k8s上的路由表信息了,而后通过下一跳来转发到目的的node的pod中

总结:只要是不一样vlan,必须是三层可达,能在上层的路由器上,访问集群的网段,pod网段仍是service网段,必定要告知它,帮它转发到下一跳是谁,下一跳若是是目的的节点,那就直接转发数据包。

网络策略

网络的限制也就是ACP访问控制,天然是有两个方向,一个是入口方向
使用network policy对Pod网络进行隔离。支持对Pod级别和Namespace级别网络访问控制。
Pod网络入口方向隔离

  • 基于Pod级网络隔离:只容许特定对象访问Pod(使用标签订义),容许白名单上的IP地址或者IP段访问Pod
  • 基于Namespace级网络隔离:多个命名空间,A和B命名空间Pod彻底隔离

Pod网络出口方向隔离

  • 拒绝某个Namespace上全部Pod访问外部
  • 基于目的IP的网络隔离:只容许Pod访问白名单上的IP地址或者IP段
  • 基于目标端口的网络隔离:只容许Pod访问白名单上的端口

BGP基础知识
BGP入门笔记
谐云Calico大规模场景落地实践
Calico 3.6 转发外部流量到集群 Pod
Calico配置双RR架构