跳到主要内容

Serverless架构部署ComfyUI

简介

在低频请求场景下,Serverless架构能够有效帮助用户降低GPU资源的使用成本。例如,在图形创作应用中,如果创作程序每分钟仅运行一次,每次运行60毫秒,GPU的空闲率将高达99.9%。而在Serverless架构中用户可以仅购买满足服务运行的资源。

此外,在流量突发的情况下,Serverless 架构能显著提升应对资源需求激增的能力。用户可以利用其弹性扩展特性,快速增加计算资源以满足高峰时段的需求。当业务高峰期过后,多余的资源会自动释放,从而大幅节省成本。

Janus-Pro 是一款统一理解与生成的多模态大语言模型 (MLLM),在多模态理解和生成任务中实现了视觉编码的解耦,其架构基于DeepSeek-LLM-7b-base。在图像生成方面,模型采用来自特定来源的tokenizer,并支持16倍下采样率处理,提升了生成效率和质量。

ComfyUI 是一个基于节点的图形用户界面(GUI),专为创建和管理图像生成的工作流而设计。它广泛应用于艺术创作、设计等领域,帮助用户高效实现创意构想。用户还可以通过 API 接口灵活地管理工作流逻辑,从而实现自动化和集成需求。 更多关于API的详细说明,请参阅ComfyUI附录。附录中包含的API包括:

前置条件

用户已经获取Alaya New企业账户和密码,如果需要帮助或尚未注册,可参考注册账户完成注册。

信息

本文的演示步骤基于Windows 11操作系统。不同操作系统的界面可能有所差异,用户实际操作时请以当前系统界面的显示为准。

准备工作

配置环境变量

本次部署会用到 helmKubernetes,请先确保本地有可用的Kubernestes客户端工具kubectl,配置环境变量的操作步骤如下所示。

  1. 下载最新版本的kubectl,本示例下载“windows-amd64-v1.27.3-kubectl.exe”文件,在本地新建“kubectl”文件夹,将下载的.exe文件名称修改为“kubectl”并移动到新建的文件夹下。

  2. 下载最新版本的helm,本示例下载“helm-v3.17.1-windows-amd64.zip”文件,在本地解压该文件,将文件名修改为“helm”。

  3. 右键点击[此电脑/属性]菜单项,进入[系统/系统信息]配置页面,点击“高级系统设置”链接,弹出[系统属性]页面,单击“环境变量”按钮,进入环境变量配置页面。

  4. 在“系统变量”处双击 Path变量新建环境变量,新建如下图所示的环境。新建完成后,单击[确定]按钮,配置环境变量操作完成。

    1739413048753

提示
  • 在实际的使用中,用户需要将上图中高亮部分替换为“kubectl.exe”、“helm.exe”文件所在的本地路径。
  • Linux系统配置环境变量:将helm文件移动到目录“ /usr/local/bin”。

配置弹性容器集群

部署前需要准备足够的资源,用户需要保证资源至少满足下表中的配置要求。

配置项配置需求
GPUH800 * 1
CPU19核

开通弹性容器集群可参看开通弹性容器集群操作步骤章节所述。集群开通完成后可在使用弹性容器集群处查看弹性容器集群的使用方式。

本次示例配置弹性容器集群的操作步骤如下所示。

  1. 使用已注册的企业账号登录Alaya NeW系统,选择[产品/弹性容器集群]菜单项,单击“新建集群”按钮,进入[弹性容器集群]配置页面,配置基本信息,例如:集群名称,集群描述,智算中心,此次使用的集群配置如下所示。

    配置项配置详情
    集群名称serverless
    智算中心北京一区
    算力配置1、型号:H800
    2、配额:1卡GPU
    存储配置1、选择大容量存储
    2、开启StorageClass开关
    对外服务开启对外服务开关
提示

