Skip to content
控制台

容器化部署 Flux.1-dev 文生图模型应用

本指南详细阐述了在共绩算力上部署 Flux.1-dev 模型应用的解决方案。

🐋

鉴于 Serverless 平台具备多节点特性,从专业角度出发,强烈不建议将 Web UI 用于生产环境。在生产场景中,使用 API 是更为适宜的选择。此镜像已集成封装好的 API,以便于您便捷使用。

一、开源案例

我们基于本教程开源了一套前端 Flux.1-dev 文生图服务网站解决方案。

具有完整的 Docker&Serverless 化部署方案,您可以参考使用。

项目地址:https://github.com/slmnb-lab/FluxEz

二、部署步骤

我们也提供了构建完毕的 Flux 镜像可以直接部署使用。

下面是部署步骤:

(一)访问共绩算力控制台 https://console.suanli.cn,点击新增部署。

(二)基于自身需要进行配置,参考配置为单卡 4090 和 1 个节点(初次使用进行调试)。

(三)配置镜像地址为harbor.suanleme.cn/last1/comfyui-flux:0.4,选择添加端口号,针对 comfyui-api 来说,我们需要 8188 和 3000 端口。

(四)点击部署服务,耐心等待节点拉取镜像并启动。

(五)节点启动后,你所在“任务列表”中看到的内容可能如下:

(六)我们可以点击“8188”端口的链接,测试 comfyui 部署情况

(七)通过 API 的形式来调用 comfyui 进行图像生成

我们不推荐直接使用 comfyui 的默认 API 接口,因为多节点时需自行解决无状态问题。更推荐的做法是通过我们暴露的 3000 端口进行请求,其通过 comfyui-api 进行包装,支持默认的同步生图请求和 webhook 实现。

以下以 POSTMAN 为例,简要描述如何向 3000 端口发送图片生成的 API 请求:

保存页面工作流

点击”导航栏——工作流——导出(API)“菜单,浏览器会自动下载一个 json 文件。

打开 POSTMAN,新建一个 POST 请求

新建一个 POST 请求,并命名为”prompt“,如下图所示:

完善请求信息

需要完善的信息如下:

(1)请求的 URL

在 3000 端口的回传链接后加上“/prompt”的路径,保证其格式类似于https://xxx/prompt

(2)将请求体参数格式设置为 raw 和 json

如图。

(3)设置参数内容基本格式

如图。

将我们下载好的工作流 json 文件粘贴为参数中prompt字段的值

如下图所示,我们将鼠标移动至 prompt 字段的冒号后,粘贴工作流的内容。

发送请求

返回结果如下所示,images字段包含一个字符数组,其中的元素即为生成图片的 base64 编码。

三、构建 comfyui 镜像

温馨提示,如果你只希望使用我们默认的镜像,那么下面的内容您无需关注。

如果您希望构建自定义的镜像,而非仅仅使用我们提供的预设 Flux 镜像,以下是一个很好的参考。您可根据自身需要,添加需要的模型和插件。

(一)下载模型文件

我们所需的模型文件共有四个,下载链接分别如下,分别将其下载至本地:

注意,如果你的显存低于 32GB,建议将上述文件中的 t5xxl_fp16.safetensors 替换为下面的低配版模型 t5xxl_fp8_e4m3n.safetensors(后续工作流中对应修改一下模型名即可),下面的案例中我们将使用低配版模型作为示例:

https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp8_e4m3fn.safetensors?download=true

(二)创建 Dockerfile 文件

一个合适的 docker 基础镜像能帮助我们节省大量的时间,同时还能大大减少我们构建出错的概率。这里我们选择comfyui-api开源库的官方镜像作为我们的基础镜像,其预装了 comfyui 及 comfyui-api 以及基础的运行环境依赖。

我们最终的需要 Dockerfile 文件内容如下,请新建一个名为 Dockerfile 的文件(注意无后缀),通过任意编辑器打开,将下面的内容复制进去。

docker
<em># 使用 comfyui-api 基础镜像</em>
FROM ghcr.io/saladtechnologies/comfyui-api:comfy0.3.29-api1.8.3-torch2.6.0-cuda12.4-runtime

<em># 设置环境变量</em>
ENV COMFYUI_PORT=8188 \
    MODEL_DIR=/opt/ComfyUI/models \
    BASE=""

<em># 4. 预创建模型目录结构</em>
RUN mkdir -p ${MODEL_DIR}/{loras,vaes,text_encoders,diffusion_models}

