# 无内网域名情况下服务间访问

微信云托管一开始有内网域名,但由于安全性方面有隐患,所以主动下掉了,后续会通过服务升级方式回归此功能。

在这期间,同一个环境下服务间访问的场景应该如何实现呢?

对此我们提出了一些路径,希望可以对你的实现有所启发。

需要声明:以下内容只是开发者对当前形态的最佳实践做了分享,并不代表官方团队的产品设计和使用导向。

# 获取容器IP

一个云托管环境下有多个服务,一个服务可能随着版本升级(你不断的发布)有多个版本,一个版本根据你的配置或者线上流量的关系可能有多个容器。

我们在一个环境中,一个服务访问另一个服务,实际就是一个服务下的容器访问另一个服务的容器。

在容器中可以通过ifconfig查看自身的内网IP,同一VPC(或内网互联)下其他服务都可以直接访问这个 IP 地址。

但有一个问题,那就是容器是不固定的,虽然他存活的时候 IP 是不变的,但由于自动弹性扩缩容或者版本更替的原因,容器可能被回收,也就是说你无法在其他服务中写一个固定的 IP 地址。

容器 IP 这个路子在服务间调用的场景下基本走不通,除非你用数据库记录 IP 地址并维持响应,一般容器 IP 主要用在服务内的多个实例的协作沟通。

比如实例中使用内存缓存数据库的数据,当数据变更时,可以通过容器 IP 通知同服务的其他实例发起自动更新。相比轮询数据库,主动触发通知的可行性要更高一些,但也对你的架构水平提出更高的要求。

# 获取版本IP

既然容器会因为弹性扩缩回收,导致容器 IP 失效,那么有什么是不回收的?那就是版本IP。

我们创建一个服务,比如名字为 server,那么在这个环境下「所有服务容器中环境变量」里,都会存在一个 server_${版本号} 开头的变量集,具体如下:

{
  "SERVER_001_SERVICE_HOST": "172.16.195.225",
  "SERVER_001_SERVICE_PORT": "80",
  "SERVER_001_SERVICE_PORT_TCP_80": "80",
  "SERVER_001_PORT": "tcp://172.16.195.225:80",
  "SERVER_001_PORT_80_TCP": "tcp://172.16.195.225:80",
  "SERVER_001_PORT_80_TCP_ADDR": "172.16.195.225",
  "SERVER_001_PORT_80_TCP_PORT": "80",
  "SERVER_001_PORT_80_TCP_PROTO": "tcp"
}

上述显示的 IP 是一个虚拟IP,只是映射同一个版本下的所有容器实例(如果有多个会轮询),其他服务如果想要访问 server 服务时,可以直接从环境变量中获取 IP 地址,并发送请求。

但这里还是有一些小问题,一个服务下如果有多个版本(之前的未删除),变量集也会有多组,所以你需要约定一下,取版本号最大的一组 IP 作为服务IP。

但也需要注意,在你回退版本时,需要把大于的版本都删除掉,这套逻辑才没有问题。

# 服务内网域名

服务内网域名其实只是做了一下服务中「线上版本虚拟IP」的 A记录,所以在服务内网域名下掉的情况下,我们可以用虚拟 IP 来代替内网域名,至于线上版本这一环节的判断,只能用版本号的约定来实现了。