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

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

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

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

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

## 获取容器 IP

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

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

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

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

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

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

## 获取版本 IP

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

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

``` json
{
  "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 来代替内网域名，至于线上版本这一环节的判断，只能用版本号的约定来实现了。
