深入浅出边缘云 | 5. 运行时控制(上)

简介: 深入浅出边缘云 | 5. 运行时控制(上)

第 5 章 运行时控制


运行时控制子系统提供 API,各主体(如终端用户、企业系统管理员和云运维人员)可以通过 API 对正在运行的系统进行更改,为一个或多个运行时参数指定新值。


下面以 Aether 5G 连接服务为例,假设企业系统管理员想更改一组移动设备的服务质量(Quality-of-Service)。Aether 定义了设备组(Device Group) 抽象,以便相关设备可以一起配置。然后,管理员可以修改最大上行带宽(Maximum Uplink Bandwidth)最大下行带宽(Maximum Downlink Bandwidth) ,甚至可以为该组选择不同的流量类(Traffic Class) 。类似的,可以设想一下运营商想为现有设备的流量类(Traffic Classes) 中添加一个新的关键任务(Mission-Critical) 选项。先不考虑这些操作的 API 调用的确切语法,运行时控制子系统需要:


  1. 验证要执行操作的主体。
  2. 确定该主体是否有执行操作的足够权限。
  3. 将新参数设置推送到一个或多个后端组件中。
  4. 记录指定的参数设置,以便保留新值。


在这个例子中,设备组(Device Group)流量类(Traffic Class) 是被操作的抽象对象,虽然运行时控制子系统必须理解这些对象,但对它们的改变可能涉及调用多个子系统的低级控制操作,如 SD-RAN(负责 RAN 中的 QoS)、SD-Fabric(负责交换网络的 QoS)、SD-Core UP(负责移动核心网用户平面的 QoS)和 SD-Core CP(负责移动核心网控制平面的 QoS)。


简而言之,运行时控制在后端组件集合之上定义了抽象层,将它们有效的转变成外部可见(和可控)的云服务。有时,单一后端组件实现了全部服务,在这种情况下,运行时控制可能只是增加了一个 AAA 层而已。但是,对于由分散组件组成的云来说,运行时控制是我们定义 API 的地方,可以在逻辑上将这些组件整合为一套统一的、连贯的抽象服务。这也是为底层子系统"提高抽象水平"和隐藏实现细节的机会。


请注意,由于其作用是基于一组后端组件提供端到端服务,本章介绍的运行时控制机制类似于服务编排器(Service Orchestrator) ,将电信网络中的 VNF 集合连在一起。这里可以使用任一术语,但我们选择"运行时控制(Runtime Control)"来强调问题的时间性,特别是与生命周期管理的关系。另外,"编排"也是一个有内涵的术语,在不同背景下有不同的含义。在云计算环境中,意味着装配虚拟资源,而在电信环境中,意味着装配虚拟功能。正如在复杂系统中经常出现的情况那样(特别是在促进竞争的商业模式时),你在堆栈中走得越高,对术语的共识就越少。


无论如何称呼这种机制,定义一组抽象和相应的 API 都是具有挑战性的工作。合适的工具能够帮助我们专注于任务的创造性部分,但却不能消除它。挑战部分在于判断哪些内容应该对用户可见,应该隐藏哪些实现细节,其中部分挑战在于如何处理、合并冲突的概念和术语。我们将在 5.3 节看到一个完整示例,但为了说明这一困难,请考虑 Aether 是如何在其 5G 连接服务中提及用户的。如果直接从电信行业借用术语,那指的是使用移动设备的人(subscriber),同时意味着向该设备提供服务的帐户和设置集合。事实上,用户(subscriber)是 SD-Core 实现的核心对象。但 Aether 是为支持企业部署 5G 而设计的,为此,将用户定义为具有某种规定权限级别的访问 API 或 GUI 门户的主体。该用户和核心网定义的用户(subscriber)之间不一定存在一对一的关系,更重要的是,不是所有设备都有用户,像物联网设备的情况一样,通常不与某个人相关联。


5.1 设计概述


在高层次上,运行时控制的目的是提供一个各方可以用来配置和控制云服务的 API。为此,运行时控制必须:


  • 支持跨多个后端子系统的端到端抽象。
  • 将控制和配置状态与抽象相关联。
  • 支持配置状态的版本控制,可以根据需要回滚更改,并且可以检索以前配置的审计历史记录。
  • 在如何实现这个抽象层方面采用高性能(performance)高可用性(high availability)可靠性(reliability)安全性(security) 的最佳实践。
  • 支持基于角色的访问控制(Role-Based Access Control, RBAC) ,以便不同主体对底层抽象对象具有不同的可见性和控制。
  • 具有可扩展性,能够随着时间的推移合并新的服务或者升级现有服务的新的抽象。


