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

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

5.2.1 介绍 service endpoints

服务并不是和 pod 直接相连的。相反有一种资源介于两者之间—-它就是 Endpoints 资源。
image.png

An Endpoints resource (yes, plural) is a list of IP addresses and ports exposing a service.
Endpoints (复数的) 资源就是暴露服务的一个IP地址和端口的列表。
image.png

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

5.2.2 手动配置服务的 endpoints

服务的 endpoints 与服务解耦后,可以分别手动配置和更新它们。

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

要使用手动配置 endpoints 的方式创建服务,需要创建服务和 Endpoints 资源两者。

创建没有选择器的服务

image.png

  1. cd /root/k8s/
  2. cat >external-service.yaml <<'EOF'
  3. apiVersion: v1
  4. kind: Service
  5. metadata:
  6. name: external-service
  7. spec:
  8. ports:
  9. - port: 80
  10. EOF
  11. kubectl create -f external-service.yaml

image.png


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

Endpoints是一个单独的资源并不是服务的一个属性。由于创建的资源中并不包含选择器,相关的Endpoints 资源并没有自动创建,所以必须手动创建。
image.png

  1. cd /root/k8s/
  2. cat >external-service-endpoints.yaml <<'EOF'
  3. apiVersion: v1
  4. kind: Endpoints
  5. metadata:
  6. name: external-service
  7. subsets:
  8. - addresses:
  9. - ip: 11.11.11.11
  10. - ip: 22.22.22.22
  11. ports:
  12. - port: 80
  13. EOF
  14. kubectl create -f external-service-endpoints.yaml

image.png

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

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

5.2.3 为外部服务创建别名

除了手动配置服务的Endpoints来暴露外部服务,有一种更简单的方法,就是通过FQDN访问外部服务。

创建ExtenalName类型的服务

例如,设想一下在api.somecompany.com上有公共可用的API,你可以定义一个指向它的服务。
image.png

cd /root/k8s/

cat >external-service-externalname.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  type: ExternalName
  externalName: api.somecompany.com
  ports:
  - port: 80
EOF

kubectl create -f external-service-externalname.yaml

image.png

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

ExternalName的服务仅在DNS级别实施——为服务创建了简单的CNAME DNS记录。因此,连接到服务的客户端将直接连接到外部服务,完全绕过服务代理。出于这个原因,这些类型的服务甚至不会获得集群IP。由于“ExternalName” 使用 CNAME 重定向,因此无法执行端口重映射。

注意:CNAME记录 (别名记录)指向FQDN而不是数字IP地址。这种记录允许你将多个名字映射到同一台计算机。