Skip to content

Commit

Permalink
docker: Add workflow for building comfyui-base images
Browse files Browse the repository at this point in the history
  • Loading branch information
hjpotter92 committed Mar 5, 2025
1 parent 258afb8 commit e8ba912
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
.git/
.venv/
.github/
ui/node_modules/
ui/
.dockerignore
79 changes: 79 additions & 0 deletions .github/workflows/comfyui-base.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Build and push comfyui-base docker image

on:
pull_request:
paths:
- docker/Dockerfile.base
- src/comfystream/scripts/
- configs/
- .github/workflows/comfyui-base.yaml
branches:
- main
push:
paths:
- docker/Dockerfile.base
- src/comfystream/scripts/
- configs/
- .github/workflows/comfyui-base.yaml
branches:
- main
tags:
- "v*"

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
docker:
name: docker builds
permissions:
packages: write
contents: read
runs-on: [self-hosted, linux, gpu]
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.CI_DOCKERHUB_USERNAME }}
password: ${{ secrets.CI_DOCKERHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: |
livepeer/comfyui-base
tags: |
type=sha
type=ref,event=pr
type=ref,event=tag
type=sha,format=long
type=ref,event=branch
type=semver,pattern={{version}},prefix=v
type=semver,pattern={{major}}.{{minor}},prefix=v
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=${{ github.event.pull_request.head.ref }}
type=raw,value=stable,enable=${{ startsWith(github.event.ref, 'refs/tags/v') }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push livepeer docker image
timeout-minutes: 200
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
file: docker/Dockerfile.base
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=registry,ref=livepeer/comfyui-base:build-cache
cache-to: type=registry,mode=max,ref=livepeer/comfyui-base:build-cache
3 changes: 0 additions & 3 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,3 @@ jobs:
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=registry,ref=${{ github.repository }}:build-cache
cache-to: type=registry,mode=max,ref=${{ github.repository }}:build-cache

- name: Notify new build upload
run: curl -X POST https://holy-bread-207a.livepeer.workers.dev
82 changes: 45 additions & 37 deletions docker/Dockerfile.base
Original file line number Diff line number Diff line change
@@ -1,58 +1,66 @@
ARG BASE_IMAGE=nvidia/cuda:12.2.2-cudnn8-devel-ubuntu22.04
FROM ${BASE_IMAGE}
ARG BASE_IMAGE=nvidia/cuda:12.2.2-cudnn8-devel-ubuntu22.04 \
CONDA_VERSION=latest \
PYTHON_VERSION=3.11

FROM "${BASE_IMAGE}"

ARG CONDA_VERSION \
PYTHON_VERSION


ENV DEBIAN_FRONTEND=noninteractive \
CONDA_VERSION="${CONDA_VERSION}" \
PATH="/workspace/miniconda3/bin:${PATH}" \
PYTHON_VERSION="${PYTHON_VERSION}"

# System dependencies
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y \
git \
wget \
nano \
socat \
libsndfile1 \
build-essential llvm tk-dev \
&& rm -rf /var/lib/apt/lists/*
RUN apt update && apt install -yqq \
git \
wget \
nano \
socat \
libsndfile1 \
build-essential llvm tk-dev && \
rm -rf /var/lib/apt/lists/*

# Conda setup
RUN mkdir -p /workspace/comfystream
RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh \
&& bash /tmp/miniconda.sh -b -p /workspace/miniconda3 \
&& rm /tmp/miniconda.sh

ENV PATH="/workspace/miniconda3/bin:${PATH}"
RUN eval "$(/workspace/miniconda3/bin/conda shell.bash hook)"
RUN conda create -n comfystream python=3.11 -y
RUN mkdir -p /workspace/comfystream && \
wget "https://repo.anaconda.com/miniconda/Miniconda3-${CONDA_VERSION}-Linux-x86_64.sh" -O /tmp/miniconda.sh && \
bash /tmp/miniconda.sh -b -p /workspace/miniconda3 && \
eval "$(/workspace/miniconda3/bin/conda shell.bash hook)" && \
conda create -n comfystream python="${PYTHON_VERSION}" -y && \
rm /tmp/miniconda.sh && \
conda run -n comfystream --no-capture-output pip install aiortc aiohttp requests tqdm pyyaml --root-user-action=ignore

# Clone ComfyUI
RUN git clone https://github.com/comfyanonymous/ComfyUI.git /workspace/ComfyUI
ADD --link https://github.com/comfyanonymous/ComfyUI.git /workspace/ComfyUI

# Copy only files needed for setup
COPY ./src/comfystream/scripts /workspace/comfystream/src/comfystream/scripts
COPY ./configs /workspace/comfystream/configs

# Install base dependencies
RUN conda run -n comfystream --no-capture-output pip install aiortc aiohttp requests tqdm pyyaml --root-user-action=ignore
COPY --link ./src/comfystream/scripts /workspace/comfystream/src/comfystream/scripts
COPY --link ./configs /workspace/comfystream/configs

# Run setup_nodes (cached unless setup_nodes.py or nodes/ changes)
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream python src/comfystream/scripts/setup_nodes.py --workspace /workspace/ComfyUI
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream python src/comfystream/scripts/setup_nodes.py --workspace /workspace/ComfyUI

# Copy ComfyStream files into ComfyUI
COPY . /workspace/comfystream
COPY . /workspace/comfystream

# Copy comfystream and example workflows to ComfyUI
COPY ./workflows/comfyui/* /workspace/ComfyUI/user/default/workflows
COPY ./workflows/comfyui/* /workspace/ComfyUI/user/default/workflows

# Install ComfyUI requirements
RUN conda run -n comfystream --no-capture-output --cwd /workspace/ComfyUI pip install -r requirements.txt --root-user-action=ignore
RUN conda run -n comfystream --no-capture-output --cwd /workspace/ComfyUI pip install -r requirements.txt --root-user-action=ignore

# Install ComfyStream requirements
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream pip install -r requirements.txt --root-user-action=ignore
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream pip install . --root-user-action=ignore
RUN ln -s /workspace/comfystream /workspace/ComfyUI/custom_nodes/comfystream
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream python install.py --workspace /workspace/ComfyUI
RUN conda run -n comfystream --no-capture-output pip install --upgrade tensorrt-cu12-bindings tensorrt-cu12-libs --root-user-action=ignore
RUN conda run -n comfystream --no-capture-output pip install mediapipe==0.10.8 --root-user-action=ignore
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream pip install -r requirements.txt --root-user-action=ignore && \
conda run -n comfystream --no-capture-output --cwd /workspace/comfystream pip install . --root-user-action=ignore && \
ln -s /workspace/comfystream /workspace/ComfyUI/custom_nodes/comfystream && \
conda run -n comfystream --no-capture-output --cwd /workspace/comfystream python install.py --workspace /workspace/ComfyUI && \
conda run -n comfystream --no-capture-output pip install --upgrade tensorrt-cu12-bindings tensorrt-cu12-libs --root-user-action=ignore && \
conda run -n comfystream --no-capture-output pip install mediapipe==0.10.8 --root-user-action=ignore

# Configure no environment activation by default
RUN conda config --set auto_activate_base false
RUN conda init bash
RUN conda config --set auto_activate_base false && \
conda init bash

WORKDIR /workspace/comfystream
WORKDIR /workspace/comfystream
60 changes: 42 additions & 18 deletions src/comfystream/scripts/setup_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,36 @@
import yaml
import argparse
from utils import get_config_path, load_model_config


def parse_args():
parser = argparse.ArgumentParser(description='Setup ComfyUI nodes and models')
parser.add_argument('--workspace',
default=os.environ.get('COMFY_UI_WORKSPACE', os.path.expanduser('~/comfyui')),
help='ComfyUI workspace directory (default: ~/comfyui or $COMFY_UI_WORKSPACE)')
parser = argparse.ArgumentParser(description="Setup ComfyUI nodes and models")
parser.add_argument(
"--workspace",
default=os.environ.get("COMFY_UI_WORKSPACE", Path("~/comfyui").expanduser()),
help="ComfyUI workspace directory (default: ~/comfyui or $COMFY_UI_WORKSPACE)",
)
return parser.parse_args()


def setup_environment(workspace_dir):
os.environ["COMFY_UI_WORKSPACE"] = str(workspace_dir)
os.environ["PYTHONPATH"] = str(workspace_dir)
os.environ["CUSTOM_NODES_PATH"] = str(workspace_dir / "custom_nodes")


def setup_directories(workspace_dir):
"""Create required directories in the workspace"""
# Create base directories
workspace_dir.mkdir(parents=True, exist_ok=True)
custom_nodes_dir = workspace_dir / "custom_nodes"
custom_nodes_dir.mkdir(parents=True, exist_ok=True)


def install_custom_nodes(workspace_dir, config_path=None):
"""Install custom nodes based on configuration"""
if config_path is None:
config_path = get_config_path('nodes.yaml')
config_path = get_config_path("nodes.yaml")
try:
config = load_model_config(config_path)
except FileNotFoundError:
Expand All @@ -42,40 +49,56 @@ def install_custom_nodes(workspace_dir, config_path=None):
os.chdir(custom_nodes_path)

try:
for _, node_info in config['nodes'].items():
dir_name = node_info['url'].split("/")[-1].replace(".git", "")
for _, node_info in config["nodes"].items():
dir_name = node_info["url"].split("/")[-1].replace(".git", "")
node_path = custom_nodes_path / dir_name

print(f"Installing {node_info['name']}...")

# Clone the repository if it doesn't already exist
if not node_path.exists():
cmd = ["git", "clone", node_info['url']]
if 'branch' in node_info:
cmd.extend(["-b", node_info['branch']])
cmd = ["git", "clone", node_info["url"]]
if "branch" in node_info:
cmd.extend(["-b", node_info["branch"]])
subprocess.run(cmd, check=True)
else:
print(f"{node_info['name']} already exists, skipping clone.")

# Checkout specific commit if branch is a commit hash
if 'branch' in node_info and len(node_info['branch']) == 40: # SHA-1 hash length
subprocess.run(["git", "-C", dir_name, "checkout", node_info['branch']], check=True)
if (
"branch" in node_info and len(node_info["branch"]) == 40
): # SHA-1 hash length
subprocess.run(
["git", "-C", dir_name, "checkout", node_info["branch"]], check=True
)

# Install requirements if present
requirements_file = node_path / "requirements.txt"
if requirements_file.exists():
subprocess.run([sys.executable, "-m", "pip", "install", "-r", str(requirements_file)], check=True)
subprocess.run(
[
sys.executable,
"-m",
"pip",
"install",
"-r",
str(requirements_file),
],
check=True,
)

# Install additional dependencies if specified
if 'dependencies' in node_info:
for dep in node_info['dependencies']:
subprocess.run([sys.executable, "-m", "pip", "install", dep], check=True)
if "dependencies" in node_info:
for dep in node_info["dependencies"]:
subprocess.run(
[sys.executable, "-m", "pip", "install", dep], check=True
)

print(f"Installed {node_info['name']}")
except Exception as e:
print(f"Error installing {node_info['name']} {e}")
raise e
return


def setup_nodes():
args = parse_args()
Expand All @@ -86,4 +109,5 @@ def setup_nodes():
install_custom_nodes(workspace_dir)


setup_nodes()
if __name__ == "__main__":
setup_nodes()

0 comments on commit e8ba912

Please sign in to comment.