5. K8S Service与Ingress

温馨提醒
总结摘要
本文深入讲解 Kubernetes 中 Service 与 Ingress 的核心机制。内容涵盖 Service 的作用(服务发现与负载均衡)、工作原理(通过 Endpoint 关联 Pod)、四种类型(ClusterIP/NodePort/LoadBalancer/ExternalName)的详细配置与适用场景,并特别说明了在云平台(如 Azure AKS)使用 LoadBalancer 时的权限与静态 IP 配置要点。同时为后续引入 Ingress 做铺垫,阐明其作为七层入口网关与四层 Service 的互补关系,是理解 K8S 网络模型的关键篇章。

Kubernetes Service与Ingress

srevice概念

kubernetes Pod是短暂的,它们会被创建,也会死掉,并且是不可被复活的。

ReplicationControllers动态的创建和销毁Pods(比如规模扩大或者缩小,或者执行动态更新)。每个Pod都有自己的IP,这些IP随着时间的变换,也不能持续依赖,这样就引发一个问题:如果一些Pods(后台、后端)提供了一些功能共其他Pod使用(前台),再Kubernetes集群中是如何让这些前台能够持续的追踪到这些后台的。

答案是:==service==

Kubernetes Service是一个定义了一组Pod的策略的抽象,我们也有时候叫做宏观服务。这些服务标记的Pod(一般)都是听过label Selector决定的。(下面会讲到为什么需要一个没有 label selector 的服务)

假设后台是一个图形处理器的后台,并且有3个副本。这些副本是可以相互代替的,并且,前台需要关心使用的哪一台Pod,当这个承载前台请求的Pod发生变化时,前台并不需要知道这些变换,或者追踪后台的这些副。service定义的抽象能够解耦这种关联。

对于Kubernetes 原生的应用,Kubernetes提供了一个简单的Endpoints API,这个Endpoints api 的作用就相当于一个服务中的Pod发生变化时,Endpoints API随之变化,对于那些不是原生的程序,Kubernetes提供了一个基于虚拟IP的网桥的服务,这个服务会将请求转发到对应的后台Pod。

Service对象的IP地址也成为ClusterIP,它位于为Kubernetes集群配置指定专用的IP地址范围之内,是一种虚拟的IP地址,它再Service对象创建之后保持不变,并且能够被同一集群中的Pod资源所访问。Service端口用于接收客户端请求,并将请求转发至后端的Pod应用端口,这样的代理机制,也称为端口代理,它基于TCP/IP协议栈的传输层。

Service存在的意义:

​ 1、防止Pod失联(服务发现)

​ 2、定义一组Pod的访问策略(负载均衡)

Pod与service的关系:

​ 1、通过label-selector相关联

​ 2、通过service实现Pod的负载均衡(TCP、UDP四层)

定义Service

使用kubectl explain svc查看更多关键字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    protocol: TCP
    port: 80
    targetPort: 9376

service不会直接到pod,service是直接到endpoint资源,就是地址加端口,再由endpoint再关联到pod。

service只要创建完,就会再dns中添加一个资源记录进行解析,添加完成即可进行解析。资源记录的格式为:

1
SVC_NAME.NS_NAME.DOMAIN.LTD.

默认的集群service的A记录:

1
svc.cluster.local.

my-service服务创建的A记录:

1
my-service.default.svc.cluster.local.

Service类型

Kubernetes ServiceTypes 允许指定一个需要的类型的Service,默认是Cluster IP类型。

也可以使用Ingress来暴露自己的服务。Ingress不是一种服务类型,但它充当集群的入口点。它可以将路由规则整合到一个资源中,因为它可以在同一IP地址下公开多个服务。

Type的类型如下:

ClusterIP:

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

NodePort

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

如果将type字段设置为NodePort,则Kubernetes控制平面将在--service-node-port-range标志指定的范围内分配端口(默认值:30000-32767)。每个节点将那个端口(每个节点上的相同端口号)代理到你的服务器中。你的服务在其.spec.port[*].nodePort字段中要求分配的端口。