核心要求是运行时控制能够代表一组抽象对象,也就是说,实现一个数据模型。虽然用于表示数据模型的规范语言有几种可行的选择,但对于运行时控制,我们使用 YANG。这有三个原因,首先,YANG 是一种丰富的数据建模语言,支持对存储在模型中的数据进行强有力的验证,并且能够定义对象之间的关系。其次,对数据的存储方式没有要求(即不直接与 SQL/RDBMS 或 NoSQL 范式挂钩),从而为我们提供了广泛的工程选项。最后,YANG 被广泛用于这一目的,意味着有大量强大的基于 YANG 的工具集合作为我们构建的基础。


延伸阅读:

YANG - A Data Modeling Language for the Network Configuration Protocol. RFC 6020. October 2010.


基于这一背景,图 22 显示了 Aether 运行时控制的内部结构,其核心是 x-config(维护一组 YANG 模型的微服务)<sup>[1]</sup>。x-config 使用 Atomix(一个键值存储微服务),使配置状态持久化。因为 x-config 最初被设计为管理设备的配置状态,使用 gNMI 作为其南向接口,将配置变化传达给设备(或在我们的例子中,软件服务)。必须为任何不支持 gNMI 的服务/设备编写适配器,这些适配器在图 22 中被显示为运行时控制的一部分,但将每个适配器视为后端组件的一部分也同样正确,它负责使该组件做好管理准备。最后,运行时控制还包括工作流引擎,负责在数据模型上执行多步骤操作。例如,当一个模型的改变触发了另一个模型上的某些操作时,就会发生这种情况。下一节将详细介绍这些组件。


[1] x-config 是一个通用的、模型无关的工具。在 AMP 中,它管理云服务的 YANG 模型,但 SD-Fabric 也基于它来管理网络交换机的 YANG 模型,SD-RAN 也用它来管理 RAN 组件的 YANG 模型。这意味着在给定的 Aether 边缘集群中运行着 x-config 微服务的多个实例。


image.png

图 22. 运行时控制的内部结构,以及与后端子系统(下层)和用户门户/应用程序(上层)的关系。


Web 框架


运行时控制在云运维中扮演的角色类似于 Web 框架在 Web 服务运维中扮演的角色。如果一开始就假设某些类别的用户将通过 GUI 与系统交互(在我们的例子中边缘云就是这一系统),那么你要么用 PHP 这样的语言编写 GUI(就像早期的 web 开发者所做的那样),要么利用 Django 或 Ruby on Rails 这样的框架。这些框架提供了一种方法来定义一组用户友好的抽象(称为模型 Models),通过这种方法来在 GUI 中可视化这些抽象(称为视图 Views),以及基于用户输入对后端系统进行更改(称为控制器 Controllers)。模型-视图-控制器(MVP, Model-View-Controller)是一种被广泛理解的设计范式,这并非偶然现象。


本章介绍的运行时控制子系统采用了类似的方法,但我们不是用 Python(如 Django)或 Ruby(如 Ruby on Rails)来定义模型,而是用一种声明性语言(YANG)来定义模型,而这种语言又被用来生成可编程 API。这个 API 可以从(1)GUI 中调用,GUI 本身通常是使用另一个框架,如 AngularJS;(2)CLI;或(3)某个闭环控制程序。还有其他不同之处,例如,适配器(控制器的一种)使用 gNMI 作为控制后端组件的标准接口,持久化状态存储在键值存储中,而不是 SQL 数据库中,但最大的区别是使用声明性语言而不是命令性语言来定义模型。


运行时控制 API 是从 YANG 数据模型自动生成的,如图 22 所示,支持两类门户以及一组闭环控制应用程序,还支持 CLI(没有显示)。这个 API 可以为所有需要读取或写入 Aether 控制信息的相关方提供单一入口,从而通过中介访问控制和管理平台(Control and Management Platform)的其他子系统(不仅仅是图 22 中所示的子系统)。


这种情况如图 23 所示,其关键启示是:(1)我们希望对所有操作进行 RBAC 和审计;(2)我们希望有权威的配置状态单一来源;(3)我们希望授予每一个负责人对管理功能的有限(细粒度)访问权,而不是假设只有一个特权类别的操作者。当然,底层子系统的私有 API 仍然存在,操作人员可以直接使用。这在诊断问题时可能特别有用,但由于上述三个原因,有强力理由支持使用运行时控制 API 来代理所有控制活动。


这个讨论与第 4 章文末的"GitOps 呢?"相关。我们在本章最后将再次讨论同样的问题,但我们现在有了运行时控制选项,在键值存储中维护了系统权威配置和控制状态,为此做好了准备。这就提出了如何与实现生命周期管理的存储库"共享配置状态所有权"的问题。


一种选择是根据具体情况来决定,运行时控制维护某些参数的权威状态,配置存储库维护其他参数的权威状态。我们只需要弄清楚哪个是哪个,这样每个后端组件就知道需要响应哪个"配置路径"。然后,对于任何我们希望运行时控制来代理访问的重新维护的状态(例如,为更广泛的主体集提供细粒度访问),我们需要小心任何对重新维护的状态的后门(直接)更改的后果,例如,通过只在运行时控制的键值存储中存储该状态的一个缓存副本(作为一种优化)。


