检查Python脚本是否在AWS实例上运行

15

我正在尝试设置一个Python记录器,以便在记录错误时发送错误电子邮件,但前提是实例已设置标签。然后我很快遇到了在AWS之外的本地开发计算机的问题。是否有一种简单快捷的方法来检查脚本是否在AWS上运行?

我正在使用以下方式加载实例数据:

import boto.utils
from boto.ec2.connection import EC2Connection
metadata = boto.utils.get_instance_metadata()
conn = EC2Connection()
instance = conn.get_only_instances(instance_ids=metadata['instance-id'])[0]

我当然可以在 get_instance_metadata 上使用超时,但是现在的问题是如何平衡让开发者等待多长时间和在生产中不发送错误邮件之间。

有没有人能想到一个好的解决方案?

5个回答

14

或者,您可以检查您的环境是否包含任何 AWS 环境变量

is_aws = True if os.environ.get("AWS_DEFAULT_REGION") else False

我选择检查我的用户名是否是ec2实例:(不是很好的解决方案,但可行)

my_user = os.environ.get("USER")
is_aws = True if "ec2" in my_user else False

6
类似于 @cgseller,假设使用 Python3,我们可以这样做:
from urllib.request import urlopen

def is_ec2_instance():
    """Check if an instance is running on AWS."""
    result = False
    meta = 'http://169.254.169.254/latest/meta-data/public-ipv4'
    try:
        result = urlopen(meta).status == 200
    except ConnectionError:
        return result
    return result

一个EC2实例不一定有公共IP。 - Paolo
这在非实例上需要很长时间,因为urlopen将会阻塞。最好添加urlopen(meta, timeout=1)或类似的内容。 - Marcin
@Foo 你可以使用private-ip - Marcin
@Marcin 是的,但这个源代码只使用了 public-ipv4 - Paolo

5
AWS实例具有元数据,因此您可以调用元数据服务并获得响应,如果响应有效,则您在AWS上,否则不是。例如:
import urllib2
meta = 'http://169.254.169.254/latest/meta-data/ami-id'
req = urllib2.Request(meta)
try:
    response = urllib2.urlopen(req).read()
    if 'ami' in response:
        _msg = 'I am in AWS running on {}'.format(response)
    else:
        _msg = 'I am in dev - no AWS AMI'
except Exception as nometa:
    _msg = 'no metadata, not in AWS'

print _msg

这只是一个初步的尝试 - 可能有更好的检查方法,但这个方法可以让你感受到它的效果,你可以根据需要对其进行改进。如果您正在使用OpenStack或其他本地云服务,当然会得到元数据响应,因此您需要相应地调整您的检查...

(如果您使用像chef、puppet、homegrown等启动工具或管理器,您也可以使用cloud-init来完成此操作。如果在AWS中,请在文件系统中放置/ec2文件,或者更好的办法是在本地放置/DEV文件)


这在非实例上需要很长时间,因为urlopen将会阻塞。最好添加urlopen(meta, timeout=1)或类似的内容。 - Marcin

2

一个简单的解决方案是检查文件/var/lib/cloud/instance/datasource的内容,在Ec2实例上,此文件包含DataSourceEc2Local: DataSourceEc2Local

$ sudo cat /var/lib/cloud/instance/datasource
DataSourceEc2Local: DataSourceEc2Local

在Python中,可以这样写:
datasource_file = "/var/lib/cloud/instance/datasource"
try:
    with open(datasource_file) as f:
        line = f.readlines()
        if "DataSourceEc2Local" in line[0]:
            print("I'm running on EC2!")
except FileNotFoundError:
        print(f"{datasource_file} not found")

1
我认为这不是一个关于boto的问题。EC2(以及其上的boto)并不关心或知道您在服务器上运行的脚本。如果您的脚本有特定的标识 - 例如监听某个端口 - 那么这将是检查的最佳方式,但除此之外,您可以在操作系统中查找其进程来确定它的标识。使用subprocess模块和您首选的bash魔法来检查它是否正在运行。
command = ["ssh", "{user}@{server}", "pgrep", "-fl", "{scriptname}"]
try:
    is_running = bool(subprocess.check_output(command))
except subprocess.CalledProcessError:
    log.exception("Checking for script failed")
    is_running = False

是的,你说得对,这不是一个boto问题。我喜欢Nathan Binkert在这篇帖子中的回答。https://dev59.com/dmgv5IYBdhLWcg3wBMOg - TristanMatthews
哦,我现在明白你的问题了。为什么不让开发计算机设置一个环境变量,并在脚本中检查该环境变量呢?看起来最简单。 - jwilner
我们谈论过这个问题,但我更愿意避免需要在所有开发或所有生产机器上执行类似操作的解决方案。 - TristanMatthews

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接