Генерация изображений через ComfyUI в одиночку — это боль. Особенно когда надо выдать сотню вариаций для A/B теста, а на RTX 4090 процесс занимает всю ночь. Перенос на AWS SageMaker превращает этот ад в конвейер: нажал кнопку — через 10 минут пачка картинок в S3. Но без правильного подхода ты просто утопишь бюджет в GPU инстансах. Я покажу, как собрать инфраструктуру на AWS CDK, чтобы ComfyUI работал как полноценный enterprise-сервис: автомасштабирование, отказоустойчивость, интеграция с пайплайнами.
Почему SageMaker, а не EC2 или Lambda?
Лямбда с GPU — пока миф (максимум 15 минут и холодный старт). EC2 — ручное управление: надо ставить NVIDIA драйверы, докер, мониторить загрузку. SageMaker съедает всю эту боль: встроенная обертка для инференса, автоскейлинг по метрикам GPU, автоматический роллинг апдейт модели. Это как перейти с самодельного велосипеда на Toyota Camry — разница колоссальная. Кстати, в SageMaker 2025 наконец-то добавили нормальные метрики GPU и rolling updates — теперь не надо изобретать костыли.
Структура решения: что и куда
У нас будет:
- Docker-образ с ComfyUI (включая кастомные ноды, модели, контролнет).
- SageMaker Model — точка входа, которая ссылается на этот образ в ECR.
- Endpoint Configuration — выбор GPU инстанса (g5.xlarge, p4d.24xlarge), автоскейлинг.
- Endpoint — сам сервис, который живет постоянно или просыпается по требованию.
- S3 bucket для входных промптов (JSON) и выходных изображений.
- CDK стек, который разворачивает всё это одной командой.
Зачем так сложно? А затем, что мы хотим не просто запустить ComfyUI, а встроить его в CI/CD для генерации контента. Чтобы любой участник команды мог дернуть API и получить результат, не думая о GPU.
Шаг 1: Собираем Docker-образ с ComfyUI (актуальный на июнь 2026)
Берем официальный образ ComfyUI (сейчас версия 2.3.1, последняя стабильная от мая 2026) и добавляем свистелки: кастомные ноды (ControlNet, IP-Adapter, AnimateDiff), модели Stable Diffusion 3.5 Medium и Flux.1 Pro. В теории можно ставить всё через скрипты, но на практике я предпочитаю зафиксировать версии в Dockerfile — меньше сюрпризов.
⚠️ Ловушка: Некоторые ноды (например, WAS Node Suite) требуют дополнительных зависимостей. Я потратил целый день, чтобы понять, что забыл установить torch.compile с triton. Просто добавьте RUN pip install torch==2.5.0+cu124 --index-url https://download.pytorch.org/whl/cu124 — и всё заработает.
FROM comfyanonymous/comfyui:2.3.1-cuda12.4
# Кастомные ноды
RUN git clone https://github.com/comfyanonymous/ComfyUI-Manager.git custom_nodes/ComfyUI-Manager
RUN git clone https://github.com/Fannovel16/comfyui_controlnet_aux.git custom_nodes/comfyui_controlnet_aux
# Скачиваем модели (предварительно залитые в EFS или S3)
COPY ./models /app/models
# Скрипт для запуска SageMaker-инференса
COPY inference.py /app/inference.py
CMD ["python3", "-u", "/app/inference.py"]
Лучше не хранить модели в образе — они весят гигабайты. Используйте EFS или S3 с монтированием через s3fs. Я предпочитаю EFS, потому что SageMaker умеет маунтить его прямо в контейнер без лишних костылей.
Шаг 2: Пишем inference.py на FastAPI
SageMaker требует, чтобы контейнер слушал порт 8080 и имел эндпоинты /invocations и /ping. Мы сделаем простой API, который принимает JSON с workflow (сохраненный из ComfyUI) и возвращает base64 изображения. Для batch-генерации просто передаём массив workflow с разными промптами.
import json
import base64
from fastapi import FastAPI, Request
from comfy_api import ComfyAPI # наша обертка
app = FastAPI()
comfy = ComfyAPI(models_path="/app/models")
@app.post("/invocations")
async def invoke(request: Request):
data = await request.json()
workflow = data.get("workflow")
images = comfy.generate(workflow) # возвращает список PIL.Image
results = []
for img in images:
buffer = BytesIO()
img.save(buffer, format="PNG")
results.append(base64.b64encode(buffer.getvalue()).decode())
return {"images": results}
Шаг 3: CDK-стек — инфраструктура как код
Пишем на TypeScript (хотя можно на Python CDK, TS удобнее для ресурсов AWS). Создаём стек с SageMaker Model, EndpointConfig и Endpoint. Указываем инстанс — g5.xlarge (16GB VRAM) для большинства задач, p4d.24xlarge для больших batch-ов.
import * as sagemaker from 'aws-cdk-lib/aws-sagemaker';
const model = new sagemaker.CfnModel(this, 'ComfyUIModel', {
executionRoleArn: role.roleArn,
primaryContainer: {
image: ecrImageUri,
modelDataUrl: 's3://bucket/models.tar.gz', // если модели не в образе
},
});
const endpointConfig = new sagemaker.CfnEndpointConfig(this, 'ComfyUIConfig', {
productionVariants: [{
variantName: 'gpu',
modelName: model.attrModelName,
instanceType: 'ml.g5.xlarge',
initialInstanceCount: 1,
initialVariantWeight: 1.0,
serverlessConfig: undefined, // для постоянной работы
managedInstanceScaling: {
minInstanceCount: 0, // авто-включение при запросе
maxInstanceCount: 2,
},
}],
});
new sagemaker.CfnEndpoint(this, 'ComfyUIEndpoint', {
endpointConfigName: endpointConfig.attrEndpointConfigName,
});
Обратите внимание на managedInstanceScaling — это новинка 2025 года, которая позволяет инстансам засыпать при простое и просыпаться по запросу. Сэкономит вам 80% стоимости, если не гоняете генерацию 24/7. Подробнее про такие фичи я писал в статье про ModelOps без головной боли.
Шаг 4: Запускаем batch-генерацию через SageMaker Processing
Для массовой генерации (например, 10 000 вариаций) не стоит долбить REST API — слишком дорого и медленно. Используем SageMaker Processing Job: даём ему список JSON-файлов из S3, Job запускает контейнер с ComfyUI на GPU обрабатывает всё и складывает результаты обратно.
import * as sagemaker from 'aws-cdk-lib/aws-sagemaker';
const processingJob = new sagemaker.CfnProcessingJob(this, 'BatchGen', {
processingResources: {
clusterConfig: {
instanceCount: 4,
instanceType: 'ml.g5.xlarge',
},
},
appSpecification: {
imageUri: ecrImageUri,
containerArguments: ['--batch-mode'],
},
processingInputs: [{
inputName: 'prompts',
s3Input: {
s3Uri: 's3://bucket/prompts/',
localPath: '/opt/ml/processing/input',
},
}],
processingOutputConfig: {
outputs: [{
outputName: 'images',
s3Output: {
s3Uri: 's3://bucket/output/',
localPath: '/opt/ml/processing/output',
},
}],
},
});
Такая обработка параллелится автоматически — SageMaker распределяет файлы по инстансам. После завершения Job вы получаете папку с готовыми PNG. Теперь можно интегрировать это в пайплайн CI/CD, чтобы при каждом пуше в репозиторий с промптами автоматом генерились новые картинки для маркетинга.
Нюансы и грабли, на которые я наступил
1. Холодный старт: разбудить инстанс быстрее
Когда инстанс засыпает (managedInstanceScaling), при первом запросе он просыпается 3-5 минут — за это время клиент свалится по таймауту. Решение: сделайте health-check с периодическим легким запросом (например, раз в 5 минут отправляйте пустой ping). Или используйте Serverless Inference — но там GPU пока не поддерживается (на июнь 2026 всё еще так).
2. Стоимость GPU: как не прогореть
g5.xlarge стоит около $1.5/час на us-east-1. Если он работает 24/7 — это $1080/месяц. Неплохо для старта, но для серьёзных объемов выгоднее взять Reserved Instance на 1 год (скидка 40%). Или использовать Spot-инстансы для batch-задач — это копейки, но есть риск прерывания. Я комбинирую: эндпоинт для реального времени использует On-Demand, а batch-генерация — Spot.
3. Несовместимость кастомных нод
ComfyUI — дикий Запад. Ноды могут требовать определённую версию torch или python. Лучше всего собирать образ на основе официального, но с фиксированными версиями нод. Я советую после сборки прогонять тестовый workflow внутри контейнера в CI — это отлавливает 90% проблем.
Как это используют в Enterprise: пример Volkswagen
Компании вроде Volkswagen уже давно гоняют такие пайплайны: SageMaker + Bedrock для генерации тысяч вариантов рекламы, а ComfyUI для тонкого управления стилем. Они зашивают brand-guidelines прямо в workflow, и модель не выходит за рамки. Если нужно больше контроля, посмотрите нашу статью про Agentic AI на Bedrock — там описан похожий подход, но с LLM-агентами.
Автоматизация всего цикла: от Git push до готовых картинок
Final step: добавить GitHub Actions, который при коммите в ветку main запускает SageMaker Processing Job. Промпты хранятся в YAML файлах в репозитории, CI пакует их в JSON и шлёт в S3, затем стартует Job. Результаты автоматом публикуются на S3 bucket с CDN — дизайнеры открывают ссылку и видят свежие варианты.
Звучит сложно? На деле это 200 строк кода. Если хотите упростить себе жизнь, используйте SageMaker JumpStart — там есть готовые пресеты для Stable Diffusion, которые можно кастомизировать. Но если вам нужен полный контроль над workflow ComfyUI (а это даёт невероятную гибкость), то кастомный контейнер — единственный путь.
И неочевидный совет: не храните секреты и API-ключи в образе — используйте AWS Secrets Manager и передавайте через переменные окружения в SageMaker. Особенно если вы используете ноды, которые стучатся к внешним API (например, Replicate или Stability AI). Утечка ключей через образ — самая частая проблема, которую я вижу у новичков.
🔥 Бонус-трек: Можно добавить webhook от SageMaker Endpoint до Discord/Slack, чтобы при завершении batch-генерации автоматически приходило уведомление с превью. Делается через SNS + Lambda за 15 минут.