手记

一文读懂k8s的外网访问方式,Ingress/NodePort/LoadBanlancer

2023-03-28 16:30:278951浏览

一凡

2实战 · 485手记 · 29推荐

集群内访问

在k8s中创建的微服务,大部分都是在集群内部互相调用,这时候,使用DNS就可以很方面访问。

比如:服务名是 my-service,端口号是8080,命名空间是yifan,那么就可以通过域名+端口 “my-service.yifan.svc.cluster.local:8080” 在集群内访问。

当然,也可以直接用服务的ClusterIP+服务的端口号,只是这么使用的较少。

DNS解析到的IP也就是这个服务的ClusterIP,只是咱们不需要记住ClusterIP,记住服务名对应的域名更加容易。

如上图所示,就是k8s集群内的服务访问流程。

客户端通过DNS服务的域名解析 my-service.yifan.svc.cluster.local 返回这个服务的ClusterIP。

然后创建TCP连接到这个ClusterIP+端口号上。

网络请求经过Iptables/ipvs规则处理,经过负载均衡策略,把这个ClusterIP重定向到服务的后端实例,也就是这个服务的某一个Pod得PodIP。

这样TCP连接成功创建,客户端也就建立了与服务的后端实例的连接,也就可以进行后续的请求了。

下面是Cluster类型的service的yaml文件示例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - name: http
      port: 80
      targetPort: 8080

这个YAML文件包含以下内容:

  • apiVersion: 指定Kubernetes API的版本。
  • kind: 指定要创建的对象类型,此处为Service。
  • metadata.name: 指定Service的名称,此处为“my-service”。
  • spec.type: 指定Service的类型,此处为“ClusterIP”。
  • spec.selector: 指定要为Service选择的Pod或副本集的标签选择器。在这个例子中,标签选择器是“app=my-app”。
  • spec.ports: 指定要公开的端口及其配置信息。在这个例子中,将公开端口80,名称为“http”,将流量转发到Pod中的端口8080。

要使用此YAML文件创建Service,请使用以下命令:

kubectl apply -f service.yaml

这是集群内访问的流程,接下来,再来看看本文的核心内容,外网如何访问。

集群外访问

k8s集群的外网访问方式有3种:

Ingress, NodePort和LoadBanlancer。

其中Ingress是k8s的一个抽象层,有很多的IngressController和服务可以来实现这个Ingress服务,然后由这个Ingress服务把外网的请求转发到集群内的服务。

NodePort和LoadBanlancer是k8s中service的类型。上面讲到的集群内访问,ClusterIP也是service的一种类型。

而LoadBanlancer类型需要各个云厂商自己来实现的CloudControllerManager,所以,采用不同的云厂商,它们的LoadBanlancer也就会有一些区别,它们的功能以及使用方法也就不一样了。

接下里,咱们就单独来看看这3种外网访问方式吧。

Ingress转发外网请求

先来看下Ingress配置的yaml文件:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: yifan-online.com
    http:
      paths:
      - path: /app1
        pathType: Prefix
        backend:
          service:
            name: app1-service
            port:
              name: http
      - path: /app2
        pathType: Prefix
        backend:
          service:
            name: app2-service
            port:
              name: http

此文件指定了一个名为“my-ingress”的Ingress,将传入的请求路由到两个不同的服务,其中一个服务名称为“app1-service”,另一个服务名称为“app2-service”。

请注意,此文件的规范部分中指定了两个规则,每个规则都包含一个主机名和一组路径规则。每个路径规则都指定了如何将传入请求路由到服务。

如要支持gRPC协议,配置的yaml文件如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: grpc-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
spec:
  rules:
  - host: yifan-online.com
    http:
      paths:
      - path: /grpc
        backend:
          serviceName: grpc-service
          servicePort: 9000

在这个示例中,我们指定了Ingress类为nginx,并使用了nginx负载均衡器来支持gRPC协议。然后,我们定义了一个名为“grpc-service”的gRPC服务,它将运行在端口9000上。

接下来,我们定义了一个Ingress规则,它将传入的请求路由到主机“yifan-online.com”的“/grpc”路径。这个规则使用了我们先前定义的gRPC服务,并将所有请求转发到端口9000上的gRPC服务。

