基于 F5 和 Cilium 的 Kubernetes 集群网络架构设计

2021-01-12 11:25:10 浏览数 (1)


Kubernetes 的重要性和火爆程度已无需多言,但各公司风格迥异的 IT 基础环境必然催生出各式各样的 Kubernetes 集群架构方案,这对整个生态的发展未尝不是一件好事。今天我们主要聊聊网络,集群网络系统是 Kubernetes 的核心部分,得益于 Kubernetes 灵活的接口设计,现在已有许多成熟方案和使用案例,比如 Calico,Flannel,Kube-router等。

Cilium 是一款为大规模和高度动态的容器环境而设计,基于 eBPF 的灵活、高性能网络插件,相比更流行的 Calico 和 Flannel,Cilium 出现的时间相对较晚,大规模应用案例也比前两者少。但是,由于 Cilium 基于 eBPF 和 XDP 设计,其处理数据包的速度更快,配置灵活度也更高。具体可查看 https://cilium.io/blog/2020/11/10/ebpf-future-of-networking/

在传统数据中心网络中,F5(本文特指 F5 BIG-IP LTM 设备)是非常重要的网络设备,其优秀的性能和超高的稳定性可以很好的保证服务质量(当然也很贵)。近几年,云原生发展迅速,原来主要为传统数据中心服务的 F5 公司也是紧跟时代脚步,推出了 F5 BIP-IP 云版本,还收购了软件负载均衡的大哥 Nginx,当然还有本文要介绍的 F5 Container Ingress Services(CIS)。

接下来就具体介绍下如何基于 F5 和 Cilium 构建 Kubernetes 集群网络系统(适合对 F5 有一定了解的朋友阅读)。

Cilium

无论有没有 F5, Cilium 都可以作为 CNI 插件部署到 Kubernetes 集群中。Cilium 支持 Overlay 和 Native Routing 两种网络模型:Overlay 基于 VXLAN 或者 Geneve 格式的封装,这种模式对网络基础设施的要求最低,只需要节点之间可以相互通信即可,Native Routing 支持 Cilium 节点通过 BIRD 运行 BGP 路由协议,将 Pod 的 IP 网段宣告到数据中心网络中。为了与 F5 直接通信,这里我们选择 Native Routing 模型。

网络接口

Cilium 会在主机网络空间创建三个虚拟接口:cilium_host,cilium_net 和 cilium_vxlan。cilium agent 在启动时会创建一个名为 "cilium_host -- cilium_net" 的虚拟链接对,并将 CIDR 的第一个 IP 地址分配给 cilium_host,之后该节点上的 Pod 都以 cilium_host 的地址作为网关。创建 Pod 时,在主机网络空间上创建带有 "lxc-xx" 的 veth 接口,另一端连接到 Pod 名称空间,cilium agent 安装所需的 BPF 程序以回复 ARP 请求,lxc-xx 接口的 MAC 地址用于 ARP 应答。Pod 生成的流量的下一个 L3 跳是cilium_host,而 Pod 生成的流量的下一个 L2 跳是 veth 对的主机端,cilium_vxlan 接口用于跨节点的 Pod 间的通信,cilium 使用 BPF 进行 LWT(轻型隧道)封装,将Pod跨节点通信的所有网络数据包都封装在标头中,该标头可以由 VXLAN 或 Geneve 帧组成,并通过标准 UDP 数据包标头进行传输。如果想要禁用 vxlan,在 helm 部署 cilium 时加上--set global.tunnel=disabled参数即可。

部署命令

代码语言:javascript复制
helm install cilium cilium/cilium --version 1.8.4 
--namespace kube-system 
--set config.ipam=kubernetes 
--set native-routing-cidr=<no_masquerade_ip_segment> 
--set global.ipMasqAgent.enabled=true 
--set global.kubeProxyReplacement=strict 
--set global.k8sServiceHost=<your_apiserver_ip> 
--set global.k8sServicePort=6443