image.png

图 23. 运行时控制还代理对其他管理服务的访问。


图 23 另一个值得注意的方面是,虽然运行时控制代理了所有与控制有关的活动,但它不在所控制的子系统的"数据路径"中。例如,监控和遥测子系统返回的监测数据不经过运行时控制,被直接传递给运行在 API 之上的仪表盘和应用程序,运行时控制只参与授权对这些数据的访问。另外,运行时控制子系统和监控子系统有自己独立的数据存储,运行时控制使用 Atomix 键值存储,监控使用时间序列数据库(在第 6 章有更详细的讨论)。


总之,对统一的运行时控制 API 的价值最好的说明是能够实现闭环控制应用程序(和其他仪表板): "读取"监控子系统收集的数据,对该数据进行某种分析,也许做出某种决定采取纠正措施,然后"写入"新的控制指令,x-config 将其传递给 SD-RAN、SD-Core 和 SD-Fabric 的其中一个或某几个,有时甚至传递给生命周期管理子系统(我们将在第 5.3 节中看到后者的例子)。图 24 介绍了这种闭环情况,通过显示 j 将监控子系统和运行时控制子系统放在同一层级(而不是在它下面)而提供了不同视角,尽管两种视角都是有效的。


image.png

图 24. 运行时控制的另一个角度,说明支持闭环控制应用的统一 API 的价值。


5.2 实现细节


本节介绍运行时控制子系统中的每个组件,重点介绍每个组件在云管理中扮演的角色。


5.2.1 模型与状态(Models & State)


x-config 是运行时控制的核心,其主要工作是对配置数据进行存储和版本控制。配置通过北向 gNMI 接口推送到 x-config,存储在持久化键值存储中,并使用南向 gNMI 接口推送到后端子系统。


一组基于 YANG 的模型定义了配置状态的模式。这些模型被加载到 x-config 中,并共同定义了运行时控制负责的所有配置和控制状态的数据模型。作为示例,Aether 的数据模型(schema)在第 5.3 节中概述,但另一个例子是用于管理网络设备的 OpenConfig 模型集。


延伸阅读:

OpenConfig: Vendor-neutral, model-driven network management.


这一机制有四个重要方面:


  • 持久化存储(Persistent Store): Atomix 是云原生键值存储,用于在 x-config 中持久化数据。Atomix 支持分布式映射抽象,实现了 Raft 共识算法,以实现容错和可伸缩性能。x-config 使用 NoSQL 数据库通用的简单 GET/PUT 接口向 Atomix 写入和读取数据。
  • 加载模型(Loading Models): 使用模型插件(Model Plugins) 加载模型。x-config 通过 gRPC API 与模型插件通信,在运行时加载模型。模型插件是预编译的,因此在运行时不需要编译。x-config 和插件之间的接口消除了动态加载兼容性问题。
  • 版本控制和迁移(Versioning and Migration): 所有加载到 x-config 中的模型都有版本控制,更新模型的过程触发持久状化态从一个版本到另一个版本的迁移。迁移机制支持多版本同时操作。
  • 同步(Synchronization): 预计 x-config 控制的后端组件将周期失败并重启。由于 x-config 是这些组件的运行时真实来源,负责确保在重启时与最新状态重新同步。x-config 的模型包括反映这些组件的操作状态的变量,因此能够检测重启(并触发同步)。


有两点需要进一步阐述。首先,因为 Atomix 只要在多个物理服务器上运行就具有容错性,可以建立在不可靠的本地(每台服务器)存储之上,因此没有理由使用高可用的云存储。另一方面,为谨慎起见,运行时控制子系统维护的所有状态都要定期备份,以防因灾难性故障而需要从头开始重启。这些检查点,加上存储在 Git 仓库中的所有配置即代码文件,共同定义了(重新)实例化云部署所需的全部权威状态。


第二,模型定义集就像任何其他的配置即代码的片段,被签入代码库中并进行版本管理,就像第 4.5 节中介绍的那样。此外,指定如何部署运行时控制子系统的 HelmChart 确定了要加载的模型版本,类似于 Helm Chart 确定要部署的每个微服务(Docker 镜像)版本的方式。因为运行时控制 API 是由模型集自动生成的,这意味着 Helm Chart 有效指定了运行时控制 API 的版本,我们将在下一小节看到。所有这些都是说,云北向接口的版本控制,作为一个聚合的整体,其管理方式与对云的内部实现作出贡献的每个功能构件的版本控制完全相同。


5.2.2 运行时控制 API


