Kubernetes 外部服务映射
集群内的应用有时候需要调用外部的服务,我们知道集群内部服务调用都是通过 Service 互相访问,那么针对外部的服务是否也可以保持统一使用 Service 呢?答案是肯定的,通过 Service 访问外部服务,除了方式统一以外,还能带来其他好处。如配置统一,不同环境(空间)相同应用访问外部不同环境的数据库,可以通过 Service 映射保持两边配置统一,达到不同空间应用通过相同 Service Name 访问不同的外部数据库。如图 test-1
和 test-2
两个空间为两个不同的业务环境,通过服务映射,不同空间相同的 Service 访问到对应外部不同环境的数据库:
另外,还可以保证最小化变更,如果外部数据库 IP 之类的变动,只需要修改 Service 对应映射即可,服务本身配置无需变动。具体场景如下:
1. 外部域名映射到内部 Service -> ExternalName
apiVersion: v1 kind: Service metadata: name: mysql spec: externalName: mysql.example.com type: ExternalName
创建之后,同一空间 Pod 就可以通过 mysql:3306
访问外部的 MySQL 服务。
需要注意的是,虽然 externalName 也支持填写 IP,但是并不会被 Ingress 和 CoreDNS 解析(KubeDNS 支持)。如果有 IP 相关的需求,则可以使用 Headless Service -> Type ExternalName 。另外一个需要注意的是,因为 CNAME 的缘故,如果外部的服务又经过一层代理转发,如 Nginx,除非配置对应的 server_name
,否则映射无效。
2. 外部 IP 映射到内部 Service
2.1. IP 映射
前文提过,虽然 externalName 字段可以配置为 IP 地址,但是 Ingress 和 CoreDNS 并不会解析,如果外部服务为 IP 提供,那么可以使用 Headless Service 实现映射。
apiVersion: v1 kind: Service metadata: name: mysql spec: clusterIP: None type: ClusterIP --- apiVersion: v1 kind: Endpoints metadata: name: mysql subsets: - addresses: - ip: 192.168.1.10
service 不指定 selector,手动维护创建 endpoint,创建之后就可以通过 mysql:3306
访问 192.168.1.10:3306
服务的目的。Headless Service 不能修改端口相关,如果要修改访问端口,则需要进一步操作。
2.2. IP + 端口映射
如果外部的端口不是标准的端口,想通过 Service 访问时候使用标准端口,如外部 MySQL 提供端口为 3307,内部想通过 Service 3306 访问,这个时候则可以通过如下方式实现:
apiVersion: v1 kind: Service metadata: name: mysql spec: type: ClusterIP ports: - port: 3306 targetPort: 3307 --- apiVersion: v1 kind: Endpoints metadata: name: mysql subsets: - addresses: - ip: 192.168.1.10 ports: - port: 3307
service 不指定 selector,手动维护创建 endpoint,创建之后就可以通过 mysql:3306
达到访问外部 192.168.1.10:3307
服务的目的。
3. 小结
我们可以看出以上外部服务映射,externalName 和 Headless Service 方式映射外部服务是没有经过中间层代理的,都是通过 DNS 劫持实现。而有端口变更需求的时候,则要经过内部 kube-proxy 层转发。正常情况下,能尽可能少的引入中间层就少引用,特别是数据库类的应用,因为引入中间层虽然带来了便利,但也意味着可能会带来性能损耗,特别是那些对延迟比较敏感的服务。