在该示例中,创建弹性集群页面上存在但表格中未列出的参数,均采用默认配置。

  1. 弹性容器集群参数配置完成后,单击“立即开通”按钮,资源开通操作完成,用户可在[资源中心/弹性容器集群]页面查看已创建的容器集群,弹性容器集群状态为“运行中”表示集群可正常使用,如下图蓝色高亮处所示。

    1739431477628

  2. 集群可正常使用后,点击“kubuconfig下载”链接,如上图绿色高亮处所示,将集群的kubeconfig配置文件下载到本机上。

  3. 在本机上找到上步已经下载的文件,本示例中为“serverless-config.json”,使用certutil -decode命令解压该文件,如下图所示。

    1739433767131

certutil -decode serverless-config.json serverless
提示

用户在解压文件的过程中需要注意以下两点:

  • 将上图中“解压前文件名称”替换为本机已下载的kubeconfig文件的名称。
  • 将上图中“解压后文件名称”替换为自己实际所需的文件名称。
  1. 在终端页面,使用$env:KUBECONFIG命令配置访问弹性容器集群的环境变量,然后查看集群连接情况。若显示如下图所示,表示弹性容器集群连接成功。
$env:KUBECONFIG="D:/serverless-comfyui/serverless"
kubectl cluster-info

alt text

重要

下文演示两种部署ComfyUI的方式,用户选择其中一种方式部署即可。

部署ComfyUI应用

Helm Chart部署ComfyUI

  1. 集群连接成功后,下载Serverles ComfyUI的Helm Chart安装包。解压已下载的安装包,双击打开解压后的文件,打开serverless-comfyui文件夹,进一步打开values.yaml文件,文件内容如下:
values.yaml
# 应用名称
appName: serverless-comfyui
vksID: vcacu2dsxxxx

model:
# comfyui的镜像
image: registry.hd-01.alayanew.com:8443/vc-app_market/comfyui:pytorch2.6-cuda124-root-0.0.1
# comfyui的容器挂载目录,目前只支持名称为 pvc-capacity-userdata 的PVC挂载
# 挂载数据尽量提前准备好,不要在容器启动时下载
# name 可随意填写(但必填),默认只挂载PVC: pvc-capacity-userdata
volumeMounts:
- name: userdata-pvc
mountPath: /app/models # 镜像启动的容器内目录
subPath: apps/serverless-comfyui/models # PVC:pvc-capacity-userdata 下的相对目录
# - name: userdata-pvc
# mountPath: /app/output
# subPath: apps/serverless-comfyui/output
# - name: userdata-pvc
# mountPath: /app/input
# subPath: apps/serverless-comfyui/input

# GPU资源,您开通VKS集群的GPU标签,不包含 `nvidia.com/` 部分
resourceProfile: gpu-h100-80gb-hbm3:1
minReplicas: 0 # 最小副本数,设置为0 ,长时间没有调用推理,则停止容器
maxReplicas: 1 # 最大副本数,comfyui 设置为 1

# TargetRequests is average number of active requests that the autoscaler
# will try to maintain on model server Pods.
# +kubebuilder:validation:Minimum=1
# +kubebuilder:default=100
targetRequests: 5


# ScaleDownDelay is the minimum time before a deployment is scaled down after
# the autoscaling algorithm determines that it should be scaled down.
# +kubebuilder:default=30
scaleDownDelaySeconds: 30

以上文件用户可自定义修改,参数说明如下表所示。

配置项参数说明参数示例保持默认值
appName待创建服务的名称serverless-comfyui
vksID已申请弹性容器集群的IDvcacu2dsxxxx×
model.imageComfyUI镜像挂在的镜像,用户可替换为自己的ComfyUI镜像-
model.volumeMounts镜像挂载,用户可替换成自己的挂载目录-
model.resourceProfile已开通集群的GPU标签, 不包含nvidia.com/部分。: 后为GPU数量gpu-h800x
model.minReplicas配置自定义资源。如果要让ComfyUI容器,无调用时,自动缩减成0,这里配置00
model.maxReplicas配置自定义资源。最多启动ComfyUI的容器数量, 这里设置为 11
重要

vksID: 替换成您开通的弹性容器集群的VKSID, 不同操作系统获取VKSID的命令行如下所示。

  kubectl cluster-info | ForEach-Object { ($_ -split '/')[-1] } | Select-Object -First 1