参数说明:

  • config.ipam=kubernetes:使用 kubeadm 定义的 Pod 和 Service 网段
  • native-routing-cidr=<no_masquerade_ip_segment>:指定不做 Masquerade 的网段
  • global.ipMasqAgent.enabled=true:可以通过配置 ConfigMap 动态更改 Cilium 的 Masquerade 策略
  • global.k8sServiceHost:指定API Server 的 IP ,在禁用 kube-proxy 的情况下显式指定
  • global.k8sServicePort:指定API Server的端口
  • global.kubeProxyReplacement=strict:在缺少底层 Linux 内核支持的情况下,cilium agent 将会退出,而不会使用 kube-proxy 来代替

这里详细介绍下 Cilium Masquerade 策略。

默认情况下,Pod 发往集群外的流量(不管是 Pod 主动发起的,还是集群外部主动发起的流量)都会通过 Cilium 进行地址伪装(Masquerade),将 Pod 地址转换为节点地址,而想要让 F5 直接发送流量给 Pod,则需要设置 Cilium 转发给 F5 SNAT Pool、相关的核心交换机和 F5 健康检查地址的流量不使用地址伪装。

使用 agent-config/config 文件配置与native-routing-cidr作用相同:

代码语言:javascript复制
nonMasqueradeCIDRs:
# LinkLocal地址
- 
#F5 SNAT Pool地址
-
#核心交换机地址
-
# F5健康检查地址
-
masqLinkLocal: false

BIRD 配置

Bird 是一个类 UNIX 系统的动态路由守护进程,它支持当代互联网中所有路由协议,如 BGP、OSPF、RIP 等。在集群所有节点以守护进程形式部署 BIRD 动态路由软件,使用 BIRD 和核心交换机建立 BGP 全互联邻居,从而将 Pod 的 IP 网段的路由宣告给核心交换机,F5通过核心交换机学到 Pod 网段的路由,从而可以将流量直接转发给 Pod,达到了流量分发的目的。

BIRD 配置:

代码语言:javascript复制
log syslog all;

router id <节点IP>;

protocol device {
        scan time 10;           # Scan interfaces every 10 seconds
}

# Disable automatically generating direct routes to all network interfaces.
protocol direct {
        disabled;               # Disable by default
}

# Forbid synchronizing BIRD routing tables with the OS kernel.
protocol kernel {
        ipv4 {                    # Connect protocol to IPv4 table by channel
                import none;      # Import to table, default is import all
                export none;      # Export to protocol. default is export none
        };
}

# Static IPv4 routes.
protocol static {
      ipv4;
      route <pod_cidr> via "cilium_host"; 
}

# BGP peers
protocol bgp uplink0 {
      description "BGP uplink 0";
      local <节点IP> as <BGP AS号>;
      neighbor <核心交换机IP> as <BGP AS号>;
      ipv4 {
              import filter {reject;};
              export filter {accept;};
      };
}

protocol bgp uplink1 {
      description "BGP uplink 1";
      local <节点IP> as <BGP AS号>;
      neighbor <核心交换机IP> as <BGP AS号>;
      ipv4 {
              import filter {reject;};
              export filter {accept;};
      };
}

核心交换机配置:

核心交换机和每个节点建立全互联BGP邻居

代码语言:javascript复制
router bgp <BGP AS号>
  neighbor <节点IP> remote-as <BGP AS号>
    update-source loopback0
    address-family ipv4 unicast
.....

正常情况下交换机可以学到Pod网段的路由

代码语言:javascript复制
# show ip route bgp 
IP Route Table for VRF "default"
'*' denotes best ucast next-hop
'**' denotes best mcast next-hop
'[x/y]' denotes [preference/metric]
'%<string>' in via output denotes VRF <string>

23.3.0.0/24, ubest/mbest: 1/0
    *via 11.8.38.43, [200/0], 3w4d, bgp-64512, internal, tag 64512, 