请注意,在此示例中,我们还使用了一个特殊的注释“nginx.ingress.kubernetes.io/backend-protocol: “GRPC””,它指定了gRPC作为后端协议。这个注释将告诉nginx负载均衡器将请求路由到gRPC服务。

上面的yaml文件,咱们知道如何通过Ingress服务来做请求转发,是通过host和path来识别请求,然后转发到backend的servieName和servicePort。

那么,外网的客户端,要怎么请求到这个Ingress呢?

这时候,还是需要有一个外网可访问LoadBanlancer来把外网请求接入进来,转发到Ingess上。

而上面的Ingress配置,只是一个配置转发的规则,还需要有一个真实存在的Ingress服务才可以实现上面的转发逻辑。

这时候,就需要例如:NginxIngress服务。

所以,还需要部署一个NginxIngress服务,当然也有很多其他类型的Ingress服务。

综上,我们再来看下Ingress方式的外网请求,是怎样的一个处理流程吧。

上面的LoadBanlancer是云厂商提供的一个服务,所以也是要单独收费的。

Ingress服务需要在集群内部署一个Nginx服务(其他的Ingress服务也是类似)。

host+path是Ingress的转发规则,所有实现了IngressController的服务都是可以支持的。

那么再来看下LoadBanlancer吧。

LoadBanlancer接入外网请求

要配置Kubernetes中的LoadBalancer,可以编写一个LoadBalancer的Service YAML文件,其中包含有关如何将Kubernetes Service公开到外部的信息。

以下是一个基本的LoadBalancer Service YAML文件示例:

apiVersion: v1
kind: Service
metadata:
  name: my-loadbalancer-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP

在这个示例中,我们定义了一个名为“my-loadbalancer-service”的Service,它将使用LoadBalancer来公开Kubernetes集群中的应用程序。其中的“type: LoadBalancer”声明将告诉Kubernetes将此服务配置为使用LoadBalancer。

接下来,我们定义了一个选择器,它将选择具有标签“app: my-app”的Pod作为后端。我们还指定了一个端口“80”,它将用于将传入请求路由到Pod的端口“8080”。

请注意,这个示例还包含一个名为“service.beta.kubernetes.io/aws-load-balancer-type”的注释,它指定了LoadBalancer的类型。在这个示例中,我们使用了Amazon Web Services(AWS)的Network Load Balancer(NLB)类型。如果您使用的是其他云提供商或自己的LoadBalancer,您可以根据需要更改此注释。

完成了这个配置文件并且Service已经创建时,Kubernetes将为您创建一个LoadBalancer,并为您的应用程序分配一个唯一的IP地址。您可以使用此IP地址来访问您的应用程序。请注意,不同的云提供商可能会有不同的方式来访问LoadBalancer的IP地址。

很多云厂商在实现LoadBanlancer的时候,还会用到NodePort服务类型,比如:腾讯云的CLB。

最后,再来看下LoadBanlancer的处理流程。

最后,咱们再来看下NodePort这种外网访问方式吧。

NodePort接入外网请求

要配置一个Kubernetes的NodePort,您可以编写一个NodePort的Service YAML文件,其中包含有关如何暴露Kubernetes Service的信息。

以下是一个基本的NodePort Service YAML文件示例:

apiVersion: v1
kind: Service
metadata:
  name: my-nodeport-service
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
    nodePort: 30000

在这个示例中,我们定义了一个名为“my-nodeport-service”的Service,它将会使用NodePort来暴露Kubernetes集群内的应用程序。其中的“type: NodePort”声明将告诉Kubernetes将此服务配置为使用NodePort。

接下来,我们定义了一个选择器,它将选择具有标签“app: my-app”的Pod作为后端。我们还指定了一个端口“80”,它将用于将传入请求路由到Pod的端口“8080”。

此外,我们还指定了一个NodePort“30000”,这将是我们将用来从集群外访问Service的端口。Kubernetes将在集群节点上随机选择此端口。

请注意,您可以通过将“nodePort”字段留空来让Kubernetes自动选择端口。但是,为了避免端口冲突,建议指定一个特定的端口号。

当您完成了这个配置文件并且Service已经创建时,您可以使用集群节点的IP地址和NodePort来访问Service。例如,在这个示例中,您可以使用节点的IP地址和端口“30000”来访问应用程序。

