0%

Kubernetes External IP服务类型

在构建裸机Kubernetes集群时,您可能会遇到一个常见问题,就像我在做的那样,除了使用NodePort之外,您真的不知道如何向Internet公开Kubernetes服务。如果使用的是NodePort服务类型,它将分配一个要打开的较大端口号,并且您必须允许防火墙规则连接到这些端口。这对您的基础架构不利,尤其是在将服务器暴露于外部Internet时。好吧,还有另一种简洁的方法可以将您的Kubernetes服务公开出去,并且使用服务的原始端口号。例如,您可以将Kubernetes群集中部署的MySQL服务通过3306而不是32767端口暴露给外界。答案是使用Kubernetes External IP服务类型

就个人而言,我发现在Kubernetes社区中并未广泛讨论此主题,这可能是因为许多人正在使用云提供商的负载均衡器或将Metal LB用于本地部署。

什么是External IP服务

Kubernetes官方文档中可以看到External IP的描述:

如果存在路由到一个或多个集群节点的外部IP,则Kubernetes Services可以在这些External IP上公开。在服务端口上使用外部IP(作为目标IP)进入群集的流量将被路由到服务端点之一。External IP不受Kubernetes的管理,由集群管理员负责。

对于大多数人来说,这种解释是可以理解的。这里最重要的是确保使用哪个IP来访问Kubernetes集群。使用External IP服务类型,我们可以将服务绑定到用于连接集群的IP。

如果您了解Kubernetes网络的工作方式,那将是很好的。如果您不熟悉它,请查看Mark Betz撰写的博客文章,以详细了解它们。这里最重要的是要知道Kubernetes网络与Overlay网络一起工作。这意味着一旦您到达群集中的任何节点(主节点或工作节点),您就可以虚拟访问群集中的所有节点。

下图就是他们的组网图:

kubernetes-external-ip

在上图中,节点1和节点2都有1个IP地址。节点1上的IP地址1.2.3.4绑定到实际Pod驻留在节点2中的httpd服务,而IP地址1.2.3.5绑定到实际Pod驻留在节点1中的nginx服务。底层的overlay网络使这成为可能。当我们curl 1.2.3.4时,应该看到来自httpd服务的响应,而curl 1.2.3.5时,则应该看到来自nginx服务的响应。

为什么不使用Ingress

即使Ingress也用于将服务公开给外部,但Ingress是为L7路由构建的。这意味着它构建为支持HTTP(端口80)和/或HTTPS(端口443)流量,而不支持其他端口。Ingress充当基于主机的路由,或类似于Web Server中的虚拟主机。一些能够为其他端口提供服务的ingress controllers,或者可能为L4路由提供了解决方法,但我从未真正尝试使用它们。

External IP的优缺点

使用External IP的优点是:

  • 您可以完全控制所使用的IP。您可以使用属于您的ASN的IP,而不要使用云提供商的ASN。

外部IP的缺点是:

  • 我们现在将要进行的简单设置并不是高可用的。这意味着,如果节点异常,则该服务将不再可用,您将需要手动修复该问题。
  • 管理IP需要做一些手工工作。IP不是为您动态配置的,因此需要人工干预。

如何使用External IP服务

同样,我们将使用与我们的群集设置相同的组网图,不同的是IP地址和主机名不同。这不是一个好例子,但是当我们验证设置时,很容易区分是哪个。在实际示例中,您可能希望在一个外部IP上公开MySQL DB,在另一个外部IP上公开Kafka群集。

kubernetes-external-ip-demo

我已为本教程配置了2个VM。k3s-external-ip-master将是我们的Kubernetes master节点,其IP为1.2.4.120。k3s-external-ip-worker将是Kubernetes worker节点,其IP为1.2.4.114。

步骤1:部署Kubernetes集群

让我们在主节点上安装k3s,然后让另一个节点加入集群。

1
2
$ k3sup install --ip <master node ip> --user <username>
$ k3sup join --server-ip <master node ip> --ip <worker node ip> --user <username>

