多应用共享公网带宽(代码示例)

本文为您介绍如何使用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 alibabacloud_credentials.client import Client as CredClient
    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
    
    # 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
    # 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
    # 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
    cred = CredClient()
    access_key_id = cred.get_access_key_id()
    access_key_secret = cred.get_access_key_secret()
    
    # 创建AcsClient实例
    client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')
    
    # 创建NAT网关实例
    request = CreateNatGatewayRequest()
    request.set_accept_format('json')
    
    # NAT网关所属的VPC ID
    request.set_VpcId("vpc-bp1fu6qir3kh9017q****")
    
    # NAT网关的名称
    request.set_Name("test")
    
    # NAT网关的描述
    request.set_Description("test")
    
    # NAT网关的付费模式
    # 取值:PostPaid(默认值)
    request.set_InstanceChargeType("PostPaid")
    
    # NAT网关所属的交换机ID
    # 创建增强型NAT网关时,您必须指定NAT网关所属的交换机,系统会为增强型NAT网关分配一个交换机内的空闲私网IP地址
    request.set_VSwitchId("vsw-bp1nz9748zh312m37****")
    
    # NAT网关的网关类型
    # 取值:Normal:普通型NAT网关 Enhanced:增强型NAT网关
    # 增强型NAT网关在普通型NAT网关的技术架构上作了升级,具有更优的弹性和更强的稳定性,帮助您更好的管理公网访问流量
    request.set_NatType("Enhanced")
    
    # NAT网关的计费类型
    # 取值:PayByLcu:按使用量计费
    request.set_InternetChargeType("PayByLcu")
    
    # 发起API请求并打印返回
    response = client.do_action_with_exception(request)
    
    # python2:  print(response)
    print(str(response, encoding='utf-8'))

    执行结果如下:

    {
        "RequestId":"8859BB3B-47F5-*****************",
        "SnatTableIds":{
            "SnatTableId":[
                "stb-bp1d09opt**********"
            ]
        },
        "ForwardTableIds":{
            "ForwardTableId":[
                "ftb-bp1h*************"
            ]
        },
        "BandwidthPackageIds":{
            "BandwidthPackageId":[]
        },
        "NatGatewayId":""ngw-uf6htj15rgyp8ivix****""
    }
  2. 根据以下代码示例,查询NAT网关的详细信息。

    from alibabacloud_credentials.client import Client as CredClient
    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
    
    # 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
    # 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
    # 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
    cred = CredClient()
    access_key_id = cred.get_access_key_id()
    access_key_secret = cred.get_access_key_secret()
    
    # 创建AcsClient实例
    client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')
    
    # 查询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,
        "PageSize":10,
        "RequestId":"6928DB33-84E0-**************",
        "PageNumber":1,
        "NatGateways":{
            "NatGateway":[
                {
                    "Description":"test",
                    "ResourceGroupId":"rg-acfmyxp******",
                    "InstanceChargeType":"PostPaid",
                    "EipBindMode":"MULTI_BINDED",
                    "FullNatTableIds":{
                        "FullNatTableId":[]
                    },
                    "BandwidthPackageIds":{
                        "BandwidthPackageId":[]
                    },
                    "BusinessStatus":"Normal",
                    "Name":"test",
                    "NetworkType":"internet",
                    "ExpiredTime":"",
                    "Tags":{
                        "Tag":[]
                    },
                    "Status":"Available",
                    "ForwardTableIds":{
                        "ForwardTableId":[
                            "ftb-bp1h*************"
                        ]
                    },
                    "SecurityProtectionEnabled":false,
                    "IpLists":{
                        "IpList":[]
                    },
                    "AutoPay":false,
                    "DeletionProtection":false,
                    "NatType":"Enhanced",
                    "InternetChargeType":"PayByLcu",
                    "NatGatewayPrivateInfo":{
                        "MaxSessionEstablishRate":100000,
                        "IzNo":"cn-hangzhou-g",
                        "PrivateIpAddress":"10.4.0.57",
                        "MaxSessionQuota":2000000,
                        "MaxBandwidth":5120,
                        "EniInstanceId":"eni-bp19ray**********",
                        "EniType":"",
                        "VswitchId":"vsw-bp1nz97***********"
                    },
                    "EcsMetricEnabled":false,
                    "VpcId":"vpc-bp1fu6***********",
                    "SnatTableIds":{
                        "SnatTableId":[
                            "stb-bp1d09opt**********"
                        ]
                    },
                    "CreationTime":"2023-02-10T07:07:03Z",
                    "IcmpReplyEnabled":true,
                    "RegionId":"cn-hangzhou",
                    "Spec":"",
                    "NatGatewayId":""ngw-uf6htj15rgyp8ivix****""
                }
            ]
        }
                            

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

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

根据以下代码示例,将EIP与NAT网关绑定。

from alibabacloud_credentials.client import Client as CredClient
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****"]

# 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
# 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
# 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
cred = CredClient()
access_key_id = cred.get_access_key_id()
access_key_secret = cred.get_access_key_secret()

# 创建AcsClient实例
client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')

# 将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 alibabacloud_credentials.client import Client as CredClient
    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
    
    # 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
    # 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
    # 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
    cred = CredClient()
    access_key_id = cred.get_access_key_id()
    access_key_secret = cred.get_access_key_secret()
    
    # 创建AcsClient实例
    client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')
    
    # 创建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 alibabacloud_credentials.client import Client as CredClient
    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
    
    # 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
    # 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
    # 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
    cred = CredClient()
    access_key_id = cred.get_access_key_id()
    access_key_secret = cred.get_access_key_secret()
    
    # 创建AcsClient实例
    client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')
    
    # 创建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 alibabacloud_credentials.client import Client as CredClient
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

# 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
# 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
# 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
cred = CredClient()
access_key_id = cred.get_access_key_id()
access_key_secret = cred.get_access_key_secret()

# 创建AcsClient实例
client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')

# 创建共享带宽实例
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 alibabacloud_credentials.client import Client as CredClient
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****"]

# 阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。
# 强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。
# 本示例通过阿里云Credentials工具从环境变量中读取AccessKey,来实现API访问的身份验证。
cred = CredClient()
access_key_id = cred.get_access_key_id()
access_key_secret = cred.get_access_key_secret()

# 创建AcsClient实例
client = AcsClient(access_key_id, access_key_secret, '<your-region-id>')

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