AI工作流多租户架构设计:从资源隔离到共享的实战指南

引言:AI平台的「租户之痛」,你遇到过吗?

想象这样的场景:
你是某企业AI平台的开发负责人,最近接到两个团队的投诉——

  • 算法团队A说:「我们的训练数据是敏感的用户行为日志,不能和其他团队的数
    据混在一起!」
  • 运营团队B说:「昨天我们的推理服务突然卡爆了,查了半天发现是算法团队C在跑一个超大的预训练任务,占了80%的GPU资源!」
  • 成本部门补充:「现在每个团队都要独立的GPU集群,成本快扛不住了,能不能让资源共享起来?」

这就是AI平台在规模化后必然遇到的「多租户困境」:如何在保障租户数据安全、资源独占的同时,最大化资源利用率?

如果你也在为这些问题头疼,那么本文正是为你写的。

本文要做什么?

本文将从「AI工作流的多租户需求」出发,拆解资源隔离资源共享的核心设计方案,并通过一个可落地的「多租户AI训练工作流」实战案例,帮你掌握从0到1搭建多租户AI平台的方法论。

读完你能收获什么?

  • 明确AI工作流中「多租户」的核心需求(数据、计算、模型、配置);
  • 掌握3类资源隔离方案(数据、计算、模型)的选择逻辑与实现细节;
  • 学会用4种共享策略(弹性调度、多租户网关、缓存共享、成本分摊)提升资源利用率;
  • 能动手搭建一个支持「隔离+共享」的多租户AI训练工作流。

准备工作:你需要这些基础

在开始之前,确保你具备以下知识或环境:

1. 技术栈/知识要求

  • 后端开发基础(熟悉至少一种后端语言,如Python/Java/Golang);
  • 了解AI工作流的核心环节(数据预处理→模型训练→推理部署→监控);
  • 云原生基础(懂Docker容器化、Kubernetes资源调度的基本概念);
  • 可选:数据库多租户经验(逻辑隔离vs物理隔离的区别)。

2. 环境/工具准备

  • 一个可用的Kubernetes(K8s)集群(用于计算资源调度,本地可⽤Minikube或Kind搭建);
  • Docker(用于打包AI任务的运行环境);
  • 对象存储服务(如MinIO,用于数据隔离存储);
  • AI实验跟踪工具(如MLflow,用于模型隔离管理);
  • 监控工具(如Prometheus+Grafana,用于多租户资源监控)。

第一章:先搞懂AI工作流的「多租户需求」

在设计架构前,我们需要先明确:AI工作流中的「租户」到底需要什么?

AI工作流的典型环节是「数据→训练→模型→推理」,对应的多租户需求可以拆解为4类:

需求类型 具体要求 示例场景
数据隔离 租户的数据(原始数据、中间结果)不能被其他租户访问或篡改 金融租户的用户交易数据、医疗租户的病例数据
计算隔离 租户的计算任务(训练/推理)不能抢占其他租户的资源(CPU/GPU/内存) 算法团队的预训练任务不能占满所有GPU,导致运营团队的推理服务超时
模型隔离 租户的模型(训练好的模型、模型版本)只能被自己访问,且版本不混淆 电商租户的推荐模型v2不能被教育租户调用
配置隔离 租户的个性化配置(如训练超参数、推理服务QPS限制)不影响其他租户 游戏租户的推理服务需要「低延迟优先」,而广告租户需要「高吞吐量优先」

关键结论:多租户架构的设计,本质是针对上述4类需求,选择「隔离强度」与「资源效率」的平衡点——

  • 强隔离(如物理集群):安全但成本高;
  • 弱隔离(如逻辑命名空间):成本低但需要更细的权限控制;
  • 共享策略:在隔离基础上,通过资源复用提升效率。

第二章:资源隔离——守住租户的「安全底线」

隔离是多租户的「基础保障」,我们需要为数据、计算、模型三类核心资源设计隔离方案。

一、数据隔离:逻辑vs物理,怎么选?

