实验背景

新版本特性:

  • 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问题
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
#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 部署简单快速 具体可以参看官方文档

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 网络设备发布路由
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
#我们根据实际环境修改下
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编号。 (默认[])
  • 更多部署请自行查询
https://github.com/cloudnativelabs/kube-router/tree/master/daemonset

部署的nginx 测试服务

#
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

测试路由

[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                      


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

# 获取 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 路由

#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 路由

#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 路由

#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 邻居状态

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 参数一栏

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)```



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"

参考文献

  • 参考: https://github.com/cloudnativelabs/kube-router/tree/master/Documentation
  • 译文: https://rocdu.io/2017/12/%E8%AF%91kube-router-documentation/
  • 转载请注明出处谢谢:http://xuzeming.top/2018/01/09/Kube-router-%E5%AE%9E%E8%B7%B5-K8s-1-9-Kube-router/