如果你想指定特定的IP代理端口,则可以设置kube-proxy中的--nodeport-addresses参数或者将kube-porxy配置文件 中的等效nodePodrtAddresses字段设置为特定的IP快。该标志采用逗号分隔的IP块列表(例如:10.0.0.0/8192.0.2.0/25)来指定kube-proxy应该认为是此节点本地的IP地址范围。

例如,如果你使用 --nodeport-addresses=127.0.0.0/8 标志启动 kube-proxy, 则 kube-proxy 仅选择 NodePort Services 的本地回路接口。 --nodeport-addresses 的默认值是一个空列表。 这意味着 kube-proxy 应该考虑 NodePort 的所有可用网络接口。 (这也与早期的 Kubernetes 版本兼容)。

如果需要特定的端口号,你可以在 nodePort 字段中指定一个值。 控制平面将为你分配该端口或报告 API 事务失败。 这意味着你需要自己注意可能发生的端口冲突。 你还必须使用有效的端口号,该端口号在配置用于 NodePort 的范围内。

使用 NodePort 可以让你自由设置自己的负载均衡解决方案, 配置 Kubernetes 不完全支持的环境, 甚至直接暴露一个或多个节点的 IP。

需要注意的是,Service 能够通过 <NodeIP>:spec.ports[*].nodePortspec.clusterIp:spec.ports[*].port 而对外可见。 如果设置了 kube-proxy 的 --nodeport-addresses 参数或 kube-proxy 配置文件中的等效字段, <NodeIP> 将被过滤 NodeIP。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
      # 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
    - port: 80
      targetPort: 80
      # 可选字段
      # 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767)
      nodePort: 30007

loadBalancer:

使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。

在使用支持外部负载均衡器的云提供商的服务时,设置 type 的值为 "LoadBalancer", 将为 Service 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer 字段发布出去。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
      - ip: 192.0.2.127

来自外部负载均衡器的流量将直接重定向到后端 Pod 上,不过实际它们是如何工作的,这要依赖于云提供商。

某些云提供商允许设置 loadBalancerIP。 在这些情况下,将根据用户设置的 loadBalancerIP 来创建负载均衡器。 如果没有设置 loadBalancerIP 字段,将会给负载均衡器指派一个临时 IP。 如果设置了 loadBalancerIP,但云提供商并不支持这种特性,那么设置的 loadBalancerIP 值将会被忽略掉。

注意:

在 Azure 上,如果要使用用户指定的公共类型 loadBalancerIP,则 首先需要创建静态类型的公共 IP 地址资源。 此公共 IP 地址资源应与集群中其他自动创建的资源位于同一资源组中。 例如,MC_myResourceGroup_myAKSCluster_eastus

将分配的 IP 地址设置为 loadBalancerIP。确保你已更新云提供程序配置文件中的 securityGroupName。 有关对 CreatingLoadBalancerFailed 权限问题进行故障排除的信息, 请参阅 与 Azure Kubernetes 服务(AKS)负载平衡器一起使用静态 IP 地址 在 AKS 集群上使用高级联网时出现 CreatingLoadBalancerFailed

详细内容: 服务 | Kubernetes

ExternalName:

通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。

类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择器,例如 my-service 或者 cassandra。 你可以使用 spec.externalName 参数指定这些服务。

例如,以下 Service 定义将 prod 名称空间中的 my-service 服务映射到 my.database.example.com

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

说明: ExternalName 服务接受 IPv4 地址字符串,但作为包含数字的 DNS 名称,而不是 IP 地址。 类似于 IPv4 地址的外部名称不能由 CoreDNS 或 ingress-nginx 解析,因为外部名称旨在指定规范的 DNS 名称。 要对 IP 地址进行硬编码,请考虑使用 headless Services

当查找主机 my-service.prod.svc.cluster.local 时,集群 DNS 服务返回 CNAME 记录, 其值为 my.database.example.com。 访问 my-service 的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。 如果以后你决定将数据库移到集群中,则可以启动其 Pod,添加适当的选择器或端点以及更改服务的 type