代码之家  ›  专栏  ›  技术社区  ›  red888

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

  •  15
  • red888  · 技术社区  · 7 年前

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

    当我更新服务并“强制新部署”时,我会查看事件并看到以下内容:

    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
    

    然后我转到集群并停止所有任务。

    然后返回到我的服务,并再次使用force new deploy进行更新。这似乎奏效了

    每次要部署新映像时,是否必须停止所有任务并更新服务?还是有一种“正确”的方法可以做到这一点?

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

    接下来,正如回答中所述,我只需要使用动态端口映射。

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

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

    6 回复  |  直到 7 年前
        1
  •  31
  •   MrDuk    7 年前

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

    [[完整性旁注:您的强制部署可能会引发您发布的错误,因为EC2需要一段时间来清理ECS停止的资源。如果您试图强制停止/启动任务,您会看到类似的问题——我们在尝试重新启动配置为分配50%可用实例内存的容器时也看到类似的错误。您将得到这些类型的资源错误,直到EC2实例被完全清除并报告回ECS。我发现这需要5分钟以上。]]

    对于您的问题,不幸的是,目前AWS没有任何优秀的内置机制来执行滚动重启任务。然而,你 可以 进行滚动 部署 .

    您可能已经知道,您的服务依赖于指定的任务定义。请注意,它依赖于 任务定义编号 ,并且不关心 容器标签 以EC2实例将采用的方式。

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

    magic

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

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

    因此,对于一个真实的示例,假设您具有以下配置:

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

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

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

        2
  •  7
  •   Laurent Jalbert Simard    7 年前

    使用ECS(或任何其他orchestrator)时,建议您使用 Dynamic Port Mapping .

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

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

        3
  •  4
  •   S.K.    7 年前

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

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

        4
  •  4
  •   ABHAY JOHRI    7 年前

    当同一个微服务(容器)的新实例由于自动缩放而启动时,我也遇到了同样的问题,因为每个微服务的端口都是在应用程序中固定和配置的。当同一个服务由于自动缩放而在同一个EC2上启动时,它会尝试获取其前一个实例已经使用的相同端口(例如,如果我在端口3102上运行X as微服务,如果同一服务的另一个实例由于aotoscaling而启动,那么它可能会在不同的EC2机器上或ECS集群中的同一EC2机器上启动,但ECS根据CPU和RAM的可用性决定在何处启动新的微服务实例,如果新实例在不同的EC2机器上启动,则不会出现问题,因为端口将是空闲的,但如果实例将在同一台ec2机器上启动,它将不会启动,并发出端口已在使用的消息)

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

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

    1. 网络模式-主机
    2. 在端口映射中,容器端口将是:在应用程序中配置的应用程序的端口。yml公司

    enter image description here

    enter image description here

    用于在ECS中启用动态端口映射

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

    enter image description here enter image description here

        5
  •  0
  •   Eric Ricardo    3 年前

    毫无疑问,这是最好的选择,因为ALB速度慢且有缺陷。谢谢@erncnerky

    首先,将所需计数设置为0

    aws ecs更新服务--群集cluster\u name--服务service\u name--所需计数0 执行以下命令后,可以动态检查正在运行的容器实例数

    aws ecs描述服务--群集cluster\u name--服务service\u name 然后在下面运行命令

    aws ecs更新服务--群集cluster\u name--服务service\u name--所需计数1 共有 编辑 跟随 2019年8月23日8:58编辑 2019年8月22日14:26回复

    erncnerky公司 35233银牌99铜牌 这是可以做到的。但是如果你有不同的环境和不同的期望值呢? 瓦西里·沙胡诺夫 2019年11月26日15:16

        6
  •  -1
  •   erncnerky    5 年前

    首先,将所需计数设置为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