11 月 19 - 20 日 Apache Pulsar 社区年度盛会来啦,立即报名! 了解详情
写点什么

如何实现对集群任务最小影响的 ECS 容器实例自动化终止方案

  • 2019-10-23
  • 本文字数:2657 字

    阅读完需:约 9 分钟

如何实现对集群任务最小影响的 ECS 容器实例自动化终止方案

问题背景

Amazon ECS 是一种容器管理服务,可以很方便地运行、停止和管理群集上的 Docker 容器。当使用 ECS 运行容器任务时,会将它们放置在 ECS 群集上。Amazon ECS 从指定的映像存储库中,下载指定的容器映像,并在集群中的容器实例上运行这些映像所承载的任务。


我的同事 Chris Barclay 发了一篇很不错的博客文章,介绍了在 Auto Scaling 组缩小 ECS 集群之前,使用容器实例耗尽的方法,自动化地删除正在进行的容器实例。


根据多个实际的客户案例,需要从 Amazon ECS 群集中终止实例的应用场景很多且重要, 例如: EC2 AMI 的升级和更新,执行系统关键升级补丁,系统核心组库的更新,Docker 软件版本的升级和更新,ECS 代理的版本升级和更新,集群大小的变更等等。


解决方案

通常而言,这些应用场景,都有一个共同的目标就是当容器实例的终止时,或从集群中删除容器实例时,不会影响集群中正在进行的任务,也就是说,阻止将新任务安排在处于 DRAINING 状态的容器实例上,如果资源可用(或预先起动新的容器实例),则新任务分配到 ECS 集群中的其他容器实例,待终止的容器实例上正在运行的任务,等其成功迁移到其他容器实例后,终止实例。实战中,亦可手动修改容器实例的状态为 DRAINING。本文中,我们将展示如何实现对集群任务最小影响的 ECS 容器实例自动化终止方案,其中会需要使用 Auto Scaling 组的生命周期挂钩以及 Amazon Lambda 提供的无服务函数调用,如下图所示:



Auto Scaling 组支持可调用的生命周期挂钩,例如:Lambda 函数,以允许其在实例启动或终止之前完成,此例为实例终止之前。生命周期挂钩调用的 Lambda 函数完成以下两个任务:


  1. 将 ECS 容器实例状态设置为 DRAINING。

  2. 检查容器实例上是否存在任何正在进行的任务。 如有则会向 SNS 发布消息,再次调用该 Lambda 函数进行检查。


该 Lambda 函数会重复执行第 2 步,直到容器实例上没有任何正在运行的任务,或者生命周期挂钩心跳超时,以先发生者为准。 之后,控制权返回到 Auto Scaling 生命周期挂钩,终止容器实例。


参考示例

要实现上述自动化容器实例终止方案,可参考开源的 CloudFormation 模板,以及 S3 存储桶中上传 Lambda 部署软件包,设置本文中描述的资源。该模板创建以下资源:


  • VPC 和关联的网络元素(子网,安全组,路由表等)

  • ECS 群集,ECS 服务和示例 ECS 任务定义

  • 具有两个 EC2 实例和包含生命周期终止挂钩的 Auto Scaling 组

  • Lambda 函数

  • SNS 话题

  • 能执行 Lambda 函数的 IAM 角色


鉴于中国区有关 Auto Scaling 组的可信任实体和全球的命名方式有所区别,因此可参考这里的修改方法,对 CloudFormation 模板进行配置和更改。


创建 CloudFormation 堆栈,我们可以通过触发实例终止事件,来了解这是如何工作的:


  • 在 Amazon EC2 控制台中 ,选择 Auto Scaling Groups 并选择由 CloudFormation 创建的 Auto Scaling 组的名称。

  • 选择操作 , 编辑并更新服务,将实例的数量减少 1 个。


这将触发一个实例的终止过程。选择 Auto Scaling 组实例选项卡:实例状态值应显示生命周期状态:



此时,生命周期挂钩被激活并向 SNS 发布消息,最终触发 Lambda 函数的响应和执行。之后, Lambda 函数将 ECS 容器实例状态更改为 DRAINING。ECS 服务介入调度,停止实例上的任务并在可用实例上启动该任务。



任务完成后,Auto Scaling 组活动历史记录确认 EC2 实例已终止。



深入分析

我们来深入分析一下 Lambda 函数内部的工作原理。该函数首先检查,收到的事件中的 LifecycleTransition 值是否为 EC2_INSTANCE_TERMINATING,表示当前已经进入生命周期挂钩的终止状态之前。


C


# If the event received is instance terminating...if 'LifecycleTransition' in message.keys():    print("message autoscaling {}".format(message['LifecycleTransition']))if message['LifecycleTransition'].find('autoscaling:EC2_INSTANCE_TERMINATING') > -1:
复制代码


继续调用函数 “checkContainerInstanceTaskStatus”。该函数根据容器实例的 ID,将容器实例状态设置为 ‘DRAINING’。


C


# Get lifecycle hook namelifecycleHookName = message['LifecycleHookName']print("Setting lifecycle hook name {} ".format(lifecycleHookName))
# Check if there are any tasks running on the instancetasksRunning = checkContainerInstanceTaskStatus(Ec2InstanceId)
复制代码