您现在应该会看到类似的内容:

1
2
3
4
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3s-external-ip-master Ready master 7m24s v1.16.3-k3s.2
k3s-external-ip-worker Ready <none> 2m21s v1.16.3-k3s.2

步骤2:创建Kubernetes Deployment资源

我们将创建nginx和httpd资源。

1
2
$ kubectl create deployment nginx --image=nginx
$ kubectl create deployment httpd --image=httpd

你现在应该看到这个:

1
2
3
4
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-86c57db685-fzxn5 1/1 Running 0 22s
httpd-7bddd4bd85-zk8ks 1/1 Running 0 16s

步骤3:将Deployment公开为External IP类型

让我们创建Nginx服务的yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat << EOF > nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
externalIPs:
- 1.2.4.114
EOF

创建httpd服务的yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat << EOF > httpd-service.yaml
apiVersion: v1
kind: Service
metadata:
name: httpd-service
spec:
selector:
app: httpd
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
externalIPs:
- 1.2.4.120
EOF

使用kubectl命令创建2个服务的yaml:

1
2
$ kubectl create -f nginx-service.yaml
$ kubectl create -f httpd-service.yaml

现在您的Kubernetes服务应该如下所示:

1
2
3
4
5
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 18m
httpd-service ClusterIP 10.43.240.149 1.2.4.120 80/TCP 32s
nginx-service ClusterIP 10.43.13.149 1.2.4.114 80/TCP 26s

您可能会在此处看到服务类型为ClusterIP。我不确定为什么它不显示“外部IP”。

k8s官网有说明,External IP与type无关

步骤4:瞧!

让我们curl httpd服务,您应该看到Apache默认页面。

1
2
3
4
5
6
7
8
9
10
$ curl -i 1.2.4.120
HTTP/1.1 200 OK
Date: Fri, 20 Dec 2019 03:36:23 GMT
Server: Apache/2.4.41 (Unix) <------
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html
<html><body><h1>It works!</h1></body></html>

接下来,curl nginx服务,您应该看到nginx默认页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ curl -i 1.2.4.114
HTTP/1.1 200 OK
Server: nginx/1.17.6 <------
Date: Fri, 20 Dec 2019 03:36:01 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 19 Nov 2019 12:50:08 GMT
Connection: keep-alive
ETag: "5dd3e500-264"
Accept-Ranges: bytes
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
....

下一步是什么

浮动IP

如今,大多数云提供商都提供浮动IP服务。浮动IP允许您拥有1个IP,并将该IP动态分配给所需的任何IP。在这种情况下,可以将IP分配给Kubernetes集群中的任何工作节点。

在DigitalOcean(我相信其他提供商也允许这样做)中,您可以使用API调用将IP重新分配给其他VM。这意味着您可以在其他VM发生故障时迅速将其主动重新分配给其他VM,或者可以定期轮换IP。

kubernetes-floating-ip

从图中可以看到,我们有1个浮动IP 1.2.3.6,该IP首先分配给节点1,当节点1不可用时将切换到节点2。IP 1.2.3.6适用于我们的MySQL服务,并将放入我们的应用程序配置中。

我尚未尝试此设置,因此无法确认它是否有效。我将在以后的博客文章中更新结果。

任播IP

anycast

您可以将Anycast IP用作外部IP,以便它们具有高可用性。对于不熟悉Anycast IP的用户,这意味着1个IP可能会路由到2个或更多服务器。你可以在这里阅读更多。就个人而言,我不确定如何设置此设置。但是,我认为这在技术上是可行的。我认为这是运行外部IP服务的最佳方法。

结论

您可以通过很多选项为裸机Kubernetes集群获取IP。例如,您可以为此使用Inlets和MetalLB。此设置可能不是您的组织需要的最合适的设置。但是,很高兴知道如何使用此方法。

免责声明:我仅将其用于实验和测试,而本文不适用于生产。如果您打算在生产中使用它,请咨询您的解决方案架构师或CTO。