K8S集群中的工作节点有外网IP,就可以通过这些外网IP+NodePort暴露的端口号来访问到K8S集群内部的服务了。

在 Kubernetes 中,NodePort 的端口号范围默认是从 30000 到 32767。这个范围可以通过 kube-apiserver 的 --service-node-port-range 参数进行配置。

在实际使用中,需要注意端口号的冲突问题,也要避免滥用NodePort暴露了外网端口引发的安全问题。

那我们再来看下NodePort的数据处理流程。

创建一个 NodePort 类型的 Service 时,Kubernetes 会在集群中的每个节点上开放一个指定的端口号,例如 30000。每个节点上的 kube-proxy 组件会监听该端口号,并将所有流量转发到后端 Pod 的相应端口上。

具体来说,kube-proxy 会在每个节点上启动一个代理服务器(即 iptables 或者 IPVS),并为每个 Service 分配一个唯一的虚拟 IP 地址(即 ClusterIP)。当有请求到达 NodePort 时,kube-proxy 会根据负载均衡策略将请求转发到某个节点上,并使用该节点上的代理服务器将请求转发到相应的后端 Pod 上。后端 Pod 的响应将通过同样的方式返回给客户端。

看到这里,大家知道如何配置和使用这些服务了吗?

现在,你能完整的把一个外网请求,从LoadBanlancer到NodePort,再到Ingress,最后到服务实例的全部过程了吗?

总结和对比

Ingress、NodePort和LoadBalancer都是Kubernetes中用于将Service公开到外部的方法,但它们之间有一些区别和适用场景。以下是一些选择的建议:

  • Ingress:如果需要在同一IP地址和端口上公开多个服务,并根据请求路径或主机名进行路由,则可以使用Ingress。 Ingress是Kubernetes中的一个抽象层,它可以将多个Service公开到同一个IP地址和端口上,并根据请求路径或主机名进行路由,非常适合用于Web应用程序。

  • NodePort:如果您需要将一个Service公开到集群外部,但又不想使用负载均衡器,则可以使用NodePort。 NodePort将Service公开到所有节点的IP地址上,并将随机端口映射到目标端口。如果您只需要将一个Service公开到外部,并且您有一个静态IP地址或DNS名称来访问它,则NodePort可能是一个不错的选择。

  • LoadBalancer:如果您需要将一个Service公开到外部,并且需要一个负载均衡器来处理流量,则可以使用LoadBalancer。 LoadBalancer可以将流量负载均衡到多个Pod之间,从而提高应用程序的可用性和可伸缩性。如果您正在运行在公共云环境中,例如AWS、Azure或GCP,那么您可以使用云提供商的负载均衡器服务,否则您可以使用Kubernetes自带的负载均衡器。

在云厂商的服务中,如果要使用Ingress暴露k8s集群内的服务到外网,实际上会用也到LoadBanlancer和NodePort类型,只是大家不必关心它的内部实现细节而已。

Ingress和网关的区别

Ingress是Kubernetes中的一个抽象层,它允许您公开多个服务到同一IP地址和端口,并根据请求路径或主机名进行路由。 Ingress通常用于HTTP/HTTPS流量,并且可以支持TLS endpoint、基于路径的路由和负载均衡等功能。可以使用Kubernetes Ingress Controller实现Ingress功能,例如Nginx Ingress Controller、Traefik Ingress Controller和Istio Ingress Gateway。

网关(Gateway)通常是一个独立的组件,用于提供对应用程序的访问控制、身份验证、安全性、流量管理和监视等功能。 网关通常可以支持多个协议和传输层,并且可以部署在Kubernetes集群之外,例如API网关、网络应用防火墙(WAF)和服务网格(Service Mesh)等。流量可以通过不同的方式路由到网关,例如DNS名、IP地址、负载均衡器和Ingress等。

简而言之,Ingress是Kubernetes中的一个抽象层,用于将多个服务公开到同一IP地址和端口,并根据请求路径或主机名进行路由,而网关则是提供对应用程序的访问控制、身份验证、安全性、流量管理和监视等功能的组件,它可以与Kubernetes集群一起使用,但也可以独立于Kubernetes集群之外部署。

不知道大家还有什么想要了解的,可以在评论区提出来,后续可以接着细聊。也请关注我的课程哟。

1人推荐
随时随地看视频
慕课网APP