提示
  • model.resourceProfile:指已开通集群的GPU资源标签,该标签显示可能因配置而异,用户以实际资源显示为准。
  • 如果需要通过ComfyUI的网页进行工作流测试,可将model.scaleDownDelaySeconds设置为一个较大的值。否则,自动缩容可能会停止 ComfyUI 容器,导致网页不可用。
  1. 根据实际需求配置完上述参数后,在同一终端页面执行以下命令以创建一个命名空间(Namespace),供后续安装部署使用。
kubectl create ns `your-namespace`
  1. 在上步新建的命名空间内执行如下命令,部署Serverless-ComfyUI。
helm install serverless-comfyui . -n `your-namespace`

alt text

部署输出如下
NAME: service
LAST DEPLOYED: Thu Feb 27 19:07:34 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
应用部署成功

默认启动 0 个 comfyui 的 pod

为了实现当没有接口调用时,自动停止comfyui的推理容器,需要将Values.model.minReplicas设置为0

Values.model.maxReplicas 设置为1

获取容器状态使用如下命令:
kubectl get pods -n default

1. 访问comfyui的接口
为了实现没有接口调用时,自动停止comfyui的推理容器,所有访问comfyui的接口调用,都会经过kubeai代理。
因此,当调用comfyui接口时,使用如下方式:

首先获取kubeai的url, 如下:
https://kubeai-x-default-x-vcacu2dsxxxx.sproxy.hd-01.alayanew.com:22443/openai

其次,拼接comfyui的接口path,如获取comfyui的状态接口:
path: /api/system_stats
则实际的访问url如下:
https://kubeai-x-default-x-vcacu2dsxxxx.sproxy.hd-01.alayanew.com:22443/openai/api/system_stats

然后,任何接口调用请求,都需要请求体body,且body体内必填model参数,参数值是 Values.appName
如本示例body体的结构是如下json:
{
"model": "serverless-comfyui"
}

示例 调用comfyui获取系统状态接口:
curl -m 300 -X GET https://kubeai-x-default-x-vcacu2dsxxxx.sproxy.hd-01.alayanew.com:22443/openai/api/system_stats -d '{"model": "serverless-comfyui"}'

注意:
当Values.model.minReplicas设置为0时,不会自动启动comfyui的容器,需要一次接口调用触发启动容器。
因此第一次调用需要设置稍长的超时时间,或者做好重试机制

2. 页面访问comfyui
本应用同样提供comfyui的页面访问方式,页面url地址如下:
https://serverless-comfyui-x-default-x-vcacu2dsxxxx.sproxy.hd-01.alayanew.com:22443

注意:
因为comfyui默认不自动启动,如果要页面访问comfyui,需要首先按第一步,调用一次comfyui的接口,触发comfyui的推理容器启动
网页访问不会经过kubeai代理,kubeai长时间没有收到请求,会停止容器,导致页面不可用。
若想长时间使用网页访问,需要调用接口,触发kubeai代理,维持容器运行
提示

如果出现上图中的报错提示,执行kubectl delete crd models.kubeai.org删除即可。

应用市场部署ComfyUI

用户可通过应用市场便捷部署ComfyUI。

  1. 下载应用市场安装脚本,并解压到本地。

  2. 请保持在“准备工作”章节同一终端页面,进入解压后的“devtron-charts”文件夹,如下图所示。

    alt text

  3. 在上述的文件路径下,执行如下的命令安装应用市场,安装页面如下所示。

    alt text

helm install devtron . --create-namespace -n devtroncd --values resources.yaml
提示

