头部背景图片
今晚月色很美、你说是的 -- ZeMing |
今晚月色很美、你说是的 -- ZeMing |

[Kube-router 实践]K8s 1.9 Kube-router BGP外部对接发布内部路由 和 高可用

实验背景

新版本特性:

  • k8s 1.9 做了很大组件性能改进 ,
  • 本版本用kube-router组件取代kube-proxy,用lvs做svc负载均衡,更快稳定。
  • 用coredns取代kube-dns,DNS更稳定。
  • 经过测试1.9版,消除了以往的kubelet docker狂报错误日志的错误 ,更完美
  • 支持 add动态插件

功能需求:

  • 发布内部k8s网络,到机房全网
  • cluster-ip,external-ip 全网路由
  • 解决iptables 性能和负载聚合问题
  • 还有iptables 负载NAT 丢失源ip问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
k8s测试版本
kubeadm version: &version. GitVersion:"v1.9.0", BuildDate:"2017-12-15T20:55:30Z"
网络设备
Cisco 7200
R1 10.129.6.91
R2 10.129.6.92
Vrrp 10.129.6.8

K8s Node网络
node01 10.129.6.211
node03 10.129.6.213
K8s 网络
10.244.0.0/16
SVC 网络
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d
nginx01 ClusterIP 10.110.133.162 10.33.1.11 80/TCP 6d

网络拓扑如图:

image

  • 网络高可用,目前我的方案是
  • 双核心交换机跑VRRP
  • 模拟器,模拟网络设备拓扑 R1 R2 主备路由器
    image
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
#R1 Cisco Config

interface FastEthernet0/0
ip address 10.129.6.91 255.255.255.0
vrrp 1 ip 10.129.6.8
vrrp 1 priority 150

router bgp 64513
no synchronization
bgp log-neighbor-changes
neighbor 10.129.6.92 remote-as 64513
neighbor 10.129.6.211 remote-as 64512
neighbor 10.129.6.213 remote-as 64512
maximum-paths 2
no auto-summary

ip route 0.0.0.0 0.0.0.0 10.129.6.1

###############################
#R2 Cisco Config
interface FastEthernet0/0
ip address 10.129.6.92 255.255.255.0
vrrp 1 ip 10.129.6.8
vrrp 1 priority 110

router bgp 64513
no synchronization
bgp log-neighbor-changes
neighbor 10.129.6.92 remote-as 64513
neighbor 10.129.6.211 remote-as 64512
neighbor 10.129.6.213 remote-as 64512
maximum-paths 2
no auto-summary

ip route 0.0.0.0 0.0.0.0 10.129.6.1

部署k8s 1.9

此处省略,测试使用所以用
kubeadm 部署简单快速
具体可以参看官方文档

1
https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/

部署 kube-router

体系结构

Kube路由器是围绕观察者和控制器的概念而建立的。 观察者使用Kubernetes监视API来获取与创建,更新和删除Kubernetes对象有关的事件的通知。 每个观察者获取与特定API对象相关的通知。 在从API服务器接收事件时,观察者广播事件。 控制器注册以获取观察者的事件更新,并处理事件。
Kube-router由3个核心控制器和多个观察者组成,如下图所示。
image
主要改进

  • 使用ipvs 替代 Iptables 方案 -性能更好
  • 使用BGP 组网 更易发布和扩展对接 之前方案要使用caclio 其他方案
  • 集成police 网络策略 之前网络层控制很弱
  • 负载均衡 更多可选功能 如rr sip hash ip回话保持
    更多信息关注https://cloudnativelabs.github.io
deployment部署Yaml文件

在Kubernetes上部署Kube-router的最好的入门方法是使用集群安装程序.

  • kubeadm 部署Kube-router,比较简单就是导入yaml文件即可
    我们使用的是如下,为了对接Cisco 网络设备发布路由
1
2
3
wget https://github.com/cloudnativelabs/kube-router/blob/master/daemonset/kube-router-all-service-daemonset-advertise-routes.yaml

