7

Calico 3.6 转发外部流量到集群 Pod

 2 years ago
source link: https://mritd.com/2019/06/18/calico-3.6-forward-network-traffic/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

由于开发有部份服务使用 GRPC 进行通讯,同时采用 Consul 进行服务发现;在微服务架构下可能会导致一些访问问题,目前解决方案就是打通开发环境网络与测试环境 Kubernetes 内部 Pod 网络;翻了好多资料发现都是 2.x 的,而目前测试集群 Calico 版本为 3.6.3,很多文档都不适用只能自己折腾,目前折腾完了这里记录一下

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

一、问题描述

在微服务架构下,由于服务组件很多,开发在本地机器想测试应用需要启动整套服务,这对开发机器的性能确实是个考验;但如果直接连接测试环境的服务,由于服务发现问题最终得到的具体服务 IP 是 Kubernetes Pod IP,此 IP 由集群内部 Calico 维护与分配,外部不可访问;最终目标为打通开发环境与集群内部网络,实现开发网络下直连 Pod IP,这或许在以后对生产服务暴露负载均衡有一定帮助意义;目前网络环境如下:

开发网段: 10.10.0.0/24
测试网段: 172.16.0.0/24
Kubernetes Pod 网段: 10.20.0.0/16

二、打通网络

首先面临的第一个问题是 Calico 处理,因为如果想要让数据包能从开发网络到达 Pod 网络,那么必然需要测试环境宿主机上的 Calico Node 帮忙转发;因为 Pod 网络由 Calico 维护,只要 Calico Node 帮忙转发那么数据一定可以到达 Pod IP 上;

一开始我很天真的认为这就是个 ip route add 10.20.0.0/16 via 172.16.0.13 的问题… 后来发现

经过翻文档、issue、blog 等最终发现需要进行以下步骤

2.1、关闭全互联模式

注意: 关闭全互联时可能导致网络暂时中断,请在夜深人静时操作

首先执行以下命令查看是否存在默认的 BGP 配置

calicoctl get bgpconfig default

如果存在则将其保存为配置文件

calicoctl get bgpconfig default -o yaml > bgp.yaml

修改其中的 spec.nodeToNodeMeshEnabledfalse,然后进行替换

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: 63400
EOF

本部分参考:

2.2、开启集群内 RR 模式

在 Calico 3.3 后支持了集群内节点的 RR 模式,即将某个集群内的 Calico Node 转变为 RR 节点;将某个节点设置为 RR 节点只需要增加 routeReflectorClusterID 既可,为了后面方便配置同时增加了一个 lable 字段 route-reflector: "true"

calicoctl get node CALICO_NODE_NAME -o yaml > node.yaml

然后增加 routeReflectorClusterID 字段,样例如下

apiVersion: projectcalico.org/v3
kind: Node
metadata:
  annotations:
    projectcalico.org/kube-labels: '{"beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/os":"linux","kubernetes.io/hostname":"d13.node","node-role.kubernetes.io/k8s-master":"true"}'
  creationTimestamp: 2019-06-17T13:55:44Z
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/hostname: d13.node
    node-role.kubernetes.io/k8s-master: "true"
    route-reflector: "true"  # 增加 lable
  name: d13.node
  resourceVersion: "61822269"
  uid: 9a1897e0-9107-11e9-bc1c-90b11c53d1e3
spec:
  bgp:
    ipv4Address: 172.16.0.13/19
    ipv4IPIPTunnelAddr: 10.20.73.82
    routeReflectorClusterID: 172.16.20.1 # 添加集群 ID
  orchRefs:
  - nodeName: d13.node
    orchestrator: k8s

事实上我们应当导出多个 Calico Node 的配置,并将其配置为 RR 节点以进行冗余;对于 routeReflectorClusterID 目前测试只是作为一个 ID(至少在本文是这样的),所以理论上可以是任何 IP,个人猜测最好在同一集群网络下采用相同的 IP,由于这是真正的测试环境我没有对 ID 做过多的测试(怕玩挂)

