aws volume 的查询、创建、挂载 和 卸载

做个集合,方面查阅,欢迎参考,哈哈哈。

 

查看  volume-id 

import boto.ec2

region = “ap-southeast-1”
aws_access_key_id = “”
aws_secret_access_key = “”

conn = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)
reservations = conn.get_all_instances()
for res in reservations:
    for instance in res.instances:
        if ‘Name’ in instance.tags:
           volume_list = []
           for i in instance.block_device_mapping:
               volume_dict = {}
               volume_dict[“device”] = i
               volume_dict[“volume_id”] = instance.block_device_mapping.get(i).volume_id
               volume_list.append(volume_dict)

           print “%s (%s) [%s]:\n %s” % (instance.tags[‘Name’], instance.id, instance.state, volume_list)
        else:
           volume_list = []
           for i in instance.block_device_mapping:
               volume_dict = {}
               volume_dict[“device”] = i
               volume_dict[“volume_id”] = instance.block_device_mapping.get(i).volume_id
               volume_list.append(volume_dict)

           print “%s [%s]:\n %s” % (instance.id, instance.state, volume_list)
        print

 

创建volume

import boto.ec2

region = “ap-southeast-1”
aws_access_key_id = “”
aws_secret_access_key = “”

conn = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)

size = “126”
zone = “ap-southeast-1b”

volume_info = conn.create_volume(size, zone)
volume_id = volume_info.id

time_init = 0
time_total = 20
time_interval = 1
while time_init < time_total:
    volume_info.update()
    status = volume_info.status
    if status == ‘available’:
        print “{0}, {1}”.format(volume_id, status)
        break
    else:
        time.sleep(time_interval)
        time_init += time_interval

 

把一个 volume-id 挂载到 一个实例上

import boto.ec2

region = “ap-southeast-1”
aws_access_key_id = “”
aws_secret_access_key = “”

volume_id = “”
instance_id = “”
device = “”

conn = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)
reservations = conn.get_all_instances()
curr_vol = conn.get_all_volumes([volume_id])[0]
#print curr_vol
#print curr_vol.zone
if curr_vol.status == ‘available’:
    conn.attach_volume(volume_id, instance_id, device)

 

把一个 volume-id 从一个实例上卸掉

import boto.ec2

region = “”
aws_access_key_id = “”
aws_secret_access_key = “”

instance_id = “”
volume_id = “”
device = “”

conn = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)
reservations = conn.get_all_instances()
curr_vol = conn.get_all_volumes([volume_id])[0]
#print curr_vol
#print curr_vol.zone
if curr_vol.status == ‘in-use’:
    conn.detach_volume(volume_id, instance_id, device)

使用aws boto 创建 自定义 的实例

之前的笔记,觉得有价值,还是拿出来分享下。

 

参考下面的python 代码:

     import requests
     import time
     import boto.ec2
     from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
     from boto.ec2.networkinterface import NetworkInterfaceSpecification, NetworkInterfaceCollection

    block_device_map = BlockDeviceMapping()
    block_dev_type = BlockDeviceType()
    block_dev_type.snapshot_id = snap_id
    block_dev_type.delete_on_termination = False
    block_dev_type.size = volume_capacity
    block_device_map[‘/dev/sdb‘] = block_dev_type

    hostname = “”
    user_data= user_data.replace(“hostname=”,”hostname=%s” % hostname)

    network_interface = NetworkInterfaceSpecification(subnet_id=subnet_id, groups=[sg_id])
    network_interfaces = boto.ec2.networkinterface.NetworkInterfaceCollection(network_interface)

    conn = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)
    reservation = conn.run_instances(ami_id,
        key_name=key_name,
        network_interfaces=network_interfaces,
        instance_type=instance_type,
        block_device_map=block_device_map,
        # security_groups=[security_groups],
        min_count=1,
        max_count=1,
        user_data=user_data,
        )

    instance = reservation.instances[0]

    time_init = 0
    time_total = 300
    time_interval = 5       
    while time_init < time_total:
        status = instance.update()   
        if status == ‘running’:
            instance.add_tag(“Name“,hostname)
            break
        else:
            time.sleep(time_interval)
            time_init += time_interval

    install_list[“instance_id”] = str(instance).split(“:”)[-1]
    install_list[“placement”] = instance.placement
    install_list[“status”] = instance.update()
    install_list[“hostname”] = hostname

