背景
专有网络环境下,云服务器ECS实例不能直接访问公网,一种方法是给需要访问公网的ECS实例申请弹性IP,但是如果有大量的ECS实例同时需要访问公网,这种方法就不可行。今天将介绍一种SNAT网关访问公网的方式。如下图所示 :
这种方法需要申请一台额外的ECS实例绑定EIP做VPC网络的SNAT网关。首先这台ECS实例要在指定的VPC网络中,要绑定EIP,配置这台ECS实例上的iptables, 最后在指定VPC网络的路由表中添加下一跳是这台ECS的路由项。详细的手动配置过程请参考这里。
ROS资源介绍
下面将介绍如何通过ROS自动化创建配置VPC SNAT网关。在模版中使用了ROS的如下资源:
- InternetChargeType:计费方式,按带宽或者按照流量
- Bandwidth: 带宽在[1~200]取值,单位是Mbps
创建EIP资源
- AllocationId:分配的EIP ID
- InstanceId: 需要绑定EIP的ECS instance ID
本资源资源将绑定EIP到指定的ECS实例
- RouteId: 指定VPC网络中的路由器ID
- RouteTableId: 指定VPC网络中路由表ID
- DestinationCidrBlock: 路由项的目标网段
- NextHopId:路由项的下一跳
本资源将会添加一条路由到指定VPC网络的路由表中,它的下一跳是SNAT网关
- 本例中主要使用了UserData属性,用户通过指定脚本给UserData,当ECS启动的时候,就会自动配置iptables。
本资源就是创建SNAT网关
编写ROS模版
在模版中,首先说明此stack需要一个EIP资源,一台ECS实例,并且把EIP绑定到ECS资源上,最终通过执行我们传给ECS的UserData脚本自动化的配置iptbales,最终把下一跳指向ECS的路由项添加到VPC路由器的路由表里面。最终的ROS模版如下:
{
"ROSTemplateFormatVersion": "2015-09-01",
"Description": "一键创建SNAT网关",
"Parameters": {
"SecurityGroupId": {
"Description": "安全组ID",
"Type": "String"
},
"RouteTableId": {
"Description": "专有网络中路由器ID",
"Type": "String"
},
"RouteId": {
"Description": "专有网络中路由器ID",
"Type": "String"
},
"EIPBandwidth": {
"Default": 5,
"MinValue": 1,
"Description": "弹性公网IP的限速,默认为 5Mbps。",
"Type": "Number",
"MaxValue": 200
},
"ECSZoneId": {
"Description": "可用区, , <a href='#/product/cn-shenzhen/list/zoneList' target='_blank'>查看可用区</a>",
"Type": "String"
},
"ECSPassword": {
"NoEcho": true,
"MaxLength": 30,
"Description": "实例的密码",
"Type": "String",
"ConstraintDescription": "8-30个字符, 必须同时包含三项(大、小写字母,数字和特殊符号).",
"MinLength": 8
},
"VSwitchId": {
"Type": "String"
},
"VpcId": {
"Type": "String"
},
"VSwitchCidrBlock": {
"Description": "通过SNAT网关访问外网的VSwitch网段,此网段必须属于VPC",
"Type": "String"
},
"EIPInternetChargeType": {
"Default": "PayByTraffic",
"AllowedValues": [
"PayByBandwidth",
"PayByTraffic"
],
"Description": "弹性公网IP计费类型,PayByBandwidth(按固定带宽计费),PayByTraffic(按使用流量计费),固定带宽的费用以天计,使用流量的费用以小时计",
"Type": "String"
},
"ECSSysDiskSize": {
"Default": 40,
"MinValue": 40,
"Description": "系统盘大小,40-500之间",
"Type": "Number",
"MaxValue": 500
},
"ECSDiskCategory": {
"Default": "cloud_efficiency",
"AllowedValues": [
"cloud",
"cloud_efficiency",
"cloud_ssd"
],
"Description": "系统盘的磁盘种类, 普通云盘(cloud)、高效云盘(cloud_efficiency)或SSD云盘(cloud_ssd)",
"Type": "String"
},
"ECSInstanceType": {
"Default": "ecs.s2.large",
"AllowedValues": [
"ecs.t1.small",
"ecs.s1.small",
"ecs.s1.medium",
"ecs.s1.large",
"ecs.s2.small",
"ecs.s2.large",
"ecs.s2.xlarge",
"ecs.s2.2xlarge",
"ecs.s3.medium",
"ecs.s3.large",
"ecs.m1.medium",
"ecs.m2.medium",
"ecs.m1.xlarge",
"ecs.c1.small",
"ecs.c1.large",
"ecs.c2.medium",
"ecs.c2.large",
"ecs.c2.xlarge",
"ecs.n1.tiny",
"ecs.n1.small",
"ecs.n1.medium",
"ecs.n1.large",
"ecs.n1.xlarge"
],
"Description": "实例规格, <a href='#/product/cn-shenzhen/list/typeList' target='_blank'>查看实例规格</a>",
"Type": "String"
},
"ECSImageId": {
"Default": "ubuntu1404_64_40G_cloudinit_20160427.raw",
"Description": "镜像文件 ID,表示启动实例时选择的镜像资源, <a href='#/product/cn-shenzhen/list/imageList' target='_blank'>查看实例规格</a>",
"Type": "String"
},
"ECSTag": {
"Description": "ECS的标签",
"Type": "String"
}
},
"Resources": {
"ElasticIpAssociation": {
"Type": "ALIYUN::ECS::EIPAssociation",
"Properties": {
"InstanceId": {
"Fn::Select": [
"0",
{
"Fn::GetAtt": [
"ECSSnatGateWay",
"InstanceIds"
]
}
]
},
"AllocationId": {
"Fn::GetAtt": [
"ElasticIp",
"AllocationId"
]
}
}
},
"VRoute": {
"Type": "ALIYUN::ECS::Route",
"Properties": {
"NextHopId": {
"Fn::Select": [
"0",
{
"Fn::GetAtt": [
"ECSSnatGateWay",
"InstanceIds"
]
}
]
},
"RouteId": {
"Ref": "RouteId"
},
"RouteTableId": {
"Ref": "RouteTableId"
},
"DestinationCidrBlock": "0.0.0.0/0"
}
},
"ECSSnatGateWay": {
"Type": "ALIYUN::ECS::InstanceGroup",
"Properties": {
"SecurityGroupId": {
"Ref": "SecurityGroupId"
},
"ImageId": {
"Ref": "ECSImageId"
},
"Password": {
"Ref": "ECSPassword"
},
"MinAmount": "1",
"InternetMaxBandwidthIn": 100,
"UserData": {
"Fn::Replace": [
{
"ros-notify": {
"Fn::GetAtt": [
"ECSSnatGateWayConditionHandle",
"CurlCli"
]
}
},
{
"Fn::Join": [
"",
[
"#!/bin/sh",
"\n",
"PostRouting=",
{
"Ref": "VSwitchCidrBlock"
},
"\n",
"SourceRouting=`ifconfig eth0|grep inet|awk '{print $2}'|tr -d 'addr:'`",
"\n",
"echo 'net.ipv4.ip_forward=1'>> /etc/sysctl.conf \n",
"sysctl -p \n",
"iptables -t nat -I POSTROUTING -s $PostRouting -j SNAT --to-source $SourceRouting \n",
"apt-get update\n",
"apt-get install -y curl\n",
"ros-notify -d '{\"data\" : \" docker swarm created\"}'\n"
]
]
}
]
},
"ZoneId": {
"Ref": "ECSZoneId"
},
"VSwitchId": {
"Ref": "VSwitchId"
},
"InternetChargeType": "PayByTraffic",
"VpcId": {
"Ref": "VpcId"
},
"InstanceType": {
"Ref": "ECSInstanceType"
},
"SystemDisk_Category": {
"Ref": "ECSDiskCategory"
},
"IoOptimized": "optimized",
"Tags": [
{
"Value": {
"Ref": "ECSTag"
},
"Key": "ECS_SNAT_GATEWAY"
}
],
"InternetMaxBandwidthOut": 100,
"SystemDisk_Size": {
"Ref": "ECSSysDiskSize"
},
"MaxAmount": "1"
}
},
"ECSSnatGateWayConditionHandle": {
"Type": "ALIYUN::ROS::WaitConditionHandle"
},
"ECSSnatGateWayGroupWaitCondition": {
"Type": "ALIYUN::ROS::WaitCondition",
"DependsOn": "ECSSnatGateWay",
"Properties": {
"Handle": {
"Ref": "ECSSnatGateWayConditionHandle"
},
"Timeout": 600,
"Count": 1
}
},
"ElasticIp": {
"Type": "ALIYUN::ECS::EIP",
"Properties": {
"InternetChargeType": {
"Ref": "EIPInternetChargeType"
},
"Bandwidth": {
"Ref": "EIPBandwidth"
}
}
}
},
"Outputs": {
"ECSSnatGateWay_INNER_IPS": {
"Value": {
"Fn::GetAtt": [
"ECSSnatGateWay",
"PrivateIps"
]
},
"Description": "Inner IP address of the ECS instance."
},
"ECSSnatGateWay_InstanceIds": {
"Value": {
"Fn::GetAtt": [
"ECSSnatGateWay",
"InstanceIds"
]
},
"Description": "The instance id of created ecs instance"
},
"EipAddress": {
"Value": {
"Fn::GetAtt": [
"ElasticIp",
"EipAddress"
]
},
"Description": "IP address of created EIP."
},
"ECSSnatGateWay_ZoneIds": {
"Value": {
"Fn::GetAtt": [
"ECSSnatGateWay",
"ZoneIds"
]
},
"Description": "Zone id of created instance."
}
}
}