Kubernetes——服务暴露
服务暴露
Service 的 IP 地址仅在集群内可达,然而,总会有些服务需要暴露到外部网络中接受各类客户端的访问,例如分层架构应用中的前端 Web 应用程序等。此时,就需要在集群的边缘为其添加一层转发机制,以实现将外部请求流量接入到集群的 Service 资源之上,这种操作也称为发布服务到外部网络中。
一、Service 类型
Kubernetes 的 Service 共有四种类型:ClusterIP、NodePort、LoadBalancer 和 ExternalName。
ClusterIP: 此为默认的 Service 类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP。
NodePort: 这种类型建立在 ClusterIP 类型之上,其在每个节点的 IP 地址的某静态端口(NodePort)暴露服务,因此,它依然会为 Service 分配集群 IP 地址,并将此作为 NodePort 的路由目标。这种类型的 Servcie 既可如 ClusterIP 一样受到集群内部客户端 Pod 的访问,也会受到集群外部客户端通过套接字 <NodeIP>:<NodePort> 进行的请求。
LoadBalancer:这种类型建立在 NodePort 类型之上,其通过 cloud provider 提供的负载均衡器将服务暴露到集群外部,因此 LoadBalancer 一样具有 NodePort 和 ClusterIP。简单的说,就是一个 LoadBalancer 类型的 Service 会指向关联至 Kubernetes 集群外部的、切实存在的某个负载均衡设备,该设备通过工作节点之上的 NodePort 向集群内部发送请求流量。
EXternalName:其通过将 Service 映射至由 externalName 字段的内容指定的主机名来暴露服务,此主机名需要被 DNS 服务解析至 CNAME 类型的记录。此种类型并非定义由 Kubernetes 集群提供的服务,而是把集群外部的某服务以 DNS CNAME 记录的方式映射到集群内,从而让集群内的 Pod 资源能够访问外部的 Service 的一种实现方式。因此,这种类型的 Service 没有 CluserIP 和 NodePort,也没有标签选择器用于选择 Pod 资源,因此也不会有 Endpoints 存在。
二、NodePort 类型的 Service 资源
NodePort 即节点 Port,通常在安装部署 Kubernetes 集群系统时会预留一个 端口范围用于 NodePort,默认为 30000~32767 之间的端口。
与 ClusterIP 类型的可省略 .spec.type 属性有所不同的是,定义 NodePort 类型的 Service 资源时,需要通过此属性明确指定其类型名称。
kind: Service
apiVersion: v1
metadata:
name: XXX-smc-biz
namespace: XXX-smc-parent
labels:
app: XXX-smc-biz
app.kubernetes.io/name: XXX-smc-biz
app.kubernetes.io/version: v1
XXX-org: XXX
annotations:
helm.sh/hook: 'pre-install, pre-upgrade'
spec:
ports:
- name: http-8982
protocol: TCP
port: 8982
targetPort: 8982
nodePort: 31569
selector:
app: XXX-smc-biz
app.kubernetes.io/name: XXX-smc-biz
app.kubernetes.io/version: v1
XXX-org: XXX
clusterIP: 10.233.0.127
type: NodePort
sessionAffinity: None
externalTrafficPolicy: Cluster
流量走向:
NodePort 类型的 Service 资源虽然能够于集群外部访问得到,但外部客户端必须得事先得知 NodePort 和集群中至少一个节点的 IP 地址,且选定的节点发生故障时,客户端还得自行选择请求访问其他的节点。另外,集群节点很可能是某 IaaS 云环境中使用私有云 IP 地址的 VM,或者是 IDC 中使用私有地址的物理机,这类地址对互联网客户端不可达,因此一般还应该在集群之外创建一个具有公网 IP 地址的负载均衡器,由它接入外部客户端的请求并调度至集群节点相应的 NodePort 之上。
三、LoadBalance 类型的 Service 资源
IaaS 云计算环境通常提供了 LBaaS(Load Balancer a Service)服务,它允许租户动态地在自己的网络中创建一个负载均衡设备。那些部署于此类环境上的 Kubernetes 集群在创建 Service 资源时,可以直接调用此接口按需创建出一个软负载均衡器,而具有这种功能的 Service 资源即为 LoadBalancer 类型。
下面是一个 LoadBalancer 类型的 Service 资源配置清单,若 Kubernetes 系统满足其使用条件,即可自行进行应用测试。需要注意的是,有些环境中可能还需要为 Service 资源的配置定义添加 Annotations,必须时请自行参考 Kubernetes 官方文档说明:
kind: servic
apiVersion: v1
metadata:
name: myapp-svc-lb
spec:
type: LoadBalancer
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 3223
四、ExternalName Service
ExternalName 类型的 Service 资源用于将集群外部的服务发布到集群中以供 Pod 中的应用程序访问,因此,它不需要使用标签选择器关联任何的 Pod 对象,但必须要使用 spec.externalName 属性定义一个 CNAME 记录用于返回外部真正提供服务的主机的别名,而后通过 CNAME 记录值获取到相关主机的 IP 地址。
下面是一个 ExternalName 类型的 Service 资源示例,名为 external-redis-svc,相应的 externalName 为 "redis.xxx.com":
kind: servic
apiVersion: v1
metadata:
name: external-redis-svc
namespace: default
spec:
type: ExternalName
externalName: redis.xxx.com
ports:
- protocol: TCP
port: 6379
targetPort: 6379
nodePort: 0
selector: {}
待 Service 资源 external-redis-svc 创建完成后,各 Pod 资源对象可通过 external-redis-svc 或其 FQDN 格式的名称 external-redis-svc.default.svc.cluster.local 访问相应的服务。
ClusterDNS 会将此名称以 CNAME 格式解析位 .spec.externalName 字段中的名称,而后通过 DNS 服务将其解析为相应的主机的 IP 地址。
由于 ExternalName 类型的 Service 资源实现基于 DNS 级别,客户端将直接接入外部的服务而完全不需要服务代理,因此,它也无须配置 ClusterIP,此种类型的服务也被称为 Headless Service。