分类目录归档:VPC

基于boto的几个Elastic IP的用法

原始的boto关于ElasticIP的api使用起来比较不友好,例如实例与EIP关联的时候,需要给出VPC里的EIP的allocation_id,而allocation_id要从eip的属性里找出来,disassociate eip的时候,需要提供association_id,这个id比较难找。而常规的思路是,不管是关联和解关联,只需要提供实例ID和EIP就行,因此我封装了几个函数来使EIP的使用变的稍微友好点。
(ElasticIP和PublicIP的区别,详见我的这篇文章http://imbusy.me/elastic_ip-and-public_ip.html)

1,将eip的allocation函数封装,返回IP和allocationIP的字典,供后面关联函数使用

import boto.ec2
region = 'ap-southeast-1'

def eip_allocation(domain='vpc'):
    conn = boto.ec2.connect_to_region(region)
    allocation = conn.allocate_address(domain='vpc', dry_run=False)
    return {'public_ip':allocation.public_ip,
            'allocation_id':allocation.allocation_id}

返回字典例如
{'public_ip':'54.169.xx.xx', 'allocation_id':'eipalloc-b2e3xxxx'}

2,原始的associate函数需要给出实例ID和EIP的allocation_id,那假如不是分配IP后立即使用,而是把已经存在的EIP与实例关联,这样就得通过EIP来解析出allocation_id,于是重新包装下,使其只需要实例ID和EIP即可,而eip_allocation函数正好二者都返回,随便选用。

def eip_association(instance_id,public_ip):
    '''Notice: need InstanceID and PublicIP to make association'''
    conn = boto.ec2.connect_to_region(region)
    ##make sure input ip is valid EIP
    try:
        address = conn.get_all_addresses(addresses=[public_ip])
    except boto.exception.EC2ResponseError:
        print "Error: IP not found or not EIP"
    else:
        allocation_id = address[0].allocation_id
    ## to call boto associate_address func
    conn.associate_address(
        instance_id=instance_id,
        public_ip=None,
        allocation_id=allocation_id,
        network_interface_id=None,
        private_ip_address=None,
        allow_reassociation=False,
        dry_run=False)

3,disassociate原始的函数也是需要association_id的,而正常思路是只需要提供EIP就可以将其与实例解除关联,于是重新包装了函数,只需要给出EIP就能解除关联

def eip_disassociation(public_ip):
    conn = boto.ec2.connect_to_region(region)
    '''Notice: use public_ip to get network_interface_id
    and use network_interface_id to get association_id'''
    ##make sure input ip is valid EIP
    try:
        address = conn.get_all_addresses(addresses=[public_ip])
    except boto.exception.EC2ResponseError:
        print "Error: IP not found or not EIP"
    else:
        association_id = address[0].association_id
        #network_interface_id = address[0].network_interface_id    
    conn.disassociate_address(
        public_ip=None,
        association_id=association_id,
        dry_run=False)

4,释放EIP,重新包装了下,使其不需要allocation_id,只需要给出EIP就能释放,并且会判断EIP是否被使用,只有没被使用的EIP才能被释放,当然,每个函数还有个判断输入的EIP是否为真实的EIP。

def eip_release(public_ip):
    conn = boto.ec2.connect_to_region(region)
    ##make sure input ip is valid EIP
    try:
        address = conn.get_all_addresses(addresses=[public_ip])
    except boto.exception.EC2ResponseError:
        print "Error: IP not found or not EIP"
    else:
        association_id = address[0].association_id
        allocation_id = address[0].allocation_id
    ## only release EIP that not associated to any instance
    if association_id == None:
        conn.release_address(
            public_ip=None,
            allocation_id=allocation_id)
    else:
        print "IP %s is in use, cannot be released" % public_ip

5,重新构造了个函数,用户给实例快速更换EIP,适用于爬虫服务器,因为他的IP经常被封掉。另外提一句,如果实例创建之初自动分配过Public IP的话,关联EIP之后,PublicIP也会变成与ElasticIP一样(被覆盖),等解除EIP关联之后,PublicIP才会显露,但此时会重新分配,因此PublicIP会变。

def eip_change(instance_id):
    conn = boto.ec2.connect_to_region(region)
    reservations = conn.get_all_reservations([instance_id])
    instances = reservations[0].instances
    inst = instances[0]
    old_public_ip = inst.ip_address
    ##make sure the public ip is valid EIP
    try:
        address = conn.get_all_addresses(addresses=[old_public_ip])
    except boto.exception.EC2ResponseError:
        print "Error: Old public IP not found or not EIP"
    else:
        eip_disassociation(old_public_ip)
        eip_release(old_public_ip)
    ## add new IP 
    allocation = eip_allocation()
    public_ip = allocation['public_ip']
    eip_association(instance_id,public_ip)

6,下面是主函数里的调用示例

def main():
    #usage demos
    #eip_disassociation('54.xx.xx.xx')
    #eip_association('i-xxxxxxxx','54.xx.xx.xx')
    #eip_release('54.xx.xx.xx')
    #eip_change('i-xxxxxxxx')
     
if __name__ == '__main__':
    main()

用Peering Connections将多个VPC私网打通

目的:打通相同region的两个VPC(相同账号或者不同账号)
VPC A 10.0.0.0/16 (主动方)
VPC B 10.1.0.0/16 (被动方)

使用web console图形界面操作
这个涉及到网络和路由层面的,建议还是浏览器操作, 在VPC服务dashboard左侧中间有Peering Connections选项
1. 创建一个AB之间的peering connection,可以跨账号打通。并获取Id”,形如”pcx-111xxx111″
2. 接受创建PeeringConnection邀请,跨账号的话,在对方账号操作
3. VPC A中创建到VPC B私网的路由,Destination写VPC B的网段,Target选择刚才创建的pcx
4. VPC B中创建到VPC A私网的路由,Destination写VPC A的网段, Target选择刚才创建的pcx

用命令行API操作
1. 列举出当前节点的所有VPC重要信息
aws ec2 describe-vpcs --query 'Vpcs[*].[VpcId,CidrBlock,Tags]'
2. 创建peering connection
aws ec2 create-vpc-peering-connection --vpc-id vpc-aaaaaaaa --peer-vpc-id vpc-bbbbbbbb
跨账号打通的话
aws ec2 create-vpc-peering-connection --vpc-id vpc-aaaaaaaa --peer-vpc-id vpc-bbbbbbbb --peer-owner-id 123456bbbbbb
并获取到VpcPeeringConnectionId,形如pcx-aaaxxxbbb
3. 在同账号或者对方账号接收邀请
aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id pcx-aaaxxxbbb
4. 在VPC A中添加到VPC B的路由
aws ec2 create-route --route-table-id rtb-aaaaaaaa --destination-cidr-block 10.1.0.0/16 --vpc-peering-connection-id pcx-aaaxxxbbb
5. 在VPC B中添加到VPC A的路由
aws ec2 create-route --route-table-id rtb-bbbbbbbb --destination-cidr-block 10.0.0.0/16 --vpc-peering-connection-id pcx-aaaxxxbbb
6. 然后修改安全组允许访问就OK了

其他:

1. 假如A和B打通了,B和C打通了,A和C之间不做操作的话,是不通的,必须也创建peering connection
2. 暂不支持跨region打通,VPC到自己机房之间打通没试过,不知可行否
3. 私网IP冲突的话,那是肯定不行的,所以使用之初,最好做下VPC网络规划
4. 这种功能对于像畅游这样十来个子账号做consolidated billing使用的话,打通私网就节省了好多监控、中控之类的辅助功能服务器

Route53增加了期待已久的私网DNS功能

现在在Route53里添加Hosted zone的时候会发现多了个选项Type,里面有Private Hosted Zone for Amazon VPC。这个就是期待已久的私网DNS服务,有了这个,我们可以将自定义的私网域名解析到实例的私网IP上。创建的时候可以选择关联一个VPC,但创建好之后发现还可以继续添加关联别的region的VPC,这样私网域名就可以在你的账号下的所有或者多个VPC内生效。

开启这个功能,得先开启VPC的DNS支持,具体的是在VPC设置里Summary里设置成
DNS resolution:yes
DNS hostnames:yes
命令行模式:

#查看当前VPC attribute
~$ aws ec2 describe-vpc-attribute --vpc-id vpc-xxxxxxxx --attribute enableDnsSupport
{
    "VpcId": "vpc-xxxxxxxx ",
    "EnableDnsHostnames": {},
    "EnableDnsSupport": {
        "Value": true
    }
}
~$ aws ec2  describe-vpc-attribute --vpc-id vpc-xxxxxxxx --attribute enableDnsHostnames
{
    "VpcId": "vpc-xxxxxxxx ",
    "EnableDnsHostnames": {
        "Value": true
    },
    "EnableDnsSupport": {}
}

如果不是true,就需要修改VPC attribute,命令行这么修改

#修改VPC attribute
~$ aws ec2 modify-vpc-attribute --vpc-id vpc-xxxxxxxx --enable-dns-support
{
    "return": "true"
}
~$ aws ec2 modify-vpc-attribute --vpc-id vpc-xxxxxxxx --enable-dns-hostnames
{
    "return": "true"
}

然后创建私网域名做解析使用就好

Elastic IP 和 Public IP 的区别

创建EC2实例的时候,我们可以勾选“自动分配Public IP”(原话是英文的哦~),也可以不勾选,然后手动关联Elastic IP(EIP),那么着二者有什么区别呢?
从亚马逊在线技术支持那里了解到:
(1)EIP是属于某个特定的账号,可以关联到账号的任意实例上,也可卸载下来重新关联到其他实例上,而且实例被删除之后,EIP依然单独存在。(分配EIP时注意VPC和EC2的EIP的区别,不同类型的EIP时能关联到自己类型的实例上,即VPC中的EIP只能用于VPC中的实例,Classic EC2只能关联非VPC的EIP)
(2)而普通的Public IP是属于具体的某台实例,不能卸载重新关联到别的实例,实例创建时,如果勾选自动分配Public IP,则会随实例一起被创建,实例删除时,跟着被删除,无法被重复利用和保留;
(3)还有一个非常重要的特性:Public IP在实例关机后再开机,可能会改变,重启不影响(这跟Classic EC2实例的Public DNS一样,可能会改变)。而EIP怎么都不会变。
(4)如果实例创建之初,有PublicIP,然后再关联了ElasticIP的话,二者都会变成ElasticIP的样子(被覆盖),当EIP被解除关联之后,PublicIP才会被显露,但此时会重新分配PublicIP,所以PublicIP会变。
所以,如果在EC2实例的生命周期内,有停机再开机的可能,还是使用EIP比较保险