用户可通过Base64 Coding工具解码输出的密码。

  1. 从上述操作步骤获取应用市场访问地址及登录密码后,登录应用市场,登录页面如下图所示。

    alt text

  2. 登录后,选择“Browse Helm Charts”进入应用市场管理页面,选择[设置/集群]菜单项,单击“添加环境”按钮,自定义环境名称及命名空间,本示例环境名称为“serverless”,命名空间为“serverless-comfyui”,配置完成后,单击“保存”按钮。

  3. 选择[应用市场]菜单项,在搜索框内检索“serverless-comfyui”,找到最新Helm Chart安装包。点击Helm Chart包链接,进入安装包信息概述页面,单击“配置&部署”按钮,进入应用安装配置页面。

  4. 在应用安装页面,自定义应用名称,选择上一步新建的部署环境,本示例应用名称为“service”,部署环境为“serverless”,其余参数保持默认。

  5. 参数配置完成后,单击“部署Chart”按钮,部署ComfyUI应用,应用部署完成后页面如下所示。

    alt text

  6. 执行如下命令,查看部署结果,如下图所示,系统已成功部署了“kubeai”Pod以及一个“devpod”Pod。

    alt text

kubectl get pod -n  `your-namespace`
  • devpod:弹性容器集群中用于开发调试的Pod,CPU启动,计费较低,可在容器内下载模型等。
  • kubeai:是Kubeai Serveless,基于Kubernetes的Operator,用于管理Model的生命周期,并根据接口调用情况实现对ComfyUI的自动启停。
  1. 部署成功后,使用如下命令进入部署Serverless ComfyUI应用的命名空间。
kubectl exec -it devpod bash -n `your-namespace`
  1. 在同一终端页面,使用如下命令进入如下所示的应用目录。
cd /mnt/serverless-comfyui/models
提示

如果不存在models目录,可使用mkdir models在对应路径下创建models。

  1. 在上述的终端页面执行如下命令,下载“DeepSeek-LLM-7b-base”模型,如下图所示。

    alt text

huggingface-cli download --resume-download deepseek-ai/Janus-Pro-7B --local-dir ./Janus-Pro/Janus-Pro-7B
注意

如果用户已经下载了相应的大模型,可忽略9-11步骤的操作。

启动ComfyUI容器

ComfyUI容器通过调用kubeai代理提供的ComfyUI接口自动启动。因此要启动ComfyUI容器,首先需要访问一次kubeai代理的ComfyUI接口。

信息

kubeai代理了ComfyUI所有位于/api路径下的接口。

  1. 用户可通过多种方式获取kubeai的URL,具体的方式如下所示。
  • 通过Helm Chart一键部署时,用户可以在部署输出信息中找到kubeai的URL。
  • 通过私有应用市场部署时,用户可以在部署后的NOTES.txt文件中找到kubeai的URL。
  • 用户也可自主拼接,模板如下所示,将your-namespace替换为用户已部署的命名空间名称;vksID替换为用户已开通集群的VKSID。
https://kubeai-x-{your-namespace}-x-{vksID}.sproxy.hd-01.alayanew.com:22443/openai  
  1. 使用MobaXterm工具调用ComfyUI的URL接口,本示例调用/api/system_stats接口,用户可选择/api/下的任意接口。
curl -X GET https://kubeai-x-serverless-comfyui-x-vcrbcqtyxxxx.sproxy.hd-01.alayanew.com:22443/openai/api/system_stats \
--header 'Content-Type: application/json' \
-d ' { "model": "serverless-comfyui" }'

提示
  • 将脚本中的vcrbcqtyxxxx替换为用户已申请弹性容器集群的VKSID。
  • 将上述命令中的model字段替换为用户的实际appName值。如果用户在部署过程中没有修改默认的appName,则此处无需更改。
  1. 调用上面的接口以后,可以通过如下命令,查看启动结果。系统新增一个以model开头的Pod,且Pod状态为Running,说明ComfyUI容器启动成功。

    alt text

kubectl get pod -n `your-namespace`
提示

因为第一次调用需要触发启动容器,可能会出现失败的情况,用户可设置稍长的超时时间并做好重试机制。

访问ComfyUI

网页访问ComfyUI

  1. 用户可通过多种方式获取网页地址,具体的方式如下所示。
  • 通过Helm Chart文件一键部署时,获取网页访问的URL地址。
  • 通过私有应用市场部署时,可以在部署应用的NOTES.txt文件中获取
  • 用户也可以自主拼接,模板如下所示,将appName替换为Values.appName的值,将your-namespace替换为用户已部署的命名空间名称;vksID替换为用户已开通集群的VKSID。