修改完成后只需要应用一下就行

calicoctl apply -f node.yaml

接下来需要创建对等规则,规则文件如下

kind: BGPPeer
apiVersion: projectcalico.org/v3
metadata:
  name: peer-to-rrs
spec:
  nodeSelector: "!has(route-reflector)"
  peerSelector: has(route-reflector)
---
kind: BGPPeer
apiVersion: projectcalico.org/v3
metadata:
  name: rr-mesh
spec:
  nodeSelector: has(route-reflector)
  peerSelector: has(route-reflector)

假定规则文件名称为 rr.yaml,则创建命令为 calicoctl create -f rr.yaml;此时在 RR 节点上使用 calicoctl node status 应该能看到类似如下输出

Calico process is running.

IPv4 BGP status
+--------------+---------------+-------+----------+-------------+
| PEER ADDRESS |   PEER TYPE   | STATE |  SINCE   |    INFO     |
+--------------+---------------+-------+----------+-------------+
| 172.16.0.19  | node specific | up    | 05:43:51 | Established |
| 172.16.0.16  | node specific | up    | 05:43:51 | Established |
| 172.16.0.17  | node specific | up    | 05:43:51 | Established |
| 172.16.0.13  | node specific | up    | 13:01:17 | Established |
+--------------+---------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.

PEER ADDRESS 应当包含所有非 RR 节点 IP(由于真实测试环境,以上输出已人为修改)

同时在非 RR 节点上使用 calicoctl node status 应该能看到以下输出

Calico process is running.

IPv4 BGP status
+--------------+---------------+-------+----------+-------------+
| PEER ADDRESS |   PEER TYPE   | STATE |  SINCE   |    INFO     |
+--------------+---------------+-------+----------+-------------+
| 172.16.0.10  | node specific | up    | 05:43:51 | Established |
| 172.16.0.13  | node specific | up    | 13:01:20 | Established |
+--------------+---------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.

PEER ADDRESS 应当包含所有 RR 节点 IP,此时原本的 Pod 网络连接应当已经恢复

本部分参考:

2.3、调整 IPIP 规则

先说一下 Calico IPIP 模式的三个可选项:

  • Always: 永远进行 IPIP 封装(默认)
  • CrossSubnet: 只在跨网段时才进行 IPIP 封装,适合有 Kubernetes 节点在其他网段的情况,属于中肯友好方案
  • Never: 从不进行 IPIP 封装,适合确认所有 Kubernetes 节点都在同一个网段下的情况

在默认情况下,默认的 ipPool 启用了 IPIP 封装(至少通过官方安装文档安装的 Calico 是这样),并且封装模式为 Always;这也就意味着任何时候都会在原报文上封装新 IP 地址,在这种情况下将外部流量路由到 RR 节点,RR 节点再转发进行 IPIP 封装时,可能出现网络无法联通的情况(没仔细追查,网络渣,猜测是 Pod 那边得到的源 IP 不对导致的);此时我们应当调整 IPIP 封装策略为 CrossSubnet

导出 ipPool 配置

calicoctl get ippool default-ipv4-ippool -o yaml > ippool.yaml

修改 ipipMode 值为 CrossSubnet

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  creationTimestamp: 2019-06-17T13:55:44Z
  name: default-ipv4-ippool
  resourceVersion: "61858741"
  uid: 99a82055-9107-11e9-815b-b82a72dffa9f
spec:
  blockSize: 26
  cidr: 10.20.0.0/16
  ipipMode: CrossSubnet
  natOutgoing: true
  nodeSelector: all()

重新使用 calicoctl apply -f ippool.yaml 应用既可

本部分参考:

2.4、增加路由联通网络

万事俱备只欠东风,最后只需要在开发机器添加路由既可

将 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 解析既可


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK