modelcar-maker 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelcar_maker-0.4.0/.agents/skills/dev-workflows/SKILL.md +70 -0
- modelcar_maker-0.4.0/.dockerignore +14 -0
- modelcar_maker-0.4.0/.github/workflows/build-push-main.yml +50 -0
- modelcar_maker-0.4.0/.github/workflows/release.yml +90 -0
- modelcar_maker-0.4.0/.gitignore +21 -0
- modelcar_maker-0.4.0/AGENTS.md +59 -0
- modelcar_maker-0.4.0/Containerfile +20 -0
- modelcar_maker-0.4.0/LICENSE +14 -0
- modelcar_maker-0.4.0/PKG-INFO +150 -0
- modelcar_maker-0.4.0/README.md +127 -0
- modelcar_maker-0.4.0/pyproject.toml +57 -0
- modelcar_maker-0.4.0/setup.cfg +4 -0
- modelcar_maker-0.4.0/src/modelcar_maker/__init__.py +154 -0
- modelcar_maker-0.4.0/src/modelcar_maker/__version__.py +24 -0
- modelcar_maker-0.4.0/src/modelcar_maker/cli/__init__.py +3 -0
- modelcar_maker-0.4.0/src/modelcar_maker/cli/cli.py +177 -0
- modelcar_maker-0.4.0/src/modelcar_maker/download/__init__.py +3 -0
- modelcar_maker-0.4.0/src/modelcar_maker/download/hf_download.py +35 -0
- modelcar_maker-0.4.0/src/modelcar_maker/image/__init__.py +17 -0
- modelcar_maker-0.4.0/src/modelcar_maker/image/common.py +41 -0
- modelcar_maker-0.4.0/src/modelcar_maker/image/olot.py +389 -0
- modelcar_maker-0.4.0/src/modelcar_maker/image/podman.py +188 -0
- modelcar_maker-0.4.0/src/modelcar_maker/image/template.py +29 -0
- modelcar_maker-0.4.0/src/modelcar_maker/image/types.py +57 -0
- modelcar_maker-0.4.0/src/modelcar_maker/templates/Containerfile.j2 +20 -0
- modelcar_maker-0.4.0/src/modelcar_maker/util/__init__.py +7 -0
- modelcar_maker-0.4.0/src/modelcar_maker/util/config.py +34 -0
- modelcar_maker-0.4.0/src/modelcar_maker/util/defaults.toml +17 -0
- modelcar_maker-0.4.0/src/modelcar_maker/util/helpers.py +18 -0
- modelcar_maker-0.4.0/src/modelcar_maker/util/logging.py +33 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/PKG-INFO +150 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/SOURCES.txt +47 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/dependency_links.txt +1 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/entry_points.txt +2 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/requires.txt +11 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/scm_file_list.json +42 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/scm_version.json +8 -0
- modelcar_maker-0.4.0/src/modelcar_maker.egg-info/top_level.txt +1 -0
- modelcar_maker-0.4.0/tests/conftest.py +70 -0
- modelcar_maker-0.4.0/tests/integration/test_build_real.py +178 -0
- modelcar_maker-0.4.0/tests/integration/test_cli.py +92 -0
- modelcar_maker-0.4.0/tests/unit/test_download.py +59 -0
- modelcar_maker-0.4.0/tests/unit/test_helpers.py +33 -0
- modelcar_maker-0.4.0/tests/unit/test_image_olot.py +293 -0
- modelcar_maker-0.4.0/tests/unit/test_image_podman.py +211 -0
- modelcar_maker-0.4.0/tests/unit/test_image_template.py +82 -0
- modelcar_maker-0.4.0/tests/unit/test_process.py +362 -0
- modelcar_maker-0.4.0/tmp/.gitkeep +0 -0
- modelcar_maker-0.4.0/tox.ini +85 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-workflows
|
|
3
|
+
description: Manage Python development environment setup, code formatting, linting, and testing for this project. Use when creating or modifying Python files, setting up the project, or verifying changes.
|
|
4
|
+
metadata:
|
|
5
|
+
author: modelcar-maker
|
|
6
|
+
version: "1.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Dev Workflows
|
|
10
|
+
|
|
11
|
+
## Environment Setup
|
|
12
|
+
|
|
13
|
+
Before doing any development work, ensure the virtual environment exists and dependencies are installed:
|
|
14
|
+
|
|
15
|
+
1. Create the virtual environment with Python 3.12:
|
|
16
|
+
```bash
|
|
17
|
+
uv venv -p 3.12
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. Install the project in editable mode with dev dependencies:
|
|
21
|
+
```bash
|
|
22
|
+
uv pip install -e ".[dev]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If `.venv/` is missing or Python version is wrong, start with step 1. If dependencies are missing, run step 2.
|
|
26
|
+
|
|
27
|
+
## Code Formatting
|
|
28
|
+
|
|
29
|
+
Before finishing any task that creates or modifies Python files, run the formatter:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
uv run tox -e format
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This runs isort (import sorting) and black (code formatting). Do not skip formatting even for "small" changes. Do not ask the user before running format — just do it.
|
|
36
|
+
|
|
37
|
+
## Linting
|
|
38
|
+
|
|
39
|
+
After formatting, or before committing, verify that lint passes:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv run tox -e lint
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This runs black --check, isort --check-only, flake8, and mypy. Fix any failures that arise.
|
|
46
|
+
|
|
47
|
+
## Testing
|
|
48
|
+
|
|
49
|
+
After making changes, run the test suite:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv run tox -e py312
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This runs pytest against the test suite and verifies everything passes.
|
|
56
|
+
|
|
57
|
+
## Full Verification Workflow
|
|
58
|
+
|
|
59
|
+
For a complete check before considering a task done, run all default environments:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv run tox
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This runs `py311`, `py312`, `py313`, and `lint`. Fix any failures before finishing.
|
|
66
|
+
|
|
67
|
+
## Troubleshooting
|
|
68
|
+
|
|
69
|
+
- If the formatter is not available, install dev dependencies: `uv pip install -e ".[dev]"`
|
|
70
|
+
- If formatting changes create new lint issues, fix them inline
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Build & Push (main branch)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions: {}
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v6
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: python -m pip install tox
|
|
19
|
+
- run: tox run -e py312
|
|
20
|
+
|
|
21
|
+
lint:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: actions/setup-python@v6
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
- run: python -m pip install tox
|
|
29
|
+
- run: tox run -e lint
|
|
30
|
+
|
|
31
|
+
container:
|
|
32
|
+
needs: [test, lint]
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
permissions:
|
|
35
|
+
packages: write
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: docker/login-action@v4
|
|
39
|
+
with:
|
|
40
|
+
registry: ghcr.io
|
|
41
|
+
username: ${{ github.actor }}
|
|
42
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
43
|
+
- uses: docker/setup-buildx-action@v4
|
|
44
|
+
- uses: docker/build-push-action@v7
|
|
45
|
+
with:
|
|
46
|
+
context: .
|
|
47
|
+
file: ./Containerfile
|
|
48
|
+
push: true
|
|
49
|
+
tags: ghcr.io/${{ github.repository_owner }}/modelcar-maker:main
|
|
50
|
+
provenance: false
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: Release (PyPI + GitHub Release + Container)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "*.*.*"
|
|
7
|
+
|
|
8
|
+
permissions: {}
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v6
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: python -m pip install tox
|
|
19
|
+
- run: tox run -e py312
|
|
20
|
+
|
|
21
|
+
lint:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: actions/setup-python@v6
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
- run: python -m pip install tox
|
|
29
|
+
- run: tox run -e lint
|
|
30
|
+
|
|
31
|
+
build:
|
|
32
|
+
needs: [test, lint]
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: actions/setup-python@v6
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.12"
|
|
39
|
+
- run: python -m pip install tox
|
|
40
|
+
- run: tox run -e build
|
|
41
|
+
- uses: actions/upload-artifact@v7
|
|
42
|
+
with:
|
|
43
|
+
name: dist
|
|
44
|
+
path: dist/
|
|
45
|
+
|
|
46
|
+
publish:
|
|
47
|
+
needs: [build]
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
permissions:
|
|
50
|
+
contents: write
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v4
|
|
53
|
+
- uses: actions/download-artifact@v8
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
- run: pip install --user --upgrade "packaging>=24.2" twine
|
|
58
|
+
- run: twine upload --skip-existing dist/*.whl dist/*.tar.gz
|
|
59
|
+
env:
|
|
60
|
+
TWINE_USERNAME: __token__
|
|
61
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
62
|
+
- uses: softprops/action-gh-release@v3
|
|
63
|
+
with:
|
|
64
|
+
files: |
|
|
65
|
+
dist/*.whl
|
|
66
|
+
dist/*.tar.gz
|
|
67
|
+
generate_release_notes: true
|
|
68
|
+
|
|
69
|
+
container:
|
|
70
|
+
needs: [test, lint]
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
permissions:
|
|
73
|
+
packages: write
|
|
74
|
+
steps:
|
|
75
|
+
- uses: actions/checkout@v4
|
|
76
|
+
- uses: docker/login-action@v4
|
|
77
|
+
with:
|
|
78
|
+
registry: ghcr.io
|
|
79
|
+
username: ${{ github.actor }}
|
|
80
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
81
|
+
- uses: docker/setup-buildx-action@v4
|
|
82
|
+
- uses: docker/build-push-action@v7
|
|
83
|
+
with:
|
|
84
|
+
context: .
|
|
85
|
+
file: ./Containerfile
|
|
86
|
+
push: true
|
|
87
|
+
tags: |
|
|
88
|
+
ghcr.io/${{ github.repository_owner }}/modelcar-maker:${{ github.ref_name }}
|
|
89
|
+
ghcr.io/${{ github.repository_owner }}/modelcar-maker:latest
|
|
90
|
+
provenance: false
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Python development things
|
|
2
|
+
.venv
|
|
3
|
+
.tox
|
|
4
|
+
__version__.py
|
|
5
|
+
*.pyc
|
|
6
|
+
*.egg-info
|
|
7
|
+
build
|
|
8
|
+
dist
|
|
9
|
+
*.env
|
|
10
|
+
uv.lock
|
|
11
|
+
|
|
12
|
+
# Preserve Containerfiles, even if not other files
|
|
13
|
+
models/*/*
|
|
14
|
+
!models/*/Containerfile
|
|
15
|
+
|
|
16
|
+
# working directory
|
|
17
|
+
tmp/*
|
|
18
|
+
!tmp/.gitkeep
|
|
19
|
+
|
|
20
|
+
# Keep a local config for myself
|
|
21
|
+
config.toml
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# modelcar-maker
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
A CLI tool that downloads Hugging Face models and packages them as OCI container images ("modelcars"), placing each model file in its own layer for efficient distribution.
|
|
6
|
+
|
|
7
|
+
## Key Concepts
|
|
8
|
+
|
|
9
|
+
- **Modelcar**: A minimal container image containing a downloaded Hugging Face model, tagged with `{normalized-model}-modelcar`.
|
|
10
|
+
- **Backends**:
|
|
11
|
+
- `podman`: Traditional container build using a generated Containerfile.
|
|
12
|
+
- `olot`: Uses OCI Layer On Top to stack model files as OCI layers directly, avoiding a traditional container build.
|
|
13
|
+
- **Layers per file**: Each model file becomes an individual image layer for deduplication and selective pulling.
|
|
14
|
+
|
|
15
|
+
## Modules
|
|
16
|
+
|
|
17
|
+
| Module | Description |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `cli/cli.py` | Typer CLI. `build` command accepts model, registry, backend, push/cleanup flags. |
|
|
20
|
+
| `__init__.py` | Core `process()` workflow: download -> build -> push -> cleanup. |
|
|
21
|
+
| `download/hf_download.py` | Downloads models via `huggingface_hub.snapshot_download`. Extracts commit hash from metadata. |
|
|
22
|
+
| `image/podman.py` | Podman backend: renders Containerfile, runs `podman build/push/image rm`. |
|
|
23
|
+
| `image/olot.py` | OLOT backend: pulls base image into OCI layout, adds model files as layers with `olot`, pushes with `oras-py`. |
|
|
24
|
+
| `image/template.py` | Renders `Containerfile.j2` with model files, labels, and base image. |
|
|
25
|
+
| `image/common.py` | Shared utilities: `_image()` (image ref naming), `list_model_files()`, file filtering. |
|
|
26
|
+
| `image/types.py` | Dataclasses (`BuildArgs`, `BuildResult`, `PushArgs`, `RmArgs`) and `Backend` enum. |
|
|
27
|
+
| `util/config.py` | Dynaconf settings. Loads `defaults.toml`, system/user/cwd config, env vars (`MODELCAR_MAKER_*`). |
|
|
28
|
+
| `util/helpers.py` | `normalize()` (repo ID -> safe tag/folder), `Truthy` string class. |
|
|
29
|
+
| `util/logging.py` | Logger factory with verbosity-controlled stderr handler. |
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Build and push a single model
|
|
35
|
+
modelcar-maker build meta-llama/Llama-3.2-3B-Instruct --push
|
|
36
|
+
|
|
37
|
+
# Build all default models with olot backend
|
|
38
|
+
modelcar-maker build --backend olot
|
|
39
|
+
|
|
40
|
+
# Build without pushing, clean up after
|
|
41
|
+
modelcar-maker build BAAI/bge-large-en-v1.5 --no-push --image-clean-up --model-clean-up
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
Config is layered via Dynaconf:
|
|
47
|
+
|
|
48
|
+
1. `src/modelcar_maker/util/defaults.toml` (built-in defaults)
|
|
49
|
+
2. `/usr/share/modelcar-maker/config.toml`
|
|
50
|
+
3. `/etc/modelcar-maker/config.toml`
|
|
51
|
+
4. `~/.config/modelcar-maker/config.toml`
|
|
52
|
+
5. `./config.toml` (project root)
|
|
53
|
+
6. Environment variables (`MODELCAR_MAKER_*`)
|
|
54
|
+
|
|
55
|
+
Key settings: `image.registry`, `image.repository`, `image.backend`, `image.push`, `image.cleanup`, `models.default` (list), `models.cleanup`.
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
Load the `dev-workflows` skill before creating or modifying Python files, setting up the project, or verifying changes. That skill contains the canonical instructions for environment setup, formatting, linting, and testing.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
FROM registry.access.redhat.com/ubi9/python-312:latest
|
|
2
|
+
|
|
3
|
+
WORKDIR /opt/app-root/src
|
|
4
|
+
|
|
5
|
+
RUN pip install --no-cache-dir pip-tools
|
|
6
|
+
|
|
7
|
+
COPY --chown=1001:1001 pyproject.toml ./
|
|
8
|
+
|
|
9
|
+
RUN pip-compile pyproject.toml && \
|
|
10
|
+
pip install --no-cache-dir -r requirements.txt
|
|
11
|
+
|
|
12
|
+
COPY --chown=1001:1001 ./ ./
|
|
13
|
+
|
|
14
|
+
RUN pip install --no-cache-dir .
|
|
15
|
+
|
|
16
|
+
WORKDIR /modelcar-maker
|
|
17
|
+
ENV HF_TOKEN ""
|
|
18
|
+
|
|
19
|
+
ENTRYPOINT ["modelcar-maker"]
|
|
20
|
+
CMD []
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
ISC License (ISC)
|
|
2
|
+
Copyright (c) 2025, James Harmison <jharmison@redhat.com>
|
|
3
|
+
|
|
4
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
5
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
6
|
+
and this permission notice appear in all copies.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
9
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
10
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
11
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
12
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
13
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
14
|
+
THIS SOFTWARE.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: modelcar-maker
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A tool to build modelcar images with layers per file
|
|
5
|
+
Author-email: James Harmison <jharmison@redhat.com>
|
|
6
|
+
License-Expression: ISC
|
|
7
|
+
Project-URL: Source, https://github.com/jharmison-redhat/modelcar-maker
|
|
8
|
+
Project-URL: Documentation, https://github.com/jharmison-redhat/modelcar-maker
|
|
9
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: dynaconf<3.3.0,>=3.2.13
|
|
14
|
+
Requires-Dist: typer<0.26.0,>=0.25.1
|
|
15
|
+
Requires-Dist: huggingface-hub<1.18.0,>=1.17.0
|
|
16
|
+
Requires-Dist: olot[oras-py]<0.2.0,>=0.1.17
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: tox; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest; extra == "dev"
|
|
20
|
+
Provides-Extra: podman
|
|
21
|
+
Requires-Dist: Jinja2<3.2,>=3.1.6; extra == "podman"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# modelcar-maker
|
|
25
|
+
|
|
26
|
+
Downloads Hugging Face models and packages them as minimal OCI container images with one file per layer. Designed for
|
|
27
|
+
use with KServe as [Modelcar images](https://kserve.github.io/website/docs/model-serving/storage/providers/oci).
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Requires Python 3.11+.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install modelcar-maker
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
modelcar-maker [OPTIONS] [MODEL]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Argument / Option | Description |
|
|
44
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
45
|
+
| `MODEL` | Hugging Face model repo ID (e.g., `meta-llama/Llama-3.2-3B-Instruct`). Optional if `models.default` is configured. |
|
|
46
|
+
| `--registry` | Registry for the output image. Default: `quay.io`. |
|
|
47
|
+
| `-r`, `--repository` | Repository within the registry. Default: `jharmison/models`. |
|
|
48
|
+
| `--backend` | Build backend. Default: `olot`. The `podman` backend requires extra dependencies (included via `pip install modelcar-maker[podman]`) |
|
|
49
|
+
| `--base-image` | Base OCI image. Default: `registry.access.redhat.com/ubi10/ubi-micro:10.2`. |
|
|
50
|
+
| `--arch` | Target architecture(s). Repeat for multiple. Default: `amd64`, `arm64`. |
|
|
51
|
+
| `--pull` / `--no-pull` | Pull base image if a newer version is available. Default: `--pull`. |
|
|
52
|
+
| `--push` / `--no-push` | Push the image after building. Default: `--push`. |
|
|
53
|
+
| `-a`, `--authfile` | Path to Docker/podman auth config for registry push. |
|
|
54
|
+
| `--image-clean-up` / `--no-image-clean-up` | Remove local container image after push. Default: off. |
|
|
55
|
+
| `--model-clean-up` / `--no-model-clean-up` | Remove downloaded model files after build. Default: off. |
|
|
56
|
+
| `--skip-if-exists` / `--no-skip-if-exists` | Skip if the tag already exists at the registry. Default: on. |
|
|
57
|
+
| `-v` | Increase logging verbosity. Repeat for more. |
|
|
58
|
+
| `-V` | Print version and exit. |
|
|
59
|
+
|
|
60
|
+
**Image tag format:** `{registry}/{repository}/{normalized-model}-modelcar`
|
|
61
|
+
|
|
62
|
+
The model repo ID is normalized for use as a tag: slashes become `--`, dots become `_`, and the string is lowercased.
|
|
63
|
+
For example, `meta-llama/Llama-3.2-3B-Instruct` produces tag `meta-llama--llama_3-2-3b-instruct-modelcar`.
|
|
64
|
+
|
|
65
|
+
**Examples:**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Build and push a model
|
|
69
|
+
modelcar-maker meta-llama/Llama-3.2-3B-Instruct
|
|
70
|
+
|
|
71
|
+
# Build locally without pushing
|
|
72
|
+
modelcar-maker BAAI/bge-large-en-v1.5 --no-push
|
|
73
|
+
|
|
74
|
+
# Explicit multi-arch build with cleanup
|
|
75
|
+
modelcar-maker mistralai/Mistral-7B --arch amd64 --arch arm64 --image-clean-up --model-clean-up
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
Settings are resolved in layer order (later layers override earlier ones):
|
|
81
|
+
|
|
82
|
+
1. Built-in defaults ([`defaults.toml`](src/modelcar_maker/util/defaults.toml))
|
|
83
|
+
2. `/usr/share/modelcar-maker/config.toml`
|
|
84
|
+
3. `/etc/modelcar-maker/config.toml`
|
|
85
|
+
4. `~/.config/modelcar-maker/config.toml`
|
|
86
|
+
5. `./config.toml` (current working directory)
|
|
87
|
+
6. Environment variables with prefix `MODELCAR_MAKER_`
|
|
88
|
+
|
|
89
|
+
Any setting can be overridden via environment variable by uppercasing the section and key and joining with underscores.
|
|
90
|
+
For example:
|
|
91
|
+
|
|
92
|
+
| Env Var | Overrides |
|
|
93
|
+
| ------------------------------- | ---------------- |
|
|
94
|
+
| `MODELCAR_MAKER_IMAGE_REGISTRY` | `image.registry` |
|
|
95
|
+
| `MODELCAR_MAKER_IMAGE_PUSH` | `image.push` |
|
|
96
|
+
| `MODELCAR_MAKER_MODELS_DEFAULT` | `models.default` |
|
|
97
|
+
|
|
98
|
+
**Example `config.toml`:**
|
|
99
|
+
|
|
100
|
+
```toml
|
|
101
|
+
[image]
|
|
102
|
+
registry = "quay.io"
|
|
103
|
+
repository = "myorg/models"
|
|
104
|
+
push = true
|
|
105
|
+
architectures = ["amd64"]
|
|
106
|
+
|
|
107
|
+
[models]
|
|
108
|
+
default = ["meta-llama/Llama-3.2-3B-Instruct", "BAAI/bge-large-en-v1.5"]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Setting default models allows running `modelcar-maker` with no arguments to build all listed models.
|
|
112
|
+
|
|
113
|
+
## Running as a Container
|
|
114
|
+
|
|
115
|
+
The tool is available as a container image at `ghcr.io/jharmison-redhat/modelcar-maker:latest` (versioned tags also
|
|
116
|
+
available).
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
podman run --rm ghcr.io/jharmison-redhat/modelcar-maker:latest --help
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For authenticated pushes, mount a credential file. For gated downloads, provide the `HF_TOKEN` environment variable:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
podman run --rm \
|
|
126
|
+
-v "$HOME/.docker/config.json:/config.json" \
|
|
127
|
+
-e HF_TOKEN="$HF_TOKEN" \
|
|
128
|
+
ghcr.io/jharmison-redhat/modelcar-maker:latest \
|
|
129
|
+
--authfile /config.json \
|
|
130
|
+
meta-llama/Llama-3.2-3B-Instruct
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
To persist downloaded model files across runs, mount a volume at `/modelcar-maker`:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
podman run --rm \
|
|
137
|
+
-v modelcar-cache:/modelcar-maker \
|
|
138
|
+
-v "$HOME/.docker/config.json:/config.json" \
|
|
139
|
+
-e HF_TOKEN="$HF_TOKEN" \
|
|
140
|
+
ghcr.io/jharmison-redhat/modelcar-maker:latest \
|
|
141
|
+
--authfile /config.json \
|
|
142
|
+
--skip-if-exists \
|
|
143
|
+
meta-llama/Llama-3.2-3B-Instruct
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`docker` may work but is untested.
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
ISC. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# modelcar-maker
|
|
2
|
+
|
|
3
|
+
Downloads Hugging Face models and packages them as minimal OCI container images with one file per layer. Designed for
|
|
4
|
+
use with KServe as [Modelcar images](https://kserve.github.io/website/docs/model-serving/storage/providers/oci).
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
Requires Python 3.11+.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install modelcar-maker
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
modelcar-maker [OPTIONS] [MODEL]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Argument / Option | Description |
|
|
21
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
22
|
+
| `MODEL` | Hugging Face model repo ID (e.g., `meta-llama/Llama-3.2-3B-Instruct`). Optional if `models.default` is configured. |
|
|
23
|
+
| `--registry` | Registry for the output image. Default: `quay.io`. |
|
|
24
|
+
| `-r`, `--repository` | Repository within the registry. Default: `jharmison/models`. |
|
|
25
|
+
| `--backend` | Build backend. Default: `olot`. The `podman` backend requires extra dependencies (included via `pip install modelcar-maker[podman]`) |
|
|
26
|
+
| `--base-image` | Base OCI image. Default: `registry.access.redhat.com/ubi10/ubi-micro:10.2`. |
|
|
27
|
+
| `--arch` | Target architecture(s). Repeat for multiple. Default: `amd64`, `arm64`. |
|
|
28
|
+
| `--pull` / `--no-pull` | Pull base image if a newer version is available. Default: `--pull`. |
|
|
29
|
+
| `--push` / `--no-push` | Push the image after building. Default: `--push`. |
|
|
30
|
+
| `-a`, `--authfile` | Path to Docker/podman auth config for registry push. |
|
|
31
|
+
| `--image-clean-up` / `--no-image-clean-up` | Remove local container image after push. Default: off. |
|
|
32
|
+
| `--model-clean-up` / `--no-model-clean-up` | Remove downloaded model files after build. Default: off. |
|
|
33
|
+
| `--skip-if-exists` / `--no-skip-if-exists` | Skip if the tag already exists at the registry. Default: on. |
|
|
34
|
+
| `-v` | Increase logging verbosity. Repeat for more. |
|
|
35
|
+
| `-V` | Print version and exit. |
|
|
36
|
+
|
|
37
|
+
**Image tag format:** `{registry}/{repository}/{normalized-model}-modelcar`
|
|
38
|
+
|
|
39
|
+
The model repo ID is normalized for use as a tag: slashes become `--`, dots become `_`, and the string is lowercased.
|
|
40
|
+
For example, `meta-llama/Llama-3.2-3B-Instruct` produces tag `meta-llama--llama_3-2-3b-instruct-modelcar`.
|
|
41
|
+
|
|
42
|
+
**Examples:**
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Build and push a model
|
|
46
|
+
modelcar-maker meta-llama/Llama-3.2-3B-Instruct
|
|
47
|
+
|
|
48
|
+
# Build locally without pushing
|
|
49
|
+
modelcar-maker BAAI/bge-large-en-v1.5 --no-push
|
|
50
|
+
|
|
51
|
+
# Explicit multi-arch build with cleanup
|
|
52
|
+
modelcar-maker mistralai/Mistral-7B --arch amd64 --arch arm64 --image-clean-up --model-clean-up
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
Settings are resolved in layer order (later layers override earlier ones):
|
|
58
|
+
|
|
59
|
+
1. Built-in defaults ([`defaults.toml`](src/modelcar_maker/util/defaults.toml))
|
|
60
|
+
2. `/usr/share/modelcar-maker/config.toml`
|
|
61
|
+
3. `/etc/modelcar-maker/config.toml`
|
|
62
|
+
4. `~/.config/modelcar-maker/config.toml`
|
|
63
|
+
5. `./config.toml` (current working directory)
|
|
64
|
+
6. Environment variables with prefix `MODELCAR_MAKER_`
|
|
65
|
+
|
|
66
|
+
Any setting can be overridden via environment variable by uppercasing the section and key and joining with underscores.
|
|
67
|
+
For example:
|
|
68
|
+
|
|
69
|
+
| Env Var | Overrides |
|
|
70
|
+
| ------------------------------- | ---------------- |
|
|
71
|
+
| `MODELCAR_MAKER_IMAGE_REGISTRY` | `image.registry` |
|
|
72
|
+
| `MODELCAR_MAKER_IMAGE_PUSH` | `image.push` |
|
|
73
|
+
| `MODELCAR_MAKER_MODELS_DEFAULT` | `models.default` |
|
|
74
|
+
|
|
75
|
+
**Example `config.toml`:**
|
|
76
|
+
|
|
77
|
+
```toml
|
|
78
|
+
[image]
|
|
79
|
+
registry = "quay.io"
|
|
80
|
+
repository = "myorg/models"
|
|
81
|
+
push = true
|
|
82
|
+
architectures = ["amd64"]
|
|
83
|
+
|
|
84
|
+
[models]
|
|
85
|
+
default = ["meta-llama/Llama-3.2-3B-Instruct", "BAAI/bge-large-en-v1.5"]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Setting default models allows running `modelcar-maker` with no arguments to build all listed models.
|
|
89
|
+
|
|
90
|
+
## Running as a Container
|
|
91
|
+
|
|
92
|
+
The tool is available as a container image at `ghcr.io/jharmison-redhat/modelcar-maker:latest` (versioned tags also
|
|
93
|
+
available).
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
podman run --rm ghcr.io/jharmison-redhat/modelcar-maker:latest --help
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
For authenticated pushes, mount a credential file. For gated downloads, provide the `HF_TOKEN` environment variable:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
podman run --rm \
|
|
103
|
+
-v "$HOME/.docker/config.json:/config.json" \
|
|
104
|
+
-e HF_TOKEN="$HF_TOKEN" \
|
|
105
|
+
ghcr.io/jharmison-redhat/modelcar-maker:latest \
|
|
106
|
+
--authfile /config.json \
|
|
107
|
+
meta-llama/Llama-3.2-3B-Instruct
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
To persist downloaded model files across runs, mount a volume at `/modelcar-maker`:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
podman run --rm \
|
|
114
|
+
-v modelcar-cache:/modelcar-maker \
|
|
115
|
+
-v "$HOME/.docker/config.json:/config.json" \
|
|
116
|
+
-e HF_TOKEN="$HF_TOKEN" \
|
|
117
|
+
ghcr.io/jharmison-redhat/modelcar-maker:latest \
|
|
118
|
+
--authfile /config.json \
|
|
119
|
+
--skip-if-exists \
|
|
120
|
+
meta-llama/Llama-3.2-3B-Instruct
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`docker` may work but is untested.
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
ISC. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "modelcar-maker"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
requires-python = ">=3.11"
|
|
5
|
+
authors = [{ name = "James Harmison", email = "jharmison@redhat.com" }]
|
|
6
|
+
description = """\
|
|
7
|
+
A tool to build modelcar images with layers per file\
|
|
8
|
+
"""
|
|
9
|
+
license = "ISC"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
classifiers = ["Operating System :: POSIX :: Linux"]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"dynaconf >=3.2.13,<3.3.0",
|
|
15
|
+
"typer >=0.25.1,<0.26.0",
|
|
16
|
+
"huggingface-hub >=1.17.0,<1.18.0",
|
|
17
|
+
"olot[oras-py] >=0.1.17,<0.2.0",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
dev = ["tox", "pytest"]
|
|
22
|
+
podman = ["Jinja2 >=3.1.6,<3.2"]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Source = "https://github.com/jharmison-redhat/modelcar-maker"
|
|
26
|
+
Documentation = "https://github.com/jharmison-redhat/modelcar-maker"
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
modelcar-maker = "modelcar_maker.cli:cli"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.package-data]
|
|
32
|
+
modelcar_maker = ["defaults.toml", "Containerfile.j2"]
|
|
33
|
+
|
|
34
|
+
[tool.setuptools_scm]
|
|
35
|
+
write_to = "src/modelcar_maker/__version__.py"
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["setuptools>=80", "setuptools-scm>=8"]
|
|
39
|
+
build-backend = "setuptools.build_meta"
|
|
40
|
+
|
|
41
|
+
[tool.black]
|
|
42
|
+
skip-string-normalization = false
|
|
43
|
+
line-length = 120
|
|
44
|
+
target-version = ["py311"]
|
|
45
|
+
|
|
46
|
+
[tool.isort]
|
|
47
|
+
profile = "black"
|
|
48
|
+
force_single_line = true
|
|
49
|
+
line_length = 120
|
|
50
|
+
src_paths = ["src", "tests"]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
markers = ["slow: marks tests as slow (deselect with -m 'not slow')"]
|
|
54
|
+
|
|
55
|
+
[tool.pyright]
|
|
56
|
+
venvPath = "."
|
|
57
|
+
venv = ".venv"
|