数据是AI工作流的「原材料」,也是最敏感的资源。数据隔离的核心是让租户只能访问自己的数据,常见方案有两种:

1. 逻辑隔离(共享存储集群,租户级权限控制)

方案说明:多个租户共享同一个对象存储集群(如MinIO、S3),每个租户对应一个独立的「存储桶(Bucket)」,通过**权限策略(Policy)**限制租户只能访问自己的Bucket。

实现示例(MinIO)

  • 为租户A创建Bucket:tenant-a-data
  • 为租户A创建访问密钥(Access Key/Secret Key);
  • 配置Policy,仅允许租户A访问自己的Bucket:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:*"],  // 允许所有S3操作(可根据需求缩小范围,如仅允许上传/下载)
      "Resource": [
        "arn:aws:s3:::tenant-a-data",
        "arn:aws:s3:::tenant-a-data/*"
      ]
    }
  ]
}

优点:成本低(共享存储集群)、管理简单;
缺点:依赖存储服务的权限控制能力,若存储集群被攻破,所有租户数据都有风险;
适用场景:非核心业务租户、对成本敏感的中小团队。

2. 物理隔离(独立存储集群)

方案说明:为每个租户部署独立的存储集群(如专属MinIO实例、专属云存储桶),租户的数据完全物理隔离。

实现示例

  • 为金融租户部署独立的MinIO集群(用K8s的Namespace隔离,或独立的云服务器);
  • 租户的所有数据都存储在自己的MinIO集群中,与其他租户无交集。

优点:隔离性最强,完全避免跨租户数据泄露;
缺点:成本高(每个租户需要独立的存储资源)、管理复杂;
适用场景:核心业务租户(如金融、医疗)、对数据安全要求极高的场景。

选择建议

  • 90%的场景用逻辑隔离(成本与隔离性的平衡);
  • 10%的核心场景用物理隔离(安全优先)。

二、计算隔离:K8s是「终极工具」

计算资源(CPU/GPU/内存)是AI工作流的「动力源」,隔离的核心是让租户的计算任务不影响其他租户的资源使用

Kubernetes(K8s)是目前最成熟的计算资源隔离工具,其核心能力是Namespace(命名空间)+ ResourceQuota(资源配额)+ LimitRange(资源限制)

1. 步骤1:用Namespace做逻辑隔离

每个租户对应一个独立的K8s Namespace,租户的所有计算任务(如训练Pod、推理Deployment)都部署在自己的Namespace中。

实现示例(创建租户A的Namespace)

# tenant-a-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: tenant-a  # 租户A的命名空间
  labels:
    tenant-id: tenant-a  # 标记租户ID,方便后续管理

执行命令创建:

kubectl apply -f tenant-a-namespace.yaml
2. 步骤2:用ResourceQuota限制资源总量

为每个Namespace设置资源配额,限制租户能使用的最大CPU/GPU/内存。

实现示例(租户A的资源配额)

# tenant-a-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-a-quota
  namespace: tenant-a  # 绑定到租户A的Namespace
spec:
  hard:
    requests.cpu: "8"         # 租户A最多可请求8核CPU
    requests.memory: 16Gi     # 最多可请求16GB内存
    requests.nvidia.com/gpu: 2  # 最多可请求2块GPU(需K8s集群支持GPU调度)
    limits.cpu: "16"          # 租户A的Pod最多可使用16核CPU
    limits.memory: 32Gi       # 最多可使用32GB内存
    limits.nvidia.com/gpu: 2  # 最多可使用2块GPU

执行命令创建:

kubectl apply -f tenant-a-quota.yaml
3. 步骤3:用LimitRange限制单个Pod的资源

为每个Namespace设置LimitRange,限制单个Pod的资源使用(避免单个Pod占满整个租户的配额)。

实现示例(租户A的LimitRange)

# tenant-a-limitrange.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: tenant-a-limitrange
  namespace: tenant-a
