【k8s in Action 笔记】 第五章 服务service 二 (Ingress、LoadBalancer 、NodePort区别)


关联文章:
第五章 服务service 一 ( dns、ENDPOINTS)
第五章 服务service 二 (Ingress、LoadBalancer 、NodePort区别)
Service种类、类型(ClusterIP、NodePort、LoadBalancer、ExternalName)
K8S中的IP地址(Node IP、Pod IP、Cluster IP)

5.3 将服务暴漏给外部客户端

在这里插入图片描述

有以下三种方式可以在外部访问服务:

  • 将服务的类型设置成 NodePort
  • 将服务的类型设置为 LoadBalance
  • 创建一个 Ingress 资源

5.3.1 NodePort

在介绍NodePort之前,我们回顾下之前的服务,实际上Service 有多种类型:

ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的ServiceType。

NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。

LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。

ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

通过创建一个 NodePort 服务,可以让 Kubernetes 在其所有节点上保留一个端口(所有节点上都使用相同端口号),并将传入的连接转发给作为服务部分的 pod 。

5.3.1.1 创建 NodePort 类型的服务

参数说明:
在这里插入图片描述
完整的样例,可以使用如下描述文件 kubia-svc-nodeport.yaml 创建一个 NodePort 类型的服务::

# 遵循 v1 版本的 Kubernetes API
apiVersion: v1
# 资源类型为 Service
kind: Service
metadata:
  # Service 的名称
  name: kubia-nodeport
spec:
  # 指定服务类型为 NodePort
  type: NodePort
  # 该服务可用的端口
  ports:
    # 第一个可用端口的名字
    - name: http
      # 集群可用端口为 80
      port: 80
      # 服务将连接转发到容器的 8080 端口
      targetPort: 8080
      # 通过集群节点的 30000 端口可以访问该服务
      nodePort: 30000
    # 第二个可用端口的名字
    - name: https
      # 可用端口为 443
      port: 443
      # 服务将连接转发到容器的 8443 端口
      targetPort: 8443
      # 通过集群节点的 32767 端口可以访问该服务
      nodePort: 32767
  # 具有 app=kubia 标签的 pod 都属于该服务
  selector:
    app: kubia

nodePort 属性不是强制的,如果忽略就会随机选择一个端口。

执行创建命令:

[root]$ kubectl create -f kubia-svc-nodeport.yaml
service/kubia-nodeport created

kubectl get services kubia-nodeport 查看该服务的基础信息:

[root]$ kubectl get services kubia-nodeport
NAME             TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
kubia-nodeport   NodePort   10.254.181.177   <none>        80:30000/TCP,443:32767/TCP   36s

PORT(S) 列显示集群 IP 内部端口 (80, 443) 和节点端口 (30000, 32767)

此时可以有2种方式访问:

  • cluster-ip:80 集群内部可以通过 10.254.181.177:80访问

  • nodeIP:30123 , nodeIP对应node节点的外部IP,假设是10.228.62.129

    http://10.228.62.129:30000/
    在这里插入图片描述

原理:

在这里插入图片描述
注意: 当然要注意防火墙,确保30000端口是可用的

使用 JSONPath 输出需要的信息:通过指定 kubectl 的 JSONPath ,我们可以只输出需要的信息。例如: kubectl get nodes -o jsonpath=’{.items[*].status.addresses[0].address}’ 将输出所有节点的 IP 地址。

[root]$  kubectl get nodes -o jsonpath='{.items[*].status.addresses[0].address}'
194.246.9.25 194.246.9.26 194.246.9.27 194.246.9.3 194.246.9.4 194.246.9.5

5.3.1.2 疑惑为什么我的EXTERNAL-IP=none

前文,我的EXTERNAL-IP=none,而书上确是nodes
在这里插入图片描述

看看EXTERNAL IP列。它显示nodes, 表明服务可通过任何集群节点的IP地址访问。PORT (S)列显示集群IP (8 0) 的内部端口和节点端口(30123), 可以通过以下地址访问该服务:
• 10.11.254.223:80
• <节点1 node’sIP>:30123
• <节点2 node’sIP>:30123, 等等

原因分析,请先参考LoadBalancer类型服务依赖(NodePort、Ingress)

