亚马逊AWS官方博客

基于亚马逊云科技弹性负载均衡实现设备内网穿透

IoT(物联网,Internet of Things)以及智能家居蓬勃发展,越来越多的家庭设备,如智能摄像头、智能家电、智能储能设备等,都引入了远程管理功能。如果设备支持 MQTT(消息队列遥测传输,Message Queuing Telemetry Transport)协议,我们可以通过 MQTT 下发命令。但 MQTT 接入需要复杂的功能点、状态点对接,在功能越来越多、越来越复杂时,我们往往希望快速打通,实现点对点的设备控制。但家庭网络是典型的内网环境,如何实现公网对内网服务的安全、直接访问?内网穿透正是为解决该问题而生。本文将基于亚马逊云科技提供的云服务,总结了几种通用的内网穿透解决方案。

内网穿透功能与场景介绍

内网穿透是指将内网中的网络服务或资源,映射到公共互联网,让公网用户可以访问和使用这些服务。内网穿透常见于远程办公、远程维护、远程监控等场景。如图 1 内网穿透所示。

图 1 内网穿透

常见的内网穿透解决方案

常见的内网穿透方案,可以分为硬件和软件两大类。

  • 硬件方案,是指使用硬件设备来实现内网穿透,这类方案通常需要用户购买相应的硬件设备,用户还需要配合进行网络配置,如虚拟专用网络设备、SDWAN、防火墙等设备。
  • 软件方案,是指使用软件来实现内网穿透,这类方案通常灵活性高、部署简单,也是云端最常见的实现方案,典型的软件内网穿透方案如反向代理、端口映射、专用内网穿透软件等。

在云端环境,硬件方案需要先实现虚拟化再部署。所以,本文选择了更灵活的软件方案来实现。

云端点对点内网穿透示例

通过亚马逊云科技,我们可以简单的通过 ssh 隧道方式,实现单台设备的快速公网暴露。在 EC2 服务器启动 sshd 服务,并更改配置启用 GatewayPorts 功能。设备端通过 `ssh user@ec2 -R 0.0.0.0:8080:localhost:80`,连接到 EC2 服务器建立 ssh 隧道,App 端即可通过`http://ec2:8080` 访问到内网设备端的 80 端口。如图 2 ssh 隧道实现点对点穿透所示,该方案适合单台设备的快速测试、调试场景,难以支持大量设备接入。

图 2 ssh 隧道实现点对点穿透

IoT 场景下内网穿透痛点

在 IoT 场景中,设备往往位于家庭、厂房等网络环境,网络建设等级低、网络设备能力弱、网络环境不稳定、通过 NAT(网络地址转换,Network Address Translation)接入等。内网穿透方案需要能应对这些复杂的网络环境,提升服务可用性。

基于亚马逊云科技构建内网穿透服务

本文方案的概念架构图如图 3 云端内网穿透总体架构所示。通过云端 EC2 集群,实现 App 端直接对家庭智能设备的访问。

图 3 云端内网穿透总体架构

本文方案中,通过使用亚马逊云科技 ELB(弹性负载均衡,Elastic Load Balancing),实现高可用内网穿透服务集群。同时,编写 API 服务,帮助设备与 App 端进行路径匹配与流量调度。

亚马逊云科技 ELB 负载均衡器负责接受客户端的请求,并将客户端请求,路由到一个或多个可用区中的目标(例如 EC2 实例)。 ELB 会监控已注册目标的运行状况,检测到不健康的目标时,停止将流量路由到该目标。  当检测到目标恢复正常运行时,恢复将流量路由到该目标。

为了更好地适配多种业务场景,亚马逊云科技 ELB 包含了多种分类:

本方案主要涉及 ALB(应用负载均衡)与 NLB(网络负载均衡)。

方案演示环境与假设

演示中,本文使用位于 NAT Gateway 之后的、私有子网的 2 台 EC2 Ubuntu 实例作为测试设备,其中 NAT Gateway 相当于家庭路由器。测试设备安装 Nginx 服务,修改默认页面展示设备 ID,添加设备信息以示区别。