https://{appName}-x-{your-namespace}-x-{vksID}.sproxy.hd-01.alayanew.com:22443         
  1. 点击下面的工作流链接,将工作流下载到本地,通过上步获取的访问地址在浏览器中打开应用,首次打开应用,系统默认打开一个示例的工作流,如下图所示。

    image

文生图

  1. 点击[工作流/在本地系统文件中打开工作流]菜单项,选择上步已下载的文生图工作流,如下图所示。

    image

  2. 在“Janus Image Generation”节点输入提示词,本示例输入“show me a fluffy bear”提示词,单击“执行”按钮,工作流执行完成后得到输出,如下图所示。

    image

  3. 按“Ctrl+S”键保存已修改的工作流,然后关闭该工作流。

图片理解

  1. 点击[工作流/在本地系统文件中打开工作流]菜单项,选择已下载的图片理解工作流,如下图所示。

    image

  2. 在“加载图像”节点上传一张要理解的图片,然后在“Janus Image Understanding”节点输入提示词,本示例保持默认值,单击“执行”按钮, 工作流执行完成后得到输出,如下图所示。

    image

  3. 按“Ctrl+S”键保存已修改的工作流,然后关闭该工作流。

接口访问

提示
  • 用户在参照上述示例进行操作时,需要将VKSID替换为实际使用的弹性容器集群ID。
  • 由于任务是在队列异步执行,如果没有完成,可能返回为空JSON,需要循环获取,并处理超时失败
  • 如果修改了工作流,例如节点ID变了,需要替换整个prompt参数值,再根据实际节点ID,替换变量。

文生图

  1. 下载文生图工作流,在终端工具页面进行操作。
信息

文生图的执行流程,需要按顺序调用如下接口。

 /api/promot                  # 上传提示词接口
/api/history/`{prompt_id}` # 根据提示词id,获取任务接口
/api/view?filename=&type=output&subfolder= # 获取生成的图片
curl -X POST https://kubeai-x-default-x-vcacu2dshr12.sproxy.hd-01.alayanew.com:22443/openai/api/prompt \
--header 'Content-Type: application/json' \
-d '
{
"model": "serverless-comfyui",
"client_id": "bc8565582c9e4d2992a7932dc7c18267 ",
"prompt": {
"1": {
"inputs": {
"model_name": "deepseek-ai/Janus-Pro-7B"
},
"class_type": "JanusModelLoader",
"_meta": {
"title": "Janus Model Loader"
}
},
"2": {
"inputs": {
"prompt": "a tiger",
"seed": 820488455847715,
"batch_size": 1,
"cfg_weight": 5,
"temperature": 1,
"top_p": 0.95,
"model": [
"1",
0
],
"processor": [
"1",
1
]
},
"class_type": "JanusImageGeneration",
"_meta": {
"title": "Janus Image Generation"
}
},
"4": {
"inputs": {
"filename_prefix": "ComfyUI",
"images": [
"2",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "保存图像"
}
},
"5": {
"inputs": {
"images": [
"2",
0
]
},
"class_type": "PreviewImage",
"_meta": {
"title": "预览图像"
}
}
}
}'
{
"prompt": {
}
},
"2": {
"inputs": {
"prompt": // 替换成您要生图的提示词(英文)
"seed": // 随机种子,用于结果的可重复性。如果不设置或设置为-1,则使用随机种子。
"batch_size": // 每次生成的样本数量。例如:3 表示一次生成3张图片。
"cfg_weight": // Classifier-Free Guidance (CFG) 权重,控制输出与提示的相关程度。通常在1到20之间。
"temperature": // 控制输出的随机性,值越低越确定,值越高越随机。通常在0到1之间。
"top_p": // 核采样阈值,仅考虑最可能的token集合,其累积概率不超过此值。通常在0到1之间。
"model": // 引用之前定义的模型加载器节点,并指定其索引。
"processor": // 同样引用之前定义的模型加载器节点,但这里可能是处理器部分,索引为[1]
},
"class_type": "JanusImageGeneration",
"_meta": {
"title": "Janus Image Generation"
}
},
"4": {
"inputs": {
"filename_prefix": // 保存图像时使用的文件名前缀。
"images": // 指定要保存的图像来源,这里引用了"2"节点生成的图像,并指定其索引[0]
},
"class_type": "SaveImage",
"_meta": {
"title": "保存图像"
}
}
}
}

