本文为您介绍如何使用Alibaba Cloud SDK for Python调用API接口,实现多个应用共享一份公网带宽,以节省公网成本。

配置场景

本文以下图场景为例。某公司创建了两台ECS实例,每台ECS实例都部署了一个应用服务,要求应用服务可以面向互联网提供服务,服务端口为80。两个ECS实例在不同时间段的带宽需求量不同,具体如下:
  • ECS1实例的业务高峰期为每天的13:00:00~18:00:00,带宽需求量为1000Mbps,其他时间为业务低谷期,带宽需求量为500Mbps。
  • ECS2实例的业务高峰期为每天的19:00:00~23:00:00,带宽需求量为1000Mbps,其他时间为业务低谷期,带宽需求量为500Mbps。

如果为每个ECS实例购买公网带宽,则需要购买2000Mbps带宽,但在业务低谷期带宽利用率低,造成带宽资源浪费。

您可以组合使用NAT网关的DNAT功能和共享带宽的共享功能,配置成功后:
  • DNAT功能可以将NAT网关上的公网IP映射给ECS实例使用,使ECS实例可以面向互联网提供服务。
  • 共享带宽可以实现多个应用共享一份公网带宽,以节省公网成本。
配置场景

前提条件

开始前,请确保以下条件:

  • 您已经注册了阿里云账号。如未注册,请先完成账号注册
  • 您已经创建了访问密钥(AccessKey)。 如未创建,请前往AccessKey管理页面创建AccessKey。
  • 您已经安装了Python开发环境和Alibaba Cloud SDK for Python。详细信息,请参见安装阿里云Python SDK
  • 您已经创建了专有网络(VPC)和交换机。具体操作,请参见CreateVpc
  • 您已经在交换机中创建了ECS实例,且ECS实例部署了应用服务。具体操作,请参见CreateInstance
  • 您已经创建了两个弹性公网IP(EIP),用于绑定NAT网关实例。EIP必须满足以下条件:
    • EIP的地域与要绑定的NAT网关的地域相同。
    • EIP的计费方式必须为按量计费。

    具体操作,请参见AllocateEipAddress

配置步骤

配置步骤

步骤一:创建NAT网关

NAT网关是一款企业级的公网网关,提供NAT代理功能。在配置DNAT条目前,您需要先创建一个NAT网关实例。
说明 创建增强型NAT网关时,您必须指定NAT网关所属的交换机,系统会为增强型NAT网关分配一个交换机内的空闲私网IP地址。
  • 如果您要在存量交换机中创建增强型NAT网关,请确保交换机所属的可用区支持创建增强型NAT网关,且交换机有可用的IP。
  • 如果您还未创建交换机,请先在支持创建增强型NAT网关的可用区创建交换机,然后再指定增强型NAT网关所属的交换机。