穿透服务器集群位于云端私有子网,采用 EC2 Ubuntu 实例。假设业务需求为 App 能通过公网直接访问设备端的 HTTP 服务。

穿透服务软件采用 FRP 穿透应用开源方案。该软件支持多种协议,配置简单,安装方便。FRP 原理如图 4 FRP 穿透原理所示,通过将 FRP 服务端的服务器端口,反射到设备端服务所在设备端口,实现借由 FRP 服务器端口,对内网设备服务的访问。具体业务中,可以根据自身情况使用其他开源或者商业方案。

图 4 FRP 穿透原理

App 端通过域名访问内网设备,所以,我们还需要配置对应的域名解析。本方案中,每个设备生成唯一 UUID,并绑定域名 DeviceUUID.frp.domain.com。对于泛域名*. frp.domain.com 指向 ALB,实现全部设备 HTTP 请求通过 ALB 收口。

域名解析服务,本文采用亚马逊云科技的 Amazon Route 53 服务。Amazon Route 53 是一种具有高度可用性和可扩展性的云域名系统(DNS)网络服务,支持多种解析路由类型,包括基于延迟的路由、加权轮询、基于地理位置等,也支持泛域名解析。所有路由类型都可以与 DNS 故障转移相结合,实现各种低延迟、容错的架构,确保业务连续性。

基础方案:基于 NLB 与 ALB 的内网穿透

在内网穿透中,最核心的功能是对连接、流量的路由:

  1. 多设备与服务端建立通信通道
  2. 多 App 与服务端建立通信通道
  3. 服务端建立 App 设备的通信通道匹配

我们编写了 Device-API REST 服务端程序,负责通信通道的管理与匹配工作,其角色就像传统电话网络中的接线员:把呼叫方线路,跟被呼叫方线路,连接上。配合亚马逊云科技的 NLB 与 ALB,该方案的部署架构如图 5 基于 NLB 与 ALB 的部署方案所示。

图 5 基于 NLB 与 ALB 的部署方案

DeviceAPI 与 FTR-Server 部署在一起,所以,我们需要提前配置好 NLB,添加 Listener 访问 FTR-Server 上的 DeviceAPI。该方案的主要用例及流程为:

  1. FTR 服务端初始化与注册,实现通过 NLB 导流 FRP 连接到当前 EC2 服务器。
    • EC2 启动 DeviceAPI 时,DeviceAPI 为 FRP-Server 分配随机监听端口。
    • 按(1-a)分配的端口,启动 FRP-Server。
    • 创建新 TCP 目标组并注册本实例,用于 NLB 流量转发。
    • 配置 NLB Listener,添加(1-a)分配的端口,目标为(1-c)中创建的目标组。
    • 创建新 HTTP 目标组并注册本实例,用于接收 ALB 分配的 App 访问流量。
  2. 设备注册与端口申请
    • 设备启动时,获取(或者生成)设备号(DeviceUUID)。
    • 访问 DeviceAPI,获取访问 NLB 的端口号,即(1-d)中配置的监听端口,以及 FTR-Server 反射端口。
    • DeviceAPI 调用 API,添加 ALB Rule,对于访问 DeviceUUID 域名的请求,路由到(1-e)中创建的目标组。
  3. 设备与云端连接
    • 启动 FTR-Client,访问 NLB 对应端口,建立与 FTR-Server 的通信通道。
    • FTR-Server 在 EC2 上监听(2-b)中反射端口。
  4. App 与设备连接
    • App 端访问 DeviceUUID 的域名,Amazon Route 53 返回 ALB 的 IP 地址。
    • ALB 根据 DeviceUUID 的域名,按(2-c)的规则配置,转发流量到对应的 FRP-Server 反射端口。
    • FRP-Server 通过 3-a 中建立的通信通道,转发流量到设备端。

以上用例的流程图参考图 6 NLB 与 ALB 用例流程图

图 6 NLB 与 ALB 用例流程图

高并发方案:基于 NLB 与 DynamoDB 的内网穿透