API 提供了位于 x-config 和更高层门户和应用程序之间的接口包装器(interface wrapper) ,北向提供了 RESTful API,南向提供了 gNMI 和 x-config 通信。运行时控制 API 有三个主要目的:


  • 与 gNMI(只支持 GET SET 操作)不同,GUI 开发需要 RESTful API(支持 GETPUTPOSTPATCH DELETE 操作)。
  • API 层是实现早期参数验证和安全检查的机会,使得我们能够在离用户更近的地方捕捉错误,并生成比 gNMI 更有意义的错误消息。
  • API 层定义了"门控",可用于审计谁在什么时候执行了什么操作的历史记录(利用下面介绍的身份管理机制)。


从加载到 x-config 的模型集自动生成 REST API 是可行的,尽管也可以为了方便而用额外的"手工制作的"调用来增强这组模型(注意这可能意味着 API 不再是 RESTful 的)。将模型规范作为单一真实来源,并从规范中导出其他工件,如 API,这个想法很吸引人,这么做能够提高开发者生产力,并减少各层之间的不一致。例如,如果开发者希望在某个模型中添加一个字段,如果没有自动生成,下面的内容必须全部更新:


  • 模型
  • API 规范
  • 通过对模型进行操作来为 API 服务的 Stub
  • 客户端库或开发人员工具包
  • 可视化模型的 GUI 视图


Aether 的解决方案是使用名为oapi-codegen的工具将 YANG 声明转换为 OpenAPI3 规范,然后使用oapi-codegen自动生成实现 API 的 stub。


延伸阅读:

OpenAPI 3.0: API Development for Everyone.


自动生成 API 并非没有缺陷。模型和 API 迅速发展成 1:1 的对应关系,意味着建模中的任何更改都会立即在 API 中可见。因此,如果要保持向后兼容性,必须小心处理建模更改。因为单个 API 不能轻易满足两组模型的需求,迁移也更加困难。


另一种方法是引入第二个面向外部的 API,并在自动生成的内部 API 和外部 API 之间建立一个小转换层(shim)。shim 层将起到减震器的作用,减轻内部 API 可能发生的频繁变更。当然,需要假设面向外部的 API 是相对稳定的,如果模型更改的首要原因是服务定义还不成熟,那么这就有问题了。如果模型由于控制的后端系统的改变而改变,那么通常情况下模型可以被区分为"低级"或"高级",只有后者通过 API 直接对客户可见。在语义版本控制术语中,对低级模型的更改可以成为向后兼容的 PATCH。

目录
相关文章
|
6月前
|
存储 边缘计算 数据处理
边缘云概述
边缘云是分布式云数据中心,位于网络边缘,提供低延迟、高带宽的实时服务。它减少数据传输时间,支持本地化处理,确保数据安全,并在无网络时仍能运作。应用于CDN、互动直播和本地服务,与云计算互补,共同优化数据处理。随着5G和IoT的发展,边缘云将在未来扮演关键角色。
|
存储 运维 Kubernetes
深入浅出边缘云 | 2. 架构
深入浅出边缘云 | 2. 架构
335 0
深入浅出边缘云 | 2. 架构
|
存储 运维 Kubernetes
深入浅出边缘云 | 1. 概述(下)
深入浅出边缘云 | 1. 概述(下)
236 0
深入浅出边缘云 | 1. 概述(下)
|
JSON 监控 架构师
深入浅出边缘云 | 6. 监控与遥测(下)
深入浅出边缘云 | 6. 监控与遥测(下)
179 1
深入浅出边缘云 | 6. 监控与遥测(下)
|
网络协议 JavaScript 应用服务中间件
深入浅出边缘云 | 3. 资源配置(上)
深入浅出边缘云 | 3. 资源配置(上)
455 0
深入浅出边缘云 | 3. 资源配置(上)
|
存储 运维 Kubernetes
深入浅出边缘云 | 3. 资源配置(下)
深入浅出边缘云 | 3. 资源配置(下)
191 0
深入浅出边缘云 | 3. 资源配置(下)
|
存储 Kubernetes 监控
深入浅出边缘云 | 4. 生命周期管理(上)
深入浅出边缘云 | 4. 生命周期管理(上)
166 0
深入浅出边缘云 | 4. 生命周期管理(上)
|
存储 运维 Kubernetes
深入浅出边缘云 | 4. 生命周期管理(下)
深入浅出边缘云 | 4. 生命周期管理(下)
260 0
深入浅出边缘云 | 4. 生命周期管理(下)
|
存储 Prometheus 运维
深入浅出边缘云 | 6. 监控与遥测(上)
深入浅出边缘云 | 6. 监控与遥测(上)
334 0
深入浅出边缘云 | 6. 监控与遥测(上)
|
存储 运维 Kubernetes
深入浅出边缘云 | 5. 运行时控制(下)
深入浅出边缘云 | 5. 运行时控制(下)
224 0