分配外部IP需要依赖云系统的一些服务,类似LoadBalancer也要EXTERNAL IP,它就依赖云平台,需要安装好多基础服务才行。

5.3.2 通过负载均衡器将服务暴露出来

负载均衡器拥有自己独一无二的可公开访问的 IP 地址,并将所有连接重定向到服务。

在云提供商上运行的Kubernetes集群通常支持从云基础架构自动提供负载平衡器。所有需要做的就是设置服务的类型为Load Badancer而不是NodePort。负载均衡器拥有自己独一无二的可公开访问的IP 地址, 并将所有连接重定向到服务。

可以通过负载均衡器的IP 地址访问服务。如果Kubemetes在不支持Load Badancer服务的环境中运行, 则不会调配负载平衡器, 但该服务仍将表现得像一个NodePort服务。这是因为LoadBadancer服务是NodePo江服务的扩展。可以在支持Load Badancer服务的GoogleK ubemetes Engine上运行此示例。Minikube没有, 至少在写作本书的时候。

5.3.2.1 创建 LoadBalance 服务

可以使用如下描述文件 kubia-svc-loadbalancer.yaml 创建一个 LoadBalancer 类型的服务:

# 遵循 v1 版本的 Kubernetes API
apiVersion: v1
# 资源类型为 Service
kind: Service
metadata:
  # Service 的名称
  name: kubia-loadbalancer
spec:
  type: LoadBalancer
  # 该服务可用的端口
  ports:
    # 第一个可用端口的名字
    - name: http
      # 可用端口为 80
      port: 80
      # 服务将连接转发到容器的 8080 端口
      targetPort: 8080
    # 第二个可用端口的名字
    - name: https
      # 可用端口为 443
      port: 443
      # 服务将连接转发到容器的 8443 端口
      targetPort: 8443
  # 具有 app=kubia 标签的 pod 都属于该服务
  selector:
    app: kubia

type: LoadBalancer 服务类型设置为LoadBalancer而不是NodePort。如果没有指定特定的节
点端口, Kubemetes将会选择一个端口。

5.3.2.2 通过负载均衡器连接服务

创建服务后, 云基础架构需要一段时间才能创建负载均衡器并将其IP 地址写入服务对象。一旦这样做了, IP 地址将被列为服务的外部IP 地址:

在这里插入图片描述

在这种情况下, 负载均衡器的IP 地址为130.211.53.173, 因此现在可以通过该IP 地址访问该服务:

$ curl http://130.211.53.173
You've hit kubia-xueql

成功了!可能像你已经注意到的那样, 这次不需要像以前使用NodePort服务那样来关闭防火墙。

会话亲和性和Web浏览器
由于服务现在已暴露在外, 因此可以尝试使用网络浏览器访问它。但是会看到一些可能觉得奇怪的东西——每次浏览器都会碰到同一个pod 。此时服务的会话亲和性是否发生变化?使用kubectl explain, 可以再次检查服务的会话亲缘性是否仍然设置为None, 那么为什么不同的浏览器请求不会碰到不同的pod, 就像使用curl时那样?

现在阐述为什么会这样。浏览器使用keep-alive连接, 并通过单个连接发送所有请求, 而curl每次都会打开一个新连接。服务在连接级别工作, 所以当首次打开与服务的连接时, 会选择一个随机集群, 然后将属于该连接的所有网络数据包全部发送到单个集群。即使会话亲和性设置为None, 用户也会始终使用相同的pod (直到连接关闭)。

请参阅图5.7, 了解HTTP 请求如何传递到该pod。外部客户端(可以使用curl)连接到负载均衡器的80端口,并路由到其中一个节点上的隐式分配节点端口。之后该连接被转发到一个pod实例。如前所述, LoadBalancer类型的服务是一个具有额外的基础设施提供的负载平衡器NodePort服务。如果使用kubectl describe 来显示有关该服务的其他信息, 则会看到为该服务选择了一个节点端口。如果要为此端口打开防火墙, 就像在上一节中对NodePort服务所做的那样, 也可以通过节点IP 访问服务。

在这里插入图片描述

5.3.3 了解外部连接的特性