spec:
  limits:
  - default:  # 默认的资源限制(Pod未指定时使用)
      cpu: "4"
      memory: 8Gi
      nvidia.com/gpu: 1
    defaultRequest:  # 默认的资源请求
      cpu: "2"
      memory: 4Gi
      nvidia.com/gpu: 1
    type: Container

效果验证
当租户A提交一个训练Pod时,若Pod的资源请求超过Quota或LimitRange的限制,K8s会直接拒绝调度:

# 尝试创建一个请求3块GPU的Pod(超过Quota的2块)
kubectl run -n tenant-a gpu-test --image=nvidia/cuda:11.0 --command -- sleep 3600 --limits=nvidia.com/gpu=3

# 输出错误:
Error from server (Forbidden): pods "gpu-test" is forbidden: exceeded quota: tenant-a-quota, requested: nvidia.com/gpu=3, used: 0, limited: 2

关键结论
K8s的「Namespace+Quota+LimitRange」是AI工作流计算隔离的标准方案,能完美解决「资源抢占」问题。

三、模型隔离:从实验跟踪到服务部署的全链路隔离

模型是AI工作流的「成果」,隔离的核心是让租户只能访问自己的模型,且模型版本不混淆

我们可以用**AI实验跟踪工具(如MLflow)模型服务网关(如Kong)**实现全链路隔离。

1. 步骤1:实验跟踪的租户隔离(MLflow)

MLflow是常用的AI实验跟踪工具,支持按租户划分Experiment(实验),每个租户的训练实验都存储在自己的Experiment下。

实现示例(Python训练脚本)

import os
import mlflow
import mlflow.pytorch
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier

# 1. 从环境变量获取租户ID(部署时注入)
tenant_id = os.getenv("TENANT_ID", "default")

# 2. 设置MLflow的Experiment(租户级)
mlflow.set_tracking_uri("http://mlflow-server:5000")  # MLflow服务地址
mlflow.set_experiment(f"/{tenant_id}/iris-classification")  # 租户专属Experiment

# 3. 加载数据(从租户的MinIO Bucket获取,此处简化为本地数据)
iris = load_iris()
X, y = iris.data, iris.target

# 4. 训练模型并跟踪实验
with mlflow.start_run(run_name=f"{tenant_id}_run_1"):
    # 记录超参数
    mlflow.log_param("n_estimators", 100)
    mlflow.log_param("max_depth", 5)
    
    # 训练模型
    clf = RandomForestClassifier(n_estimators=100, max_depth=5)
    clf.fit(X, y)
    
    # 记录指标(准确率)
    accuracy = clf.score(X, y)
    mlflow.log_metric("accuracy", accuracy)
    
    # 保存模型到租户的Experiment
    mlflow.pytorch.log_model(clf, "model")

效果

  • 租户A的实验会出现在/tenant-a/iris-classification下;
  • 租户B的实验会出现在/tenant-b/iris-classification下;
  • 租户之间无法查看或修改对方的实验。
2. 步骤2:模型服务的租户隔离(Kong网关)

当模型训练完成后,需要部署成推理服务供业务调用。此时可以用**API网关(如Kong)**实现租户隔离:

  • 每个租户的模型服务对应一个独立的路由(Route),如/tenant-a/model1
  • 网关通过API密钥(API Key)OAuth2验证租户身份,仅允许合法租户访问自己的路由;
  • 网关将请求转发到租户的模型服务(部署在K8s的租户Namespace中)。

实现示例(Kong路由配置)

# 1. 为租户A创建Service(指向租户A的模型Deployment)
kong service create --name tenant-a-model1 --url http://tenant-a-model1.tenant-a.svc.cluster.local:8080

# 2. 为租户A创建Route(路径前缀为/tenant-a/model1)
kong route create --name tenant-a-model1-route --service tenant-a-model1 --paths /tenant-a/model1

# 3. 为租户A创建API Key(用于身份验证)
kong consumer create --username tenant-a
kong key-auth add --consumer tenant-a --key tenant-a-secret-key

