【问题标题】:Check if python script is running on an aws instance检查 python 脚本是否在 aws 实例上运行
【发布时间】:2025-12-22 14:50:11
【问题描述】:

我正在尝试设置一个 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 上使用超时,但是现在让开发人员等待与在生产中不发送错误电子邮件的可能性之间存在紧张关系。

谁能想到一个好的解决方案?

【问题讨论】:

    标签: python amazon-web-services boto


    【解决方案1】:

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

    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
    

    【讨论】:

      【解决方案2】:

      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 执行此操作。如果 /ec2 文件位于 AWS 或更好的文件系统中,则将其放入文件系统中但是如果本地在盒子上放一个/DEV)

      【讨论】:

        【解决方案3】:

        类似于@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
        

        【讨论】:

          【解决方案4】:

          我不认为这真的是一个博托问题。 EC2(以及 boto 反过来)不关心或不知道您在服务器上运行的脚本。

          如果您的脚本具有特定的签名 - 例如监听一个端口——这将是最好的检查方法,但是你可以在操作系统中寻找它的签名——它的进程。

          使用 subprocess 模块和你的preferred bash magic to check if it's running:

          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
          

          【讨论】:

          • 是的,你说得对,这不是真正的博托问题。我喜欢 Nathan Binkert 对这篇文章的回答。 *.com/questions/10907418/…
          • 哦,我现在明白你的问题了。为什么不让开发计算机设置一个环境变量并在脚本中检查该环境变量?看起来最简单。
          • 我们讨论过这个问题,但我宁愿避免需要在所有开发或所有生产机器上执行类似操作的解决方案。
          【解决方案5】:

          一个简单的解决方案是检查文件/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")
          

          【讨论】: