【SaaS】详解在Azure AKS上构建多租户SaaS应用程序架构及示例
推荐超级课程:
@TOC
SaaS ?
SaaS(软件即服务)是一种业务和软件交付模型,它使组织能够以服务为中心的方式大规模提供其解决方案,通常基于订阅模式。SaaS的采用通常针对以增长为驱动的转型、市场扩张、运营简单性和更快的创新,以及更快的 产品发布。
SaaS基础设施通过利用规模经济、资源池和共享以及提高基础设施的一般利用率,提供了更好的成本效益。SaaS基础设施模式对于ISV(独立软件供应商)尤其有吸引力,因为SaaS加速了租户的上线,使平台用户能够收集和挖掘数据(例如,计算CAC、CLTV、MRR、产品消耗指标……),并更容易集中解决成本高昂的客户服务,同时实现由数据驱动的主动客户互动。
SaaS基础设施托管多个隔离的租户,并提供自动配置它们的工具和服务,以及收集每个租户的指标和分析。每个上线的SaaS应用程序的租户都称为“租户”。
SaaS系统的所有客户都在单个Azure订阅/租户中运行,使用部分或完全共享的资源。这样的基础设施称为“多租户”基础设施。
在本文中,我们将解释如何在Azure AKS上构建多租户SaaS基础设施。在云中处理多租户架构挑战有多种方法。我们将专注于特定的部署模型“集群多租户”,该模型适用于使用微服务架构云原生开发的 应用程序。
本文主要关注构建SaaS基础设施的两个最大挑战: a) AKS的租户隔离能力; b) AKS上租户上线的自动化。
SaaS基础设施要求
SaaS解决方案的定义是多租户的。然而,仅靠多租户不足以使解决方案成为SaaS解决方案。可靠性和安全性是基础设施的两大支柱,因为这两个支柱中的问题可能会导致产品发布时的声誉失败,从而导致启动服务和产品失败。
SaaS解决方案有四个主要的基础设施要求。
- 多租户实现
- SaaS用户的身份解决方案
- 租户上线的自动化
- 每个租户的指标和分析,以推动计费和计量
1. 计算多租户
容器非常适合SaaS基础设施,因为它们可以根据系统负载快速、细致地扩展,提高基础设施层的成本效益。 租户模型涵盖了从为每个租户提供专用集群到为所有租户使用共享集群的广泛选择。在实际部署模型中,通常采用这两种模型的组合,将一些基础设施完全共享,而将其他基础设施专用用于具有特殊要求的租户和服务。 在本文中,我们将重点讨论“集群多租户”模型,其中为一批客户将工作负载的多个实例部署到同一个计算集群中。集群多租户是管理许多单租户集群的替代方案。在某些情况下,对于“高级”客户,可能会将某些服务部署到专用集群以确保服务可用性,而“免费增值”服务则部署到共享集群。 在共享基础设施上运行多个租户意味着每个SaaS提供商都可以通过池化资源带来的规模经济效益来提高效率。然而,这需要隔离每个单独租户的资源并保护它们免受邻居(例如,未经授权的访问、数据泄露或DoS攻击)的侵害,这些攻击可能来自同一共享基础设施内的邻居租户。共享同一基础设施还引发了“吵闹邻居”问题,导致“公平性”问题,其中一个租户以牺牲其他租户为代价垄断资源。在这些情况下,“敌对多租户”需要“硬租户隔离”,我们将在下面进一步探讨,不假设租户之间有任何信任水平。租户隔离需要实现AKS / k8s控制平面和数据平面的某些功能,我们将在配置部分深入探讨。博客附带了AKS上多租户的示例实现,包括控制平面和数据平面隔离功能。
2. 自动化租户上线
租户应该通过简单、可重复的过程上线,其中自定义项被参数化并自动化。(例如,为每个租户自动创建命名空间并将服务部署到新命名空间。Azure函数非常适合自动化上线,其中Azure函数在租户注册后捕获租户上下文并启动IaC模板运行,每个租户使用Github Actions。 以下是完整性的要求,Azure实现将在单独的博客文章中介绍。
3. 设置SaaS的身份解决方案
设置身份解决方案对于多租户架构的成功至关重要。上线的客户通常希望使用单点登录(SSO)体验通过其Active Directory部署的集成登录到SaaS服务。Azure Active Directory B2C 是这里的关键解决方案,它允许SaaS用户使用他们首选的社交、企业或本地帐户身份获得对SaaS应用程序或API的单点登录访问。
4. 计费和 Analytics
需要将挂钩嵌入到SaaS基础设施组件中,以便正确计量和定价每个客户的计算资源消耗。 一种方法是将租户上下文注入基础设施日志和监控中。计费应用程序可以将这些日志视为“客户详细记录”(CDR),处理每个租户的成本并生成详细的租户账单。
其他方法包括消费估算而不是消费计算。这些模型不太准确但更容易实现。SaaS提供商可以利用以下一些方法:
- 使用每个租户的交易指标(例如,租户接收的API调用次数)或每个租户的SaaS用户数量。
- 使用指示性消费指标(例如,为每个租户累积的数据)。
- 利用“Azure成本分析”使用Azure资源标签(例如,AKS节点池标签)。
对于专门为单个租户提供的基础设施组件,可以使用Azure资源标签。例如,对于专用集群,租户上下文可以以AKS节点池标签的形式注入,因为本文重点介绍了AKS的SaaS实现细节。 我们现在将进一步深入探讨租户隔离,包括原生Kubernetes构造和独特的AKS和Azure功能……
k8s / AKS多租户隔离
多租户需要租户隔离。
租户隔离需要…… a - 控制平面隔离 b - 数据平面隔离
现在让我们覆盖K8s & AKS功能和构造,用于多租户控制平面和数据平面隔离要求……
AKS控制平面隔离
k8s命名空间: 命名空间提供了一种机制,用于在单个AKS集群中隔离一组API资源。它们可以用作逻辑容器,以存储和分隔每个租户的资源在共享集群上。
资源配额: 可以用来限制租户在命名空间内创建的API资源(例如,Pod的数量)。这有助于缓解集群内的“吵闹邻居”问题。
服务网格: 服务网格是促进服务之间或微服务之间通信的一层,使用代理。有各种服务网格实现,如Open Service Mesh、Istio、Linkerd。服务网格可以通过以下功能改善SaaS基础设施:
- 提供对容器通信的可观察性
- 提供安全的连接
- 通过路由规则、断路器、故障注入、重试和回退失败的请求进行流量管理。
以下是进一步的重要控制平面功能,将帮助构建SaaS基础设施,解决特定的SaaS基础设施要求……
KEDA - 快速自动扩展是SaaS基础设施的重要要求。这对于b2c SaaS产品尤其重要,因为平台用户会同步响应某些事件,例如,加密交换基础设施需要非常快速地根据加密资产移动进行扩展,或者在线市场在特定时间向其用户宣布折扣。AKS对KEDA的支持使k8s能够根据外部和增强的内部指标进行扩展,这些指标可以作为扩展事件的领先指标,加快Pod的自动扩展,帮助k8s HPA(水平Pod自动扩展器) 。KEDA文档 。基于事件的扩展比等待工作负载增加、资源消耗激增然后开始扩展要有效得多 - 正确的应用程序扩展可以大大减少节点扩展带来的陷阱。避免扩展时间的最佳方法是使用KEDA提前扩展…… 目前,KEDA不支持按租户(命名空间)自动扩展,并且在超出指标时扩展所有命名空间中的所有Pod。
AKS数据平面隔离
网络策略: 可以使用网络策略来控制Pod到Pod的通信,这些策略限制基于命名空间标签或IP地址范围的Pod到Pod通信。
QoS: 可以使用K8s带宽插件、Pod优先级和抢占,为不同的SLA(例如,高级与免费增值)分配不同的服务级别。例如,属于付费客户的更高优先级Pod将驱逐属于免费客户的Pod,当集群资源不足以部署额外的付费客户Pod时。
Kata Containers: 容器是运行在共享内核上的进程;它们从底层主机挂载诸如/sys和/proc之类的文件系统,这使得它们不如运行在虚拟机上的应用程序安全,后者具有自己的内核。Kata Containers是轻量级VM(具有专用内核和嵌套虚拟化),与k8s(例如,用于自动扩展或滚动更新)无缝集成。Kata Containers的设计目标是拥有专用内核而不会因运行在VM上而速度降低。Kata Containers使用硬件虚拟化技术作为第二层防御,提供更强的工作负载隔离,并使AKS上的“机密计算”用例成为可能。尽管Kata Containers提供了对高度监管行业工作负载的隔离要求更为严格的重量级方法,但它们可能在敌对多租户用例中不可或缺。
Defender - Microsoft Defender for Containers 通过数据平面强化、漏洞评估和持续监控功能,帮助您安全地运行容器。
Azure上的SaaS参考架构
 这是在Azure AKS上部署多租户SaaS基础设施的提议架构,使用Github Actions自动化。Azure函数在注册后获取租户上下文,并使用GitHub的REST API触发GitHub Actions工作流程。该REST API调用可以使用Azure函数的HTTP触发器,然后运行GitHub Action作业,将租户特定的配置推送到AKS并启动应用程序Pod。 值得注意的是,API管理级别的限流和流量整形可以用来保护AKS后端。API密钥可以绑定到API网关上的使用计划,以便在网关级别对用户进行限流,以免在计算基础设施中引起吵闹邻居问题。
使用Azure AKS和Github Actions部署云原生SaaS应用程序
我们首先启动AKS集群并应用集群“全局”配置。一旦集群启动并运行,我们将推送“每个租户配置”到集群,这将在下面定义。 为了存储容器镜像,我们需要创建一个ACR - 容器注册表。对于SaaS,所有租户都需要运行软件的相同版本,因此我们不会期望存储库中有多个版本。按照标准DevOps部署,开发人员使用ACR跟踪代码,并使用CI/CD将镜像部署到AKS。
配置摘要
AKS SaaS集群配置
以下是AKS集群所需配置。
启用CNI以进行高级网络(AKS策略需要CNI插件。)
启用网络策略
Azure策略/启用 - 网络策略功能只能在创建集群时启用。重要的是不要跳过启用网络策略。
启用秘密存储CSI驱动程序(将为每个租户启用)
az aks get-credentials --resource-group aksbookrg01 --name aks-saas-cluster
启用Defender for Containers 以保护集群 Defender for Containers 通过以下三个核心方面的安全性协助基础设施:
环境强化 - 每个对k8s API服务器的请求都将被监控,以符合预定义的最佳实践。
漏洞评估 - 扫描ACR中的镜像以查找漏洞。
运行时威胁防护,针对节点和集群 - 检测集群节点中的可疑活动。
启用KEDA - 您可以通过运行以下Azure CLI命令来启用KEDA:
az extension add --name aks-preview az feature register --namespace "Microsoft.ContainerService" --name "AKS-KedaPreview" az feature show --namespace "Microsoft.ContainerService" --name "AKS-KedaPreview" az provider register --namespace Microsoft.ContainerService
通过Azure资源管理器模板和指定workloadAutoScalerProfile字段:
"workloadAutoScalerProfile": { "keda": { "enabled": true } }
每个租户的AKS配置
- 每个租户的独立命名空间 当您在单个AKS集群上托管多个租户应用程序,并且每个应用程序都在单独的命名空间中时,每个工作负载都应该使用不同的Kubernetes服务帐户和凭据来访问下游Azure服务链接 。服务帐户凭据存储为k8s机密。
- 为每个租户实施k8s资源配额
您需要实施资源配额
,在命名空间级别设置配额。您需要监控资源使用情况并根据需要调整每个租户(读取为命名空间)的配额。
资源配额可以用于设置以下内容的配额:
- 计算资源 - 例如CPU和内存或GPU
- 存储资源 - 总卷数或磁盘空间量。
- 对象计数 - 最大数量的机密、服务或作业 例如,下面的.yaml为命名空间设置资源配额,为6个vCPU和20 GB内存以及最大Pod计数为3:
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-app-team
spec:
hard:
cpu: "6"
memory: 20Gi
pods: "3"
配置资源配额时,需要确保Pod清单文件中也添加了资源配置。否则,Pod将不会被添加到集群中。
- 为每个租户实施网络策略
使用网络策略定义一组按顺序的规则,以发送和接收流量,并将其应用于符合一个或多个标签选择器或仅限于同一命名空间内的Pod的集合。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-policy
namespace: demo
spec:
podSelector:
matchLabels:
app: server
ingress:
- from:
- podSelector:
matchLabels:
app: client
ports:
- port: 80
protocol: TCP
部署到AKS的示例SaaS应用程序
对于配置自动化,我们将使用GitHub Actions…… 一旦集群启动并运行,租户可以通过门户的注册过程上线到集群。 租户特定的配置将通过GitHub Actions自动化,这将通过Azure函数触发。
为了使GitHub Actions能够推送租户特定的配置,我们需要通过Azure AD连接GitHub Actions到Azure,以便GitHub Actions可以访问部署所需的服务(例如,Azure AKS)。
这需要:
- 配置一个服务主体,GitHub Actions将使用并定义其范围
- 将主体凭据添加到GitHub Actions作为机密
- 添加一个“登录”工作流程步骤,以将GitHub Actions登录到Azure。
- 添加工作流程步骤,以便您可以使用kubectl与GitHub Actions一起使用,如此处 所述。
配置了正确的访问权限后,GitHub Actions将首先创建集群并推送需要集群级别范围配置的配置。 
一旦集群启动并运行,另一个GitHub Actions工作流程可以手动触发或集成到Azure函数中,并将租户特定的配置推送到AKS集群。配置将:
- 使用kubectl嵌入到GitHub Actions作业中创建AKS命名空间。
- 为命名空间配置资源配额。
- 为租户Pod实施每个租户的网络策略
- 为每个租户创建秘密存储
- 为每个租户获取ACR凭据
- 最后,为租户部署应用程序实例Pod。
最后完整示例代码请查看本文资源链接。