0%

使用Calico的BGP发布Kubernetes Service IP路由

访问Kubernetes集群中托管的服务的两种最常见方法是通过IngressLoad Balancer。对于公有云用户来说,这些是访问服务的简单有效方法。云托管的控制器可以完成分配公共IP,设置负载平衡和管理SSL的繁重工作。

在本地运行私有托管的Kubernetes集群的运营商将很快意识到,将服务公开提供比在公有云上更为复杂。服务将在公共互联网上还是仅对本地用户公开?应该如何设置Ingress,负载平衡,IP分配和SSL管理?在维护安全性的同时将服务公开发布的最有效方法是什么?

Calico项目通过其服务IP发布功能为某些问题提供了答案,该功能与现有的机架(ToR)基础架构集成在一起,可以提供Kubernetes服务IP或Kubernetes外部服务IP的路由。在以下情况下,服务IP发布是一个很好的解决方案:

  • 您的ToR解决方案能够运行边界网关协议(BGP)
  • 您希望将服务从群集共享到网络基础结构的其余部分
  • 您想利用网络负载均衡

为了启用服务IP发布功能,Calico需要与BGP路由器建立对等关系,该路由器在Calico的内部路由器之外,但在网络本地。BGP是网络中使用的最基本的路由协议之一。在较高级别,BGP通过在信任对等方之间共享路由来工作。与ToR对等时,Calico共享Kubernetes服务的路由,这使它们可用于整个网络。

为了帮助讨论此功能,假定我们安装以下方式配置了网络和群集:

  • 托管Kubernetes节点的服务器机架通过顶部机架式路由器连接到物理网络
  • Calico作为CNI和网络策略插件运行
  • Calico和Rack顶部路由器配置为使用BGP对等

在此设置中,我们具有以下网络配置:

  • 机架顶部路由器的IP地址是192.168.1.1,服务器的IP地址是从192.168.1.0/24分配的
  • Kubernetes Pod网络配置了CIDR 10.48.0.0/16
  • Kubernetes服务集群IP范围配置为10.49.0.0/16
  • 外部服务IP范围配置为192.168.3.0/24

您的ToR BGP路由器的确切配置超出了本文的范围,并且会因您使用的供应商或软件包而异。如果您没有可用的服务器机架,但仍然想尝试该功能,那么在单独的服务器上运行的Bird Internet Routing Daemon(BIRD)是尝试进行操作的不错选择。

第一步是启用ToR和Calico网络之间的对等连接。其工作方式将根据您的ToR实现而有所不同,但是要牢记一些关键事项:

  • 必须将ToR路由器配置为与在每个节点上运行的Calico对等
  • ToR需要接受来自外部网络,外部服务网络和Pod服务网络的路由和流量
  • 如果可以选择,ToR应该启用正常重启,以防止网络服务中断

将ToR配置为接受路由后,下一步是在Calico端启用对等。首先通过以下清单告诉Calico有关外部BGP路由器的信息:

1
2
3
4
5
6
7
8
9
calicoctl apply -f - << EOF
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: bgppeer-global-64512
spec:
peerIP: 192.168.1.1
asNumber: 64512
EOF

启用对等功能后,Calico可以使Pod成为网络中的头等公民,而无需覆盖网络,并使他们可以直接在群集外部访问。

尽管启用了对等连接,但是Calico仍需要进一步配置以公开Kubernetes服务IP范围。这可以通过创建新的Calico BGPConfiguration资源来完成:

1
2
3
4
5
6
7
8
9
calicoctl create -f - <<EOF
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
serviceClusterIPs:
- cidr: 10.49.0.0/16
EOF

启用服务群集IP范围的发布后,ToR上的路由表将如下所示:

1
2
3
4
5
6
7
$ ip r
...
10.49.0.0/16
nexthop via 192.168.1.10 dev eth2 weight 1
nexthop via 192.168.1.11 dev eth2 weight 1
nexthop via 192.168.1.12 dev eth2 weight 1
...