23.3.1.0/24, ubest/mbest: 1/0
    *via 11.8.37.57, [200/0], 3w4d, bgp-64512, internal, tag 64512, 
23.3.2.0/24, ubest/mbest: 1/0
    *via 11.8.36.66, [200/0], 3w4d, bgp-64512, internal, tag 64512, 
23.3.3.0/24, ubest/mbest: 1/0
    *via 11.8.83.11, [200/0], 3w4d, bgp-64512, internal, tag 64512, 
23.3.4.0/24, ubest/mbest: 1/0
    *via 11.8.84.13, [200/0], 3w4d, bgp-64512, internal, tag 64512, 
23.3.5.0/24, ubest/mbest: 1/0
    *via 11.8.84.12, [200/0], 3w4d, bgp-64512, internal, tag 64512,

F5 BIG-IP Container Ingress Services(CIS)

对于有外部访问的服务,需要在 Kubernetes 集群中以 Deployment 形式部署 F5 官方提供的插件 k8s-bigip-ctlr 作为 F5 在集群中的 agent。CIS 作为一个重要控制平面,监控着 API Server 并根据配置信息自动的配置 F5 BIG-IP,CIS 以 Pod 的方式运行在集群环境中,完美地融合进集群网络,让F5 Service 类似一个原生的 Kubernetes Service 监控着 Pod 资源并对外提供服务。

BIG-IP Controller Modes

--pool-member-type选项决定了 CIS 运行的模式,有两种模式可选:NodePort 和 Cluster。

NodePort 模式是 CIS 默认运行的模式,该模式更容易设置,只需要 BIG-IP 与 集群节点能够通信即可,但是该模式有几点限制:

  • Kubernetes Service 必须使用 NodePort 模式
  • F5 BIG-IP 无法对隐藏在 Service 后的 Pod 做感知和健康检查
  • 增加网络延迟

由此我们选择了 CIS 的 Cluster 模式,让 F5 BIG-IP 可以直接对 Pod 做健康检查和流量转发,使用Cluster 模式的前提是需要打通 BIG-IP 到集群中 Pod 的通信。

默认情况下,CIS 使用 BIG-IP Automap SNAT 为所有通过 CIS 创建的 Virtual Service 做客户端的源地址转换,通过--vs-snat-pool-name=K8S-SNAT-POOL为 K8S 集群单独指定 SNAT POOL。

CIS 部署

部署之前在 F5 BIG-IP 上为 K8S 集群新建一个名为 K8S 的 partition,通过 PodAntiAffinity 将主备两台 F5 BIG-IP 对应的 F5 CIS 调度到不同的节点中,使用 SNAT-vlan130 地址池中的地址作为负载均衡时 F5 SNAT 的地址。

代码语言:javascript复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-bigip-ctlr-standby-clusterip
  namespace: kube-system
spec:
  # DO NOT INCREASE REPLICA COUNT
  replicas: 1
  selector:
    matchLabels:
      app: k8s-bigip-ctlr-standby
  template:
    metadata:
      name: k8s-bigip-ctlr-standby
      labels:
        app: k8s-bigip-ctlr-standby
    spec:
      affinity:
          PodAntiAffinity:
             preferredDuringSchedulingIgnoredDuringExecution:
             - weight: 1
               PodAffinityTerm:
                 labelSelector:
                     matchExpressions:
                      - key: app
                        operator: In
                        values:
                        - k8s-bigip-ctlr-active
                 topologyKey: "kubernetes.io/hostname"
      # Name of the Service Account bound to a Cluster Role with the required
      # permissions
      serviceAccountName: bigip-ctlr
      containers:
        - name: k8s-bigip-ctlr-standby
          image: f5networks/k8s-bigip-ctlr:latest
          env:
            - name: BIGIP_USERNAME
              value: F5 BIG-IP用户名
            - name: BIGIP_PASSWORD
              value: F5 BIG-IP密码
          command: ["/app/bin/k8s-bigip-ctlr"]
          args: [
            # See the k8s-bigip-ctlr documentation for information about
            # all config options
            # https://clouddocs.f5.com/products/connectors/k8s-bigip-ctrl/latest
            "--bigip-username=F5 BIG-IP用户名",
            "--bigip-password=F5 BIG-IP密码",
            "--bigip-url=F5地址",
            "--bigip-partition=K8S",
            "--pool-member-type=cluster",
            "--insecure=true",
            "--vs-snat-pool-name=SNAT-vlan130"
            ]