kubectl apply -f kube-router-all-service-daemonset-advertise-routes.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#我们根据实际环境修改下
containers:
- args:
- --run-router=true
#启用Pod网络 - 通过iBGP发布并学习到Pod的路由。 (默认为true)
- --run-firewall=true
#启用网络策略 - 设置iptables为pod提供入口防火墙。 (默认为true)
- --run-service-proxy=true
#启用服务代理 - 为Kubernetes服务设置IPVS。 (默认为true)
- --advertise-cluster-ip=true
#将该服务的集群IP添加到RIB,以便通告给BGP peers.
- --advertise-external-ip=true
#将服务的外部IP添加到RIB,以便将其通告给BGP peers.
- --cluster-asn=64512
#集群自身节点运行iBGP的ASN编号.
- --peer-router-ips=10.129.6.8
#所有节点将对等的外部路由器的IP地址,并通告集群ip和pod cidr。 (默认[])
- --peer-router-asns=64513
#集群节点将向其通告集群ip和节点的pid cidr的BGP peers的ASN编号。 (默认[])
  • 更多部署请自行查询
1
https://github.com/cloudnativelabs/kube-router/tree/master/daemonset

部署的nginx 测试服务

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
#
apiVersion: v1
kind: Service
metadata:
annotations:
kube-router.io/service.scheduler: sh
labels:
app: nginx01
group: default
role: master
tier: backend
name: nginx01
namespace: default
spec:
clusterIP: 10.110.133.162
externalIPs:
- 10.33.1.11
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx01
group: default
role: master
tier: backend
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx01
# these labels can be applied automatically
# from the labels in the pod template if not set
# labels:
# app: redis
# role: master
# tier: backend
namespace: default
spec:
# this replicas value is default
# modify it according to your case
replicas: 1
# selector can be applied automatically
# from the labels in the pod template if not set
# selector:
# matchLabels:
# app: guestbook
# role: master
# tier: backend
template:
metadata:
labels:
app: nginx01
role: master
tier: backend
group: default
spec:
containers:
- name: nginx01
image: devhub.beisencorp.com/test/nginx:v3 # or just image: redis
resources:
requests:
cpu: 100m
memory: 80Mi
limits:
cpu: 500m
memory: 200M
ports:
- 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
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
[root@node01 k8s]#kubectl get svc            
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d
nginx01 ClusterIP 10.110.133.162 10.33.1.11 80/TCP 6d
[root@node01 k8s]# curl 10.33.1.11
< !DOCTYPE html>
< html>
< head>
< meta charset="UTF-8">
< title> 主标题 | 副标题< /title>
< /head>
< body>
<p>Hello, world! 我是版本V1
My V2 e WorldZ</p>
<p>Hello, world! ^ ^ ^ ^ ^ ^ V1
My V2 Bye WorldZ</p>
<p>Hello, world! ^ ^ ^ ^ ^ ^ V1
My V2 Bye WorldZ</p>
<p>Hello, world! ^ ^ ^ ^ ^ ^ V1
My V2 Bye WorldZ</p>ZX
< /body>
< /html>


## 我们查看下 网络设备路由器信息是否学习过来
#BGP邻居已建立
R1#sh bgp sum
BGP router identifier 10.129.6.91, local AS number 64513
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.129.6.92 4 64513 147 146 25 0 0 02:16:05 6
10.129.6.211 4 64512 306 269 0 0 0 01:28:40 Active
10.129.6.213 4 64512 314 270 0 0 0 01:28:40 Active
R1#sh ip route
10.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
B 10.33.1.11/32 [200/0] via 10.129.6.92, 01:28:33
B 10.110.133.162/32 [200/0] via 10.129.6.92, 01:28:33
B 10.96.0.10/32 [200/0] via 10.129.6.92, 01:28:33
B 10.96.0.1/32 [200/0] via 10.129.6.92, 01:28:33
C 10.129.6.0/24 is directly connected, FastEthernet0/0
B 10.244.0.0/24 [200/0] via 10.129.6.211, 01:28:33
B 10.244.1.0/24 [200/0] via 10.129.6.213, 01:28:33
S* 0.0.0.0/0 [1/0] via 10.129.6.1

