使用Elastic Beanstalk部署的应用程序上的弹性IP

时间:2012-05-06 23:52:00

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

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

  1. 在新的EC2实例上部署新版本
  2. 正确配置新版本并使用暂存数据库进行测试
  3. 经过适当测试后,请将此新版本用于实时数据库
  4. 将弹性IP与此实例相关联
  5. 终止所有无用的服务(登台DB和旧的EC2实例)
  6. 这是部署新版Web应用程序的常用方法吗?

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

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

    谢谢!

5 个答案:

答案 0 :(得分:61)

Elastic Load Balancing (ELB)不适用于Amazon EC2 Elastic IP addresses,实际上这两个概念根本不合用。

通过弹性负载平衡

弹性

相反,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 ),请参阅< em> Aliases和Zone Apex 在Moving Ahead With Amazon Route 53中进行快速浏览,Using Domain Names with Elastic Load Balancing了解详情。

通过Elastic Beanstalk的弹性

首先,AWS Elastic Beanstalk依次使用Elastic Load Balancing,如上所述。如果是这样,它会增加应用程序生命周期管理:

  

AWS Elastic Beanstalk是您更轻松地快速部署的方式   并在AWS云中管理应用程序。你只需上传你的   应用程序,Elastic Beanstalk自动处理   容量配置,负载均衡,   自动缩放和应用程序运行状况监视。 [...] [强调我的]

这是通过在混合中添加 Environment 的概念来实现的,这在Architectural Overview中有解释:

  

环境是应用程序的核心。 [...]当你创造   在环境中,AWS Elastic Beanstalk提供资源   需要运行您的应用程序。为。创建的AWS资源   环境包括一个弹性负载平衡器(图中的ELB),a   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管理控制台可能会为您提供此平台工作原理的最佳整体情况。

祝你好运!

答案 1 :(得分:14)

除了Steffen的精彩答案中描述的选项之外,如果您不需要Elastic Load Balancer的全部功能(例如,Elastic Beanstalk)似乎最近启用了弹性IP 。自动缩放超过一个实例。)

我在my answer to a similar question中描述了该选项。 Elastic Beanstalk现在允许您在两个Environment Types之间进行选择,单实例选项可以创建一个弹性IP。

Dropdown with options "Single instance" and "Load balancing, autoscaling".


我认为在大多数情况下使用ELB将是更好的选择,但是对于登台服务器来说,拥有一个不那么复杂(且更便宜)的替代方案是件好事。

答案 2 :(得分:3)

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

他们当然不喜欢这样做 - 但是如果你可以证明这一点(主要理由是你的客户端通过防火墙对出站连接有IP白名单限制,而且完全不愿意让姿态)。

请注意,基于流量选项的“自动缩放”不再是直接的 - AWS无法动态地向ELB添加更多ELB端点,因为它们使用开箱即用的解决方案并且您拥有经历与客户一起开辟新IP地址的痛苦。

对于原始问题,EB使用ELB来实现EC2实例,其中实际上不需要静态IP地址(没有客户端出站防火墙问题)是根据接受的答案的最佳方式。

答案 3 :(得分:1)

在上述解决方案均无效的情况下,一种替代方法是将NAT网关附加到专用子网,然后将EIP与NAT网关关联。在这种情况下,您可以使用ELB,使用自动缩放并保留EIP。

这有点贵,尤其是对于大吞吐量的用例。而且,SSH进入实例进行调试变得更加复杂。

答案 4 :(得分:0)

我写了a post,描述了如何在启动新实例和lambda函数时使用Cloudwatch规则来完成此任务。这是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);
  }
};