我想在 EC2 实例主机上运行一些脚本,但我不知道如何确保主机真的EC2 实例。
我已经做了一些测试,但这还不够:
- 测试二进制 ec2_userdata 是否可用(但这并不总是正确的)
- 测试“的可用性http://169.254.169.254/latest/meta-data“(但这总是正确的吗?这个“神奇的 IP” 又是什么?)
答案1
首先,我觉得有必要发布一个新的答案,因为现有答案存在以下细微问题,并且在收到有关我的评论@qwertzguy 的回答。目前答案存在以下问题:
- 这接受的答案@MatthieuCerda 的答案肯定不可靠,至少在我检查过的任何 VPC 实例上都不是。(在我的实例上,我获得了一个 VPC 名称
hostname -d
,用于内部 DNS,而不是任何带有“amazonaws.com”的东西。) - 这得票最高的答案来自@qwertzguy不适用于新的 m5 或 c5 实例,没有这个文件。据我所知,亚马逊忽略了记录这种行为变化,尽管文档页面关于这个问题确实说过“......如果/sys/hypervisor/uuid 存在...”。我询问 AWS 支持,这种更改是否是故意的,见下文†。
- 这来自@Jer 的回答不一定在所有地方都有效,因为
instance-data.ec2.internal
DNS 查找可能不起作用。在我刚刚测试过的 Ubuntu EC2 VPC 实例上,我看到:$ curl http://instance-data.ec2.internal curl: (6) Could not resolve host: instance-data.ec2.internal
这会导致依赖此方法的代码错误地得出结论,它不在 EC2 上! - 这回答使用
dmidecode
来自@tamale 可能会起作用,但依赖于 a.)dmidecode
在您的实例上可用,以及 b.)sudo
在您的代码中具有 root 或无密码能力。 - 这回答检查 /sys/devices/virtual/dmi/id/bios_version@spkane 的警告具有误导性!我检查了一个 Ubuntu 14.04 m5 实例,得到了
bios_version
。1.0
该文件根本没有记录在亚马逊的文档中,所以我确实不会依赖它。 - 第一部分来自@Chris-Montanaro 的回答检查不可靠的第三方 URL 并
whois
根据结果使用,在多个层面上都是有问题的。请注意,该答案中建议的 URL 现在是一个 404 页面!即使你确实找到了一个有效的第三方服务,它也相对非常速度很慢(与在本地检查文件相比)并且可能遇到速率限制问题或网络问题,或者您的 EC2 实例甚至没有外部网络访问权限。 - 第二个建议来自@Chris-Montanaro 的回答去检查http://169.254.169.254/稍微好一点,但另一位评论者指出,其他云提供商也提供此实例元数据 URL,因此您必须小心避免误报。此外,它仍然会比本地文件慢得多,我见过这种检查在负载很重的实例上特别慢(需要几秒钟才能返回)。此外,您应该记得将
-m
或--max-time
参数传递给 curl,以避免它挂起很长时间,特别是在非 EC2 实例上,这个地址可能无处可去并挂起(如@algal 的回答)。
此外,我没看到有人提到亚马逊的记录检查(可能的)文件的后备/sys/devices/virtual/dmi/id/product_uuid
。
谁知道确定您是否在 EC2 上运行会如此复杂?!好的,现在我们已经列出了所列方法的(大多数)问题,下面是建议的 bash 代码片段,用于检查您是否在 EC2 上运行。我认为这应该适用于几乎所有 Linux 实例,Windows 实例是读者的练习。
#!/bin/bash
# This first, simple check will work for many older instance types.
if [ -f /sys/hypervisor/uuid ]; then
# File should be readable by non-root users.
if [ `head -c 3 /sys/hypervisor/uuid` == "ec2" ]; then
echo yes
else
echo no
fi
# This check will work on newer m5/c5 instances, but only if you have root!
elif [ -r /sys/devices/virtual/dmi/id/product_uuid ]; then
# If the file exists AND is readable by us, we can rely on it.
if [ `head -c 3 /sys/devices/virtual/dmi/id/product_uuid` == "EC2" ]; then
echo yes
else
echo no
fi
else
# Fallback check of http://169.254.169.254/. If we wanted to be REALLY
# authoritative, we could follow Amazon's suggestions for cryptographically
# verifying their signature, see here:
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
# but this is almost certainly overkill for this purpose (and the above
# checks of "EC2" prefixes have a higher false positive potential, anyway).
if $(curl -s -m 5 http://169.254.169.254/latest/dynamic/instance-identity/document | grep -q availabilityZone) ; then
echo yes
else
echo no
fi
fi
显然,您可以通过更多后备检查来扩展这一点,并包括对处理例如偶然发生的误报/sys/hypervisor/uuid
以“ec2”开头等的偏执。但对于说明目的和几乎所有非病理用例来说,这是一个足够好的解决方案。
[†] 从 AWS 支持部门获得了有关 c5/m5 实例更改的解释:
C5 和 M5 实例使用新的虚拟机管理程序堆栈并且相关内核驱动程序不会像 Xen 驱动程序那样在 sysfs(挂载在 /sys)中创建文件其他/较旧的实例类型所使用的。检测操作系统是否在 EC2 实例上运行的最佳方法是考虑您链接的文档。
答案2
更改了 Hannes 的答案以避免出现错误消息并在脚本中包含示例用法:
if [ -f /sys/hypervisor/uuid ] && [ `head -c 3 /sys/hypervisor/uuid` == ec2 ]; then
echo yes
else
echo no
fi
这在 Windows 实例中不起作用。与 curl 相比,它的优势在于它在 EC2 和非 EC2 上都接近即时。
更新:对于新的 C5/M5 实例,请使用文件/sys/devices/virtual/dmi/id/product_uuid
代替并检查EC2
而不是ec2
。(感谢评论中的 Josh 和 Saumitra 提到这一点)
答案3
如果目标是判断它是 EC2 实例还是另一种云实例(如谷歌),那么这种方法dmidecode
非常有效,而且不需要联网。与其他一些方法相比,我喜欢这种方法,因为 EC2 和 GCE 的元数据 URL 路径不同。
# From a google compute VM
$ sudo dmidecode -s bios-version
Google
# From an amazon ec2 VM
$ sudo dmidecode -s bios-version
4.2.amazon
答案4
主机名可能会改变,请针对你的公共 IP 运行 whois:
if [[ ! -z $(whois $(curl -s shtuff.it/myip/short) | grep -i amazon) ]]; then
echo "I'm Amazon"
else
echo "I'm not Amazon"
fi
或者点击 AWS 元数据 URL
if [[ ! -z $(curl -s http://169.254.169.254/1.0/) ]]; then
echo "I'm Amazon"
else
echo "I'm not Amazon"
fi