你必须了解与服务的外部发起的连接有关的几件事情。

5.3.3.1 了解并防止不必要的网络跳数

当外部客户端通过节点端口连接到服务时(这也包括先通过负载均衡器时的情况), 随机选择的pod并不一定在接收连接的同一节点上运行。可能需要额外的网络跳转才能到达pod, 但这种行为并不符合期望。

通过节点端口访问方式语法是:nodeIP:NodePort,因此,客户端连接的node节点,会做负载均衡或随机选择pod,因此,可能出现要额外,比如连接的node1,但是node1会转发请求至node2上的pod来完响应。

可以通过将服务配置为仅将外部通信重定向到接收连接的节点上运行的pod来阻止此额外跳数。这是通过在服务的spec部分中设置externalTrafficPolicy字段来完成的:

spec:
  externalTrafficPolicy: Local

设定local后,node1不会转发请求至node2了

  • 如果接收连接的节点上没有运行对应的 pod ,那么连接将挂起,所以需要确保负载均衡器将连接转发给至少具有一个 pod 的节点
  • 假设有一个两节点三个 pod 的集群(节点 A 运行一个 pod ,节点 B 运行两个 pod),如果负载均衡器在两个节点间均匀分布连接,那么 pod 的负载分布不均衡

在这里插入图片描述

5.3.3.2 客户端IP是不记录的

通常, 当集群内的客户端连接到服务时, 支持服务的pod可以获取客户端的IP地址。但是, 当通过节点端口接收到连接时, 由于对数据包执行了源网络地址转换(SNAT), 因此数据包的源IP将发生更改。

后端的pod无法看到实际的客户端IP,这对于某些需要了解客户端IP的应用程序来说可能是个问题。例如, 对千Web服务器, 这意味着访问日志无法显示浏览器的IP。

上一节中描述的local外部流量策略会影响客户端IP的保留, 因为在接收连接的节点和托管目标pod的节点之间没有额外的跳跃(不执行SNAT)。

5.4 通过 Ingress 暴露服务

为什么需要 Ingress

每个 LoadBalancer 服务都需要自己的负载均衡器,以及独有的公有 IP 地址,而 Ingress 只需要一个公网 IP 就能为许多服务提供访问。当客户端向 Ingress 发送 HTTP 请求时, Ingress 会根据请求的主机名和路径决定请求转发到的服务。

可以理解为一个简化版本的nginx。

Ingress控制器是能够为Ingress资源健康某套接字,然后根据ingress规则匹配机制路由调度流量的一个组件
只能工作在七层网络下,建议暴露http, https可以使用前端nginx来做证书方面的卸载

5.4.1 创建 Ingress 资源

可以使用如下描述文件 kubia-ingress.yaml 创建一个 Ingress 资源:

# 遵循 extensions/v1beta1 版本的 Kubernetes API
apiVersion: extensions/v1beta1
# 资源类型为 Ingress
kind: Ingress
metadata:
  # Ingress 的名称
  name: kubia
spec:
  # Ingress 的规则列表
  rules:
    # 第一条规则匹配的域名为 kubia.example.com
    - host: kubia.example.com
      # 匹配 http
      http:
        # 匹配的路径列表
        paths:
          # 第一条路径为 /
          - path: /
            # 该路径将被转发到的后端服务
            backend:
              # 将被转发到 kubia-nodeport 服务
              serviceName: kubia-nodeport
              # 对应服务的端口为 80
              servicePort: 80

执行kubectl create -f kubia-ingress.yam进行创建。

查看创建的ingresses kubectl get ingresses

[root]$ kubectl get ingresses
NAME    CLASS    HOSTS               ADDRESS   PORTS   AGE
kubia   <none>   kubia.example.com             80      13m

ingresses 是个单独类型,不是svc(service)了

Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress,改语法有点老了

5.4.2 通过Ingress 访问服务

要通过http : //kubi a . example.com 访问服务,需要确保域名解析为Ingress 控制器
的IP 。

由于域名kubia.example.com存在主机上,而不是全局的dns,所以外部的客户端是无法访问的。
在这里插入图片描述
IP 在ADDRESS 列中显示出来。

5.4.2.1 确保在Ingress 中配置的Host 指向Ing ress 的IP 地址

