| 导语 一篇关于云原生面向终态的声明式应用生命周期管理的介绍
前言
在 Kubernetes 成为容器编排事实标准的云原生时代,无数开源或者闭源项目,如众星捧月般围绕着它,建立各种生态,涵盖着集群管理,资源管理、平台管理、可观测性领域的运维管理等诸多领域,其中很多优秀项目都如雨后春笋似地出现。然而,作为这个编排系统的终端使用者的应用领域,却似乎是受到了冷落。本文将以应用的第一视角,对腾讯自研的云原生应用定义Tencent Application Definition(简称TAD)进行介绍,简要说明腾讯研发团队基于 K8s 之上的应用层面做的一些探索。
背景
在介绍 TAD 之前,我们需要先介绍一下 TCS。TCS 是腾讯云推出的一款 PaaS 平台产品,可以作为腾讯专有云(TCE)的底座,也可以做为私有化 SaaS 的底座,亦可以作为一款 PaaS 类产品独立输出。在这个基于 K8s(TKE)构建的 PaaS 平台上,如何解决用户零 K8s 基础,从无到有,快速部署应用并管理其监控、日志、服务注册在内生命周期,成为一个关键课题。基于 K8s 功能特性和腾讯自研业务接入的强烈需求,TAD 的研发工作迫在眉睫应运而生。
TAD ,全称 Tencent Application Definition,是 TCS 平台上的应用定义标准,是面向企业级的应用编排解决方案。TAD 作为连接云产品 SaaS 产品和 TCS 平台之间的桥梁,在应用侧承接云产品和 SaaS 产品复杂的部署流程(大量应用间的编排依赖,服务注册与服务发现,跨 AZ 容灾等)和异构的应用形态(容器,虚拟机应用,有状态服务), 面向底层基础架构释放 TCS 强大的平台能力(一体化的日志、监控告警、多租户) 和云原生基础设施带来的应用架构革命(弹性资源,服务网格), 在兼容 Kubernetes 原生与社区开源能力的同时, 也尽量降低 Kubernetes 带来的额外使用复杂性。
原理
TAD 利用 Kubernetes 的 CRD(自定义资源对象)能力,创建了一个新的资源类型 -Application。该资源类型的 Spec(功能定义)包含了业务应用自身部署用到的原生 workload(如 deployment,statefulset,daemonset 等)和自定义 workload(如statefulsetPlus),业务应用依赖的自研中间件服务 MiddlewareWorkload(Kafka,MariaDB 等) 依赖关系,以及运维相关的 trait (如服务发现)等。
以下一个简单的例子可以大致理解 Application 的定义:
apiVersion: infra.tce.io/v1
kind: Application
metadata:
name: nginx
spec:
components:
- name: nginx
type: deployment # TAD内置工作负载能力的类型名称,用户不需要了解内部细节,只需要按照文档或样例填写 name 和 args 参数值即可
args:
image: nginx:latest
volumes:
configMap:
- name: middleware-config # 将挂载的 ConfigMap 名称
mountPath: /data # 挂载到容器中的路径
items:
- key: config.yaml # 将挂载的 ConfigMap data
# path: config.yaml # 如果不声明 path,将直接使用 key 作为 path
traits:
- type: service # TAD内置运维能力的类型名称,用户不需要了解内部细节,只需要按照文档或样例填写args 参数值即可(每一个组件中,同一类运维能力只允许使用一次)
args:
register: # 用于注册服务
id: svcid-1
port: 8081
host: svc.tce.io
services:
- name: nginx-svc-1
ports:
- port: 8081
- name: nginx-svc-2
ports:
- port: 8082
deps: # TAD 依赖管理能力
- config: nginx-config # 指明该组件依赖的 Config,只有当该 Config .status.phase==Ready 时才会 Apply 该组件
- application: other-app # 指明该组件依赖的其他 Application,只有当该 Application status.phase == succeeded 时才会 Apply 该组件
- service: svcId-from-other-comp # 指明该组件依赖一个全局可用的 ServiceId(基于 TCS/Pajero 服务注册发现能力)
- name: demo-kafka
type: middleware # TAD内置工作负载能力的类型名称,middleware 工作负载专门用于创建中间件服务
args:
class: kafka
# serviceId: my-kafka-id # 如果此处没有声明 ServiceId,TAD 将自动生成一个 SvcId,规则:{component.name}-{app.name}
# 例如,注释掉上面一行,该 kafka 服务将使用自动生成的全局 ServiceId:demo-kafka-nginx
capacity:
cpu: "4"
memory: 8Gi
storage: 200Gi
- name: demo-maria
type: middleware
args:
class: mariadb
ServiceId: my-mariadb-id # 该 maria 服务将使用全局 ServiceId:my-mariadb-id
capacity:
cpu: "4"
memory: 8Gi
storage: 200Gi
一个应用对应一个完整的声明文件,就可以把它在 K8s 上所需要的各种零散资源对象一口气定义清楚。虽然看似简单的一个小集成,却可以让业务应用在 K8s 平台上化繁为简,只用关注几个字段的输入,即可享受 K8s 部署分布式应用的各种便利。
TAD 在演进过程中,一直坚持 3 个原则:标准、扩展、开放。
标准:应用声明和定义自研,兼容业界的 OAM 标准,更便于产品化输出和广泛使用。
扩展:组件管理能力和应用运维能力 out-of-tree 独立开发,更便于协作和快速迭代需求。
开放:任何开发者都可以按标准开发,贡献和分享组件管理和运维能力控制器及定义。
核心功能
TAD 应用管理平台对 TAD 应用全生命周期下的管理能力,它最大的特点是屏蔽应用下辖的 K8s 资源细节。
如前文样例应用展示,一个 TAD 应用由一个或者多个组件(Component)数组构成,每个组件由一个工作负载能力、任意数量的运维能力以及任意数量的依赖配置构成。
因此我们定义:
应用(Application) = ∑ 组件(Component)+ ∑ 运维特征(Traits)!
工作负载是每个组件的核心,下表简要列举其中的一些常用workload。
工作负载能力类型名称 | 描述 | 底层 K8s 资源 |
---|---|---|
deployment | 用于持续运行的无状态的容器化应用的工作负载。 | Deployment k8s.apps/v1 |
statefulset | 用于持续运行的有状态的容器化应用的工作负载。 | Statefulset k8s.apps/v1 |
middleware | 用于创建 TCS/PaaS (中间件服务)的工作负载,每个中间件工作负载将自动(或手动)生成提供一个全局可用 ServiceId 供访问使用。目前支持的中间件服务详见 middleware 工作负载参数说明。 | MiddlewareWorkload, ServcieInstance, ServiceBinding, ServicePlan, etc infra.tce.io/v1 |
job | 用于一次性运行的任务型容器化应用的工作负载 | Job k8s.apps/v1 |
statefulsetplus | TCS 定制化 Statefulset | StatefulsetPlus infra.tce.io/v1 |
运维能力是指围绕工作负载创建的运维特征,包括但不限于:服务暴露、服务注册、流量管控、sidecar 注入、日志采集、监控等等。如下表的简介:
运维能力类型名称 | 描述 | 底层 K8s 资源 |
---|---|---|
service | 基于 TCS 自研的服务注册与发现能力(pajero),用于暴露 & 注册(可选)工作负载提供的服务,通过自动(或手动)生成一个全局可用的 ServiceId 供访问使用。 | ServiceTrait infra.tce.io/v1 |
polaris | 基于腾讯开源的北极星服务治理能力,用于暴露 & 注册工作负载提供服务,用户必须指定注册到北极星中的服务实例名称。 | Service k8s.core/v1 |
产品化
在对接 SaaS 服务私有化输出和支持云产品接入的过程中,TAD 基于这些腾讯专有云的场景积累了大量的生产级复杂应用的编排和治理的实践,TAD 团队希望这些能力同样可以给 TCS 的客户带来价值,帮助客户更好地在 TCS 平台上进行业务云原生化改造。同时我们选择了产品化的方式,将专有云中应用编排与管理的能力沉淀到 TCS 的一款白屏化云产品 --- 应用中心。
应用中心的核心能力分为应用的定义(模板管理)和发布运维(应用管理)两个部分:
多种异构工作负载
设置组件的工作负载,可选的工作负载包括容器、有状态中间件和非容器工作负载(即将支持):
设置工作负载的详细信息, 例如容器工作负载的镜像地址、环境变量、网络、数据卷等。MySQL 工作负载的数据库名称、用户名称等。熟悉 Kubernetes 的同学 都知道 Kubernetes 中容器的配置非常复杂,于是将容器配置做了划分为:容器配置、数据卷、网络设置、调度策略、更多(监控日志) 这五个步骤分布处理。 如果用户的容器配置足够简单,也能简化填写过程。
应用间的编排依赖
在生产实践中我们发现,一个复杂的业务系统中应用之间往往会存在错综复杂的依赖关系。例如业务容器运行需要使用数据库和缓存服务,那么应用部署时应该优先部署数据库和 redis 组件,当数据库和 Redis 部署就绪后渲染出包含数据库访问凭证的配置信息,此时才能进行业务容器的部署。 同样业务服务之间的也会存在依赖关系,如服务 A 作为服务 B 的访问下游, 服务 B 需要等待服务 A 部署完成,并且完成域名注册后才能进行部署。
在 TAD 可以通过依赖配置声明应用内组件与跨应用组件的依赖关系,并在界面上通过一个有向无环图实现依赖关系的可视化, 由于有向无环图的不闭合特性,同样可以保证组件之间不会出现循环依赖。
开放兼容
为了兼容社区标准,用户在应用中心中制作的所有模板都能够以 Helm Chart 形式导入与导出,模板格式和平台解耦,做到一次定义到处部署。 用户除了在应用中心自制的 TAD 应用模板,也可以上传第三方或自己编写的 Helm Chart 应用,并在 TAD 应用中心里无缝运行。
在 TAD 的应用市场里也内置了部分开箱即用的开源应用,同时用户也可以将自己制作的组件发布到应用市场, 实现租户之间的共享。
应用生命周期管理
TAD 支持了应用完整的生命周期管理,从应用的发布,到持续更新运维。完整的生命周期包括以下:
分批发布
持续发布是应用必不可少的部分, TAD 应用中心提供自动分批、指定步骤分批、和手动分批三种分批发布的模式,并和 Ingress、Istio 等上层的网关做了深度的权重集成。
此外应用中心即将支持容器的原地升级, 适用于有状态应用的场景,在更新时无需重建 Pod 而是直接更新容器信息,从而避免重复进入调度和 Volume 挂载等流程,提高发布的变更效率。
版本化的配置管理
在现代应用的 12 条原则 (The Twelve-Factor App ) 中第三条就提到,应用的配置应该储存在环境中而非应用里(Store config in the environment), 应用配置通常包括外部服务的配置、第三方服务的访问信息、每次部署特有的环境信息(如域名等)。
Kubernetes 中虽然提供 ConfigMap 和 Secret 对象用于描述应用的配置信息, 但在实际生产实践中,Kubernetes 的原生能力远不能满足应用对配置文件的需求:
于是在 TAD 中,基于专有云场景的需求扩展配置资源,TAD 提供一个新的 Config 资源, Config 资源既能声明静态的配置文件,也支持生命动态的渲染模板,并基于内部的服务发现渲染出真实的配置内容,并生成相关资源(ConfigMap/Secret)。
同时对 Config 的内容做了版本化的记录和管理,用户可以为业务设置 Config 的固定版本,也可以选择一直使用最新版本。 版本信息变化,由用户决定是否应用触发灰度/手动更新。
客户场景
后续规划
多集群管理
越来越多的公司在生产环境中运维着一套以上 Kubernetes 集群,无论是为了突破单集群的规模瓶颈,还是为了多云/混合云等更先进的部署架构,我们都能看到多集群逐渐发展成为常态。
如何高效地管理多套集群,既能利用多集群带来的架构灵活性和隔离性,又能通过和单集群一致的部署体验降低运维复杂度,同时合理提高多套集群的资源利用率。
目前在 TAD 应用中心中支持多集群发布的第一步,可以将应用下发到指定的 TCS 子集群,团队也正在推进研发多集群的应用的编排调度策略,适用于多地域发布的多集群复制模式,以及基于容量的多集群调度模式。希望基于 TAD 提供应用多集群发布的能力,同时给应用提供和单集群一样既高效又简单丝滑的使用体验。
服务网格能力产品化
服务网格是用于处理服务间通信的基础设施层,它负责通过包含现代云原生应用程序的复杂服务拓扑来可靠地传递请求。通过服务网格能将过去依赖特定语言,特定框架或 SDK 的服务治理能力下沉到基础设施。
而 Istio 一直最被诟病的就是其引入的复杂性 ,虽然社区一直致力于通过架构精简,提供各种工具等手段降低使用门槛,但其基于 label 的松耦合匹配机制,复杂的 API 和概念一直都令许多有意使用服务网格的公司望而却步 。
TAD 封装了 Istio 的能力,通过 TAD 自身的应用视角,将 Istio 相关资源根据应用维度聚合,并通过抽象简化了 Istio API,简化 Istio 使用的。后续也计划将基于 TAD 的服务网格能力通过应用中心产品化,给在 TCS 场景里提供轻量化的服务治理能力。
TAD