从实例元数据端点检索正确的Amazon附加EBS设备

时间:2018-04-18 04:09:22

标签: amazon-web-services amazon-ec2 block-device

EDIT和TL; DR:

ubuntu@ip-172-31-19-77:~/.aws$ aws ec2 describe-instances | jq . | grep -i device
          "BlockDeviceMappings": [],
          "RootDeviceType": "ebs",
          "RootDeviceName": "/dev/sda1",
                "DeviceIndex": 0,
          "BlockDeviceMappings": [
              "DeviceName": "/dev/sda1",
              "DeviceName": "/dev/xvdb",
          "RootDeviceType": "ebs",
          "RootDeviceName": "/dev/sda1",
                "DeviceIndex": 0,
          "BlockDeviceMappings": [
              "DeviceName": "/dev/sda1",
          "RootDeviceType": "ebs",
          "RootDeviceName": "/dev/sda1",
                "DeviceIndex": 0,
          "BlockDeviceMappings": [
              "DeviceName": "/dev/xvda",
          "RootDeviceType": "ebs",
          "RootDeviceName": "/dev/xvda",
                "DeviceIndex": 0,
          "BlockDeviceMappings": [
              "DeviceName": "/dev/sda1",
              "DeviceName": "/dev/sdf",
          "RootDeviceType": "ebs",
          "RootDeviceName": "/dev/sda1",
ubuntu@ip-172-31-19-77:~/.aws$ aws ec2 describe-volumes | jq . | grep -i device
          "Device": "/dev/sda1"
          "Device": "/dev/sdf"
          "Device": "/dev/xvda"
          "Device": "/dev/sda1"
          "Device": "/dev/xvdb"
          "Device": "/dev/sda1"
ubuntu@ip-172-31-19-77:~/.aws$ ls /dev/sd*
ls: cannot access '/dev/sd*': No such file or directory
ubuntu@ip-172-31-19-77:~/.aws$ ls /dev/xv*
ls: cannot access '/dev/xv*': No such file or directory
ubuntu@ip-172-31-19-77:~/.aws$ lsblk
NAME        MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nvme0n1     259:0    0   1G  0 disk
nvme1n1     259:1    0   8G  0 disk
└─nvme1n1p1 259:2    0   8G  0 part /

解释

我想事先知道特定AWS实例应该在哪个块设备上进行后附件。

不幸的是,the instance metadata endpoint for block devices introduced back in 2007似乎不再可靠了吗?

以下是我在撰写本文时使用latest Ubuntu (17.10) AMI运行的示例t2.medium实例(not Amazon Linux):

enter image description here

不仅EBS模块出现在控制台中,而且似乎已正确连接:

enter image description here

根据官方AWS docs on block-device-mappings

  

block-device-mapping/ebsN:与Amazon EBS卷关联的虚拟设备(如果有)。 Amazon EBS卷仅在元数据中可用,如果它们在启动时或上次启动实例时存在。 N表示Amazon EBS卷的索引(例如ebs1或ebs2)。 2007-12-15

但遗憾的是,在实例完全启动并运行并且已连接所有EBS卷之后,没有此类端点存在:

$ curl http://169.254.169.254/latest/meta-data/block-device-mapping/
ami
ephemeral0
ephemeral1
$ curl http://169.254.169.254/latest/meta-data/block-device-mapping/ami
/dev/sda1
$ curl http://169.254.169.254/latest/meta-data/block-device-mapping/ebs1
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
  <title>404 - Not Found</title>
 </head>
 <body>
  <h1>404 - Not Found</h1>
 </body>
</html>
$ curl http://169.254.169.254/latest/meta-data/block-device-mapping/ebs2
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
  <title>404 - Not Found</title>
 </head>
 <body>
  <h1>404 - Not Found</h1>
 </body>
</html>

另一方面,操作系统(在XEN设备方案下)通过xvdXX设备公开卷:

$ ls /dev/xvd*
/dev/xvda  /dev/xvda1  /dev/xvdf  /dev/xvdg

所以这给我留下了just assuming which block device is going to be depending on which instance我正在运行的一个糟糕的解决方案,例如,Amazon introduces new iron可以预测会中断一次完全不同的底层块设备命名方案,例如{{1} }}:

https://twitter.com/braincode/status/968005482102190080

这是在附加了EBS卷的新实例化的M5实例上发生的事情:

/dev/nvme0n1p1
  1. 为什么只列出$ curl http://169.254.169.254/latest/meta-data/block-device-mapping/ ami ebs2 root $ curl http://169.254.169.254/latest/meta-data/block-device-mapping/ebs2 sdf 而不是ebs2
  2. ebs1
  3. 在m5实例的操作系统上没有一个sdf

    sd*

    我做错了什么?这是一个已知的错误? people / boto / cloudinit模块如何处理?

3 个答案:

答案 0 :(得分:1)

元数据服务在实例启动时显示块设备映射,并且是不可变的。您可以信任根设备的值和任何实例存储卷在实例的生命周期中是准确的。 NVMe块设备不需要映射。 / dev / xvd *下的任何其他块设备当前都将附加EBS卷。

如果您需要知道哪个卷对应于每个设备文件,唯一准确的方法是使用attachment.instance-id过滤器调用ec2.DescribeVolumes。您的实例需要适当的实例配置文件才能允许它进行该调用。您还需要注意不要经常调用它并使用指数退避和抖动实现重试以处理限制。

答案 1 :(得分:1)

通过运行EC2instance获取并标记EBS RootVolume : 这是实现它的方法:

Instance_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
Instance_Name=$(aws ec2 describe-instances --instance-ids ${Instance_ID} --query 'Reservations[0].Instances[0].Tags[?Key==`Name`].Value' --output text)
RootDeviceName=$(aws ec2 describe-instances --instance-ids ${Instance_ID} --query 'Reservations[0].Instances[0].RootDeviceName' --output text)
RootVolumeId=$(aws ec2 describe-instances --instance-ids ${Instance_ID} --query "Reservations[0].Instances[0].BlockDeviceMappings[?DeviceName==\`${RootDeviceName}\`].Ebs.VolumeId" --output text)

如果要设置RootVolume标记(CloudFormation尚不支持(2019-03-14)):

aws ec2 create-tags --resources ${RootVolumeId} --tags Key=Name,Value=RootVolume-${Instance_Name}

您需要以下IAM权限:

"ec2:DescribeInstances"
"ec2:CreateTags"

它是这样工作的:

只看(缩短的)ec2 json响应:

aws ec2 describe-instances --instance-ids ${Instance_ID}
{
    "Reservations": [
        {
            "Instances": [
                {
                    "InstanceId": "i-XXXXX", 
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda", 
                            "Ebs": {
                                "Status": "attached", 
                                "DeleteOnTermination": true, 
                                "VolumeId": "vol-XXXXX", 
                                "AttachTime": "2019-02-27T07:56:07.000Z"
                            }
                        }, 
                        {
                            "DeviceName": "/dev/sdm", 
                            "Ebs": {
                                "Status": "attached", 
                                "DeleteOnTermination": false, 
                                "VolumeId": "vol-XXXXX", 
                                "AttachTime": "2019-02-27T07:58:02.000Z"
                            }
                        }
                    ], 
                    "RootDeviceType": "ebs", 
                    "RootDeviceName": "/dev/xvda", 
                }
            ], 
            "ReservationId": "r-XXXXX", 
            "RequesterId": "XXXXX", 
            "Groups": [], 
            "OwnerId": "XXXXX"
        }
    ]
}

您将看到:每个实例都具有BlockDeviceMappings和RootDeviceName属性。
1)您可以从 RootDeviceName 属性中选择当前值作为 DeviceName 作为值。
2)利用这些信息,您可以通过匹配所选的 DeviceName 来解析 BlockDeviceMappings ,并最终获得 VolumeID

就这样。

答案 2 :(得分:0)

所有信息在EC2元数据中都不可用,但是您可以基于Ec2元数据中可用的EC2实例ID获取所有必需的信息。

获取实例ID

Instance_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)

基于实例ID,获取连接的块设备

Instance_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
aws ec2 describe-instances --instance-ids ${Instance_ID} --query "Reservations[].Instances[].BlockDeviceMappings"

输出

[
    [
        {
            "DeviceName": "/dev/xvda", 
            "Ebs": {
                "Status": "attached", 
                "DeleteOnTermination": true, 
                "VolumeId": "vol-12345adv ", 
                "AttachTime": "2020-05-11T07:01:58.000Z"
            }
        }, 
        {
            "DeviceName": "/dev/xvdcz", 
            "Ebs": {
                "Status": "attached", 
                "DeleteOnTermination": true, 
                "VolumeId": "vol-sdfsdfs", 
                "AttachTime": "2020-05-11T07:01:58.000Z"
            }
        }
    ]
]