亚马逊AWS官方博客
深度解析:AWS Fargate 数据平面
Original URL:https://aws.amazon.com/cn/blogs/containers/under-the-hood-fargate-data-plane/
今天,我们推出了AWS Fargate的1.4全新版本,其中为客户带来一系列新的功能与特性。大家可以参考本篇博文了解新版本中的更多功能信息。作为1.4版本中的重要变化之一,我们用Containered替代Docker Engine作为Fargate的容器执行引擎。在本文中,我们将详细介绍这一调整对于容器工作负载的实际影响,做出调整的深层动机以及此项变动如何重新构建容器执行环境(即Fargate数据平面)。
专业术语
在开始今天的内容前,我们首先回顾本文以及系列博文中经常提及的术语与概念。
- 容器运行时/执行引擎:常被称为“容器运行时”,即用于容器创建、启动以及终止的相关软件。本文中的Docker Engine、Containered以及CRI-O等都属于容器运行时。
- runC: 一款基于开放容器倡议(OCI)运行时规范、用于生成及运行容器的工具。
- Containerd: 常见于runC主机环境上容器生命周期管理的守护程序。关于runC与Containerd交互方式的更多详细信息,请参阅Michel Crosby撰写的相关博文。
- Docker Engine: 由Docker推出的容器引擎。其中包含Docker守护程序二进制文件,此二进制文件需要被安装在负责运行容器的主机之上以发挥作用。Docker Engine以Containerd为基础,Containerd又以runC为基础。
转向Containerd,会对运行在Fargate上的容器产生哪些影响?
简而言之,此次调整不会对您的工作负载产生任何影响。
虽然Fargate将转向Containerd以管理容器,但您的应用程序本身不会在执行方式层面发生任何变化。Containerd能够简化并提高容器运行的灵活性,进而改善Fargate的数据平面架构(我们将在后文中做出详细说明)。您的应用程序本身不会察觉到此项变更,具体原因主要有以下三点:
- OCI兼容性:Containerd完全支持OCI镜像与Docker镜像。这意味着所有使用Dockerfile与Docker工具链构建的容器镜像,将能够继续在Fargate上无缝运行。实际上,这也是我们选择Containerd的先决条件之一,我们希望保证所有客户都能将由现有工具链与CI/CD集成管道构建而成的应用程序与Fargate继续匹配使用。
- 编排工具抽象:运行在Farate之上的工作负载,是由Amazon Elastic Container Service(ECS)任务或者Amazon Elastic Kubernetes Service(EKS)Pod规范定义而成。这些编排工具提供的抽象级别要高于容器本身,因此只要Fargate能够支持这些抽象,容器工作负载就不会受到影响。例如,ECS与EKS都不支持通过Docker CLI的run命令参数为容器指定日志记录选项。ECS在任务定义与FireLens配置当中支持日志驱动程序配置,而EKS则直接集成有日志记录代理。我们已经保证Fargate当前支持的所有功能与容器接口,都能够在此次引擎变更之后继续无缝运行。
- 托管基础设施:由于Fargate会为运行中容器所对应的基础设施进行无差别设置与维护,也负责维护这些容器的生命周期。具体包括引导容器镜像、捕捉容器日志并将日志流传输至适当目的地,而后提供适当接口以实现容器的存储、联网、IAM角色凭证访问以及元数据检索。Fargate将继续兼容这些集成点,因此客户应用程序将不会受到任何影响。
为什么选择Containerd?
下面我们来看Fargate数据平面中的各项组件。图一所示,为各组件在1.4版本发布之前的堆叠方式。感兴趣的朋友可以参考re: Invent 2019的主题演讲以了解更多详细信息。
Containerd集成能够简化堆栈、提高可靠性并最大程度减少Fargate组件的占用空间,从而提高整体堆栈的灵活性,保证用户获得更低的新功能运行开销。我们将在后文中进一步探讨这些议题。
容器运行时最小化的意义
随着对Fargate功能集的不断扩展,我们也在持续对堆栈内的不同组件进行自定义。例如:
- 容器原生VPC网络支持:为了支持awsvpc网络模式,我们绕过了Docker Engine提供的所有网络功能,转而使用容器网络接口(CNI)插件(详见 amazon-ecs-cni-plugins GitHub repo)以实现Fargate中的联网功能。这也是新版本发布前可维护性最好、客户友好度最高的网络功能实现途径。我们在Docker Engine之外运行这些网络插件,从而实现Fargate上的联网功能。
- 通过FireLens实现日志记录扩展:为了扩展Fargate上ECS任务的日志记录功能,我们增加了对FIreLens的支持。FireLens提供多种高级功能,例如在日志源处进行内容过滤,并将结果发送至多个目标。我们决定将FireLens日志记录驱动程序作为边车容器,将其与用户的任务容器并排运行。同样的,这些增强功能同样需要在Docker Engine外部实现。
- 面向ECS任务的元数据端点:某些容器及应用程序需要在任务当中查询其他容器的元数据与统计信息。在Fargate之外,最常见的实现方法就是直接访问容器运行时。但Fargate一直着力强调工作负载中的安全与权限分离原则;针对基础容器运行时(例如Docker Engine)的直接访问有可能削弱安全水平,导致恶意攻击者乘机发起“权限提升”攻击。为此,我们决定通过容器中的本地HTTP端点自主提供这类数据。
这种设计思路也成为我们构建的多种原生功能中的整体趋势,也是上图当中第二与第三层部分最需要进行的更改。在Fargate中,我们只需要一套最小化的容器运行时引擎,单纯使用由其提供的基础容器CRUID API。除此之外的所有功能,都可以由Fargate数据平面栈中的其他组件处理完成。
Containerd非常适合这种模式,其中只保留最低程度的状态,但又能够保证支持Fargate需求。例如,在启动容器时,Containerd支持使用外部创建的网络命名空间。这意味着在Fargate的1.4版本上,我们不再需要为ECS任务运行pause容器。以往之所以需要pause容器,是因为这是我们使用Docker创建网络命名空间、并保证在启动应用程序容器前正确完成网络配置的唯一方法。而在新版本上,Fargate数据平面将不再需要额外管理并维护这样一个容器镜像。
管理开销最小化
在运行时消耗的资源以及需要安装的配套软件包方面,Containerd同样拥有突出的优势。以1.4版本为例,我们不再需要安装任何面向客户端的CLI来管理虚拟机上的容器或者容器镜像,这一点与Fargate的设计初衷也更为贴合(Fargate本身一直通过编程方式与相应SDK进行容器管理)。同样的,Fargate也将借此消除由容器镜像构建所带来的组件需求。Fargate的责任在于代表客户规划执行环境,因此减少软件占用空间是一种重要的优化方向。安装的软件包越少,需要维护及安装补丁的软件包就越少,平台本身的健壮性与运营态势也将随之提升。
可扩展架构
在实现容器执行引擎最小化与Fargate数据平面简化的同时,Containers还通过自身基于插件的架构设计带来更强的可扩展性。Containerd使客户端可以通过插件对容器执行生命周期中的几乎任何环节加以配置。这一点对于Fargate非常重要,使得Fargate能够以更具实际意义的方式扩展功能集,进而将价值传递给运行其上的各个容器。
例如,我们希望实现Fargate本身已经支持的、将流式容器日志传输至多个目的地的功能。通过扩展Containerd的垫片式日志插件,我们可以直接实现这项功能。我们专门为容器日志的路由功能创建了一组垫片日志插件,并随1.4版本将其推向开源。大家可以在amazon-ecs-shim-loggers-for-containerd repo中找到相应文件。这些插件将全面取代Fargate之前版本所使用的Docker Engine进程内日志记录驱动程序,且提供完全相同的功能集。如果大家正在尝试或使用Containerd,并希望寻找可扩展的日志记录解决方案,建议各位试试这款插件。关于这些插件的更多详细信息,请点击此处。
再举一例,Fargate只需要将Containerd的运行时插件由runC切换为firecracker-containerd,即可直接使用Firecracker VMM等基于虚拟机的容器运行时。该插件使Containerd能够将容器作为Firecracker microVM进行管理。为了适应Fargate当前能够支持的各类用例,我们显然需要这种在尽可能减少配置变更的前提下灵活切换不同容器运行时的能力。
Fargate数据平面架构
在决定采用Containerd之后,我们自然据此为Fargate数据平面创建出对应组件,用以替代以往使用ECS代理进行容器编排的处理方式。为此,我们编写了新的Fargate代理,负责与Containerd交互并替代ECS代理在虚拟机上实现容器编排。这一全新Fargate代理不仅能够与Containerd良好集成,同时也针对Fargte进行了优化。以此为基础,Fargate能够无缝提供EKS Pod支持等丰富功能。这套新的架构还允许Fargate通过firecracker-containerd运行时利用Firecracker microVM实现容器运行。图二所示,为Fargate数据平面栈的全新架构。
图三所示,为Fargate代理在开始ECS任务时,在VM上运行客户容器的事件处理大体顺序。
- Fargate代理收到一条消息,要求其启动任务。消息中还包含关于该任务所需要的弹性网络接口(ENI)的详细信息。
- 此后,该代理创建一个新的网络命名空间,并为该命名空间提供网络接口以设置符合需求的网络连接(参见图三)。
- 接下来,代理利用ENI从客户的账户中下载容器镜像,所有秘密凭证以及容器引导所需要的其他配置信息。
- 随后,客户容器在Containerd API的支持下开始启动。
- Containerd进一步创建垫片进程,作为容器的父进程。另外,这些垫片进程还将使用runC启动容器。
- Fargate代理最后根据客户指定的配置选择能够满足实际需求的Containerd日志记录垫片,并由Containerd借此启动对应的容器日志记录插件。
总结
我们一直在不断向Fargate平台注入创新成果,努力为客户提供更多新的功能与用例。而新架构所表现出的强大、简单与灵活特性也着实令我们感到兴奋。欢迎大家在评论区中分享您对新版本变更的反馈意见以及垫片日志插件的使用感受。当然,大家也可以通过GitHub上的容器路线图repo与我们交流。