调用示例
租户A调用自己的模型服务时,需要在请求头中携带API Key:

curl -H "apikey: tenant-a-secret-key" http://kong-gateway:8000/tenant-a/model1/predict -d '{"features": [5.1, 3.5, 1.4, 0.2]}'

效果

  • 若租户B用自己的API Key调用/tenant-a/model1,网关会返回403错误;
  • 若未携带API Key,网关会返回401错误。

第三章:资源共享——提升平台的「效率上限」

隔离解决了「安全问题」,但会导致资源利用率低下(比如租户A的GPU在夜间空闲,而租户B的GPU不够用)。此时需要共享策略,在隔离的基础上提升资源利用率。

一、策略1:弹性计算资源共享(K8s Cluster Autoscaler)

问题:固定资源配额会导致「忙时资源不够,闲时资源闲置」。
方案:用K8s的Cluster Autoscaler(集群自动扩缩容),根据租户的资源需求自动添加或删除节点。

实现原理

  1. 当租户的计算任务请求的资源超过当前集群的可用资源时,Cluster Autoscaler会自动向云服务商(如AWS、阿里云)申请新的节点;
  2. 当节点空闲超过一定时间(如10分钟),Cluster Autoscaler会自动删除节点,释放资源。

配置示例(Cluster Autoscaler)

# cluster-autoscaler.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: cluster-autoscaler
        image: k8s.gcr.io/cluster-autoscaler:v1.26.0
        command:
        - ./cluster-autoscaler
        - --cloud-provider=aws  # 根据你的云服务商调整(如aliyun、gcp)
        - --nodes=1:10:my-node-group  # 节点组的最小/最大节点数(1到10)
        - --scale-down-delay-after-add=10m  # 新增节点后10分钟再考虑缩容
        - --scale-down-unneeded-time=10m  # 节点空闲10分钟后缩容

效果

  • 租户A在白天跑训练任务时,集群自动扩容到10个节点;
  • 夜间租户A的任务结束后,集群自动缩容到1个节点;
  • 所有租户共享弹性扩容的资源,降低整体成本。

二、策略2:共享模型服务的「无服务器」架构(Knative Serving)

问题:传统模型服务部署后,即使没有请求也会占用资源(如一个推理Pod始终运行)。
方案:用Knative Serving实现「无服务器(Serverless)」的模型服务,按需扩容(从0到N)。

实现原理

  1. 每个租户的模型服务部署为Knative Service;
  2. 当没有请求时,Knative会将Pod缩容到0(不占用资源);
  3. 当有请求时,Knative会自动创建Pod处理请求(根据并发数动态扩容)。

实现示例(租户A的Knative Service)

# tenant-a-model1-knative.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: tenant-a-model1
  namespace: tenant-a  # 绑定到租户A的Namespace
spec:
  template:
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/tenant-a/model1:v1  # 租户A的模型镜像
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "1"
            memory: "2Gi"
          limits:
            cpu: "2"
            memory: "4Gi"
  traffic:
  - latestRevision: true
    percent: 100  # 100%的流量指向最新版本

效果

  • 租户A的模型服务在没有请求时,Pod数为0,不占用资源;
  • 当有10个并发请求时,Knative会自动创建2个Pod(每个Pod处理5个请求);
  • 多个租户的Serverless服务共享K8s集群的资源,资源利用率提升50%以上。

三、策略3:共享数据缓存(租户级权限控制)

问题:多个租户可能需要访问同一份公共数据(如ImageNet数据集),重复存储会浪费空间。
方案:用共享缓存服务(如Redis、MinIO)存储公共数据,通过租户级权限控制允许租户访问。

实现示例(MinIO共享Bucket)

  1. 创建一个公共Bucket:public-datasets,存储ImageNet数据集;
  2. 配置Policy,允许所有租户读取该Bucket(但不能修改):
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],  // 仅允许读取
      "Resource": [
        "arn:aws:s3:::public-datasets",
        "arn:aws:s3:::public-datasets/*"
      ]
    }
  ]
}
  1. 租户的训练脚本可以直接从public-datasets读取数据,无需自己存储。