一旦知道IP 地址,通过配置DNS 服务器将kubi a . exampl e.com 解析为此IP地址,或者在ect/ hosts 文件( Windows 系统为C : \windows\system32\drivers\etc\hosts ) 中添加下面一行内容:

192 168.99.100 kubia.example.com

此时我们在主机上就可以通过 curl kubia.example.com 访问 kubia-nodeport 服务了。

$ curl http: / /kubia.exampl e.com
You ’ve hit kubia-ke823

5.4.2.2 了解 Ingress 的工作原理

  • 客户端对 kubia.example.com 执行 DNS 查找,本地操作系统返回了 Ingress 控制器的 IP
  • 客户端向 Ingress 控制器发送 HTTP 请求,并在 Host 头中指定 kubia.example.com
  • 控制器从头部确定客户端尝试访问哪个服务,通过与该服务关联的 Endpoint 对象查看 pod IP ,并将客户端的请求转发给其中一个 pod

在这里插入图片描述

5.4.3 通过相同的 Ingress 暴露多个服务

Ingerss 的 rules 和 paths 都是数组,所以它们可以包含多个条目,因此一个 Ingress 可以将多个域名和路径映射到多个服务。

5.4.3.1 将不同的服务映射到相同主机的不同路径

将不同的服务映射到相同主机的不同pa ths ,以下面的代码清单为例。
在这里插入图片描述