#R2 同上类同 R2备节点从R1主节点 学习全网路由


### 我们在看下 kube-router邻居和路由是否学习过来
Here's a quick look at what's happening on this Node
--- BGP Server Configuration ---
AS: ======64512======
Router-ID: 10.129.6.211
Listening Port: 179, Addresses: 0.0.0.0, ::

--- BGP Neighbors ---
Peer AS Up/Down State |#Received Accepted
10.129.6.8 64513 00:00:15 Establ | 6 0
10.129.6.213 64512 03:40:40 Establ | 1 1

--- BGP Route Info ---
Network Next Hop AS_PATH Age Attrs
*> 10.33.1.11/32 10.129.6.211 00:00:58 [{Origin: i}]
*> 10.96.0.1/32 10.129.6.211 00:00:58 [{Origin: i}]
*> 10.96.0.10/32 10.129.6.211 00:00:58 [{Origin: i}]
*> 10.110.133.162/32 10.129.6.211 00:00:58 [{Origin: i}]
*> 10.244.0.0/24 10.129.6.211 00:00:58 [{Origin: i}]
*> 10.244.1.0/24 10.129.6.213 03:40:40 [{Origin: i} {LocalPref: 100}]

--- IPVS Services ---
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.33.1.11:80 sh
-> 10.244.1.16:80 Masq 1 0 0
TCP 10.96.0.1:443 rr persistent 10800
-> 10.129.6.211:6443 Masq 1 0 0
TCP 10.96.0.10:53 rr
-> 10.244.0.13:53 Masq 1 0 0
TCP 10.110.133.162:80 sh
-> 10.244.1.16:80 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 10.244.0.13:53 Masq 1 0 0


NAME

我们找台机器加下静态路由 指向网络设备测试下 访问

1
2
3
4
5
6
7
8
# 获取 SVC 和pod ip
[root@node01 k8s]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d <none>
nginx01 ClusterIP 10.110.133.162 10.33.1.11 80/TCP 6d app=nginx01,group=default,role=master,tier=backend
[root@node01 k8s]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx01-d87b4fd74-7tw2x 1/1 Running 0 6d 10.244.1.16 node03

ClusterIP 路由

1
2
3
4
5
6
7
#ClusterIP 路由
route add -net 10.96.0.0 netmask 255.255.0.0 gw 10.129.6.8

ping 10.96.0.1
64 bytes from 10.96.0.1: icmp_seq=2 ttl=64 time=38.2 ms
64 bytes from 10.96.0.1: icmp_seq=3 ttl=64 time=0.258 ms
64 bytes from 10.96.0.1: icmp_seq=4 ttl=64 time=0.374 ms

external-ip 路由

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
#external-ip 路由
route add -net 10.33.1.11 netmask 255.255.255.255 gw 10.129.6.8

[root@haproxy02 zeming]# ping 10.33.1.11
PING 10.33.1.11 (10.33.1.11) 56(84) bytes of data.
From 10.129.6.8: icmp_seq=1 Redirect Host(New nexthop: 10.129.6.211)
64 bytes from 10.33.1.11: icmp_seq=1 ttl=64 time=41.4 ms
^C
--- 10.33.1.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 755ms
rtt min/avg/max/mdev = 41.459/41.459/41.459/0.000


# 获取页面
[root@haproxy02 zeming]# curl 10.33.1.11
< !DOCTYPE html>
< html>
< head>
< meta charset="UTF-8">
< title> 主标题 | 副标题< /title>
< /head>
< body>
<p>Hello, world! 我是版本V1
My V2 e WorldZ</p>
<p>Hello, world! ^ ^ ^ ^ ^ ^ V1
My V2 Bye WorldZ</p>
<p>Hello, world! ^ ^ ^ ^ ^ ^ V1
My V2 Bye WorldZ</p>
<p>Hello, world! ^ ^ ^ ^ ^ ^ V1
My V2 Bye WorldZ</p>ZX
< /body>
< /html>