1. ami_id 是制作的镜像,系统的基础配置已经在镜像里做了。

2. snap_id 是10G的一个snapshot ,我们把它挂载/home,用作数据盘,注意,block_dev_type.size 指定的值如果小于10,依然会创建10G的盘。

3. user_data 是通过http获取的脚本内容,我们把脚本里面的hostname值替换掉,实现不同机器不同主机名的目的(hostname 通过API从资产系统获得)。

4. 这里我把 “Name” 这个 tag 改成 主机名。

5. user_data 的内容如下:

#!/bin/bash

hostname=
hostname $hostname
sed -i “s/^HOSTNAME=.*/HOSTNAME=$hostname/g” /etc/sysconfig/network

mount /dev/sdb /home/
/sbin/blkid |egrep -v “vda” |sort -u -k1 |awk ‘{print $2″ /home/ ext4    noexec,nosuid,noatime   1 2″}’ >>/etc/fstab

echo “[`date`] personal post config script exec finished.” >>/var/log/message

 

问题:

1. 装完机器发现 /dev/sdb 或者 /dev/xvdb 只有 快照的大小,而不是指定的 volume_capacity
可以在装机之后执行下 resize2fs ,类似:
echo “resize2fs /dev/xvdb ;sed -i ‘/resize2fs/d’ /etc/rc.d/rc.local ” >>/etc/rc.d/rc.local
    reboot

 

 

aws 如何在创建实例的时候不自动生成公网IP,同时实例能够访问公网

一开始我的需求是如何在创建实例的时候不自动生成公网IP(为了安全),但是实例也能访问外网(有访问外网的需求,可以通过NAT),因为对aws的网络架构不了解,所以准备从头开始。

 

aws 提供四种网络架构,分别是

VPC with a Single Public Subnet

VPC with Public and Private Subnets

VPC with Public and Private Subnets and Hardware VPN Access

VPC with a Private Subnet Only and Hardware VPN Access

看了很多资料之后发现 aws提供这四种网络架构是为了方面配置,我们可以完全不管这四种网络架构,可以自定义适合自己需求的网络架构,比如我不止需要公有子网和私有子网,还同时需要NAT和VPN,这四种架构都满足不了,这时候可以自定义来解决。

先说下 公网 和 私网,公网可以直接访问外网,私网需要有NAT。一般在AWS里建立一个VPC,再在VPC里面建立多个子网,每个子网可以被指定为 公网 或者 私网,公网和私网的区别在于创建实例的时候是否自动分配公网IP,那么 是否分配公网IP 可以在子网页面的 Modify Auto-Assign Public IP 配置里修改,第一个问题解决了,很简单。

 

我准备说说 VPC with Public and Private Subnets 这种架构,同时证明我们可以自定义出这种网络架构。

aws的官方说明:

762b05ceb5a37091e9f523bd213813d0

此架构会 创建/16网段的VPC,然后在里面建立/24 的两个子网,一个是公有子网,另一个是私有子网,这两个子网默认都不创建公有IP。

公有子网里的实例可以绑定EIP并连接(如果无法连接可能是安全组问题);私有子网里的实例也可以绑定EIP,但是从外网没法连接(已实验)。

另外,创建此VPC架构的时候会在公有子网创建一个NAT实例,并会给这个NAT实例自动绑定EIP(可以连接),私有子网的实例通过此NAT连接外网,我们来看看。

我登陆我测试时的NAT实例,看了一下,也就是普通的 iptables 转发,所以NAT实例本身的配置我们可以自己搞定。
route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.0.1        0.0.0.0         UG    0      0        0 eth0
10.0.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
169.254.169.254 0.0.0.0         255.255.255.255 UH    0      0        0 eth0