您可以通过ListEnhanhcedNatGatewayAvailableZones接口查询增强型NAT网关的资源可用区,通过DescribeVSwitches接口查询交换机中的可用IP数。

  1. 根据以下代码示例,创建NAT网关。
    from aliyunsdkcore.client import AcsClient
    from aliyunsdkcore.acs_exception.exceptions import ClientException
    from aliyunsdkcore.acs_exception.exceptions import ServerException
    from aliyunsdkvpc.request.v20160428.CreateNatGatewayRequest import CreateNatGatewayRequest
    
    # 创建AcsClient实例
    # yourAccessKeyId:您的AccessKey ID
    # yourAccessKeySecret:您的AccessKey Secret
    # yourRegionId:地域ID
    client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")
    
    # 创建NAT网关实例
    request = CreateNatGatewayRequest()
    request.set_accept_format('json')
    
    # NAT网关所属的VPC ID
    request.set_VpcId("vpc-uf68wppzf839896z7****")
    
    # NAT网关的名称
    request.set_Name("test")
    
    # NAT网关的描述
    request.set_Description("test")
    
    # NAT网关的规格
    # 取值:Small(默认值):小型 Middle:中型 Large:大型 XLarge.1:超大型-1,本示例取值Small,请根据实际业务需求设置规格
    request.set_Spec("Small")
    
    # NAT网关的付费模式
    # 取值:PostPaid(默认值):按量付费 PrePaid:包年包月
    request.set_InstanceChargeType("PrePaid")
    
    # 包年包月的计费周期
    # 取值:Month(默认值):按月付费 Year:按年付费
    # 当InstanceChargeType参数的取值为PrePaid时,该参数必选;当InstanceChargeType参数的值为PostPaid时,该参数可不填
    request.set_PricingCycle("Month")
    
    # 购买时长
    # 当PricingCycle取值Month时,Period取值范围为1~9,当PricingCycle取值Year时,Period取值范围为1~3
    request.set_Duration("1")
    
    # 自动付费
    # 取值:false:不开启自动付费,生成订单后需要到订单中心完成支付 true:开启自动付费,自动支付订单
    request.set_AutoPay(True)
    
    # NAT网关所属的交换机ID
    # 创建增强型NAT网关时,您必须指定NAT网关所属的交换机,系统会为增强型NAT网关分配一个交换机内的空闲私网IP地址
    request.set_VSwitchId("vsw-uf6gnat6e5tk0gnbm****")
    
    # NAT网关的网关类型
    # 取值:Normal:普通型NAT网关 Enhanced:增强型NAT网关
    # 增强型NAT网关在普通型NAT网关的技术架构上作了升级,具有更优的弹性和更强的稳定性,帮助您更好的管理公网访问流量
    request.set_NatType("Enhanced")
    
    # NAT网关的计费类型
    # 取值:PayBySpec:按固定规格计费 PayByLcu:按使用量计费
    request.set_InternetChargeType("PayBySpec")
    
    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)
    
    # python2:  print(response)
    print(str(response, encoding='utf-8'))
    执行结果如下:
    {
        "RequestId": "3164006B-33DB-46BB-B77D-FC80094D1F10",
        "SnatTableIds": {
            "SnatTableId": []
        },
        "ForwardTableIds": {
            "ForwardTableId": []
        },
        "NatGatewayId": "ngw-uf6htj15rgyp8ivix****"
    }
  2. 根据以下代码示例,查询NAT网关的详细信息。
    from aliyunsdkcore.client import AcsClient
    from aliyunsdkcore.acs_exception.exceptions import ClientException
    from aliyunsdkcore.acs_exception.exceptions import ServerException
    from aliyunsdkvpc.request.v20160428.DescribeNatGatewaysRequest import DescribeNatGatewaysRequest
    
    # 创建AcsClient实例
    # yourAccessKeyId:您的AccessKey ID
    # yourAccessKeySecret:您的AccessKey Secret
    # yourRegionId:地域ID
    client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")
    
    # 查询NAT网关的详细信息
    request = DescribeNatGatewaysRequest()
    request.set_accept_format('json')
    
    # 要查询的NAT网关实例ID
    request.set_NatGatewayId("ngw-uf6htj15rgyp8ivix****")
    
    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)
    
    # python2:  print(response)
    print(str(response, encoding='utf-8'))
    执行结果如下:
    {
        "TotalCount": 1,
        "RequestId": "4040A37C-45C0-4C85-B16D-0F7EA3084108",
        "PageSize": 10,
        "PageNumber": 1,
        "NatGateways": {
            "NatGateway": [{
                "Status": "Available",
                "Description": "test",
                "ResourceGroupId": "rg-acfmx2k5un****",
                "InstanceChargeType": "PrePaid",
                "ForwardTableIds": {
                    "ForwardTableId": ["ftb-uf6hdobgppflyr2ng****"]
                },
                "IpLists": {
                    "IpList": []
                },
                "BandwidthPackageIds": {
                    "BandwidthPackageId": []
                },
                "AutoPay": false,
                "DeletionProtection": false,
                "BusinessStatus": "Normal",
                "NatType": "Enhanced",
                "Name": "test",
                "InternetChargeType": "PayBySpec",
                "NatGatewayPrivateInfo": {
                    "IzNo": "",
                    "PrivateIpAddress": "",
                    "EniInstanceId": "",
                    "VswitchId": ""
                },
                "EcsMetricEnabled": false,
                "VpcId": "vpc-uf68wppzf839896z7****",
                "SnatTableIds": {
                    "SnatTableId": ["stb-uf6qneg0l83lxignc****"]
                },
                "ExpiredTime": "2020-10-28T16:00Z",
                "CreationTime": "2020-09-28T07:24:09Z",
                "RegionId": "cn-shanghai",
                "Spec": "Small",
                "NatGatewayId": "ngw-uf6htj15rgyp8ivix****"
            }]
        }
    }

步骤二:将EIP与NAT网关绑定

NAT网关作为一个网关设备,需要绑定公网IP才能正常工作。

根据以下代码示例,将EIP与NAT网关绑定。
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkvpc.request.v20160428.AssociateEipAddressRequest import AssociateEipAddressRequest

# 要绑定NAT网关的EIP的ID,本示例取值EIP1和EIP2的ID
allocationIds = ["eip-uf6pvlaprugu1azc8****", "eip-uf69ls0f3qgv0alk6****"]

# 创建AcsClient实例
# yourAccessKeyId:您的AccessKey ID
# yourAccessKeySecret:您的AccessKey Secret
# yourRegionId:地域ID
client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")