基于 NLB 与 ALB 的基础方案,依托托管服务,可以帮助我们快速构建原型系统。但 ALB Rule 规则有上限。对于 IoT 场景的海量设备,存在 Rule 规则数量限制。因而,在高并发场景,我们对基于 NLB 与 ALB 的基础方案进行了优化改造,通过 FTR-Server 端搭建 Nginx 来实现。

由于基于 NLB 与 ALB 的域名-设备对应关系其实是存储在 ALB Rule 中。替换 ALB 后,我们需要一个新的、全局的元数据管理服务(相当于传统电话网络中的电话本)。因而,我们选择了 Amazon DynamoDB 作为元数据管理服务。

Amazon DynamoDB 是一种完全托管的 NoSQL 数据库服务,它提供快速且可预测的性能,并具有无缝扩展能力。Amazon DynamoDB 让用户无需担心硬件管理、软件设置和配置、补丁或集群扩展等操作,减轻用户运维和扩展数据库的管理负担。Amazon DynamoDB 还提供静态数据加密,保护数据隐私。

同时,DeviceAPI 也需要做相应调整,动态将元数据存入 Amazon DynamoDB,动态取回数据更新 Nginx 配置,实现 Nginx 流量转发。Nignx 单一域名的转发配置参考如下:

1.	upstream 1234567789abcdef1234567789abcdef {
2.	        server 10.1.2.3:12345;
3.	}
4.	
5.	map $http_upgrade $connection_upgrade {
6.	        default upgrade;
7.	        '' close;
8.	}
9.	
10.	server {
11.	        listen 80;
12.	        server_name 1234567789abcdef1234567789abcdef.frp.domain.com;
13.	
14.	        location / {
15.	                proxy_pass http://1234567789abcdef1234567789abcdef;
16.	                proxy_set_header X-Real-IP $remote_addr;
17.	                proxy_set_header Host $host;
18.	                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
19.	
20.	                proxy_http_version 1.1;
21.	                proxy_set_header Upgrade $http_upgrade;
22.	                proxy_set_header Connection $connection_upgrade;
23.	                proxy_set_header X-Scheme $scheme;
24.	        }
25.	}

本方案中,DeviceAPI 需要通过 DynamoDB 读写数据库,因而整体步骤与前述方案有相应调整:

  1. FTR 服务端初始化与注册,实现通过 NLB 导流 FRP 连接到当前 EC2 服务器。
    • EC2 启动 DeviceAPI 时,DeviceAPI 为 FRP-Server 分配随机监听端口。
    • 按(1-a)分配的端口,启动 FRP-Server。
    • 创建新 TCP 目标组并注册自己,用于 NLB 流量转发。
    • 配置 NLB Listener,添加(1-a)分配的端口,目标为(1-b)中创建的目标组。
  2. 设备注册与端口申请
    • 设备启动时,获取(或者生成)设备号(DeviceUUID)。
    • 访问 DeviceAPI,获取访问 NLB 的端口号,即(1-d)中配置的监听端口,以及 FTR-Server 反射端口。
    • DeviceAPI 将 client UUID,所在 EC2 IP 以及反射端口等元数据信息存入 DynamoDB。
    • DeviceAPI 添加新的 Nginx 转发规则,对于访问 DeviceUUID 域名的请求,转发到(2-b)中分配的 EC2 反射端口。
  3. 设备与云端连接
    • 启动 FTR-Client,访问 NLB 对应端口,建立与 FTR-Server 的通信通道。
    • FTR-Server 在 EC2 上监听(2-b)中反射端口。

设备端与服务端的部署架构及设备访问情况如图 7 NLB 高并发方案部署与设备注册所示。

图 7 NLB 高并发方案部署与设备注册