# iptables -vnL -t nat
Chain PREROUTING (policy ACCEPT 15 packets, 1081 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 7 packets, 417 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 22 packets, 2157 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
   30  2821 MASQUERADE  all  —  *      eth0    10.0.0.0/16          0.0.0.0/0

另外,在私有网络创建的实例可以通过NAT访问外网:
ping www.baidu.com
PING www.a.shifen.com (180.76.3.151) 56(84) bytes of data.
64 bytes from 180.76.3.151: icmp_seq=1 ttl=49 time=79.7 ms
64 bytes from 180.76.3.151: icmp_seq=2 ttl=49 time=79.5 ms

route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         10.0.1.1        0.0.0.0         UG    0      0        0 eth0

这里可以看到,私有子网里的实例的默认网关是 XXX.XXX.XXX.1 这种格式,我们不用指定为NAT实例的内网IP。

最后,私有子网的路由表的默认路由会指向此NAT实例(i-e310e3c8),如图:
1111

那么参考上面,我们可以自己建立一个 VPC with Public and Private Subnets ,大概步骤如下:

1. 创建一个VPC,再创建两个子网,一个公有子网,一个私有子网(私有子网不分配公网IP,通过Modify Auto-Assign Public IP 修改。)

2. 在公有子网里创建一台NAT实例,配置iptables转发,同时把NAT实例的Change Source/Dest. Check 关掉 (此为一坑)。

3. 为私有子网创建一个Route Tables,把0.0.0.0/0 指向NAT实例的ID,比如下图。

2222

4. 在Route Tables 配置里,配置公有子网的Route Table,把它的Subnet (内网段)关联上,同时配置私有子网的Route Table,把它的Subnet (内网段) 关联上(此为另一坑,花费我很长时间排查)。

5. 在Subnet 配置里,把私有子网的Route Table 修改成 第3步添加的 Route Table

NAT实例配置正确之后,创建在私有子网中的机器就没有公网IP,而且能访问外网了。

AWS TCP Load Balancer 的一个坑

今天在迁移服务的时候发现了aws TCP的Load Balancer 的一个大坑, TCP 负载均衡其实是把客户端的请求截断,然后自己发送一个请求给后端,拿到后端返回的数据之后再返回给 客户端,这样后端看到的是 负载均衡器的IP,看不到客户端的真实IP了 (如果用基于HTTP的Load Balancer,会自动在HTTP头记录 X-Forwarded-For , 后端自然很容易获取到源IP )。其实这和LVS FULLNAT 模式有点像,LVS FULLNAT的解决办法是把真实IP写在TCP option里面,然后后端用toa模块拿到。

8612DFCC-601A-4F8D-92C0-CC863DDCF40E

 

对于这个问题,AWS给了一个解决办法,叫做  Proxy Protocol ,可以对TCP 负载均衡器开启Proxy Protocol,它会在请求的第一行写入 源IP、源端口等信息,以 \r\n 结尾,格式如下:

PROXY_STRING + single space + INET_PROTOCOL + single space + CLIENT_IP + single space + PROXY_IP + single space + CLIENT_PORT + single space + PROXY_PORT + “\r\n”

 

先说说如何开启 Proxy Protocol 。

第一步,为集群 ProxyProtocolTest  创建一个Proxy Protocol,叫 EnableProxyProtocol
# aws elb create-load-balancer-policy –load-balancer-name ProxyProtocolTest –policy-name EnableProxyProtocol  –policy-type-name ProxyProtocolPolicyType –policy-attributes AttributeName=ProxyProtocol,AttributeValue=True

第二步,为 ProxyProtocolTest  激活 EnableProxyProtocol
# aws elb set-load-balancer-policies-for-backend-server –load-balancer-name ProxyProtocolTest –instance-port 80 –policy-names EnableProxyProtocol

然后确认开启
# aws elb describe-load-balancers –load-balancer-name ProxyProtocolTest

可以看到类似下面的字段:

            “BackendServerDescriptions”: [
                {
                    “InstancePort”: 80,
                    “PolicyNames”: [
                        “EnableProxyProtocol”
                    ]
                }
            ]

如果想关闭Proxy Protocol 的话,用下面的命令
# aws elb set-load-balancer-policies-for-backend-server –load-balancer-name ProxyProtocolTest –instance-port 80 –policy-names “[]”

 

开启Proxy Protocol之后,看看后端如何获取到源IP,这里只看nginx。

nginx 从1.5.12 版本开始支持Proxy Protocol ,只需要配置一下就OK了,说说怎么配。

第一部分,在http 里面配置如下:
    set_real_ip_from   172.0.0.0/8;
    real_ip_header     proxy_protocol;

表示把来在172.0.0.0/8 段(TCP负载均衡器的IP段)的所有请求的来源地址,都改成 $proxy_protocol_addr,并且记录在 $remote_addr 变量里。

    log_format  main  ‘$proxy_protocol_addr $remote_addr – $remote_user [$time_local] “$request” ‘
                      ‘$status $body_bytes_sent “$http_referer” ‘
                      ‘”$http_user_agent” “$http_x_forwarded_for” ‘
                      ‘”$upstream_addr” “$request_time” “$upstream_response_time” “$upstream_cache_status”‘; 

这是日志格式。

第二部分,在server里面linsten的时候开启 proxy_protocol

    listen      80  proxy_protocol;

此时我请求的时候,日志刷出来了,这里可以看到 $proxy_protocol_addr  和 $remote_addr  都是客户端源IP。

202.134.72.73 202.134.72.73 – – [09/Oct/2014:08:00:12 -0400] “GET / HTTP/1.1” 200 0 “-” “curl/7.30.0” “-” “-” “0.000” “-” “-“
 

 

AWS 的几个”坑”

这篇文章简单说说最近搭建 aws 基础环境遇到的几个”坑”,有兴趣的可以参考下呃。

1. 默认公网IP 在机器重启之后会变化,如果想保持固定,可以申请一个 弹性IP 与实例绑定。

2. Classic 网络里 内网IP 在重启之后是有可能变化的,VPC 则不会。

3. /etc/resolv.conf 文件里面的 nameserver 重启之后会被重置(重置成aws内部的DNS IP),如果想固定,可以修改 /etc/rc.d/rc.local

4. 用aws的AMI创建出来的实例,assign 一个新的内网IP 给实例,实例里会自动生成这个IP 的网卡配置,这个是 ec2-net-utils 包 实现的;而 如果你用 redhat 或者 centos 创建的实例,默认不装 ec2-net-utils,所以你得手动配置新的地址了,当然你也可以给 redhat  或者 centos  装上  ec2-net-utils (这个包我有,可以找我要:| )

5. 如果想在aws ec2 里面实现 可以在实例之间移动的虚拟IP,比如 两台实例A 和 B,可以先给A assign 一个新的内网IP,然后A 和 B 互相检测,假如B 发现A 挂了,可以把 之前 assign 给A 的内网IP reassign 给 B 。

    命令类似:

     /opt/aws/bin/ec2-assign-private-ip-addresses -n $ENI_ID –secondary-private-ip-address $VIP –allow-reassignment –region $REGION –aws-access-key ${aws_access_key} –aws-secret-key ${aws_secret_key}

    如果需要公网的虚拟IP,那么再创建一个弹性IP 和 这个内网IP 绑定。

6. 实例不要创建在Classic 网络里,要自己建立VPC,实例都放在VPC里,VPC 比 Classic 有几个好处(不止):

   1). 支持实例有多个私有IP

   2). 实例停止后,弹性IP会依然保持与实例的关联

   3). 实例创建的时候可以不创建公网IP

7. 如果 VPC 的子网是私有子网(创建机器不自动分配公网IP),在这个子网创建的实例即使手动分配了弹性IP 也是无效的(从外面也连不上),所以想创建能从外部连上的实例,需要在公网子网(自动分配外网IP)。

8. 建立 LB 选取子网的时候要选择「公有子网」,LB 的实例会建在 「公网子网」内,所以如果选择了私有子网会连不上。

36751CB1-44B8-42BF-803D-5C241132B71A

9. 对于建立在 VPC 的 RDS,如果想从外网访问,除了选择「公开访问」 ,对于子网组,要选择「公网子网」,因为分配的 RDS 实例在选择的子网中,如果是私有子网,从外网连不上,和 EC2 LB 的子网选择类似。

F0D0795D-59A1-4B84-86C0-14BF892E2D75