注意到10.49.0.0/16网络的路由如何在节点之间实现ECMP负载平衡。您公开的所有服务将由ToR在所有节点上进行负载平衡。为了说明这一点,我们可以创建一个基本的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
control:~$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
EOF
control:~$ kubectl expose nginx
control:~$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.49.0.1 <none> 443/TCP 19m
nginx ClusterIP 10.49.62.131 <none> 80/TCP 4m43s

现在,您可以从外部网络通过其内部群集IP地址访问Kubernetes托管服务。

1
2
3
4
5
6
external:~$ curl 10.49.62.131
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

这里有两个阶段的负载平衡。首先,ToR通过将其路由到节点来对与群集IP的连接进行负载平衡。然后,使用NAT(网络地址转换)在该节点上运行的kube-proxy负载均衡到特定的Pod,以将目标IP从群集IP更改为后备Pod之一的IP地址。后备Pod可能在本地节点上,也可能在其他节点之一上,从而导致了另一个网络跃点。

如果我们想避免额外的潜在网络跳数,可以通过将服务上的外部流量策略设置为本地来实现。

1
2
control:~$ kubectl patch service nginx \
-p '{"spec":{"type": "NodePort", "externalTrafficPolicy":"Local"}}'

现在,在ToR上,您将看到路由表的新增内容,包括Nginx服务到正在运行Nginx的特定节点的ECMP负载平衡:

1
2
3
4
5
6
7
8
9
10
$ ip r
...
10.49.0.0/16
nexthop via 192.168.2.10 dev eth2 weight 1
nexthop via 192.168.2.11 dev eth2 weight 1
nexthop via 192.168.2.12 dev eth2 weight 1
...
10.49.62.131
nexthop via 192.168.2.11 dev eth2 weight 1
nexthop via 192.168.2.12 dev eth2 weight 1

这是公开Kubernetes网络服务的简便方法,但是在操作上,它具有将Kubernetes群集中该IP范围内的每个服务都暴露给网络其余部分的缺点。如果您想更精细地控制提供哪些服务,或者想要分配真正面向公众的IP地址,Calico可以通过发布外部服务IP来解决这个问题。该方法类似,主要区别在于外部IP不由Kubernetes集群管理,必须手动分配给服务。

下一个示例将说明这一点。首先重新配置BGPConfiguration,以发布外部IP而不是内部IP(值得注意的是,您可以一次公开这两个集合,但是在此示例中,我们要关闭对内部网络的公共访问,同时仍提供对应用程序的访问)。

1
2
3
4
5
6
7
8
9
10
control :~$calicoctl create -f - <<EOF
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
serviceClusterIPs:
serviceExternalIPs:
- cidr: 192.168.3.0/24
EOF

检查路由时,请注意已删除到群集IP范围的路由,并已添加到外部服务网络的路由。

1
2
3
4
5
6
7
$ ip r
...
192.168.3.0/24
nexthop via 192.168.1.10 dev eth2 weight 1
nexthop via 192.168.1.11 dev eth2 weight 1
nexthop via 192.168.1.12 dev eth2 weight 1
...

该服务的群集IP不再公开可见。

1
2
external :~$ curl -m 10 10.49.62.131
curl: (28) Connection timed out after 10001 milliseconds

我们现在在发布外部IP范围,但我们还需要为服务分配一个外部IP:

1
2
3
4
5
6
control:~$ kubectl patch svc nginx \
-p '{"spec": {"externalIPs": ["192.168.3.180"]}}'
control:~$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.49.0.1 <none> 443/TCP 152m
nginx NodePort 10.49.62.131 192.168.3.180 80:31890/TCP 109m

检查连接性:

1
2
3
4
5
6
external:~$ curl 192.168.3.180
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

到此为止,我们快速完成了Calico如何在Kuberentes群集之外发布服务和外部服务IP的快速浏览。对于具有启用BGP路由的本地云,这是一种简单的解决方案,无需提供安装和维护自定义Kubernetes负载均衡器或Ingress控制器的额外工作即可访问Kubernetes服务。如果您想了解更多有关此功能的信息,请查阅官方的Calico项目”Advertise Kubernetes Service IPs“。