# 将EIP与NAT网关绑定
for i in range(0, 2):
    request = AssociateEipAddressRequest()
    request.set_accept_format('json')

    # 要绑定EIP的NAT网关ID
    request.set_InstanceId("ngw-uf6htj15rgyp8ivix****")

    # 要绑定NAT网关的EIP的ID
    request.set_AllocationId(allocationIds[i])

    # 要绑定EIP的资源类型
    request.set_InstanceType("NAT")
    
    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)

    # python2:  print(response)
    print(str(response, encoding='utf-8'))
执行结果如下:
{
    "RequestId": "8292A46D-F720-4AEE-98FB-7D3352BA2B63"
}
{
    "RequestId": "E62EEBF8-D327-440E-95BC-8884832C1326"
}

步骤三:创建DNAT条目

通过NAT网关的DNAT功能,可以将NAT网关上的公网IP映射给ECS实例使用,使ECS实例能够提供互联网服务。在本示例中,您需要为ECS1和ECS2实例创建如下DNAT条目。
条目名称 公网IP地址 公网端口 协议类型 私网IP地址 私网端口
DNAT1 EIP1 80 TCP ECS1 80
DNAT2 EIP2 80 TCP ECS2 80
  1. 根据以下代码示例,为ECS1实例创建DNAT条目。
    from aliyunsdkcore.client import AcsClient
    from aliyunsdkcore.acs_exception.exceptions import ClientException
    from aliyunsdkcore.acs_exception.exceptions import ServerException
    from aliyunsdkvpc.request.v20160428.CreateForwardEntryRequest import CreateForwardEntryRequest
    
    # 创建AcsClient实例
    # yourAccessKeyId:您的AccessKey ID
    # yourAccessKeySecret:您的AccessKey Secret
    # yourRegionId:地域ID
    client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")
    
    # 创建DNAT条目
    request = CreateForwardEntryRequest()
    request.set_accept_format('json')
    
    # 要创建DNAT条目的DNAT列表ID
    request.set_ForwardTableId("ftb-uf6hdobgppflyr2ng****")
    
    # 提供公网访问的公网IP地址,本示例取值EIP1的IP地址
    request.set_ExternalIp("101.xx.xx.137")
    
    # 需要进行端口转发的外部端口,取值范围:1~65535。本示例取值80
    request.set_ExternalPort("80")
    
    # 需要进行公网通信的ECS实例的私网IP地址,本示例取值ECS1的IP地址
    request.set_InternalIp("192.xx.xx.100")
    
    # 需要进行端口转发的内部端口,取值范围:1~65535。本示例取值80
    request.set_InternalPort("80")
    
    # 协议类型
    # 取值:TCP:转发TCP协议的报文 UDP:转发UDP协议的报文 Any:转发所有协议的报文
    request.set_IpProtocol("TCP")
    
    # DNAT条目的名称,本示例取值DNAT1
    request.set_ForwardEntryName("DNAT1")
    
    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)
    
    # python2:  print(response)
    print(str(response, encoding='utf-8'))
    执行结果如下:
    {
        "RequestId": "93A6E13E-C168-4444-9DF1-F4B22B1E0A12",
        "ForwardEntryId": "fwd-uf69gp4nyj8b9aa2n****"
    }
  2. 根据以下代码示例,为ECS2实例创建DNAT条目。
    from aliyunsdkcore.client import AcsClient
    from aliyunsdkcore.acs_exception.exceptions import ClientException
    from aliyunsdkcore.acs_exception.exceptions import ServerException
    from aliyunsdkvpc.request.v20160428.CreateForwardEntryRequest import CreateForwardEntryRequest
    
    # 创建AcsClient实例
    # yourAccessKeyId:您的AccessKey ID
    # yourAccessKeySecret:您的AccessKey Secret
    # yourRegionId:地域ID
    client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")
    
    # 创建DNAT条目
    request = CreateForwardEntryRequest()
    request.set_accept_format('json')
    
    # 要创建DNAT条目的DNAT列表ID
    request.set_ForwardTableId("ftb-uf6hdobgppflyr2ng****")
    
    # 提供公网访问的公网IP地址,本示例取值EIP1的IP地址
    request.set_ExternalIp("106.xx.xx.94")
    
    # 需要进行端口转发的外部端口,取值范围:1~65535。本示例取值80
    request.set_ExternalPort("80")
    
    # 需要进行公网通信的ECS实例的私网IP地址,本示例取值ECS1的IP地址
    request.set_InternalIp("192.xx.xx.101")
    
    # 需要进行端口转发的内部端口,取值范围:1~65535。本示例取值80
    request.set_InternalPort("80")
    
    # 协议类型
    # 取值:TCP:转发TCP协议的报文 UDP:转发UDP协议的报文 Any:转发所有协议的报文
    request.set_IpProtocol("TCP")
    
    # DNAT条目的名称,本示例取值DNAT2
    request.set_ForwardEntryName("DNAT2")
    
    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)
    
    # python2:  print(response)
    print(str(response, encoding='utf-8'))
    执行结果如下:
    {
        "RequestId": "EB455CB3-222E-4F62-AF20-FAF908615717",
        "ForwardEntryId": "fwd-uf6g8gu2ld36nohly****"
    }

