背景说明
众所周知,业务服务器是企业用以提供服务实现盈利的核心,绝大多数情况业务服务器都部署于私有网络中,以保证安全。
在私有网络中的业务服务器提供业务功能时,对网络的诉求会分成两种类型:第一种是经由互联网被访问,可以借助负载均衡器进行服务暴露实现;第二种则是主动访问互联网。
对于第二种类型,如果需要的公网 IP 数量少于或等于 8 个,可以使用 Amazon NAT Gateway 实现;若需要的公网 IP 数量大于 8 个,则需要更加灵活的方案。
本文将介绍两种方案,用于满足“需要的公网 IP 数量大于 8 个”的场景,并在文章的最后,对这两种方案进行优劣势比较。
─────◆─────
a. 架构图
b. 环境搭建(执行命令的机器需要有足够的权限)
1) 创建网络资源
# 0. 进入screen模式,以保证环境变量不会因为退出Session而消失 screen# 1. 创建VPC ningxia_vpc_id=$(aws ec2 create-vpc –cidr-block 10.0.0.0/16 –region cn-northwest-1 –query “Vpc.VpcId” –output text)# 2. 创建Subnet # 在AZ1中创建ningxia_subnet_az1_id1(私有子网1) ningxia_subnet_az1_id1=$(aws ec2 create-subnet –cidr-block 10.0.0.0/24 –vpc-id $ningxia_vpc_id –region cn-northwest-1 –availability-zone cn-northwest-1a –query “Subnet.SubnetId” –output text) # 在AZ1中创建ningxia_subnet_az1_id2(公有子网) ningxia_subnet_az1_id2=$(aws ec2 create-subnet –cidr-block 10.0.1.0/24 –vpc-id $ningxia_vpc_id –region cn-northwest-1 –availability-zone cn-northwest-1a –query “Subnet.SubnetId” –output text)# 3. 创建路由表 # 创建ningxia_route_table_id1(私有子网1路由表) ningxia_route_table_id1=$(aws ec2 create-route-table –vpc-id $ningxia_vpc_id –region cn-northwest-1 –query “RouteTable.RouteTableId” –output text) # 创建ningxia_route_table_id2(公有子网路由表) ningxia_route_table_id2=$(aws ec2 create-route-table –vpc-id $ningxia_vpc_id –region cn-northwest-1 –query “RouteTable.RouteTableId” –output text)# 4. 更改子网路由表 aws ec2 associate-route-table –route-table-id $ningxia_route_table_id1 –subnet-id $ningxia_subnet_az1_id1 –region cn-northwest-1 aws ec2 associate-route-table –route-table-id $ningxia_route_table_id2 –subnet-id $ningxia_subnet_az1_id2 –region cn-northwest-1# 5. 修改安全组 # 获取宁夏的groupid groupid_ningxia=$(aws ec2 describe-security-groups –region cn-northwest-1 –filter “Name=vpc-id,Values=$ningxia_vpc_id” –query “SecurityGroups[].GroupId” –output text) # 基于获取的groupid,修改安全组 aws ec2 authorize-security-group-ingress –group-id “$groupid_ningxia” –protocol all –port all –cidr “0.0.0.0/0” –region cn-northwest-1# 6. 创建并附加Internet Gateway internet_gateway_id_ningxia=$(aws ec2 create-internet-gateway –region cn-northwest-1 –query “InternetGateway.InternetGatewayId” –output text) aws ec2 attach-internet-gateway –region cn-northwest-1 –internet-gateway-id $internet_gateway_id_ningxia –vpc-id $ningxia_vpc_id# 7. 修改路由表 aws ec2 create-route –destination-cidr-block 0.0.0.0/0 –gateway-id $internet_gateway_id_ningxia –region cn-northwest-1 –route-table-id $ningxia_route_table_id1 aws ec2 create-route –destination-cidr-block 0.0.0.0/0 –gateway-id $internet_gateway_id_ningxia –region cn-northwest-1 –route-table-id $ningxia_route_table_id2 |
2) 创建实例资源
# 8. 创建业务服务器1 business_instance_id=$(aws ec2 run-instances –region cn-northwest-1 –image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 –instance-type t3.micro –key-name id_rsa_test.pub –security-group-ids $groupid_ningxia –subnet-id $ningxia_subnet_az1_id1 –associate-public-ip-address –query ‘Instances[].InstanceId’ –output text) # 等待实例创建完成 aws ec2 wait instance-status-ok –instance-ids $business_instance_id –region cn-northwest-1 # 获得business_instance_ip business_instance_ip=$(aws ec2 describe-instances –instance-ids “$business_instance_id” –region cn-northwest-1 –query ‘Reservations[0].Instances[0].PublicIpAddress’ –output text)# 9. 创建转发服务器 proxy_instance_id=$(aws ec2 run-instances –region cn-northwest-1 –image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 –instance-type t3.medium –key-name id_rsa_test.pub –security-group-ids $groupid_ningxia –subnet-id $ningxia_subnet_az1_id2 –associate-public-ip-address –query ‘Instances[].InstanceId’ –output text) # 等待实例创建完成 aws ec2 wait instance-status-ok –instance-ids $proxy_instance_id –region cn-northwest-1 # 获得proxy_instance_ip proxy_instance_ip=$(aws ec2 describe-instances –instance-ids “$proxy_instance_id” –region cn-northwest-1 –query ‘Reservations[0].Instances[0].PublicIpAddress’ –output text)# 创建好转发服务器,需要修改业务服务器1的路由表,将路由条目0.0.0.0/0的下一跳指向转发服务器的主网卡,这样所有流量都将流向转发服务器。 |
c. 配置转发服务器
1) 原理解释
iptables 中提供两种模式实现四层负载均衡,分别是 random(随机)和 nth(轮询)。
random 模式基于概率实现负载均衡,请参考如下示例说明:
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 –dport 27017 -m statistic –mode random –probability 0.33 -j DNAT –to-destination 10.0.0.2:1234 iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 –dport 27017 -m statistic –mode random –probability 0.5 -j DNAT –to-destination 10.0.0.3:1234 iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 –dport 27017 -j DNAT –to-destination 10.0.0.4:1234 |
rules 说明:
第一条规则中,指定 –probability 0.33 ,则说明该规则有 33% 的概率会命中。
第二条规则也有 33% 的概率命中,因为规则中指定 –probability 0.5。 则命中的概率为:50% * (1 – 33%)=0.33。
第三条规则中,没有指定 –probability 参数,因此意味着当匹配走到第三条规则时,则一定命中,此时走到第三条规则的概率为:1 – 0.33 -0.33 ≈ 0.33。
由上可见,可以通过修改 –probability 参数调整规则命中率。
probability 计算规则说明:
假设有 n 个 server,则可以设定 n 条 rule 将流量均分到 n 个 server 上,其中 –probability 参数的值可通过以下公式计算得到:p=1/(n−i+1)
# 其中 i 代表规则的序号(第一条规则的序号为1)
# n 代表规则/server的总数
# p 代表第 i 条规则中 –probability 的参数值
nth 模式基于轮询实现负载均衡,请参考如下示例说明:
# every:每n个包匹配一次规则 # packet:从第p个包开始iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 –dport 27017 -m statistic –mode nth –every 1 –packet 0 -j DNAT –to-destination 10.0.0.1:1234 iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 –dport 27017 -m statistic –mode nth –every 2 –packet 0 -j DNAT –to-destination 10.0.0.2:1234 iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 –dport 27017 -m statistic –mode nth –every 3 –packet 0 -j DNAT –to-destination 10.0.0.3:1234 |
rules 说明:
第一条规则是从第 0 个包开始计算,匹配第 1 个包
第二条规则是从第 0 个包开始计算,匹配第 2 个包
第三条规则是从第 0 个包开始计算,匹配第 3 个包
第 4 个包回到原点,再次重新匹配,以此反复循环
2) 部署转发服务器(这次实验采用 nth 方式进行)
为了实现多公网 IP 轮询,首先需要转发服务器拥有多个公网 IP,可以将 Elastic IP 与主网卡的多个 Secondary Private IP 进行绑定实现。又由于路由的原因,无法使用 Secondary Network Interface。所以,转发服务器可以拥有多少个公网 IP,将由实例的主网卡可以拥有多少个 Secondary Private IP 决定。这次实验使用的是 t3.medium,此实例类型主网卡可以拥有最多 6 个私网地址,去掉已经使用的 Primary Private IP,总计有 5 个 Secondary Private IP。具体哪种实例可以有多少 IP,请参考如下链接:Elastic network interfaces – Amazon Elastic Compute Cloud。
# 10. 创建Secondary Private IP并绑定EIP # 获取主网卡id network_interface_id=$(aws ec2 describe-instances –region cn-northwest-1 –instance-ids $proxy_instance_id –query “Reservations[].Instances[].NetworkInterfaces[].NetworkInterfaceId” –output text) # 分配私网地址 private_ip_list=$(aws ec2 assign-private-ip-addresses –region cn-northwest-1 –network-interface-id $network_interface_id –secondary-private-ip-address-count 5 –query “AssignedPrivateIpAddresses[].PrivateIpAddress” –output text) # 申请并绑定EIP count=1; for i in $private_ip_list; do allocation_id=$(aws ec2 allocate-address –region cn-northwest-1 –query “AllocationId” –output text); allocation_id_list[$count]=$allocation_id; association_id=$(aws ec2 associate-address –region cn-northwest-1 –allocation-id $allocation_id –network-interface-id $network_interface_id –private-ip-address $i –output text) association_id_list[$count]=$association_id ((count++)); done |
创建完 Secondary Private IP 并绑定 EIP 后,下一步就是关闭实例的 source/destination check 以及登录到转发服务器进行 iptables nth 规则的设置。
# 关闭source/destination check aws ec2 modify-instance-attribute –region cn-northwest-1 –no-source-dest-check –instance-id $proxy_instance_id # 登录转发服务器(以下命令通过root账号执行) sysctl -w net.ipv4.ip_forward=1 iptables -t nat -I POSTROUTING -m statistic –mode nth –every 1 –packet 0 -j SNAT –to-source 10.0.1.184 iptables -t nat -I POSTROUTING -m statistic –mode nth –every 2 –packet 0 -j SNAT –to-source 10.0.1.177 iptables -t nat -I POSTROUTING -m statistic –mode nth –every 3 –packet 0 -j SNAT –to-source 10.0.1.9 iptables -t nat -I POSTROUTING -m statistic –mode nth –every 4 –packet 0 -j SNAT –to-source 10.0.1.252 iptables -t nat -I POSTROUTING -m statistic –mode nth –every 5 –packet 0 -j SNAT –to-source 10.0.1.46 iptables -t nat -I POSTROUTING -m statistic –mode nth –every 6 –packet 0 -j SNAT –to-source 10.0.1.63 yum install iptables-services -y service iptables save # 持久化规则 |
d. 测试
登录到业务服务器 1,通过 curl ip.sb 获取访问公网的 IP 地址,可以看到是以轮训的方式获取到了不同的 IP 地址,而这些 IP 地址就是在转发服务器上绑定的 EIP。
e. 环境清理
下载环境清理:
# 删除资源,对应# 10 # 解绑并释放EIP count=1; for i in $private_ip_list; do aws ec2 disassociate-address –association-id ${association_id_list[$count]} –region cn-northwest-1 aws ec2 release-address –allocation-id ${allocation_id_list[$count]} –region cn-northwest-1 ((count++)); done # 删除私网地址 aws ec2 unassign-private-ip-addresses –region cn-northwest-1 –network-interface-id $network_interface_id –private-ip-addresses $private_ip_list# 删除资源,对应# 8, 9 aws ec2 terminate-instances –region cn-northwest-1 –instance-ids $proxy_instance_id aws ec2 wait instance-terminated –region cn-northwest-1 –instance-ids $proxy_instance_id aws ec2 terminate-instances –region cn-northwest-1 –instance-ids $business_instance_id aws ec2 wait instance-terminated –region cn-northwest-1 –instance-ids $business_instance_id# 删除资源,对应#2. 创建Subnet aws ec2 delete-subnet –region cn-northwest-1 –subnet-id $ningxia_subnet_az1_id1 aws ec2 delete-subnet –region cn-northwest-1 –subnet-id $ningxia_subnet_az1_id2# 删除资源,对应# 3. 创建路由表 for i in $(aws ec2 describe-route-tables –region cn-northwest-1 –filter “Name=vpc-id,Values=$ningxia_vpc_id” –query “RouteTables[].RouteTableId” –output text); do aws ec2 delete-route-table –region cn-northwest-1 –route-table-id $i; done# 删除资源,对应# 6. 创建并附加Internet Gateway aws ec2 detach-internet-gateway –internet-gateway-id $internet_gateway_id_ningxia –vpc-id $ningxia_vpc_id –region cn-northwest-1 aws ec2 delete-internet-gateway –internet-gateway-id $internet_gateway_id_ningxia –region cn-northwest-1# 删除资源,对应# 1. 创建VPC aws ec2 delete-vpc –region cn-northwest-1 –vpc-id $ningxia_vpc_id |