我想在作为EC2实例的主机上运行一些脚本,但是我不知道如何确定主机确实是EC2实例。
我做了一些测试,但这还不够:
- 测试二进制ec2_userdata是否可用(但这并不总是正确的)
- 测试“ http://169.254.169.254/latest/meta-data ”的可用性(但这将永远是正确的吗?这是什么“神奇IP”?)
我想在作为EC2实例的主机上运行一些脚本,但是我不知道如何确定主机确实是EC2实例。
我做了一些测试,但这还不够:
Answers:
好吧,实际上,有一种非常简单的方法来检测主机是否为EC2实例:检查公共IP的反向查找。EC2的反向功能很难错过。
另外,如果您未进行修改,则主机名应该是您的反向名称,这样可以更轻松地发现它。
您可能还使用了您所说的“神奇IP”,因为它确实是获取EC2实例标签的标准方法,但是,如果您不在EC2网络上,则必须等待超时,通常这不是理想的...
如果这些方法还不够,只需对您的IP进行Whois检查并检查您是否在Amazon EC2 IP阻止范围之内。
编辑:您可以使用此小外壳程序位:
#!/bin/bash
LOCAL_HOSTNAME=$(hostname -d)
if [[ ${LOCAL_HOSTNAME} =~ .*\.amazonaws\.com ]]
then
echo "This is an EC2 instance"
else
echo "This is not an EC2 instance, or a reverse-customized one"
fi
不过,[[是一种bashism。您也可以使用Python或Perl单行代码YMMV。
hostname -d
返回eu-west-1.compute.internal
更改了Hannes的答案,以避免出现错误消息,并在脚本中包括示例用法:
if [ -f /sys/hypervisor/uuid ] && [ `head -c 3 /sys/hypervisor/uuid` == ec2 ]; then
echo yes
else
echo no
fi
这在Windows实例中不起作用。与curl相比,优点是EC2和非EC2都接近瞬时。
ec2
-误报开头的UUID 。只有在您使用填充该文件的管理程序的情况下,这种情况才不太可能(256分之一的机会)。这就是为什么上面链接的文档说“您可能正在查看EC2实例”的原因。
首先,由于现有答案存在以下细微问题,并且收到有关我对@qwertzguy答案的评论的问题后,我感到有必要发布新答案。以下是当前答案的问题:
hostname -d
,用于内部DNS,而不是其中包含“ amazonaws.com”的任何名称。)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可以工作,但依赖于你。),其dmidecode
可在您的实例,和b。),具有root或sudo
从代码中使用密码的能力。bios_version
的1.0
。该文件完全没有在Amazon的文档中记录,因此我真的不会依赖它。whois
结果,这在几个级别上都是有问题的。请注意,该答案中建议的URL现在是404页!即使你没有发现,没有工作第三方服务,这将是相对很慢(相比于本地检查文件),并可能碰到限速问题或网络问题,或者可能是您的EC2实例,甚至没有外部网络访问。-m
or --max-time
参数来卷曲,以防止它长时间挂起,尤其是在非EC2实例中,该地址可能导致无处挂起(如@algal的答案)。此外,我看不到有人提到过Amazon记录的检查(possible)file的备用记录/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实例上运行的最佳方法是考虑所链接文档中列出的各种可能性。
elif
块上方的注释,这就是elif
测试使用-r
测试运算符的原因,该运算符检查文件是否存在以及您是否对该文件具有读取权限。
通过EC2内部域名而不是IP查找元数据,如果您不在EC2上,它将返回快速DNS故障,并避免IP冲突或路由问题:
curl -s http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
在某些发行版中,非常基本的系统,或者在安装初期就无法使用curl。使用wget代替:
wget -q http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
如果目标是判断它是EC2实例还是其他类型的云实例(如google),则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
1.0
-不提及amazon
。
主机名可能会更改,请针对您的公共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元数据网址
if [[ ! -z $(curl -s http://169.254.169.254/1.0/) ]]; then
echo "I'm Amazon"
else
echo "I'm not Amazon"
fi
这也适用于ec2中的Linux主机,并且不需要网络和任何相关的超时:
grep -q amazon /sys/devices/virtual/dmi/id/bios_version
这行得通,因为Amazon定义该条目的方式如下:
$ cat /sys/devices/virtual/dmi/id/bios_version
4.2.amazon
1.0
。没有提及amazon
。
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes
但我不知道这在各个发行版之间的可移植性如何。
快速回答:
if [[ -f /sys/devices/virtual/dmi/id/product_uuid ]] && \
grep -q "^EC2" /sys/devices/virtual/dmi/id/product_uuid
then
echo "IS EC2"
else
echo "NOT EC2"
fi
我使用这里发布的答案之一已经有一年多了-但它不适用于新的'c5'实例类型(我现在正在努力从'c4'升级)。
我喜欢这种解决方案,因为它似乎在将来最不可能突破。
在较旧的实例类型和较新的实例类型上,此文件存在并以“ EC2”开头。我检查了在VirtualBox上运行的Ubuntu(我也需要支持),它包含字符串'VirtualBox'。
正如以前的海报所指出的(但很容易错过)-有关于如何执行此操作的Amazon文档-包括我的答案。
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html
也许您可以使用“因素”:
“ Facter是一个跨平台的库,用于检索简单的操作系统事实,例如操作系统,Linux发行版或MAC地址。”
http://www.puppetlabs.com/puppet/related-projects/facter/
例如,如果我们看一下ec2事实(facter-1.6.12 / lib / facter / ec2.rb):
require 'facter/util/ec2'
require 'open-uri'
def metadata(id = "")
open("http://169.254.169.254/2008-02-01/meta-data/#{id||=''}").read.
split("\n").each do |o|
key = "#{id}#{o.gsub(/\=.*$/, '/')}"
if key[-1..-1] != '/'
value = open("http://169.254.169.254/2008-02-01/meta-data/#{key}").read.
split("\n")
symbol = "ec2_#{key.gsub(/\-|\//, '_')}".to_sym
Facter.add(symbol) { setcode { value.join(',') } }
else
metadata(key)
end
end
end
def userdata()
begin
value = open("http://169.254.169.254/2008-02-01/user-data/").read.split
Facter.add(:ec2_userdata) { setcode { value } }
rescue OpenURI::HTTPError
end
end
if (Facter::Util::EC2.has_euca_mac? || Facter::Util::EC2.has_openstack_mac? ||
Facter::Util::EC2.has_ec2_arp?) && Facter::Util::EC2.can_connect?
metadata
userdata
else
Facter.debug "Not an EC2 host"
end
参加这个聚会有点晚,但是我遇到了这篇文章,然后找到了这个AWS文档:
对于确定且经过密码验证的EC2实例的方法,请检查实例身份文档,包括其签名。这些文档可在每个EC2实例上的本地不可路由地址http://169.254.169.254/latest/dynamic/instance-identity/中找到。
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html
当然,尽管您可以像这样设置curl超时,但是这需要网络开销:
curl -s --connect-timeout 5 http://169.254.169.254/latest/dynamic/instance-identity/
将超时设置为5s。