diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 205c7dd..b502883 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,9 +3,9 @@ name: build # Builds the app image so an orchestrator can pull and run it; amd64 only, since # Livepeer GPU work is NVIDIA/amd64. # -# This image is ~25 GB (CUDA devel, torch, TensorRT, ONNX Runtime), so it does not +# This image is ~15 GB (torch, TensorRT, ONNX Runtime), so it does not # fit a GitHub-hosted runner as shipped: the job reclaims disk first, skips the -# layer cache (a 25 GB image would blow the 10 GB Actions cache anyway), and does +# layer cache (an image this size would blow the 10 GB Actions cache anyway), and does # not run on pull requests, where a build this size buys little for what it costs. # # GHCR needs no setup (ghcr.io//, public if the repo is). Docker Hub @@ -32,7 +32,8 @@ jobs: steps: - uses: actions/checkout@v7 - # A stock runner has roughly 25 GB free, which this image alone exceeds. + # A stock runner has roughly 25 GB free, which this image plus its build + # layers still crowds. # These are preinstalled toolchains the build never touches; dropping them # frees about 25 GB more. - name: Reclaim disk diff --git a/Dockerfile b/Dockerfile index 7c03ca2..f5f66d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,34 +5,47 @@ # the whole point of the static-registration path — an app needs no SDK, and no # awareness of Livepeer at all, to run on the network. # -# NOTE: the fork's own Dockerfile clones the UPSTREAM cumulo-autumn repo, not the -# fork, so it would not run this rewritten server. We clone the fork at a pinned -# commit instead. -FROM nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 +# NOTE: the fork's demo/realtime-img2img/Dockerfile clones the UPSTREAM +# cumulo-autumn repo, not the fork, so it would not run this rewritten server. +# We clone the fork at a pinned commit instead. +# +# Base is python-slim, not nvidia/cuda:*-devel: nothing here compiles against +# CUDA (torch's cu128 wheels carry the runtime, install-tensorrt is pure pip), +# and the driver arrives through the container runtime. +FROM python:3.11-slim + +LABEL org.opencontainers.image.title="streamdiffusion-livepeer-runner" +LABEL org.opencontainers.image.description="daydream's StreamDiffusion realtime-img2img server, packaged unmodified to run as a Livepeer live runner" +LABEL org.opencontainers.image.source="https://github.com/livepeer/streamdiffusion-livepeer-runner" +LABEL org.opencontainers.image.licenses="Apache-2.0" ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1 ENV HF_HUB_ENABLE_HF_TRANSFER=1 +# git: pip resolves streamdiffusion from the fork, and demo/ is cloned below. +# libgl1/libglib2.0-0 are opencv's, not CUDA's, so slim needs them either way. RUN apt-get update && apt-get install -y --no-install-recommends \ - software-properties-common ca-certificates curl git \ - && add-apt-repository ppa:deadsnakes/ppa \ - && apt-get update && apt-get install -y --no-install-recommends \ - python3.11 python3.11-venv python3.11-dev \ - && ln -sf /usr/bin/python3.11 /usr/local/bin/python \ - && curl -sS https://bootstrap.pypa.io/get-pip.py | python \ - && python -m pip --version \ + git libgl1 libglib2.0-0 \ && apt-get clean && rm -rf /var/lib/apt/lists/* RUN python -m pip install --no-cache-dir \ torch==2.7.1+cu128 torchvision==0.22.1+cu128 torchaudio==2.7.1+cu128 \ --index-url https://download.pytorch.org/whl/cu128 -RUN python -m pip install --no-cache-dir \ - "streamdiffusion[tensorrt,controlnet,ipadapter] @ git+https://github.com/daydreamlive/StreamDiffusion.git@94b9b96cb8a17d401ffbce516393d6482326ce62" -RUN apt-get update && apt-get install -y --no-install-recommends \ - libgl1 libglib2.0-0 \ +# insightface (ipadapter extra) is sdist-only, so it compiles here. Plain g++, +# nothing CUDA: install for this step only, purge in the same layer. +RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ + && python -m pip install --no-cache-dir \ + "streamdiffusion[tensorrt,controlnet,ipadapter] @ git+https://github.com/daydreamlive/StreamDiffusion.git@94b9b96cb8a17d401ffbce516393d6482326ce62" \ + && apt-get purge -y --auto-remove build-essential \ && apt-get clean && rm -rf /var/lib/apt/lists/* -RUN python -m streamdiffusion.tools.install-tensorrt +ENV LD_LIBRARY_PATH=/usr/local/lib/python3.11/site-packages/nvidia/cuda_runtime/lib:/usr/local/lib/python3.11/site-packages/nvidia/cudnn/lib:/usr/local/lib/python3.11/site-packages/nvidia/cublas/lib:/usr/local/lib/python3.11/site-packages/tensorrt_libs + +# Pure pip: the tensorrt + cuDNN wheels, polygraphy, onnx-graphsurgeon. polygraphy +# globs libcudart.so* over LD_LIBRARY_PATH, which on slim is the only place it +# will find one; the check fails the build rather than the first stream. +RUN python -m streamdiffusion.tools.install-tensorrt \ + && python -c "import torch,tensorrt; from polygraphy.cuda.cuda import Cuda; Cuda(); print('ok',torch.__version__,tensorrt.__version__)" # The pip package doesn't ship the demo/ dir, so clone the fork (pinned) for the server. RUN git clone https://github.com/daydreamlive/StreamDiffusion.git /src \ @@ -55,4 +68,6 @@ RUN rm -rf engines && ln -s /models/engines engines EXPOSE 7860 # --api-only: skip the built Node frontend (a Livepeer client drives the API directly). -CMD ["python", "main.py", "--host=0.0.0.0", "--port=7860", "--acceleration=tensorrt", "--api-only"] +# /models/engines is made at start because the volume masks a build-time mkdir, +# and mkdir(exist_ok=True) re-raises on the symlink while it dangles. +CMD ["sh", "-c", "mkdir -p /models/engines && exec python main.py --host=0.0.0.0 --port=7860 --acceleration=tensorrt --api-only"] diff --git a/README.md b/README.md index 387acb0..d41435e 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ The price is unchanged by the overlay: static runners advertise it from `runners CI publishes the image to `ghcr.io/livepeer/streamdiffusion-livepeer-runner` on `main` and `v*` tags. An operator then runs it with a `runners.json` like this repo's, pointed at wherever they run the container, and needs no credentials for a public package. -The image is **~25 GB** (CUDA devel, torch, TensorRT, ONNX Runtime), which is more than a GitHub-hosted runner has free out of the box, so [build.yml](.github/workflows/build.yml) reclaims disk before building and skips the build on pull requests. Building locally is `docker compose build`. +The image is **~15 GB** (torch, TensorRT, ONNX Runtime), which is still close enough to what a GitHub-hosted runner has free that [build.yml](.github/workflows/build.yml) reclaims disk before building and skips the build on pull requests. Building locally is `docker compose build`. To publish to Docker Hub as well, set the repository variable `DOCKERHUB_NAMESPACE` and the secrets `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN`. GHCR keeps working either way. @@ -119,6 +119,12 @@ uvx pre-commit run --all-files CI runs the same hooks, checks the compose file parses, and builds the image. +## License and attribution + +This repo is an **example** of how to run StreamDiffusion on the [live runner](https://github.com/livepeer/go-livepeer/blob/master/doc/live-runner.md), not a production-ready pipeline. The wrapper here (Dockerfile, [client.py](client.py), the compose files, [runners.json](runners.json)) is MIT, and CI publishing to `ghcr.io/livepeer/` is packaging convenience so an operator can pull it, not a product commitment. + +What runs inside the image is daydream's [StreamDiffusion](https://github.com/daydreamlive/StreamDiffusion), itself a fork of [cumulo-autumn/StreamDiffusion](https://github.com/cumulo-autumn/StreamDiffusion). Both are **Apache-2.0**, and this repo builds the fork pinned at `94b9b96` and **unmodified**, so redistribution is permitted and there are no changes to state under section 4(b). The fork ships no `NOTICE` file; its `LICENSE` travels in the image at `/src/LICENSE`. Model weights are downloaded from Hugging Face on first run under their own licenses and are not redistributed here. + ## Building your own Start from [**template-livepeer-runner**](https://github.com/livepeer/template-livepeer-runner), then list yours in [**runner-app-examples**](https://github.com/livepeer/runner-app-examples#external-examples). That repo also has a minimal example of each transport, mode, registration, and pricing option; the [live runner docs](https://github.com/livepeer/go-livepeer/blob/master/doc/live-runner.md) are the reference.