步骤四:创建共享带宽

共享带宽提供地域级带宽共享和复用功能,可以为您节省公网带宽使用成本。

根据以下代码示例,创建一个共享带宽实例。

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkvpc.request.v20160428.CreateCommonBandwidthPackageRequest import CreateCommonBandwidthPackageRequest

# 创建AcsClient实例
# yourAccessKeyId:您的AccessKey ID
# yourAccessKeySecret:您的AccessKey Secret
# yourRegionId:地域ID
client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")

# 创建共享带宽实例
request = CreateCommonBandwidthPackageRequest()
request.set_accept_format('json')

# 共享带宽的带宽峰值,取值:1000~5000,单位为Mbps,本示例取值1500,请根据实际业务需求设置带宽峰值
request.set_Bandwidth(1500)

# 线路类型
# 取值:BGP:BGP(多线)线路 BGP_PRO:BGP(多线)精品线路
request.set_ISP("BGP")

# 共享带宽的名称
request.set_Name("test")

# 共享带宽的描述
request.set_Description("test")

# 共享带宽的计费方式
# 取值:PayByBandwidth(默认值):按带宽计费 PayBy95:按增强型95计费
request.set_InternetChargeType("PayByBandwidth")

# 发起API请求并打印返回
response = client.do_action_with_exception(request)

# python2:  print(response)
print(str(response, encoding='utf-8'))
执行结果如下:
{
    "RequestId": "592C8AB6-09AC-4751-9B17-231BF8FEEA44",
    "ResourceGroupId": "rg-acfmx2k5unk****",
    "BandwidthPackageId": "cbwp-uf6jvfp1wqps1vywa****"
}

步骤五:将EIP添加到共享带宽

您可以将EIP1和EIP2添加到共享带宽实例中,EIP添加到共享带宽实例后:
  • EIP绑定的NAT网关会共享已购买的共享带宽。
  • EIP原本的带宽峰值无效,与共享带宽实例的带宽峰值相同。
  • EIP原本的计费方式无效。EIP变为一个公网IP,不额外收取EIP的流量费和带宽费。
根据以下代码示例,将EIP添加到共享带宽。
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkvpc.request.v20160428.AddCommonBandwidthPackageIpRequest import AddCommonBandwidthPackageIpRequest

# 定义要添加到共享带宽实例的EIP,本示例要将EIP1和EIP2添加到共享带宽
IpInstanceIds = ["eip-uf6pvlaprugu1azc8****","eip-uf69ls0f3qgv0alk6****"]

# 创建AcsClient实例
# yourAccessKeyId:您的AccessKey ID
# yourAccessKeySecret:您的AccessKey Secret
# yourRegionId:地域ID
client = AcsClient("yourAccessKeyId","yourAccessKeySecret","yourRegionId")

for i in range(0, 2):
    # 将EIP添加到共享带宽
    request = AddCommonBandwidthPackageIpRequest()
    request.set_accept_format('json')
    
    # 共享带宽的ID
    request.set_BandwidthPackageId("cbwp-uf6jvfp1wqps1vywa****")

    # 要添加到共享带宽实例的EIP
    request.set_IpInstanceId(IpInstanceIds[i])

    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)

    # python2:  print(response)
    print(str(response, encoding='utf-8'))
                
执行结果如下:
{
    "RequestId": "658D8E3C-A85E-406C-AE49-EE6ECA2B9252"
}
{
    "RequestId": "166E9BF2-C12B-45B6-A712-633AD535B446"
}

步骤六:访问测试

您可以使用互联网中的任意一台电脑访问ECS1和ECS2实例上部署的应用服务,测试ECS实例的连通性。
说明 请确保ECS实例的安全组规则允许互联网访问ECS实例。
  1. 打开互联网任意电脑的浏览器。
  2. 输入绑定到NAT网关的EIP,访问部署在ECS实例上的应用服务。
    经验证,可以从互联网访问部署在ECS1和ECS2实例上的应用服务,同时ECS1和ECS2实例共用一份公网带宽,可以应对业务高峰。
    图 1. 访问ECS1实例上的应用服务
    访问测试ECS1
    图 2. 访问ECS2实例上的应用服务
    访问测试ECS2