在这种情况下,根据请求的URL 中的路径, 请求将发送到两个不同的服务。因此,
客户端可以通过一个IP 地址( I ngress 控制器的IP 地址〉访问两种不同的服务。

5.4.3.2 将不同的服务映射到不同的主机上

同样,可以使用Ingress 根据HTTP 请求中的主机而不是(仅)路径映射到不同
的服务,如下面的代码清单所示。
在这里插入图片描述
根据请求中的Host 头(虚拟主机在网络服务器中处理的方式),控制器收到的请求将被转发到foo 服务或bar 服务。DNS 需要将foo .example.combar.example.com 域名都指向I ngress 控制器的IP 地址。

5.7 排除服务故障

服务是Kubemetes的一个重要概念, 也是让许多开发人员感到困扰的根源。许多开发人员为了弄清楚无法通过服务IP 或FQDN 连接到他们的pod的原因花费了大量时间。出于这个原因, 了解一下如何排除服务故障是很有必要的:

如果无法通过服务访问pod, 应该根据下面的列表进行排查:
• 首先, 确保从集群内连接到服务的集群IP, 而不是从外部。
• 不要通过ping服务IP 来判断服务是否可访问(请记住, 服务的集群IP 是虚拟IP, 是无法ping通的)。
• 如果已经定义了就绪探针, 请确保它返回成功;否则该pod不会成为服务的一部分。
• 要确认某个容器是服务的一部分, 请使用kubectl get endpoints来检查相应的端点对象。
• 如果尝试通过FQDN或其中一部分来访问服务(例如, myservice.mynamespace.svc.cluster.local或myservice.mynamespace), 但并不起作用, 请查看是否可以使用其集群IP而不是FQDN来访问服务。
• 检查是否连接到服务公开的端口, 而不是目标端口。
• 尝试直接连接到podIP以确认pod正在接收正确端口上的连接。
• 如果甚至无法通过pod的IP 访问应用, 请确保应用不是仅绑定到本地主机。

这应该可以帮助解决大部分与服务相关的问题。

总结

Ingress、LoadBalancer 、NodePort的区别

它们都是将集群外部流量导入到集群内的方式,只是实现方式不同。让我们看一下它们分别是如何工作的,以及你该如何选择它们。

ClusterIP

ClusterIP 服务是 Kubernetes 的默认服务。它给你一个集群内的服务,集群内的其它应用都可以访问该服务。集群外部无法访问它

什么是集群外部?简单来说就是集群节点之外的主机或客户端。

k8s集群会默认为服务提供一个ClusterIP,至少保证集群内部之间可以互相访问,这也是各种复杂访问机制的基础,其他的机制,最终都会转为ClusterIP访问形式。

ClusterIP 服务的 YAML 文件类似如下:



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

如果 从Internet 没法访问 ClusterIP 服务,那么我们为什么要讨论它呢?那是因为我们可以通过 Kubernetes 的 proxy 模式来访问该服务!

Kubernetes Proxy

如果 从Internet 没法访问 ClusterIP 服务,那么我们为什么要讨论它呢?那是因为我们可以通过 Kubernetes 的 proxy 模式来访问该服务!
在这里插入图片描述
启动Kubernetes代理:

$ kubectl proxy --port=8080

现在,您可以使用Kubernetes API以访问此服务:

http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/

因此,要访问我们上面定义的服务,您可以使用以下地址,样例:

http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/

什么时候使用Kubernetes Proxy访问服务?
-在某些情况下,您可以使用Kubernetes代理来访问您的服务。

  • 调试您的服务或出于某种原因直接从您的笔记本电脑连接它们

  • 允许内部流量,显示内部dashboard等

Kubernetes Proxy等价于后门,只让管理员操作,不能暴露给普通人

因为此方法要求您作为经过身份验证的用户运行kubectl,所以不应使用此方法将服务公开给Internet或将其用于生产服务。

NodePort

NodePort服务是将外部流量直接发送给您的服务的最原始方式。 顾名思义,NodePort在所有节点(VM)上打开一个特定端口,并且发送到该端口的任何流量都将转发到该服务。
在这里插入图片描述
注意:上图并不是技术上最精确的图示,但我认为它说明了NodePort的工作原理。
NodePort服务的YAML如下所示:

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



基本上,NodePort服务与普通的“ClusterIP”服务有两点不同:

  • 首先,类型是“NodePort”。
  • 还有一个名为nodePort的附加端口,用于指定在节点上打开的端口。 如果您不指定此端口,它将选择一个随机端口。 大多数时候你应该让Kubernetes选择端口;正如thockin所说,对于你可以使用的端口有很多必要的说明。

什么时候使用这种方法?
这种方法有许多缺点:

  • 每个端口只能有一个服务

    nodePort: 30036中的30036只能被该服务独占,类似tomcat8080端口是独占的一样,因此,多个服务就需要多个这样的端口。

  • 您只能使用端口30000-32767

  • 如果您的Node/VM的IP地址发生变化,您需要处理好

出于这些原因,我不建议在生产中使用此方法直接公开您的服务。 如果您运行的服务不必始终可用,或者您的成本非常敏感,则此方法适合您。 比如演示应用程序或临时的东西。

LoadBalancer

LoadBalancer服务是将服务公开给Internet的标准方法。 在GKE上,这将启动Network Load Balancer[2],它将为您提供单个IP地址,以便将所有流量转发到您的服务。
在这里插入图片描述
何时使用这种方式?

如果你想要直接暴露服务,这就是默认方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。

这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。

IP 地址 就是kubectl get svc结果中,EXTERNAL-IP列

在这里插入图片描述

Ingress

有别于以上所有例子,Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。

Ingress类似ngix软件,是个具体的软件,不是k8s内的一个服务。

你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。

GKE 上的默认 ingress 控制器是启动一个 HTTP(S) Load Balancer[3]。它允许你基于路径或者子域名来路由流量到后端服务。例如,你可以将任何发往域名 foo.yourdomain.com 的流量转到 foo 服务,将路径 yourdomain.com/bar/path 的流量转到 bar 服务。

在这里插入图片描述
使用L7 HTTP负载均衡器的GKE上的Ingress对象的YAML可能如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  backend:
    serviceName: other
    servicePort: 8080
  rules:
  - host: foo.mydomain.com
    http:
      paths:
      - backend:
          serviceName: foo
          servicePort: 8080
  - host: mydomain.com
    http:
      paths:
      - path: /bar/*
        backend:
          serviceName: bar
          servicePort: 8080

为什么Ingress节约IP?

很简单,就是类似/path语法实现不同的连接,类似spring mvc一样,提供一个IP和Port,通过controller定义不同的servlet入口。

参考

Kubernetes 实战 —— 05. 服务:让客户端发现 pod 并与之通信(下)
Kubernetes NodePort、LoadBalancer和Ingress介绍 注要提供几种代理的区别

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值