pod 路由

1
2
3
4
5
6
7
#pod 路由
route add -net 10.244.0.0 netmask 255.255.0.0 gw 10.129.6.8

[root@haproxy02 xuzeming]# ping 10.244.0.13
PING 10.244.0.13 (10.244.0.13) 56(84) bytes of data.
64 bytes from 10.244.0.13: icmp_seq=1 ttl=63 time=41.8 ms
64 bytes from 10.244.0.13: icmp_seq=2 ttl=63 time=1.15 ms

主备网络设备BGP 切换测试

  • 测试方式 关闭R1主节点网络设备 互联网口 制造 R1离线
  • 观察 Vrrp 状态转移到备机
  • 观察 BGP 备机 建立所有mesh 邻居状态
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

R2#
*Mar 1 02:58:09.451: %VRRP-6-STATECHANGE: Fa0/0 Grp 1 state Backup -> Master
R10#
*Mar 1 02:58:46.415: %BGP-5-ADJCHANGE: neighbor 10.129.6.211 Up
R10#
*Mar 1 02:58:53.007: %BGP-5-ADJCHANGE: neighbor 10.129.6.213 Up

#
R10#sh ip rou
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
ia - IS-IS inter area, * - candidate default, U - per-user static route
o - ODR, P - periodic downloaded static route

Gateway of last resort is 10.129.6.1 to network 0.0.0.0

10.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
B 10.33.1.11/32 [20/0] via 10.129.6.213, 00:00:19
[20/0] via 10.129.6.211, 00:00:25
B 10.110.133.162/32 [20/0] via 10.129.6.213, 00:00:19
[20/0] via 10.129.6.211, 00:00:25
B 10.96.0.10/32 [20/0] via 10.129.6.213, 00:00:19
[20/0] via 10.129.6.211, 00:00:25
B 10.96.0.1/32 [20/0] via 10.129.6.213, 00:00:19
[20/0] via 10.129.6.211, 00:00:27
C 10.129.6.0/24 is directly connected, FastEthernet0/0
B 10.244.0.0/24 [20/0] via 10.129.6.211, 00:00:27
B 10.244.1.0/24 [20/0] via 10.129.6.213, 00:00:21
S* 0.0.0.0/0 [1/0] via 10.129.6.1

R10#sh bgp sum
BGP router identifier 10.129.6.92, local AS number 64513
BGP table version is 69, main routing table version 69
6 network entries using 702 bytes of memory
10 path entries using 520 bytes of memory
4 multipath network entries and 8 multipath paths
3/1 BGP path/bestpath attribute entries using 372 bytes of memory
1 BGP AS-PATH entries using 24 bytes of memory
0 BGP route-map cache entries using 0 bytes of memory
0 BGP filter-list cache entries using 0 bytes of memory
BGP using 1618 total bytes of memory
BGP activity 6/0 prefixes, 64/54 paths, scan interval 60 secs

Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
10.129.6.91 4 64513 187 194 0 0 0 00:00:33 Active
10.129.6.211 4 64512 683 364 69 0 0 00:02:38 5
10.129.6.213 4 64512 688 362 69 0 0 00:02:32 5

补充拓展

