k8s in action实践笔记

5.2 连接集群外部的服务

2021-07-20  本文已影响0人  众神开挂

5.2 连接集群外部的服务

到现在为止,我们已经讨论了后端是集群中运行的一个或多个pod的服务。但也存在希望通过Kubernetes服务特性暴露外部服务的情况。不要让服务将连接重定向到集群中的pod,而是让它重定向到外部IP和端口。

这样做可以让你充分利用服务负载平衡和服务发现。在集群中运行的客户端pod可以像连接到内部服务一样连接到外部服务。

5.2.1 介绍服务endpoint

在进入如何做到这一点之前,先阐述一下服务。服务并不是和pod直接相连的。相反,有一种资源介于两者之间——它就是Endpoint资源。如果之前在服务上运行过kubectl describe,可能已经注意到了endpoint,如下面的代码清单所示。

代码清单5.7 用kubectl describe展示服务的全部细节

# kubectl describe svc kubia
Name:              kubia
Namespace:         custom
Labels:            <none>
Annotations:       <none>
Selector:          app=kubia  #用于创建endpoint列表的服务pod选择器
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.111.56.158
IPs:               10.111.56.158
Port:              <unset>  80/TCP
TargetPort:        8080/TCP
Endpoints:         172.18.0.2:8080,172.18.0.3:8080,172.18.0.4:8080 # 代表服务endpoint的pod的IP和端口列表
Session Affinity:  None
Events:            <none>

Endpoint资源就是暴露一个服务的IP地址和端口的列表,Endpoint资源和其他Kubernetes资源一样,所以可以使用 kubectl info 来获取它的基本信息。

$ kubectl get endpoint kubia

尽管在 spec服务中定义了pod选择器,但在重定向传入连接时不会直接使用它。相反,选择器用于构建IP和端口列表,然后存储在Endpoint资源中。当客户端连接到服务时,服务代理选择这些IP和端口对中的一个,并将传入连接重定向到在该位置监听的服务器。

5.2.2 手动配置服务的endpoint

或许已经意识到这一点,服务的 endpoint与服务解耦后,可以分别手动配置和更新它们。

如果创建了不包含pod选择器的服务,Kubernetes将不会创建Endpoint资源(毕竟,缺少选择器,将不会知道服务中包含哪些pod)。这样就需要创建Endpoint资源来指定该服务的endpoint列表。

要使用手动配置endpoint的方式创建服务,需要创建服务和Endpoint资源。

创建没有选择器的服务

首先为服务创建一个YAML文件,如下面的代码清单所示。

代码清单5.8 不含pod选择器的服务:external-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: external-service # 服务的名字必须和endpoint对象的名字相匹配
spec:
  ports:
  - port: 80
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
  externalIPs:
    - 80.11.12.10

定义一个名为external-service的服务,它将接收端口80上的传入连接。并没有为服务定义一个pod选择器。

为没有选择器的服务创建Endpoint资源

Endpoint是一个单独的资源并不是服务的一个属性。由于创建的资源中并不包含选择器,相关的Endpoints资源并没有自动创建,所以必须手动创建。如下所示的代码清单中列出了YAML manifest。

k get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
kubia-7d5b548867-4qn2x   1/1     Running   1          23h   172.18.0.2   minikube   <none>           <none>
kubia-7d5b548867-8wnls   1/1     Running   1          23h   172.18.0.3   minikube   <none>           <none>
kubia-7d5b548867-m4bfz   1/1     Running   1          23h   172.18.0.4   minikube   <none>           <none>

代码清单5.9 手动创建Endpoint资源:external-service-endpoints.yaml

apiVersion: v1
kind: Endpoints
metadata:
  name: external-service # endpoint的名称必须和服务相匹配
subsets:
  - addresses:
    - ip: 172.18.0.2 #服务将连接重定向到endpoint的ip地址
    - ip: 192.168.0.105 
    - ip: 119.147.33.43
    ports:
    - port: 8080  #endpoint的目标端口

验证一下

$ k exec -it kubia-7d5b548867-4qn2x -- bash
$ curl http://external-service

Endpoint对象需要与服务具有相同的名称,并包含该服务的目标IP地址和端口列表。服务和Endpoint资源都发布到服务器后,这样服务就可以像具有pod选择器那样的服务正常使用。在服务创建后创建的容器将包含服务的环境变量,并且与其IP:port对的所有连接都将在服务端点之间进行负载均衡。

图5.4显示了三个pod连接到具有外部endpoint的服务。

如果稍后决定将外部服务迁移到Kubernetes中运行的pod,可以为服务添加选择器,从而对Endpoint进行自动管理。反过来也是一样的——将选择器从服务中移除,Kubernetes将停止更新Endpoints。这意味着服务的IP地址可以保持不变,同时服务的实际实现却发生了改变。

5.2.3 为外部服务创建别名

除了手动配置服务的Endpoint来代替公开外部服务方法,有一种更简单的方法,就是通过其完全限定域名(FQDN)访问外部服务

创建ExternalName类型的服务

要创建一个具有别名的外部服务的服务时,要将创建服务资源的一个type字段设置为ExternalName。例如,设想一下在http://api.somecompany.com上有公共可用的API,可以定义一个指向它的服务,如下面的代码清单所示。

代码清单5.10 ExternalName类型的服务:external-service-externalname.yaml\

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  type: ExternalName
  externalName: www.baidu.com  #实际服务的域名
  ports:
  - port: 80

服务创建完成后,pod可以通过 external-service.default.svc.cluster.local 域名(甚至是 external-service )连接到外部服务,而不是使用服务的实际FQDN。这隐藏了实际的服务名称及其使用该服务的pod的位置,允许修改服务定义,并且在以后如果将其指向不同的服务,只需简单地修改externalName属性,或者将类型重新变回ClusterIP并为服务创建Endpoint——无论是手动创建,还是对服务上指定标签选择器使其自动创建。

ExternalName 服务仅在DNS级别实施——为服务创建了简单的CNAME DNS记录。因此,连接到服务的客户端将直接连接到外部服务,完全绕过服务代理。

出于这个原因,这些类型的服务甚至不会获得集群IP。

注意 CNAME记录指向完全限定的域名而不是数字IP地址。

上一篇下一篇

猜你喜欢

热点阅读