<em># 5. 复制模型文件</em>
COPY diffusion_models/*.safetensors ${MODEL_DIR}/diffusion_models/
COPY vae/*.safetensors ${MODEL_DIR}/vae/
COPY text_encoders/*.safetensors ${MODEL_DIR}/text_encoders/

<em># 6. 暴露端口</em>
EXPOSE ${COMFYUI_PORT}

(三)创建目录

创建目录是为了便于我们指定路径,请按照下面的路径放置上述的文件。

comfyUI/

└── Dockerfile

├── diffusion_models/

│ └── flux1-dev.safetensors

├── text_encoders/

│ ├── clip_l.safetensors

│ └── t5xxl_fp8_e4m3fn.safetensors

├── vae/

│ └── ae.safetensors

(四)执行构建

进入 comfyuiUI 目录,打开控制台,执行如下命令 (可根据需要自行修改标签和镜像名):

docker
docker build -t comfyui-flux:0.1 .

耐心等待构建完毕,最终生成的镜像体积约 42GB。

(五)本地测试(推荐)

虽然即使不经过本地测试也可以直接上传使用,但本地测试可以更快的预览镜像构建效果,还能提前排除可能的一些问题,避免构建过程中的错误在上传远程仓库后才发现。

我们可以在任意位置打开控制台,键入以下指令:

docker
docker run --rm --gpus all -p 3000:3000 comfyui-flux:0.1

当容器运行完毕后,,我们可以通过 API 来判断其是否正常工作。

获取 API 文档

我们可以打开浏览器,网址栏输入http://localhost:3000/docs,即可打开默认的 comfyui-api 基于 swagger 的文档页面,如下图所示:

其中介绍了我们可以使用的 4 个常用方法,可自行了解详情。

测试生图接口

接下来我们需要测试镜像容器的生图功能——当然也是最重要的功能。这一步推荐使用 PostMan 这类 API 测试工具,以下将以 PostMan 作为示例:

(1)创建请求

新建一个请求,将其请求方法设置为 POST,并键入http://localhost:3000/prompt作为请求的 URL。

(2)选择参数

找到下方的body栏,点击raw一项,并选择右侧的类型为JSON。在下方键入我们的 JSON 参数。

我们所需的参数如下,prompt 对应的是 comfyui 的工作流内容(API 形式)如果有自定义需要,我们也可以修改其中的参数值。

{
  "prompt":{
    "8": {
      "inputs": {
        "samples": [
          "40",
          0
        ],
        "vae": [
          "10",
          0
        ]
      },
      "class_type": "VAEDecode",
      "_meta": {
        "title": "VAE解码"
      }
    },
    "10": {
      "inputs": {
        "vae_name": "ae.safetensors"
      },
      "class_type": "VAELoader",
      "_meta": {
        "title": "加载VAE"
      }
    },
    "11": {
      "inputs": {
        "clip_name1": "t5xxl_fp8_e4m3fn.safetensors",
        "clip_name2": "clip_l.safetensors",
        "type": "flux",
        "device": "default"
      },
      "class_type": "DualCLIPLoader",
      "_meta": {
        "title": "双CLIP加载器"
      }
    },
    "17": {
      "inputs": {
        "scheduler": "normal",
        "steps": 25,
        "denoise": 1,
        "model": [
          "46",
          0
        ]
      },
      "class_type": "BasicScheduler",
      "_meta": {
        "title": "基本调度器"
      }
    },
    "38": {
      "inputs": {
        "model": [
          "46",
          0
        ],
        "conditioning": [
          "42",
          0
        ]
      },
      "class_type": "BasicGuider",
      "_meta": {
        "title": "基本引导器"
      }
    },
    "39": {
      "inputs": {
        "filename_prefix": "FluxEz",
        "images": [
          "8",
          0
        ]
      },
      "class_type": "SaveImage",
      "_meta": {
        "title": "保存图像"
      }
    },
    "40": {
      "inputs": {
        "noise": [
          "45",
          0
        ],
        "guider": [
          "38",
          0
        ],
        "sampler": [
          "47",
          0
        ],
        "sigmas": [
          "17",
          0
        ],
        "latent_image": [
          "44",
          0
        ]
      },
      "class_type": "SamplerCustomAdvanced",
      "_meta": {
        "title": "自定义采样器(高级)"
      }
    },
    "42": {
      "inputs": {
        "guidance": 3.5,
        "conditioning": [
          "43",
          0
        ]
      },
      "class_type": "FluxGuidance",
      "_meta": {
        "title": "Flux引导"
      }
    },
    "43": {
      "inputs": {
        "text": "beautiful photography of a gonger haired artist with Lots of Colorful coloursplashes in face and pn her hands, she is natural, having her hair in a casual bun, looking happily into camera, cinematic,",
        "clip": [
          "11",
          0
        ]
      },
      "class_type": "CLIPTextEncode",
      "_meta": {
        "title": "CLIP文本编码"
      }
    },
    "44": {
      "inputs": {
        "width": 1024,
        "height": 1024,
        "batch_size": 1
      },
      "class_type": "EmptySD3LatentImage",
      "_meta": {
        "title": "空Latent图像(SD3)"
      }
    },
    "45": {
      "inputs": {
        "noise_seed": 454905699352480
      },
      "class_type": "RandomNoise",
      "_meta": {
        "title": "随机噪波"
      }
    },
    "46": {
      "inputs": {
        "max_shift": 1.15,
        "base_shift": 0.5,
        "width": 1024,
        "height": 1024,
        "model": [
          "48",
          0
        ]
      },
      "class_type": "ModelSamplingFlux",
      "_meta": {
        "title": "采样算法(Flux)"
      }
    },
    "47": {
      "inputs": {
        "sampler_name": "euler"
      },
      "class_type": "KSamplerSelect",
      "_meta": {
        "title": "K采样器选择"
      }
    },
    "48": {
      "inputs": {
        "unet_name": "flux1-dev.safetensors",
        "weight_dtype": "default"
      },
      "class_type": "UNETLoader",
      "_meta": {
        "title": "UNet加载器"
      }
    }
  }
}
(3)发送请求

请求返回的结果应该如下:

docker
{
    "id": "63c4114c-108a-4178-a37b-e53334607805",
    "prompt"://你的工作流参数,
    "images": []//返回的图片数组,
}

(六)推送镜像到平台

这一步会将上一步中自定义的镜像上传到我们的镜像仓库服务中。请参考文档进行:https://www.gongjiyun.com/docs/docker/harbor.html