Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
630e8c7
feat(diffusers): implement diffusers backend for image generation
ilopezluna Jan 14, 2026
1993372
feat(diffusers): add support for DDUF (Diffusers Unified Format) file…
ilopezluna Jan 14, 2026
c886d00
feat(dduf): implement DDUF format support and enhance model loading
ilopezluna Jan 15, 2026
3f7394e
feat(dduf): calculate total size of files and add human-readable size…
ilopezluna Jan 15, 2026
4c22678
feat(platform): restrict Diffusers support to Linux only until macOS …
ilopezluna Jan 15, 2026
c89429a
feat(diffusers): add support for DDUF file type handling in repositor…
ilopezluna Jan 15, 2026
a749093
feat(diffusers): sanitize log output for Diffusers arguments
ilopezluna Jan 15, 2026
e916b40
feat(docker): streamline Python server code copying in Dockerfile
ilopezluna Jan 15, 2026
d54ea4a
feat(docker): specify exact versions for Python packages in Dockerfile
ilopezluna Jan 15, 2026
2daa296
feat(model): add DDUF file support to packaging command and documenta…
ilopezluna Jan 15, 2026
cd090d5
Update pkg/distribution/internal/bundle/unpack.go
ilopezluna Jan 15, 2026
400f1a1
refactor(dduf): replace formatDDUFSize with formatSize and clean up u…
ilopezluna Jan 15, 2026
f62e4e5
feat(docker): add support for building and running Diffusers Docker i…
ilopezluna Jan 15, 2026
09d7117
Merge remote-tracking branch 'origin/add-stable-diffusion-backend' in…
ilopezluna Jan 15, 2026
a4f76e9
feat(client): add support for Diffusers format in GetSupportedFormats…
ilopezluna Jan 15, 2026
237b9dd
feat(docker): enhance GPU support for additional Docker image variants
ilopezluna Jan 15, 2026
7d16258
Merge branch 'main' into add-stable-diffusion-backend
ilopezluna Jan 15, 2026
200f84b
feat: add support for image-generation mode in backend operations
ilopezluna Jan 15, 2026
3562f8a
feat(loader): support fallback for image-generation mode in runner co…
ilopezluna Jan 16, 2026
cf31231
feat(diffusers): initialize Diffusers backend in main.go
ilopezluna Jan 16, 2026
587cdad
feat(diffusers): add error transformation for Python output and enhan…
ilopezluna Jan 16, 2026
78d8bcd
fix(scripts/docker-run): conditionally add nvidia runtime flags
doringeman Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ ENV MODEL_RUNNER_PORT=12434
ENV LLAMA_SERVER_PATH=/app/bin
ENV HOME=/home/modelrunner
ENV MODELS_PATH=/models
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed $LD_LIBRARY_PATH because I didn't find any usage. Please let me know if I'm missing anything here 🙏

ENV LD_LIBRARY_PATH=/app/lib:$LD_LIBRARY_PATH
ENV LD_LIBRARY_PATH=/app/lib

# Label the image so that it's hidden on cloud engines.
LABEL com.docker.desktop.service="model-runner"
Expand Down Expand Up @@ -144,6 +144,60 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | sh \
&& ~/.local/bin/uv pip install --python /opt/sglang-env/bin/python "sglang==${SGLANG_VERSION}"

RUN /opt/sglang-env/bin/python -c "import sglang; print(sglang.__version__)" > /opt/sglang-env/version

# --- Diffusers variant ---
FROM llamacpp AS diffusers
Comment thread
ilopezluna marked this conversation as resolved.

# Python package versions for reproducible builds
ARG DIFFUSERS_VERSION=0.36.0
ARG TORCH_VERSION=2.9.1
ARG TRANSFORMERS_VERSION=4.57.5
ARG ACCELERATE_VERSION=1.3.0
ARG SAFETENSORS_VERSION=0.5.2
ARG HUGGINGFACE_HUB_VERSION=0.34.0
ARG BITSANDBYTES_VERSION=0.45.4
ARG FASTAPI_VERSION=0.115.12
ARG UVICORN_VERSION=0.34.1
ARG PILLOW_VERSION=11.2.1

