【问题标题】:Elastic IP on application deployed using Elastic Beanstalk使用 Elastic Beanstalk 部署的应用程序上的弹性 IP
【发布时间】:2012-05-15 13:26:12
【问题描述】:

我对 Amazon Web Services 提供的弹性 IP 服务的使用感到有些困惑。我想主要的想法是我可以按照这个简单的过程切换到新版本的 Web 应用程序而无需停机:

  1. 在新的 EC2 实例上部署新版本
  2. 正确配置新版本并使用暂存数据库对其进行测试
  3. 正确测试后,让这个新版本使用实时数据库
  4. 将弹性 IP 关联到此实例
  5. 终止所有无用的服务(暂存数据库和旧 EC2 实例)

这是部署新版本 Web 应用程序的常用方法吗?

现在,如果在更多实例上扩展应用程序会怎样?我在 Elastic Beanstalk 设置中配置了自动缩放,这创建了一个负载均衡器(我可以在 AWS 管理控制台的 EC2 部分看到它)。问题是我显然无法将弹性 IP 与负载均衡器相关联,我必须将其与现有实例相关联。我应该将它关联到哪个实例?我很困惑...

对不起,如果有些问题听起来很愚蠢,但我只是一名程序员,这是我第一次设置云系统。

谢谢!

【问题讨论】:

    标签: amazon-ec2 amazon-web-services amazon-elastic-beanstalk


    【解决方案1】:

    Elastic Load Balancing (ELB) 不能与Amazon EC2 Elastic IP addresses 一起使用,实际上这两个概念根本不能放在一起。

    通过 Elastic Load Balancing 实现弹性

    相反,ELB 通常通过CNAME records 使用(但见下文),这通过允许别名 DNS 地址在需要时更改正在使用的 ELB 的 IP 来提供第一级弹性/可用性是。第二级弹性/可用性由负载均衡器在您注册的 EC2 实例之间分配流量时执行。

    这样想:CNAME 永远不会改变(就像弹性 IP 地址),EC2 实例的替换是通过负载均衡器Auto Scaling 或您自己处理的(通过注册/注销实例)。

    这在 Shlomo Swidler 的出色分析 The “Elastic” in “Elastic Load Balancing”: ELB Elasticity and How to Test it 中有更详细的解释,该分析又指 AWS 最近提供的 Best Practices in Evaluating Elastic Load Balancing,这证实了他的分析并提供了关于 Elastic Load Balancing 服务及其工作原理(但缺乏 Shlomo 提供的说明性逐步示例)。

    域名

    请注意,以前需要 CNAME 的限制同时已通过对Amazon Route 53 的相应添加来解决,以允许也使用根域(或 Zone Apex),请参阅部分 Moving Ahead With Amazon Route 53 中的别名和 Zone Apex 可快速概览,Using Domain Names with Elastic Load Balancing 可了解详细信息。

    通过 Elastic Beanstalk 实现弹性

    首先,AWS Elastic Beanstalk 依次使用 Elastic Load Balancing,如上所述。最重要的是,它添加了应用程序生命周期管理:

    AWS Elastic Beanstalk 是一种更简单的快速部署方式 和管理 AWS 云中的应用程序。您只需上传您的 应用程序,并且 Elastic Beanstalk 会自动处理 容量配置、负载均衡的部署细节, 自动扩展和应用程序运行状况监控。 [...] [强调我的]

    这是通过将环境的概念添加到组合中来实现的,这在Architectural Overview中进行了解释:

    环境是应用程序的核心。 [...] 当您创建 环境,AWS Elastic Beanstalk 预置资源 需要运行您的应用程序。为某项创建的 AWS 资源 环境包括一个弹性负载均衡器(图中的 ELB),一个 Auto Scaling 组和一个或多个 Amazon EC2 实例。

    请注意每个环境都有一个指向负载均衡器的 CNAME (URL),也就是说,就像单独使用 ELB。

    所有这些都集中在Managing and Configuring Applications and Environments 中,详细讨论了 AWS Elastic Beanstalk 的一些最重要的功能,包括使用 AWS 管理控制台、CLI 和 API 的使用示例

    零停机时间

    很难确定最相关的部分以用于说明目的,但Deploying Versions With Zero Downtime 准确地解决了您的用例并暗示了所有必需的前面步骤(例如Creating New Application VersionsLaunching New Environments),因此请阅读AWS 管理控制台部分 可能会为您提供该平台如何运作的最佳整体情况。

    祝你好运!

    【讨论】:

      【解决方案2】:

      除了 Steffen 的精彩回答中描述的选项之外,如果您不需要 Elastic Load Balancer 的全部功能(例如自动缩放超过一个实例)。

      我在my answer to a similar question 中描述了该选项。 Elastic Beanstalk 现在允许您在两个 Environment Types 之间进行选择,Single-instance 选项会创建一个 Elastic IP。


      我认为在大多数情况下使用 ELB 将是更可取的选择,但例如对于登台服务器,最好有一个不太复杂(且更便宜)的替代方案。

      【讨论】:

      • 如果您重建 Elastic Beanstalk 环境,请注意 EIP 将被释放并分配一个新的......这有点愚蠢。
      • 但是,幸运的是,当我们使用eg时,它是同一个EIP。更改实例的类型。
      • 我发现使用“负载平衡、自动缩放”选项为 beanstalk 应用程序设置 HTTPS 要容易得多。
      【解决方案3】:

      很抱歉几年后回复了一个帖子,但是对于那些确实需要 ELB 上的一组静态 IP 地址的人,可以很好地要求 AWS 将他们所谓的“稳定 IP”地址添加到 ELB ,从而赋予它静态 IP 地址功能。

      他们当然不喜欢这样做 - 但如果你能证明它是合理的(主要理由是当你的客户端通过他们的防火墙对出站连接有 IP 白名单限制并且完全不愿意让步时)立场)。

      请注意,基于流量选项的“自动缩放”不再是直截了当的 - AWS 将无法像使用开箱即用的解决方案那样动态地将更多 ELB 端点添加到您的 ELB,而您有随着时间的推移,要经历与客户开放新 IP 地址的痛苦。

      不过,对于最初的问题,EB 使用 ELB 连接实际不需要静态 IP 地址的 EC2 实例(没有客户端出站防火墙问题)是公认答案的最佳方式。

      【讨论】:

      • 您是否遇到同样的问题并让 AWS 为您添加了“稳定 IP”? (我只是为了确保 AWS 在需要时提供这种服务)
      • 是的 - 我们有分配了静态(稳定)IP 地址的 ELB。
      • 从 2017 年 9 月开始,您可以在 Beanstalk 中使用网络负载均衡器(支持 EIP)-aws.amazon.com/elasticloadbalancing/details
      • 更疯狂的是:如果您想要通过网络负载均衡器使用 EIP/静态 IP 的应用程序负载均衡器的所有功能,您可以同时运行这两个功能加上一个 lambda 以将它们绑定在一起: aws.amazon.com/blogs/networking-and-content-delivery/…
      【解决方案4】:

      如果上述解决方案均无效,另一种选择是将 NAT 网关附加到私有子网并将 EIP 与 NAT 网关关联。在这种情况下,您可以使用 ELB、使用自动缩放并拥有预留的 EIP。

      不过,这有点贵,尤其是对于大吞吐量的用例。此外,通过 SSH 连接到实例进行调试变得有点复杂。

      【讨论】:

        【解决方案5】:

        我写了a post,描述了如何在启动新实例时使用 Cloudwatch 规则和 lambda 函数来完成此任务。下面是 lambda 函数代码:

        const AWS = require('aws-sdk');
        const ec2 = new AWS.EC2();
        const PROD_ENV_NAME = 'my-prod-env-name';
        
        // Example Event
        // {
        //   "version": "0",
        //   "id": "ee376907-2647-4179-9203-343cfb3017a4",
        //   "detail-type": "EC2 Instance State-change Notification",
        //   "source": "aws.ec2",
        //   "account": "123456789012",
        //   "time": "2015-11-11T21:30:34Z",
        //   "region": "us-east-1",
        //   "resources": [
        //     "arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
        //   ],
        //   "detail": {
        //     "instance-id": "i-abcd1111",
        //     "state": "running"
        //   }
        // }
        
        exports.handler = async (event) => {
          console.log("EVENT:", event);
        
          // The newly launched instance ID.
          const instanceId = event.detail['instance-id'];
        
          // Fetch info about the newly launched instance
          const result = await ec2.describeInstances({
            Filters: [ { Name: "instance-id", Values: [instanceId] } ]
          }).promise()
        
          // The instance details are buried in this object
          const instance = result.Reservations[0].Instances[0];
          const isAttached = instance.NetworkInterfaces.find(int => int.Association.IpOwnerId !== 'amazon');
        
          // Bail if the instance is already attached to another EIP
          if (isAttached) {
            console.log("This instance is already assigned to an elastic IP")
            return { statusCode: 200, body: '' }
          }
        
          // In elastic beanstalk, the instance name gets assigned to the enviroment name.
          // There is also an environment name tag, which could be used here.
          const name = instance.Tags.find(t => t.Key === 'Name').Value;
        
          // Only assign EIPs to production instances
          if (name !== PROD_ENV_NAME) {
            console.log('Not a production instance. Not assigning. Instance name:', name)
            return { statusCode: 200, body: ''}
          }
        
          // Get a list of elastic IP addresses
          const addresses = await ec2.describeAddresses().promise();
        
          // Filter out addresses already assigned to instances
          const availableAddresses = addresses.Addresses.filter(a => !a.NetworkInterfaceId);
        
          // Raise an error if we have no more available IP addresses
          if (availableAddresses.length === 0) {
            console.log("ERROR: no available ip addresses");
            return { statusCode: 400, body: JSON.stringify("ERROR: no available ip addresses") }
          }
        
          const firstAvail = availableAddresses[0]
          try {
            // Associate the instance to the address
            const result = await ec2.associateAddress({
              AllocationId: firstAvail.AllocationId,
              InstanceId: instanceId
            }).promise();
        
            console.log('allocation result', result)
        
            return { statusCode: 200, body: JSON.stringify('Associated IP address.') };
          } catch (err) {
              console.log("ERROR: ", err);
          }
        };
        
        

        【讨论】:

          猜你喜欢
          • 2021-04-28
          • 2016-11-20
          • 2018-09-13
          • 2017-08-01
          • 2012-09-24
          • 2013-01-20
          • 2017-05-11
          • 2013-06-25
          • 2016-01-24
          相关资源
          最近更新 更多