由于正在使用端口,我无法将新容器部署到我的ECS群集

时间:2018-02-22 15:58:02

标签: amazon-web-services amazon-ecs

我的服务使用的任务定义是拉动我图像的“最新”标记版本。

当我更新我的服务并“强制进行新部署”时,我会查看事件并看到:

service MYSERVICE was unable to place a task because no container instance met all of its requirements. The closest matching container-instance .... is already using a port required by your task

然后我去了我的群集并停止了所有任务。

然后返回我的服务并再次强制新部署更新。这似乎有效

每次要部署新映像时,是否必须停止所有任务并更新服务?或者有“正确”的方式来做到这一点吗?

编辑:所以如果我停止一项任务,服务将自动替换它。所以我可以更新我的服务并“强制新部署”,然后一次停止一个任务以获得一种滚动更新。不确定是否有一个功能可以自动执行我自己的脚本

只是跟进,正如答案中所述,我只需要使用动态端口映射。

最初,当我第一次启动时,我没有负载均衡器,因此我直接访问EC2实例以访问正在运行的容器。当然,为了做到这一点,我不得不在EC2主机上公开一个静态端口。

我添加了一个负载均衡器,但保留了静态端口映射,而不了解动态端口映射的工作原理。我所要做的就是更改我的任务定义,将主机端口设置为“0”。现在我在主机上没有静态端口映射,NLB为我做路由并按预期部署工作

5 个答案:

答案 0 :(得分:3)

使用ECS(或任何其他协调器)时,建议您使用Dynamic Port Mapping

基本上ECS会为您的容器分配一个随机的未分配端口。然后,ECS使用代理instrospection API或docker客户端本身提供检索该端口号的方法。但是我不会尝试检索端口,而是依赖于应用程序负载均衡器(ALB),它允许您使用单个端点独立于其动态分配的端口访问任何目标容器。更新服务时,ALB将无缝地转换到最新版本的容器,而不会中断。

最后,在容器内部,本地端口将保持不变,因此您不必以不同方式处理事物。

答案 1 :(得分:3)

如果没有动态端口,则每个容器只能部署一个服务实例,因为实例使用的端口不能被任何其他实例使用。更新服务时,它将尝试重新启动其所有实例,如果在单个EC2容器上启动了多个实例,则启动将失败。

最好在ECS集群中使用具有动态端口映射的docker容器。

答案 2 :(得分:3)

虽然其他答案都是正确的,但我认为它们不适用于您所遇到的问题。我之所以这么说,是因为这也是我的团队面临的一个问题,并且与尝试在同一个实例上启动多个容器没有任何关系 - 如果我理解正确的话,你就是这样的尝试从更新的任务定义中替换现有容器。如果要将同一容器的多个副本放在一个盒子上,请务必查看其他答案中的建议(除了下面的详细信息),但对于滚动部署,不需要动态端口。

[[完整性附注:您的强制部署可能会抛出您发布的错误,因为EC2只需要一段时间来清理ECS停止的资源。如果您尝试强制停止/启动任务,您会看到同样的问题 - 我们在尝试重新启动配置为分配> 50%的容器时看到了类似的错误可用的实例内存。在完全清理EC2实例并报告回ECS之前,您将获得这些类型的资源错误。我已经看到这需要花费5分钟。 ]

对于您的问题,遗憾的是,目前还没有来自AWS的任何强大的内置机制来执行滚动重启任务。但是, 可以滚动部署

您可能已经意识到,您的服务依赖于指定的任务定义。请注意,它依赖于任务定义编号,并且不像EC2实例那样关心容器标记

以下设置是启用滚动部署的神奇之处;您可以在服务设置中找到这些配置选项。

magic

为了能够进行滚动部署,您必须至少运行2个任务。

  • 任务数量 - 您的服务要运行的任务数量(n)
  • 最低健康百分比 - 部署新任务时n的最低健康百分比
  • 最高百分比 - 部署新任务时可添加的n的最大百分比

因此,对于一个真实的例子,我们假设你有以下配置:

Number of tasks: 3
Minimum healthy percent:  50
Maximum percent: 100

如果更改服务所指向的任务定义,它将启动滚动部署。我们有3个正在运行的任务,但允许>=50%健康。 ECS将终止您的一项任务,使健康%降至66%,仍高于50%。一旦新任务出现,服务再次位于100%,ECS可以继续将部署滚动到下一个实例。

同样,如果您的配置位于minimum % == 100maximum % == 150(假设您有容量),则ECS将启动其他任务;一旦它上升,你的健康百分比为133%,它可以安全地杀死其中一个旧任务。此过程将继续,直到您的新任务完全部署完毕。

答案 3 :(得分:1)

当由于自动扩展而启动相同微服务(容器)的新实例时,我也遇到了同样的问题,因为每个微服务的端口都是在application.yml中修复和配置的,并且当同一服务由于自动扩展而在相同的EC2上启动时然后它尝试获取其先前实例已经使用的相同端口(例如,如果我在端口3102上运行X作为微服务,如果由于aotoscaling而相同服务的另一个实例起来,那么它可能会在不同的EC2机器上运行或者在ECS集群中的相同EC2机器上,但是ECS根据CPU和RAM的可用性决定在哪里启动新的微服务实例,如果新实例在不同的EC2机器上运行,那么没有问题,因为端口将是空闲的,但是如果实例将起来在相同的ec2机器上它不会启动并喊出该端口已经在使用中)

为了解决这个问题,我们只需要更新ECS集群的任务定义,不需要在映像中进行任何更改,必须在任务定义中启用动态端口映射,以便任意数量的微服务实例可以在同一个Ec2上运行机

没有动态端口映射任务定义配置将

  1. 网络模式 - 主机
  2. 在端口映射中,容器端口将是:在application.yml中配置的应用程序的端口
  3. enter image description here

    enter image description here

    在ECS中启用动态端口映射

    • 更改网络模式:网桥
    • 配置端口映射,使主机端口为0,容器端口等效于application.yml中配置的应用程序端口

    enter image description here enter image description here

答案 4 :(得分:1)

首先,将期望计数设置为0

aws ecs update-service --cluster cluster_name --service service_name --desired-count 0

在执行以下命令后,您可以动态检查正在运行的容器实例的数量

aws ecs describe-services --cluster cluster_name --service service_name

然后在命令下运行

aws ecs update-service --cluster cluster_name --service service_name --desired-count 1