效果

  • 公共数据仅存储一份,节省90%的存储空间;
  • 租户无需维护公共数据,提升开发效率。

四、策略4:成本分摊(按资源使用量收费)

问题:共享资源会导致「租户用得多但不付费」的问题,无法激励租户优化资源使用。
方案按资源使用量分摊成本,让租户为自己使用的CPU/GPU/存储付费。

实现步骤

  1. Prometheus收集每个租户的资源使用数据(如CPU使用时长、GPU使用时长、存储容量);
  2. Grafana展示租户的资源使用Dashboard;
  3. 成本核算工具(如Cloudability、kubecost)将资源使用量转换为成本(如每核CPU每小时0.5元,每GB存储每月0.1元);
  4. 每月向租户发送成本账单。

示例Dashboard(Grafana)

  • 租户A的CPU使用:100核·小时;
  • 租户A的GPU使用:20卡·小时;
  • 租户A的存储使用:100GB·月;
  • 总费用:100×0.5 + 20×5 + 100×0.1 = 50 + 100 + 10 = 160元。

效果

  • 租户会主动优化资源使用(如缩短训练时间、删除无用数据);
  • 平台的成本压力得到缓解。

第四章:实战:搭建多租户AI训练工作流

现在,我们将前面的方案整合起来,搭建一个支持多租户的AI训练工作流

一、目标:实现什么?

  • 租户可以提交训练任务,数据存储在自己的MinIO Bucket;
  • 训练任务运行在自己的K8s Namespace,资源受Quota限制;
  • 训练实验跟踪在自己的MLflow Experiment;
  • 资源使用情况可监控,成本可分摊。

二、步骤:从0到1搭建

1. 环境准备
  • 搭建K8s集群(用Minikube,命令:minikube start --cpus=4 --memory=8g --driver=docker);
  • 部署MinIO(用Helm,命令:helm install minio bitnami/minio --set accessKey=minioadmin --set secretKey=minioadmin);
  • 部署MLflow(用Docker Compose,参考MLflow官方文档);
  • 部署Prometheus+Grafana(用Helm,命令:helm install prometheus prometheus-community/prometheushelm install grafana grafana/grafana)。
2. 租户初始化(以租户A为例)

为租户A创建以下资源:

  • K8s Namespace:tenant-a
  • K8s ResourceQuota:限制CPU=8核,GPU=2块(若集群有GPU);
  • MinIO Bucket:tenant-a-data
  • MLflow Experiment:/tenant-a/iris-classification
  • Kong Route:/tenant-a/model1(后续部署模型服务用)。
3. 提交训练任务(Python脚本)

编写训练脚本train.py(参考第二章第三节的示例),并打包成Docker镜像:

# Dockerfile
FROM python:3.9-slim

# 安装依赖
RUN pip install mlflow scikit-learn torch

# 复制训练脚本
COPY train.py /app/train.py

# 设置工作目录
WORKDIR /app

# 运行训练脚本(注入租户ID)
CMD ["python", "train.py"]

构建镜像:

docker build -t tenant-a-train:v1 .

将镜像推送到K8s集群可访问的镜像仓库(如Docker Hub):

docker push your-dockerhub-username/tenant-a-train:v1
4. 部署训练任务到K8s

创建K8s Job配置文件tenant-a-train-job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: tenant-a-train-job
  namespace: tenant-a  # 绑定到租户A的Namespace
spec:
  template:
    spec:
      containers:
      - name: tenant-a-train
        image: your-dockerhub-username/tenant-a-train:v1  # 你的镜像地址
        env:
        - name: TENANT_ID
          value: "tenant-a"  # 注入租户ID
        - name: MLFLOW_TRACKING_URI
          value: "http://mlflow-server:5000"  # MLflow服务地址
        - name: MINIO_ACCESS_KEY
          value: "tenant-a-access-key"  # 租户A的MinIO Access Key
        - name: MINIO_SECRET_KEY
          value: "tenant-a-secret-key"  # 租户A的MinIO Secret Key
        resources:
          requests:
            cpu: "2"
            memory: "4Gi"
          limits:
            cpu: "4"
            memory: "8Gi"
      restartPolicy: Never  # 任务失败后不重启