服务暴露

CIS 可以关联 K8S 原生的 Service ,通过 ConfigMap(L4)或者 Ingress(L7)对 Pod 的服务暴露提供配置。

ConfigMap(L4)

配置 Configmap 资源,关联 Service,做4层服务发布,可以指定相应的健康检查规则和负载均衡方法。

代码语言:javascript复制
kind: ConfigMap
apiVersion: v1
metadata:
  name: sugar-cmdb-v2-vs
  labels:
    f5type: virtual-server
data:
  schema: "f5schemadb://bigip-virtual-server_v0.1.7.json"
  data: |
    {
      "virtualServer": {
        "backend": {
          "servicePort": 80,
          "serviceName": "myservice",
          "healthMonitors": [{
            "interval": 5,
            "protocol": "http",
            "send": "GET /health.html HTTP/1.1rnHost:1.1.1.1rnrn",
            "recv": "server is ok",
            "timeout": 16
          }]
        },
        "frontend": {
          "virtualAddress": {
            "port": 80,
            "bindAddr": "<F5分配的虚地址>"
          },
          "partition": "K8S",
          "balance": "least-connections-member",
          "mode": "http"
        }
      }
    }

CIS 关联到 Service 后端的 Pod 信息,并在 F5 上创建了一个 Pool,并且使用了我们配置的 Least-Connections 负载均衡算法。

并且为 Pool member 关联了相应的健康检查规则。

最后根据我们分配的IP和端口号创建出对应的 Virtual Service。

Ingress(L7)

配置 Ingress 资源,关联2个 Service,做7层的服务发布,基于访问域名转发给不同 Service 下的 Pod。

代码语言:javascript复制
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-l7-domain-ingress
  namespace: default
  annotations:
    virtual-server.f5.com/ip: "<F5分配的虚拟地址>" 
    virtual-server.f5.com/http-port: "80" 
    virtual-server.f5.com/partition: "Cilium" 
    virtual-server.f5.com/balance: "round-robin" 
    virtual-server.f5.com/health: | 
      [
        {
          "path":     "mysite1.example.com/",
          "send":     "HTTP GET /",
          "interval": 5,
          "timeout":  10
        }, {
          "path":     "mysite2.example.com/",
          "send":     "HTTP GET /",
          "interval": 5,
          "timeout":  10
        }
      ]
spec:
  rules:
  - host: mysite1.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80
  - host: mysite2.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat
          servicePort: 80

CIS 会根据 Ingress 规则在 F5 上创建一个 Virtual Service 并且关联一条 Published Policy。

F5 动态感知容器服务变化

通过部署在 K8S 集群内的 F5 CIS 动态感知容器服务的变化,解析服务的创建以及销毁事件,动态更新 F5 配置,实现服务自动发现,动态感知能力,以此来支持应用弹性伸缩能力。这部分就留给大家自己验证吧。

参考文献

  1. Cilium Doc: Using BIRD to run BGP
  2. Cilium Doc: Masquerading
  3. 民生银行:基于 F5 技术实现 Kubernetes 生产环境最佳实践
  4. F5 Doc:Using the BIG-IP Controller as an Ingress controller
  5. F5 Doc:Manage your BIG-IP virtual servers
  6. 最Cool Kubernetes网络方案Cilium入门

点击屏末 | 阅读原文 | 即刻学习

文章转载自k8s技术圈。点击这里阅读原文了解更多

扫描二维码联系我们!


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux Foundation,是非营利性组织。

CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。请长按以下二维码进行关注。

0 人点赞