Dawn's Blogs

分享技术 记录成长

0%

Kubernetes学习 (7) 服务 通信

服务

Kubernetes 中服务是一种为一组功能相同的 Pod 提供单一不变的入口点的资源。当服务存在时,入口地址不会改变。 客户端通过 服务的入口地址建立连接,这些连接会被路由到提供该服务的任意一个 pod 上。 通过这种方式, 客户端不需要知道每个单独的提供服务的 pod 的地址, 这样这些 pod 就可以在集群中随时被创建或移除。

创建服务

服务使用标签来选择哪些 Pod 属于服务,哪些标签不属于服务。spec. ports.port 声明服务对外暴露的端口,而 spec.ports.targetPort 声明的是将消息转发给 Pod 的端口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
selector:
app: kubia

如果希望特定客户端产生的所有请求每次都指向同一个 Pod,则可以设置服务的 spec.sessionAffinity 属性为 ClientIP。sessionAffinity 属性仅支持两个值,none(默认)和 ClientIP。

DNS 服务发现

在集群内部的客户端如何知道访问服务的地址,这就需要服务发现了。在 Kubernetes 中提供了 DNS 服务器,Pod 可以使用内部的 DNS 服务器作为服务发现。客户端可以通过全限定域名(FQDN)来访问。

在创建一个服务时,Kubernetes 会创建一个相应的 DNS 条目,条目的内容为 <服务名称>.<名字空间名称>.svc.cluster.local,其中 svc.cluster.local 是在所有集群本地服务名称中使用的可配置集群域后缀。

如果客户端 Pod 和目标 Pod 在同一个命名空间下,则可以省略 svc.cluster.local 后缀,甚至是命名空间名字。

Endpoint

介绍

服务 和 Pod 不是直接相连的,而是通过 Endpoint 资源进行连接。Endpoint 就是一个记录 IP 和 端口的列表,用于指示服务的转发地址。

尽管在 服务中定义了 Pod 选择器,但在重定向传入连接时不会直接使用它。选择器用于构建 Pod 的 IP 端口列表,然后存储在 Endpoint 资源中。当客户端连接服务时,会从 Endpoint 资源中选择一个地址,将客户端的请求重定向到这个地址上。

手动配置 Endpoint

当服务和 Endpoint 解耦后,可以分别手动配置它们。如果创建了不包含 Pod 选择器的服务,那么 Kubernetes 就不会创建 Endpoint 资源。所以在创建服务时不指定 Pod 选择器,然后手动的创建 Endpoint 资源,实现服务的任意重定向

Endpoints 资源与服务需要具有相同的名称,这样才能使二者进行绑定。

创建 ExternalName 类型的服务

客户端 Pod 通过访问服务,手动配置服务的 Endpoint,就相当于创建了一个具有别名(别名就是 Kubernetes 中服务的名字)的外部服务。更简单的方法就是将服务的 spec.type 字段声明为 ExternalName。

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
type: ExternalName
externalName: xxx.yyy.com
ports:
- port 80

在 ExternalName 服务创建完毕后,K8s 集群内部的 Pod 可以通过 external-service 来连接到外部服务,而不是使用实际的远程 URL。在以后如果将其指向不同的服务,只需简单地修改 spec.externalName 属性,或者将类型改为 ClusterIP(集群内部地址)。

将服务暴露给外部客户端

外部的客户端访问服务有以下三种方式:

  • 服务类型设置为 NodePort:每一个集群节点上都会打开一个端口,在这个端口上收到的请求重定向给类型为 NodePort 的服务。
  • 服务类型设置为 LoadBalance:作为 NodePort 的扩展,服务可以通过专用的负载均衡器访问。负载均衡器将流量重定向到 NodePort 端口,客户端通过负载均衡器连接到服务。
  • Ingress 资源:运行在 HTTP 层,通过一个 IP 地址公开多个服务(类似于 Niginx 反向代理)。

NodePort 服务

将服务的类型设置为 NodePort,通过创建 NodePort 服务,可以让 Kubernetes 上的每一个节点都保留一个端口,将收到的请求转发给作为服务。

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: kubia-node-port
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30123 # 不是强制的,如果不指定则选择一个随机端口
selector:
app: kubia

通过访问集群内任意一个节点的 30123端口,就可以访问该服务了。

image-20230530181524181

LoadBalance 服务

使用 NodePort 时,访问集群内的任意一个节点就可以访问服务。但是,如果一个节点发生故障,客户端必须手动切换节点。LoadBalance 就是为了解决这样的问题,在所有节点之前放置一个负载均衡器,用于选择健康节点而不用客户端来手动切换

可以这样说,LoadBalance 就是一个具有额外基础设施(负载均衡器)的 NodePort 服务。

云服务商提供的 Kubernetes 集群通常支持从云基础架构自动提供负载平衡器。将服务的类型设置为 LoadBalance,通过访问负载均衡器,就可以访问到内部的服务了。

image-20230530182214724

Ingress

LoadBalance 服务需要有自己的负载均衡器并且独有公网 IP,但是 Ingress 只需要一个公网 IP 就可以为多个服务提供外部访问。Ingress 工作在 HTTP 层,当客户端向 Ingress 发送 HTTP 请求时,Ingress 会根据请求路径决定转发的服务

Ingress 提供反向代理的功能,因为工作在应用层所以也可以配置 TLS 安全连接

需要注意的是,Ingress 不会将客户端请求转发给服务(再由服务转发给具体 Pod),Ingress 仅仅会通过服务选择一个 Pod,然后直接将请求转发给 Pod

image-20230530183832502

就绪探针

如果 Pod 的标签和服务的标签选择器相匹配,那么 Pod 就成为了服务的后端。创建了相同标签的 Pod,就会成为服务的一部分。但是新创建的 Pod 可能需要时间来加载配置或者数据,在这种情况下不希望 Pod 立即开始接收请求,直到这个 Pod 准备就绪

Kubernetes 还允许为容器定义准备就绪探针,就绪探针会定期调用,以确定 Pod 是否已经准备好提供服务。和存活探针一样,就绪探针也有三种类型:

  • Exec 探针:在容器中执行,准备状态由退出结果码决定。
  • HTTP Get 探针:向容器发送 HTTP GET 请求,通过响应码来判断。
  • TCP Socket 探针:与容器建立 TCP 连接,通过是否成功建立连接来判断。