kube-router 参数一栏

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
Usage of ./kube-router:
--advertise-cluster-ip 将该服务的集群IP添加到RIB,以便通告给BGP peers.
--advertise-external-ip 将服务的外部IP添加到RIB,以便将其通告给BGP peers.
--cleanup-config 清理iptables规则,ipvs,ipset配置并退出.
--cluster-asn uint 集群节点运行iBGP的ASN编号.
--cluster-cidr string 群集中的CIDR范围。它被用来识别pods的范围.
--config-sync-period duration apiserver配置同步之间的延迟(例如“5s”,“1m”)。必须大于0.(默认1m0s)
--enable-overlay 当enable-overlay设置为true时,IP-in-IP隧道将用于跨不同子网中节点的pod-pod联网。如果设置为false,则不使用隧道,并且路由基础架构预计为不同子网中的节点之间的pod-pod联网路由流量(默认值为true)
--enable-pod-egress 从Pod到群集外的SNAT流量。 (默认为true)
--hairpin-mode 为每个服务端点添加iptable规则以支持流量管控.
-h, --help 打印使用信息.
--hostname-override string 覆盖节点的NodeName。如果kube-router无法自动确定您的NodeName,请设置此项.
--iptables-sync-period duration iptables规则同步之间的延迟(例如'5s','1m')。必须大于0.(默认1m0s)
--ipvs-sync-period duration ipvs config同步之间的延迟(例如'5s','1m','2h22m')。必须大于0.(默认1m0s)
--kubeconfig string 具有授权信息的kubeconfig文件的路径(主位置由主标志设置)。
--masquerade-all SNAT所有流量到群集IP /节点端口。
--master string Kubernetes API服务器的地址(覆盖kubeconfig中的任何值)。
--nodeport-bindon-all-ip 对于NodePort类型的服务,创建监听节点的所有IP的IPVS服务.
--nodes-full-mesh 集群中的每个节点都将建立与其他节点的BGP对等关系。 (默认为true)
--peer-router-asns uintSlice 集群节点将向其通告集群ip和节点的pid cidr的BGP peers的ASN编号。 (默认[])
--peer-router-ips ipSlice 所有节点将对等的外部路由器的IP地址,并通告集群ip和pod cidr。 (默认[])
--peer-router-passwords stringSlice 用“--peer-router-ips”定义的BGP peers进行认证的密码。
--routes-sync-period duration 路线更新与广播之间的延迟(例如“5s”,“1m”,“2h22m”)。必须大于0.(默认1m0s)
--run-firewall 启用网络策略 - 设置iptables为pod提供入口防火墙。 (默认为true)
--run-router 启用Pod网络 - 通过iBGP发布并学习到Pod的路由。 (默认为true)
--run-service-proxy 启用服务代理 - 为Kubernetes服务设置IPVS。 (默认为true)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

### DSR模式


请阅读以下博客,了解如何结合使用DSR和“–advertise-external-ip”构建高度可扩展和可用的入口。 https://cloudnativelabs.github.io/post/2017-11-01-kube-high-available-ingress/
您可以为每个服务启用DSR(直接服务器返回)功能。当启用的服务端点将直接响应客户端通过签署服务代理。启用DSR时,Kube-router将使用LVS的隧道模式来实现此功能。
要启用DSR,您需要使用kube-router.io/service.dsr = tunnel注释来注释服务。例如,

kubectl annotate service my-service "kube-router.io/service.dsr=tunnel"
在当前的实现中,当在服务上应用注释时,DSR将仅适用于外部IP。
此外,当使用DSR时,当前的实现不支持端口重新映射。所以你需要使用相同的端口和目标端口的服务
你需要在kube-router守护进程清单中启用hostIPC:true和hostPID:true。并且必须将主路径/var/run/docker.sock设置为kube-router的一个volumemount。
上述更改需要kube-router输入pod namespace,并在pod中创建ipip隧道,并将外部IP分配给VIP。
对于示例清单,请查看启用DSR要求的[manifest](../ daemonset / kubeadm-kuberouter-all-features-dsr.yaml).


### 负载均衡调度算法
kube-router使用LVS作为服务代理。 LVS支持丰富的调度算法。您可以为该服务添加注释以选择一个调度算法。当一个服务没有注释时,默认情况下选择“轮询”调度策略

For least connection scheduling use:
kubectl annotate service my-service “kube-router.io/service.scheduler=lc”
For round-robin scheduling use:
kubectl annotate service my-service “kube-router.io/service.scheduler=rr”
For source hashing scheduling use:
kubectl annotate service my-service “kube-router.io/service.scheduler=sh”
For destination hashing scheduling use:
kubectl annotate service my-service “kube-router.io/service.scheduler=dh”
```
参考文献