然后,检查实例上是否有任务正在运行。如有任务正在运行,则向 SNS 发布消息以再次触发 Lambda 函数后退出。


C


# Use Task ARNs to get describe tasksdescTaskResp = ecsClient.describe_tasks(cluster=clusterName, tasks=listTaskResp['taskArns'])for key in descTaskResp['tasks']: print("Task status {}".format(key['lastStatus'])) print("Container instance ARN {}".format(key['containerInstanceArn'])) print("Task ARN {}".format(key['taskArn']))
# Check if any tasks are runningif len(descTaskResp['tasks']) > 0: print("Tasks are still running..") return 1else: print("NO tasks are on this instance {}..".format(Ec2InstanceId)) return 0
复制代码


继续执行的 Lambda 函数,发现容器实例上没有运行的任务时,则继续完成生命周期挂钩并终止 EC2 实例。


C


#Complete lifecycle hook.try: response = asgClient.complete_lifecycle_action( LifecycleHookName=lifecycleHookName, AutoScalingGroupName=asgGroupName, LifecycleActionResult='CONTINUE', InstanceId=Ec2InstanceId) print("Response = {}".format(response)) print("Completedlifecycle hook action")except Exception, e: print(str(e))
复制代码


结论

本文讨论了 ECS 容器实例终止的多种应用场景,提供了对集群任务最小影响的 ECS 容器实例自动化终止方案,并通过参考示例展示和深入分析了其工作原理。基于参考示例,可以使用 CloudFormation,Lambda 等服务,实现真正的滚动部署 ,先启动新实例并批量终止实例,同时保证对现有的集群任务带来最小影响。要了解有关容器实例耗尽的更多信息,请参阅 Amazon ECS 开发人员指南


作者介绍:


黄帅(Henry Huang)


亚马逊 AWS 专业服务团队 DevOps 咨询顾问。负责企业级客户的云架构设计和优化、DevOps 组织咨询和技术实施。在软件研发领域有多年架构设计和运维、团队管理经验,对 DevOps、云原生微服务治理框架、容器化平台运维等有深入的研究和热情。
复制代码


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/how-to-automate-the-termination-of-ecs-container-instances-that-minimize-cluster-tasks/


2019-10-23 08:00609

评论

发布
暂无评论
发现更多内容

最优组合问题-贪心算法

公众号:好奇心森林

从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(二)

图雀社区

node.js vue.js Vue

思考:如何打造一个优秀的研发体系?

菜根老谭

研发管理 研发效能 研发体系

ARTS第一周

困到清醒

ARTS 打卡计划 起跑

JUC整理笔记二之聊聊volatile

JFound

Spring事务@Transactional底层原理

公众号:好奇心森林

spring 事务 hiber

在线文档的开发难度与突破

葡萄城技术团队

分布式协同 SpreadJS 在线文档

产品周刊 | 第 16 期(20200524)

Herbert

产品 设计 产品经理 产品设计

企业微信机器人在大型财务共享中心的应用实践

DT极客

Cassandra集群架构及算法剖析

老任物联网杂谈

大数据 分布式 Cassandra 时序数据库

回“疫”录(24):开始了就不算晚

小天同学

疫情 个人成长 回忆录 个人感想 日常思考

绿宝这条宝藏街,夜宵也太太太太太好吃了吧!

极客编

Implement Stack using Queues

Forelax

LeetCode

python实现·十大排序算法之归并排序(Merge Sort)

南风以南

Python 排序算法 归并排序

DDD 中的那些模式 — CQRS

Joshua

领域驱动设计 DDD 事件驱动 CQRS Event Driven

ARTS 打卡 WEEK1

编程之心

ARTS 打卡计划

人工智能学习心得--人工智能分类

岛乾坤

AI

Jsp页面报错后如何找到提示信息中的_jsp.java文件

阡陌r

Java | @Override 不要再把它当成可有可无的了

YoungZY

Java 注解 Override annotation

重学 Java 设计模式:实战抽象工厂模式

小傅哥

设计模式 小傅哥 重构 代码质量 代码坏味道

理解这八大优势,才算精通单元测试

禅道项目管理

测试 单元测试

爬虫框架Scrapy应用实践-淘宝保险频道数据抓取【1】-前期准备

hadesxiong

Python 爬虫 保险 Scrapy

ziliqa生态打造区块链技术实体应用新标杆

极客编

我是程序员,我为自己代言,我相信程序改变世界,虽然少不了质疑和嘲笑

程序员陆通

编程 程序员 高薪 代码

微信gif图片大小的规则

石云升

微信 GIF

ARTS打卡第一周

落曦

列个清单-《清单革命》

Jack Hong

20200518-20200524朋友圈思考汇总

仙女的猪

日常思考

足不出户“逛”银行,37家城商行、农商行手机银行App性能大比拼

博睿数据

APM App 评测 网银 银行

别在发愁写页面了,强烈推荐几款傻瓜式扒网站神器!!

公众号:V5codings

坚持ARTS(week-1)

王钰淇

ARTS 打卡计划

如何实现对集群任务最小影响的 ECS 容器实例自动化终止方案_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章