图片理解

  1. 首先下载图片理解工作流的工作流,在终端工具页面进行操作。
信息

图片理解的执行流程,需要按顺序调用如下接口:

1. /api/upload/image            # 上传图片
2. /api/promot # 上传提示词接口
3. /api/history/`{prompt_id}` # 根据提示词id,获取任务接口
curl -X POST https://kubeai-x-default-x-vcacu2dshr12.sproxy.hd-01.alayanew.com:22443/openai/api/upload/image \
-F "image=@/mnt/comfyui/test.png" \
-F "model=serverless-comfyui"
"4": {
"inputs": {
"question": "用中文详细描述一下这个图片", // 提供的问题或请求,这里是要求以中文详细描述图片内容。
"seed": 8880086473644, // 随机种子,用于结果的可重复性。如果不设置或设置为-1,则使用随机种子。
"temperature": 0.1, // 控制输出的随机性,值越低越确定,值越高越随机。通常在0到1之间。
"top_p": 1, // 核采样阈值,仅考虑最可能的token集合,其累积概率不超过此值。通常在0到1之间。
"max_new_tokens": 512, // 生成文本的最大新token数,限制生成文本的长度。
"model": ["1", 0], // 引用之前定义的模型加载器节点,并指定其索引。
"processor": ["1", 1], // 同样引用之前定义的模型加载器节点,但这里可能是处理器部分,索引为[1]
"image": ["5", 0] // 指定要理解的图像来源,这里引用了"5"节点加载的图像,并指定其索引[0]
},
"class_type": "JanusImageUnderstanding",
"_meta": {
"title": "Janus Image Understanding" // 节点标题,这里是"Janus Image Understanding"
}
}

"5": {
"inputs": {
"image": "test.png", // 图像文件名,表示要加载的图像文件。
"upload": "image" // 指示这是一个图像上传操作。
},
"class_type": "LoadImage",
"_meta": {
"title": "加载图像" // 节点标题,这里是"加载图像"
}
}

ComfyUI-API附录

发布提示词任务

Post
发布提示词任务
请求地址:{kubeai-url}/api/prompt
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值
client_id
bc8565582c9e4d2992a7932dc7c18267
String
全局唯一id,一般用uuid
prompt
String
工作流的JSON字符串

根据ID获取任务数据

Get
根据id获取历史任务数据
请求地址:{kubeai-url}/api/history/{prompt_id}
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值

预览图片

Get
预览图片
请求地址:{kubeai-url}/api/view?filename={生成的图片名称}&type=&subfolder=
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值

上传图片

Post
上传图片
请求地址:{kubeai-url}/api/upload/image
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值
image
File
上传的图片
type
input
String
类型
subfolder
String
图片子路径

获取系统状态

Get
获取系统状态
请求地址:{kubeai-url}/api/system_stats
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值

获取任务数据

Get
获取历史任务数据
请求地址:{kubeai-url}/api/http://127.0.0.1:8188/history
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值

获取任务队列

Get
获取任务队列
请求地址:{kubeai-url}/api/queue
参数名称参数值类型说明是否必须
model
serverless-comfyui
String
Values.appName的值

总结

本文档详细介绍了如何通过一键部署方案快速搭建Serverless-ComfyUI环境,并以Janjus-Pro-7B模型为例展示了ComfyUI在实际应用中的使用方法。此外,还列出了常用的ComfyUI API接口,帮助开发者更快上手。

对于有兴趣开发自己ComfyUI应用的用户,可以将应用程序打包为镜像文件,并上传至个人或组织的镜像仓库中(有关镜像仓库的开通与管理,请参阅镜像仓库开通及管理及相关文档。 完成上述步骤后,您可以参照本指南发布自己的Serverless-ComfyUI服务,开启个性化应用之旅。

关于ComfyUI的更多详细内容,可参考: