Kubernetes - Mapping External Services

在使用 Kubernetes 集群时,我们有访问外部服务的需要,比如一些公共的 API 服务,或者是自己自建的一些数据存储服务等。

如果在不同环境中的应用程序连接到相同的外部 Endpoint,并且没有计划将外部服务引入 Kubernetes 集群,那么直接在代码中使用外部服务 Endpoint 是完全可以的。但是,有些情况是例外的,比如某些 Cloud Native 的数据库(例如 Cloud Firestore 或 Cloud Spanner)使用单个端点进行所有访问,但大多数数据库对于不同实例具有单独的端点。

一种解决方法是:使用 ConfigMap。只需将端点地址存储在 ConfigMap 中,然后在代码中将其用作环境变量。这个解决方案有效,但存在一些缺点:需要修改 ConfigMap 并编写其他代码以从环境变量中读取;但最重要的是,如果端点地址发生更改,则可能需要重新启动所有正在运行的容器以获取更新的端点地址。而 Kubernetes 为我们提供了内置的服务发现机制来更好的解决这个问题。

Kubernetes 如何做外部服务映射

Kubernetes 的内置服务发现机制为集群外运行的服务提供服务,就像为集群内的服务一样!这使得跨开发环境和产品环境提供了方便,并且如果最终将服务移至群集内,则完全不必更改代码。

在 Kubernetes 群集外具有 IP 地址的数据库做服务映射

这种场景比较常见:在 Kubernetes 集群外有一个独立的数据库服务,需要让集群内的服务可以访问到这个带有 IP 地址的外部服务。

  • 首先创建一个 Service

kind: Service
apiVersion: v1
metadata:
 name: external-mysql-svc
Spec:
 type: ClusterIP
 ports:
 - port: 3306
   targetPort: 13306

这个服务没有 Pod 选择器,在创建 Service 后,并不知道将流量发送到哪里,接下来需要创建一个 Endpoint,该对象将接收来自该服务的流量。

  • 再创建一个 Endpoint

kind: Endpoints
apiVersion: v1
metadata:
 name: external-mysql-svc
subsets:
 - addresses:
     - ip: 10.240.0.4
   ports:
     - port: 13306

Endpoint 手动定义了数据库的 IP 地址,并且使用了与 Service 相同的名称。 Kubernetes 使用 Endpoint 中定义的所有 IP 地址,就像它们是常规的 Kubernetes Pod 一样。

然后就可以使用下面的方式在应用服务中访问数据库:

jdbc:mysql://external-mysql-svc/test?useSSL=false&characterEncoding=utf8

这种方式完全不需要在代码中使用 IP 地址!如果将来 IP 地址发生变化,则可以使用新的 IP 地址更新 Endpoint,并且应用程序无需进行任何更改.

在 Kubernetes 群集外具有 URI 地址的数据库做服务映射

如果使用的是来自第三方的托管数据库服务,则很可能会提供了可用于连接的统一资源标识符(URI)。三方托管的服务可能为不同的环境提供了不同的 URI 地址:

// dev 环境
mongodb://<dbuser>:<dbpassword>@ds149763.mlab.com:49763/dev

// prod 环境
mongodb://<dbuser>:<dbpassword>@ds145868.mlab.com:45868/prod

这个时候可以创建 ExternalName Service,这提供了静态 Kubernetes 服务,可将流量重定向到外部服务。此服务在内核级别执行简单的 CNAME 重定向,因此对性能的影响很小。如下:

kind: Service
apiVersion: v1
metadata:
  name: mongo
spec:
  type: ExternalName
  externalName: ds149763.mlab.com

由于 ExternalName 使用 CNAME 重定向,因此无法进行端口映射。对于具有静态端口的服务,这种方式会更加适用。

总结

通过将外部服务映射到内部服务,可以灵活地将来将这些服务引入群集中,同时最大程度地减少重构工作。此外,它使管理和了解正在使用哪些外部服务变得更加容易。

如果外部服务具有有效的域名,并且不需要重新映射端口,则使用 ExternalName 服务类型是将外部服务映射到内部服务的简便快捷方式。如果没有域名或需要进行端口重新映射,只需将 IP 地址添加到 Endpoint 并使用它即可。

via: https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-mapping-external-services

via: https://blog.opskumu.com/kubernetes-ext-service.html

最后更新于