USER root

RUN apt update && apt install -y \
python3 python3-venv python3-dev \
curl ca-certificates build-essential \
&& rm -rf /var/lib/apt/lists/*

RUN mkdir -p /opt/diffusers-env && chown -R modelrunner:modelrunner /opt/diffusers-env

USER modelrunner

# Install uv and diffusers as modelrunner user
RUN curl -LsSf https://astral.sh/uv/install.sh | sh \
&& ~/.local/bin/uv venv --python /usr/bin/python3 /opt/diffusers-env \
&& ~/.local/bin/uv pip install --python /opt/diffusers-env/bin/python \
"diffusers==${DIFFUSERS_VERSION}" \
"torch==${TORCH_VERSION}" \
"transformers==${TRANSFORMERS_VERSION}" \
"accelerate==${ACCELERATE_VERSION}" \
"safetensors==${SAFETENSORS_VERSION}" \
"huggingface_hub==${HUGGINGFACE_HUB_VERSION}" \
"bitsandbytes==${BITSANDBYTES_VERSION}" \
"fastapi==${FASTAPI_VERSION}" \
"uvicorn[standard]==${UVICORN_VERSION}" \
"pillow==${PILLOW_VERSION}"

# Copy Python server code
USER root
COPY python/diffusers_server /tmp/diffusers_server/
RUN PYTHON_SITE_PACKAGES=$(/opt/diffusers-env/bin/python -c "import site; print(site.getsitepackages()[0])") && \
mkdir -p "$PYTHON_SITE_PACKAGES/diffusers_server" && \
cp -r /tmp/diffusers_server/* "$PYTHON_SITE_PACKAGES/diffusers_server/" && \
chown -R modelrunner:modelrunner "$PYTHON_SITE_PACKAGES/diffusers_server/" && \
rm -rf /tmp/diffusers_server
USER modelrunner

RUN /opt/diffusers-env/bin/python -c "import diffusers; print(diffusers.__version__)" > /opt/diffusers-env/version

FROM llamacpp AS final-llamacpp
# Copy the built binary from builder
COPY --from=builder /app/model-runner /app/model-runner
Expand All @@ -155,3 +209,7 @@ COPY --from=builder /app/model-runner /app/model-runner
FROM sglang AS final-sglang
# Copy the built binary from builder-sglang (without vLLM)
COPY --from=builder-sglang /app/model-runner /app/model-runner

FROM diffusers AS final-diffusers
# Copy the built binary from builder (with diffusers support)
COPY --from=builder /app/model-runner /app/model-runner
40 changes: 32 additions & 8 deletions cmd/cli/commands/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,43 @@ func newPackagedCmd() *cobra.Command {
var opts packageOptions

c := &cobra.Command{
Use: "package (--gguf <path> | --safetensors-dir <path> | --from <model>) [--license <path>...] [--mmproj <path>] [--context-size <tokens>] [--push] MODEL",
Short: "Package a GGUF file, Safetensors directory, or existing model into a Docker model OCI artifact.",
Long: "Package a GGUF file, Safetensors directory, or existing model into a Docker model OCI artifact, with optional licenses and multimodal projector. The package is sent to the model-runner, unless --push is specified.\n" +
Use: "package (--gguf <path> | --safetensors-dir <path> | --dduf <path> | --from <model>) [--license <path>...] [--mmproj <path>] [--context-size <tokens>] [--push] MODEL",
Short: "Package a GGUF file, Safetensors directory, DDUF file, or existing model into a Docker model OCI artifact.",
Long: "Package a GGUF file, Safetensors directory, DDUF file, or existing model into a Docker model OCI artifact, with optional licenses and multimodal projector. The package is sent to the model-runner, unless --push is specified.\n" +
"When packaging a sharded GGUF model, --gguf should point to the first shard. All shard files should be siblings and should include the index in the file name (e.g. model-00001-of-00015.gguf).\n" +
"When packaging a Safetensors model, --safetensors-dir should point to a directory containing .safetensors files and config files (*.json, merges.txt). All files will be auto-discovered and config files will be packaged into a tar archive.\n" +
"When packaging a DDUF file (Diffusers Unified Format), --dduf should point to a .dduf archive file.\n" +
"When packaging from an existing model using --from, you can modify properties like context size to create a variant of the original model.\n" +
"For multimodal models, use --mmproj to include a multimodal projector file.",
Args: func(cmd *cobra.Command, args []string) error {
if err := requireExactArgs(1, "package", "MODEL")(cmd, args); err != nil {
return err
}

// Validate that exactly one of --gguf, --safetensors-dir, or --from is provided (mutually exclusive)
// Validate that exactly one of --gguf, --safetensors-dir, --dduf, or --from is provided (mutually exclusive)
sourcesProvided := 0
if opts.ggufPath != "" {
sourcesProvided++
}
if opts.safetensorsDir != "" {
sourcesProvided++
}
if opts.ddufPath != "" {
sourcesProvided++
}
if opts.fromModel != "" {
sourcesProvided++
}

if sourcesProvided == 0 {
return fmt.Errorf(
"One of --gguf, --safetensors-dir, or --from is required.\n\n" +
"One of --gguf, --safetensors-dir, --dduf, or --from is required.\n\n" +
"See 'docker model package --help' for more information",
)
}
if sourcesProvided > 1 {
return fmt.Errorf(
"Cannot specify more than one of --gguf, --safetensors-dir, or --from. Please use only one source.\n\n" +
"Cannot specify more than one of --gguf, --safetensors-dir, --dduf, or --from. Please use only one source.\n\n" +
"See 'docker model package --help' for more information",
)
}
Expand Down Expand Up @@ -141,6 +145,15 @@ func newPackagedCmd() *cobra.Command {
}
}

// Validate DDUF path if provided
if opts.ddufPath != "" {
var err error
opts.ddufPath, err = validateAbsolutePath(opts.ddufPath, "DDUF")
if err != nil {
return err
}
}

// Validate dir-tar paths are relative (not absolute)
for _, dirPath := range opts.dirTarPaths {
if filepath.IsAbs(dirPath) {
Expand All @@ -167,6 +180,7 @@ func newPackagedCmd() *cobra.Command {

c.Flags().StringVar(&opts.ggufPath, "gguf", "", "absolute path to gguf file")
c.Flags().StringVar(&opts.safetensorsDir, "safetensors-dir", "", "absolute path to directory containing safetensors files and config")
c.Flags().StringVar(&opts.ddufPath, "dduf", "", "absolute path to DDUF archive file (Diffusers Unified Format)")
c.Flags().StringVar(&opts.fromModel, "from", "", "reference to an existing model to repackage")
c.Flags().StringVar(&opts.chatTemplatePath, "chat-template", "", "absolute path to chat template file (must be Jinja format)")
c.Flags().StringArrayVarP(&opts.licensePaths, "license", "l", nil, "absolute path to a license file")
Expand All @@ -182,6 +196,7 @@ type packageOptions struct {
contextSize uint64
ggufPath string
safetensorsDir string
ddufPath string
fromModel string
licensePaths []string
dirTarPaths []string
Expand All @@ -197,7 +212,7 @@ type builderInitResult struct {
cleanupFunc func() // Optional cleanup function for temporary files
}

// initializeBuilder creates a package builder from GGUF, Safetensors, or existing model
// initializeBuilder creates a package builder from GGUF, Safetensors, DDUF, or existing model
func initializeBuilder(cmd *cobra.Command, opts packageOptions) (*builderInitResult, error) {
result := &builderInitResult{}

Expand Down Expand Up @@ -246,7 +261,14 @@ func initializeBuilder(cmd *cobra.Command, opts packageOptions) (*builderInitRes
return nil, fmt.Errorf("add gguf file: %w", err)
}
result.builder = pkg
} else {
} else if opts.ddufPath != "" {
cmd.PrintErrf("Adding DDUF file from %q\n", opts.ddufPath)
pkg, err := builder.FromPath(opts.ddufPath)
if err != nil {
return nil, fmt.Errorf("add dduf file: %w", err)
}
result.builder = pkg
} else if opts.safetensorsDir != "" {
// Safetensors model from directory
cmd.PrintErrf("Scanning directory %q for safetensors model...\n", opts.safetensorsDir)
safetensorsPaths, tempConfigArchive, err := packaging.PackageFromDirectory(opts.safetensorsDir)
Expand Down Expand Up @@ -276,6 +298,8 @@ func initializeBuilder(cmd *cobra.Command, opts packageOptions) (*builderInitRes
}
}
result.builder = pkg
} else {
return nil, fmt.Errorf("no model source specified")
}

return result, nil
Expand Down
16 changes: 13 additions & 3 deletions cmd/cli/docs/reference/docker_model_package.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
command: docker model package
short: |
Package a GGUF file, Safetensors directory, or existing model into a Docker model OCI artifact.
Package a GGUF file, Safetensors directory, DDUF file, or existing model into a Docker model OCI artifact.
long: |-
Package a GGUF file, Safetensors directory, or existing model into a Docker model OCI artifact, with optional licenses and multimodal projector. The package is sent to the model-runner, unless --push is specified.
Package a GGUF file, Safetensors directory, DDUF file, or existing model into a Docker model OCI artifact, with optional licenses and multimodal projector. The package is sent to the model-runner, unless --push is specified.
When packaging a sharded GGUF model, --gguf should point to the first shard. All shard files should be siblings and should include the index in the file name (e.g. model-00001-of-00015.gguf).
When packaging a Safetensors model, --safetensors-dir should point to a directory containing .safetensors files and config files (*.json, merges.txt). All files will be auto-discovered and config files will be packaged into a tar archive.
When packaging a DDUF file (Diffusers Unified Format), --dduf should point to a .dduf archive file.
When packaging from an existing model using --from, you can modify properties like context size to create a variant of the original model.
For multimodal models, use --mmproj to include a multimodal projector file.
usage: docker model package (--gguf <path> | --safetensors-dir <path> | --from <model>) [--license <path>...] [--mmproj <path>] [--context-size <tokens>] [--push] MODEL
usage: docker model package (--gguf <path> | --safetensors-dir <path> | --dduf <path> | --from <model>) [--license <path>...] [--mmproj <path>] [--context-size <tokens>] [--push] MODEL
pname: docker model
plink: docker_model.yaml
options:
Expand All @@ -30,6 +31,15 @@ options:
experimentalcli: false
kubernetes: false
swarm: false
- option: dduf
value_type: string
description: absolute path to DDUF archive file (Diffusers Unified Format)
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
- option: dir-tar
value_type: stringArray
default_value: '[]'
Expand Down
52 changes: 26 additions & 26 deletions cmd/cli/docs/reference/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ Docker Model Runner

### Subcommands

| Name | Description |
|:------------------------------------------------|:------------------------------------------------------------------------------------------------|
| [`bench`](model_bench.md) | Benchmark a model's performance at different concurrency levels |
| [`df`](model_df.md) | Show Docker Model Runner disk usage |
| [`inspect`](model_inspect.md) | Display detailed information on one model |
| [`install-runner`](model_install-runner.md) | Install Docker Model Runner (Docker Engine only) |
| [`list`](model_list.md) | List the models pulled to your local environment |
| [`logs`](model_logs.md) | Fetch the Docker Model Runner logs |
| [`package`](model_package.md) | Package a GGUF file, Safetensors directory, or existing model into a Docker model OCI artifact. |
| [`ps`](model_ps.md) | List running models |
| [`pull`](model_pull.md) | Pull a model from Docker Hub or HuggingFace to your local environment |
| [`purge`](model_purge.md) | Remove all models |
| [`push`](model_push.md) | Push a model to Docker Hub |
| [`reinstall-runner`](model_reinstall-runner.md) | Reinstall Docker Model Runner (Docker Engine only) |
| [`requests`](model_requests.md) | Fetch requests+responses from Docker Model Runner |
| [`restart-runner`](model_restart-runner.md) | Restart Docker Model Runner (Docker Engine only) |
| [`rm`](model_rm.md) | Remove local models downloaded from Docker Hub |
| [`run`](model_run.md) | Run a model and interact with it using a submitted prompt or chat mode |
| [`search`](model_search.md) | Search for models on Docker Hub and HuggingFace |
| [`start-runner`](model_start-runner.md) | Start Docker Model Runner (Docker Engine only) |
| [`status`](model_status.md) | Check if the Docker Model Runner is running |
| [`stop-runner`](model_stop-runner.md) | Stop Docker Model Runner (Docker Engine only) |
| [`tag`](model_tag.md) | Tag a model |
| [`uninstall-runner`](model_uninstall-runner.md) | Uninstall Docker Model Runner (Docker Engine only) |
| [`unload`](model_unload.md) | Unload running models |
| [`version`](model_version.md) | Show the Docker Model Runner version |
| Name | Description |
|:------------------------------------------------|:-----------------------------------------------------------------------------------------------------------|
| [`bench`](model_bench.md) | Benchmark a model's performance at different concurrency levels |
| [`df`](model_df.md) | Show Docker Model Runner disk usage |
| [`inspect`](model_inspect.md) | Display detailed information on one model |
| [`install-runner`](model_install-runner.md) | Install Docker Model Runner (Docker Engine only) |
| [`list`](model_list.md) | List the models pulled to your local environment |
| [`logs`](model_logs.md) | Fetch the Docker Model Runner logs |
| [`package`](model_package.md) | Package a GGUF file, Safetensors directory, DDUF file, or existing model into a Docker model OCI artifact. |
| [`ps`](model_ps.md) | List running models |
| [`pull`](model_pull.md) | Pull a model from Docker Hub or HuggingFace to your local environment |
| [`purge`](model_purge.md) | Remove all models |
| [`push`](model_push.md) | Push a model to Docker Hub |
| [`reinstall-runner`](model_reinstall-runner.md) | Reinstall Docker Model Runner (Docker Engine only) |
| [`requests`](model_requests.md) | Fetch requests+responses from Docker Model Runner |
| [`restart-runner`](model_restart-runner.md) | Restart Docker Model Runner (Docker Engine only) |
| [`rm`](model_rm.md) | Remove local models downloaded from Docker Hub |
| [`run`](model_run.md) | Run a model and interact with it using a submitted prompt or chat mode |
| [`search`](model_search.md) | Search for models on Docker Hub and HuggingFace |
| [`start-runner`](model_start-runner.md) | Start Docker Model Runner (Docker Engine only) |
| [`status`](model_status.md) | Check if the Docker Model Runner is running |
| [`stop-runner`](model_stop-runner.md) | Stop Docker Model Runner (Docker Engine only) |
| [`tag`](model_tag.md) | Tag a model |
| [`uninstall-runner`](model_uninstall-runner.md) | Uninstall Docker Model Runner (Docker Engine only) |
| [`unload`](model_unload.md) | Unload running models |
| [`version`](model_version.md) | Show the Docker Model Runner version |



Expand Down
Loading
Loading