在 App 与设备连接时,流程会较基础方案变化较大:

  • App 端访问 DeviceUUID 的域名,Amazon Route 53 返回 NLB IP
  • NLB 随机转发到后端 FTR-Server 服务器
  • DeviceAPI 根据 DeviceUUID 的域名,从 DynamoDB 获取所需的元数据信息
  • DeviceAPI 根据元数据信息,更新 Nginx 配置(本机可能未配置过)
  • DeviceAPI 返回 HTTP 307 Redirect,触发 App 重新访问
  • Nginx 匹配到新配置的 Host,转发流量到目标 FRP-Server 及反射端口
  • FRP-Server 通过已经建立的通道,转发流量到目标设备

App 与设备连接的部署架构及设备访问情况如图 8 NLB 高并发方案 App 访问所示。

图 8 NLB 高并发方案 App 访问

引入 Amazon DynamoDB 后的高并发方案,用例流程图更新如图 9 NLB 与 DynamoDB 高并发用例流程所示。

图 9 NLB 与 DynamoDB 高并发用例流程

方案测试与验证

测试环境部署如图 10 验证环境部署架构所示。测试测试到的代码、脚本参考 https://github.com/kealiu/Nat-Penetrate。具体的安装、运行步骤参考代码文档,本文不再重复。

图 10 验证环境部署架构

在穿透服务 VPC 中的 EC2 上,部署 server 代码。然后,安装 Nginx 用于流量转发。配置 NLB 用于暴露服务器的 FRP 服务地址。然后,启动 server 代码,运行 DeviceAPI 服务。

在设备 VPC 中的 EC2 上,部署 client 代码。然后,安装 Nignx 用于对外暴露 Web 服务。更改对应的 Ngninx 主页,更新为相应的 Deivce 名称。然后只想 client 代码,与服务器端建立 FRP 连接。

在测试机器上,通过浏览器进行设备访问,确认整个访问流程与图 9 NLB 与 DynamoDB 高并发用例流程用例 4 一致。最终测试如图 11 浏览器测试结果所示。

图 11 浏览器测试结果

总结

本文介绍了两种通过亚马逊云科技服务搭建云端内网穿透的方案,只需设备能连入互联网,即可通过亚马逊云科技全球丰富的网络资源,快速实现家庭、办公环境内网设备的外部访问,并提供了详细的部署以及业务流程方案,以及示例代码、测试结果。

当然,本文方案仅介绍了内网 Web 服务的外部访问。如需要适配非 HTTP 协议,可以进一步扩展本方案或引入商用方案。商用方案(如 ngrok)能将本文中 Nginx 功能与反向代理 FRP 融为一体,在软件内部实现流量分配,根据域名自动转发到对应网络设备。部署架构上,依然可以参考本文实现。

参考文献

  1. 亚马逊云科技网络负载均衡监听 https://docs.thinkwithwp.com/elasticloadbalancing/latest/network/load-balancer-listeners.html
  2. 亚马逊云科技应用负载均衡分发规则 https://docs.thinkwithwp.com/elasticloadbalancing/latest/application/listener-update-rules.html
  3. 亚马逊云科技 NoSQL 数据库 DynamoDB https://thinkwithwp.com/cn/dynamodb/
  4. 亚马逊云科技 Python SDK Boto DynamoDB API https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html
  5. Nginx 转发规则配置 https://nginx.org/en/docs/http/ngx_http_upstream_module.html
  6. FRP 高性能的反向代理https://github.com/fatedier/frp
  7. 基于 ELB 的内网穿透示例方案代码 https://github.com/kealiu/Nat-Penetrate/

本篇作者

刘科

西云数据解决方案架构师,15+年 IT 研发、管理经验,曾就职于知名通信设备厂商、头部互联网企业,有丰富、广泛的系统架构与研发管理经验。擅长帮助企业打造完善研发 Devops 体系,构建网络与安全体系,帮助企业业务产品项目落地。

蔡如海

西云数据解决方案架构师,10+年开发和架构经验,曾就职于知名外企,在媒体、金融等业务领域有丰富的工作经验,擅长云计算、机器学习等技术,并且有丰富的项目管理经验。

卢达

解决方案架构师,10+年产品研发和解决方案架构咨询经验,曾就职于知名外企,对企业 IT 架构、云计算以及企业级存储等技术领域有丰富的经验。