一个叫木头,一个叫马尾

如何将外部服务纳入到k8s集群内

我们知道,k8s 中的 service 最主要的一个功能,是允许我们对集群中的一个或一组 pods 方便地进行网络访问。但其实它还有另外一个用途,将外部服务映射到集群内,方便集群内的其它应用像访问内部服务一样地访问它。

问题背景

在采用 k8s 后,一些遗留系统或者因为迁移不方便或者因为为了同时服务于多个环境,而仍然以原来的方式运行着(不受 k8s 管理)。如果想让 k8s 内的 pods 访问这些遗留的服务,怎么办?

解决方案

  1. 最简单的,直接在 pod 内以 ip加端口 的形式访问外部服务。不好的地方在于,此时的 ip 是应编码的,当需要变更时,项目可能要重新打包部署;
  2. 通过 pod 定义文件中的hostAliases,给外部服务定义一个别名,以别名的方式访问。不好的地方在于,每个需要访问该外部服务的 pod,都需要定义hostAliases:
    apiVersion: v1kind: Podmetadata:  name: hostaliases-podspec:  hostAliases:  - ip: "172.16.181.198"    hostnames:    - "some-external-service"
  3. 利用 k8s 内置的service,定义一个统一的可访问服务:
    kind: ServiceapiVersion: v1metadata: name: some-external-servicespec: type: ClusterIP ports: - port: 8088   targetPort: 8088
    ---
    kind: EndpointsapiVersion: v1metadata: name: some-external-servicesubsets: - addresses: - ip: 172.16.181.198 ports: - port: 8088

Service外部服务配置说明

对于上面第三个方案,当配置完成后,所有 pod 都可以以http://some-external-service:8088的形式来访问外部服务了。

需要注意的点有:

  1. serviceendpointname要一致;
  2. 如果你的外部服务部署了多个实例,可以在endpoint下配置多个相应的实例ip.

另外,如果这个外部服务需要暴露到公网,你原先可能是用 nginx 在公网机器做代理转发,而现在,我们可以复用 k8singress 机制,让 k8s 去管理代理转发了,我们要做的,就是定义一个简单的 Ingress 对象:

apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: ingress-some-external-service  namespace: defaultspec:  rules:  - host: some-external-service.example.com    http:      paths:      - backend:          serviceName: some-external-service          servicePort: 8088        path: /  tls:  - hosts:    - some-external-service.example.com    secretName: tls-example.com

上述的host即公网可访问的域名,而backend就是我们要暴露的外部服务,如果需要启用https访问,就再配置一个tls条目。


如此,一个完整的外部服务纳入 k8s 集群的方案就完成了。