执行命令部署:

kubectl apply -f tenant-a-train-job.yaml
5. 监控训练任务
  • 查看Job状态:kubectl get jobs -n tenant-a
  • 查看Pod日志:kubectl logs -n tenant-a $(kubectl get pods -n tenant-a -l job-name=tenant-a-train-job -o jsonpath='{.items[0].metadata.name}')
  • 在MLflow UI中查看实验结果:访问http://mlflow-server:5000,进入/tenant-a/iris-classification实验。
6. 成本核算

用kubecost查看租户A的资源使用成本:

  • 访问kubecost UI(默认地址:http://kubecost:9090);
  • 选择「Tenant」维度,查看租户A的CPU、GPU、存储使用量及成本。

第五章:进阶探讨:更复杂的多租户场景

一、混合隔离策略:强隔离与弱隔离结合

对于核心租户(如金融),使用物理隔离(独立K8s集群、独立MinIO);对于普通租户,使用逻辑隔离(共享K8s集群、Namespace隔离)。

实现示例

  • 核心租户用独立的K8s集群:core-tenant-cluster
  • 普通租户用共享的K8s集群:shared-tenant-cluster
  • 用**集群联邦(Kubernetes Federation)**统一管理多个集群。

二、Serverless AI工作流的多租户

Knative Eventing实现Serverless的AI工作流:

  • 租户提交训练任务(事件);
  • Knative Eventing将事件路由到对应的处理函数(如数据预处理函数、训练函数、模型部署函数);
  • 每个函数都是Serverless的,按需扩容。

三、多租户下的模型版本管理

Model Registry(如MLflow Model Registry)实现租户级的模型版本管理:

  • 每个租户的模型版本存储在自己的Registry中;
  • 租户可以将模型版本标记为「 staging(测试)」或「 production(生产)」;
  • 模型部署时,自动选择「 production」版本。

第六章:总结:多租户架构的「平衡之道」

AI工作流的多租户架构设计,本质是平衡「隔离」与「共享」

  • 隔离是「底线」:通过数据、计算、模型的隔离,保障租户的安全与权益;
  • 共享是「上限」:通过弹性调度、Serverless、缓存共享,提升资源利用率与平台效率。

你已经学会了什么?

  1. 拆解AI工作流的多租户需求(数据、计算、模型、配置);
  2. 选择数据隔离方案(逻辑vs物理);
  3. 用K8s实现计算资源隔离(Namespace+Quota+LimitRange);
  4. 用MLflow和Kong实现模型隔离;
  5. 用弹性调度、Serverless、缓存共享提升资源利用率;
  6. 搭建一个可落地的多租户AI训练工作流。

下一步:如何深化?

  • 尝试将推理服务也纳入多租户管理(用Knative Serving+Kong);
  • 实现多租户的模型监控(用Prometheus+Grafana监控推理服务的QPS、延迟);
  • 探索多租户的联邦学习(Federated Learning),让租户在不共享数据的情况下共同训练模型。

行动号召:一起讨论多租户设计

如果你在实践中遇到以下问题:

  • 如何选择数据隔离的方案?
  • K8s的资源配额设置不合理导致租户投诉?
  • Serverless模型服务的冷启动问题怎么解决?

欢迎在评论区留言讨论!

如果你有更好的多租户设计方案,也欢迎分享——让我们一起打造更高效、更安全的AI平台!

最后想说:多租户架构不是「银弹」,没有「通用方案」。最重要的是理解租户的需求,选择最适合的设计策略。

祝你早日实现AI平台的「多租户自由」! 🚀

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