Skip to content

Commit 9258bbf

Browse files
committed
feat(vllm-metal): include python
Signed-off-by: Dorin Geman <dorin.geman@docker.com>
1 parent 8626ed7 commit 9258bbf

3 files changed

Lines changed: 43 additions & 115 deletions

File tree

Makefile

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ docker-run-impl:
144144
DEBUG="${DEBUG}" \
145145
scripts/docker-run.sh
146146

147-
# vllm-metal (macOS ARM64 only, requires Python 3.12 for wheel compatibility)
147+
# vllm-metal (macOS ARM64 only)
148+
# The tarball is self-contained: includes a standalone Python 3.12 + all packages.
148149
VLLM_METAL_RELEASE ?= v0.1.0-20260126-121650
149150
VLLM_METAL_INSTALL_DIR := $(HOME)/.docker/model-runner/vllm-metal
150151
VLLM_METAL_TARBALL := vllm-metal-macos-arm64-$(VLLM_METAL_RELEASE).tar.gz
@@ -169,26 +170,9 @@ vllm-metal-install:
169170
exit 1; \
170171
fi; \
171172
echo "Installing vllm-metal to $(VLLM_METAL_INSTALL_DIR)..."; \
172-
PYTHON_BIN=""; \
173-
if command -v python3.12 >/dev/null 2>&1; then \
174-
PYTHON_BIN="python3.12"; \
175-
elif command -v python3 >/dev/null 2>&1; then \
176-
version=$$(python3 --version 2>&1 | grep -oE '[0-9]+\.[0-9]+'); \
177-
if [ "$$version" = "3.12" ]; then \
178-
PYTHON_BIN="python3"; \
179-
fi; \
180-
fi; \
181-
if [ -z "$$PYTHON_BIN" ]; then \
182-
echo "Error: Python 3.12 required (vllm-metal wheel is built for cp312)"; \
183-
echo "Install with: brew install python@3.12"; \
184-
exit 1; \
185-
fi; \
186-
echo "Using Python 3.12 from $$(which $$PYTHON_BIN)"; \
187173
rm -rf "$(VLLM_METAL_INSTALL_DIR)"; \
188-
$$PYTHON_BIN -m venv "$(VLLM_METAL_INSTALL_DIR)"; \
189-
SITE_PACKAGES="$(VLLM_METAL_INSTALL_DIR)/lib/python3.12/site-packages"; \
190-
mkdir -p "$$SITE_PACKAGES"; \
191-
tar -xzf "$(VLLM_METAL_TARBALL)" -C "$$SITE_PACKAGES"; \
174+
mkdir -p "$(VLLM_METAL_INSTALL_DIR)"; \
175+
tar -xzf "$(VLLM_METAL_TARBALL)" -C "$(VLLM_METAL_INSTALL_DIR)"; \
192176
echo "$(VLLM_METAL_RELEASE)" > "$$VERSION_FILE"; \
193177
echo "vllm-metal $(VLLM_METAL_RELEASE) installed successfully!"
194178

@@ -266,10 +250,10 @@ help:
266250
@echo " make run LOCAL_LLAMA=1"
267251
@echo " make docker-run LLAMA_ARGS=\"--verbose --jinja -ngl 999 --threads 4 --ctx-size 2048\""
268252
@echo ""
269-
@echo "vllm-metal (macOS ARM64 only, requires Python 3.12):"
253+
@echo "vllm-metal (macOS ARM64 only):"
270254
@echo " 1. Auto-pull from Docker Hub (clean dev installs first: make vllm-metal-clean):"
271255
@echo " make run"
272256
@echo " 2. Build and install from tarball:"
273257
@echo " make vllm-metal-build && make vllm-metal-install && make run"
274-
@echo " 3. Install from local source (for development):"
258+
@echo " 3. Install from local source (for development, requires Python 3.12):"
275259
@echo " make vllm-metal-dev VLLM_METAL_PATH=../vllm-metal && make run"

pkg/inference/backends/vllmmetal/vllmmetal.go

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type vllmMetal struct {
4242
modelManager *models.Manager
4343
// serverLog is the logger to use for the vllm-metal server process.
4444
serverLog logging.Logger
45-
// pythonPath is the path to the python3 binary in the venv.
45+
// pythonPath is the path to the bundled python3 binary.
4646
pythonPath string
4747
// customPythonPath is an optional custom path to a python3 binary.
4848
customPythonPath string
@@ -127,54 +127,9 @@ func (v *vllmMetal) Install(ctx context.Context, httpClient *http.Client) error
127127
return v.verifyInstallation(ctx)
128128
}
129129

130-
// findSystemPython finds Python 3.12 interpreter on the system.
131-
// Python 3.12 is required because the vllm-metal wheel is built for cp312.
132-
func (v *vllmMetal) findSystemPython(ctx context.Context) (string, string, error) {
133-
// Try python3.12 first
134-
for _, pyCmd := range []string{"python3.12", "python3"} {
135-
pythonPath, err := exec.LookPath(pyCmd)
136-
if err != nil {
137-
continue
138-
}
139-
140-
// Verify version is exactly 3.12
141-
out, err := exec.CommandContext(ctx, pythonPath, "--version").Output()
142-
if err != nil {
143-
continue
144-
}
145-
146-
versionStr := strings.TrimPrefix(strings.TrimSpace(string(out)), "Python ")
147-
parts := strings.Split(versionStr, ".")
148-
if len(parts) < 2 {
149-
continue
150-
}
151-
152-
major, err := strconv.Atoi(parts[0])
153-
if err != nil {
154-
continue
155-
}
156-
minor, err := strconv.Atoi(parts[1])
157-
if err != nil {
158-
continue
159-
}
160-
161-
// Must be exactly Python 3.12 for wheel compatibility
162-
if major == 3 && minor == 12 {
163-
return pythonPath, "3.12", nil
164-
}
165-
}
166-
167-
return "", "", fmt.Errorf("python 3.12 required (vllm-metal wheel is built for cp312); install with: brew install python@3.12")
168-
}
169-
170130
// downloadAndExtract downloads the vllm-metal image from Docker Hub and extracts it.
131+
// The image contains a self-contained Python installation with all packages pre-installed.
171132
func (v *vllmMetal) downloadAndExtract(ctx context.Context, _ *http.Client) error {
172-
pythonPath, pyVersion, err := v.findSystemPython(ctx)
173-
if err != nil {
174-
return err
175-
}
176-
177-
v.log.Infof("Using system Python %s from %s", pyVersion, pythonPath)
178133
v.log.Infof("Downloading vllm-metal %s from Docker Hub...", vllmMetalVersion)
179134

180135
// Create temp directory for download
@@ -196,7 +151,6 @@ func (v *vllmMetal) downloadAndExtract(ctx context.Context, _ *http.Client) erro
196151
return fmt.Errorf("failed to extract image: %w", err)
197152
}
198153

199-
v.log.Infof("Creating Python venv at %s...", v.installDir)
200154
if err := os.MkdirAll(filepath.Dir(v.installDir), 0755); err != nil {
201155
return fmt.Errorf("failed to create parent dir: %w", err)
202156
}
@@ -206,18 +160,13 @@ func (v *vllmMetal) downloadAndExtract(ctx context.Context, _ *http.Client) erro
206160
return fmt.Errorf("failed to remove existing install dir: %w", err)
207161
}
208162

209-
venvCmd := exec.CommandContext(ctx, pythonPath, "-m", "venv", v.installDir)
210-
if out, err := venvCmd.CombinedOutput(); err != nil {
211-
return fmt.Errorf("failed to create venv: %w\nOutput: %s", err, string(out))
212-
}
213-
214-
v.log.Infof("Extracting packages...")
215-
sitePackagesDir := filepath.Join(v.installDir, "lib", fmt.Sprintf("python%s", pyVersion), "site-packages")
163+
v.log.Infof("Extracting self-contained Python environment...")
216164

217-
// Copy extracted files to site-packages (the image contains /vllm-metal/*)
165+
// Copy the extracted self-contained Python installation directly to install dir
166+
// (the image contains /vllm-metal/ with bin/, lib/, etc.)
218167
vllmMetalDir := filepath.Join(extractDir, "vllm-metal")
219-
if err := copyDir(vllmMetalDir, sitePackagesDir); err != nil {
220-
return fmt.Errorf("failed to copy to site-packages: %w", err)
168+
if err := copyDir(vllmMetalDir, v.installDir); err != nil {
169+
return fmt.Errorf("failed to copy to install dir: %w", err)
221170
}
222171

223172
v.log.Infof("vllm-metal %s installed successfully", vllmMetalVersion)
Lines changed: 30 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
#!/bin/bash
22
# Build script for vllm-metal macOS tarball distribution
3-
# Creates a tarball containing Python site-packages for vllm-metal and dependencies
3+
# Creates a self-contained tarball with a standalone Python 3.12 + vllm-metal packages.
4+
# The result can be extracted anywhere and run without any system Python dependency.
45
#
56
# Usage: ./scripts/build-vllm-metal-tarball.sh <VLLM_METAL_RELEASE> <TARBALL>
67
# VLLM_METAL_RELEASE - vllm-metal release tag (required)
78
# TARBALL - Output tarball path (required)
89
#
910
# Requirements:
1011
# - macOS with Apple Silicon (ARM64)
11-
# - Python 3.12+ installed (standard on macOS 14+, or via Homebrew)
1212
# - uv (will be installed if missing)
1313

1414
set -e
1515

1616
VLLM_METAL_RELEASE="${1:?Usage: $0 <VLLM_METAL_RELEASE> <TARBALL>}"
1717
TARBALL_ARG="${2:?Usage: $0 <VLLM_METAL_RELEASE> <TARBALL>}"
1818
WORK_DIR=$(mktemp -d)
19-
VENV_DIR="$WORK_DIR/venv"
2019

2120
# Convert tarball path to absolute before we cd elsewhere
2221
TARBALL="$(cd "$(dirname "$TARBALL_ARG")" && pwd)/$(basename "$TARBALL_ARG")"
@@ -37,56 +36,52 @@ if ! command -v uv &> /dev/null; then
3736
export PATH="$HOME/.local/bin:$PATH"
3837
fi
3938

40-
# Python 3.12 required (vllm-metal wheel is built for cp312)
41-
if command -v python3.12 &> /dev/null; then
42-
PYTHON_BIN="python3.12"
43-
elif command -v python3 &> /dev/null && [ "$(python3 --version 2>&1 | grep -oE '[0-9]+\.[0-9]+')" = "3.12" ]; then
44-
PYTHON_BIN="python3"
45-
else
46-
echo "Error: Python 3.12 is required (the vllm-metal wheel is built for cp312)"
47-
echo "Install with: brew install python@3.12"
48-
exit 1
49-
fi
39+
# Install standalone Python 3.12 via uv (from python-build-standalone, relocatable)
40+
echo "Installing standalone Python 3.12 via uv..."
41+
uv python install 3.12
5042

51-
PYTHON_VERSION=$($PYTHON_BIN --version 2>&1 | grep -oE '[0-9]+\.[0-9]+')
52-
echo "Using Python $PYTHON_VERSION from: $(which $PYTHON_BIN)"
43+
PYTHON_BIN=$(uv python find 3.12)
44+
PYTHON_PREFIX=$(cd "$(dirname "$PYTHON_BIN")/.." && pwd)
45+
echo "Using standalone Python from: $PYTHON_PREFIX"
5346

54-
echo "Creating Python venv..."
55-
uv venv "$VENV_DIR" --python "$PYTHON_BIN"
47+
# Copy the standalone Python to our work area
48+
PYTHON_DIR="$WORK_DIR/python"
49+
cp -Rp "$PYTHON_PREFIX" "$PYTHON_DIR"
5650

57-
export VIRTUAL_ENV="$VENV_DIR"
58-
export PATH="$VENV_DIR/bin:$PATH"
51+
# Remove the externally-managed marker so we can install packages into it
52+
rm -f "$PYTHON_DIR/lib/python3.12/EXTERNALLY-MANAGED"
5953

6054
echo "Installing vLLM $VLLM_VERSION from source (CPU requirements)..."
6155
cd "$WORK_DIR"
6256
curl -fsSL -O "https://github.com/vllm-project/vllm/releases/download/v$VLLM_VERSION/vllm-$VLLM_VERSION.tar.gz"
6357
tar xf "vllm-$VLLM_VERSION.tar.gz"
6458
cd "vllm-$VLLM_VERSION"
65-
uv pip install -r requirements/cpu.txt --index-strategy unsafe-best-match
66-
uv pip install .
59+
uv pip install --python "$PYTHON_DIR/bin/python3" --system -r requirements/cpu.txt --index-strategy unsafe-best-match
60+
uv pip install --python "$PYTHON_DIR/bin/python3" --system .
6761
cd "$WORK_DIR"
6862
rm -rf "vllm-$VLLM_VERSION" "vllm-$VLLM_VERSION.tar.gz"
6963

7064
echo "Installing vllm-metal from pre-built wheel..."
7165
curl -fsSL -O "$VLLM_METAL_WHEEL_URL"
72-
uv pip install vllm_metal-*.whl
66+
uv pip install --python "$PYTHON_DIR/bin/python3" --system vllm_metal-*.whl
7367
rm -f vllm_metal-*.whl
7468

75-
echo "Packaging site-packages..."
76-
SITE_PACKAGES_DIR="$VENV_DIR/lib/python$PYTHON_VERSION/site-packages"
77-
if [ ! -d "$SITE_PACKAGES_DIR" ]; then
78-
echo "Error: site-packages directory not found at $SITE_PACKAGES_DIR"
79-
exit 1
80-
fi
69+
# Strip files not needed at runtime to reduce tarball size
70+
echo "Stripping unnecessary files..."
71+
rm -rf "$PYTHON_DIR/include"
72+
rm -rf "$PYTHON_DIR/share"
73+
PYLIB="$PYTHON_DIR/lib/python3.12"
74+
rm -rf "$PYLIB/test" "$PYLIB/tests"
75+
rm -rf "$PYLIB/idlelib" "$PYLIB/idle_test"
76+
rm -rf "$PYLIB/tkinter" "$PYLIB/turtledemo"
77+
rm -rf "$PYLIB/ensurepip"
78+
find "$PYTHON_DIR" -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
8179

82-
tar -czf "$TARBALL" -C "$SITE_PACKAGES_DIR" .
80+
echo "Packaging standalone Python with vllm-metal..."
81+
tar -czf "$TARBALL" -C "$PYTHON_DIR" .
8382

8483
SIZE=$(du -h "$TARBALL" | cut -f1)
8584
echo "Created: $TARBALL ($SIZE)"
8685
echo ""
87-
echo "To use this tarball:"
88-
echo " 1. Upload to GitHub releases"
89-
echo " 2. Model-runner will auto-download on first use"
90-
echo " 3. Or manually extract for testing:"
91-
echo " python3.12 -m venv ~/.model-runner/vllm-metal"
92-
echo " tar -xzf $TARBALL -C ~/.model-runner/vllm-metal/lib/python$PYTHON_VERSION/site-packages/"
86+
echo "This tarball is fully self-contained (includes Python 3.12 + all packages)."
87+
echo "To use: extract to a directory and run bin/python3 -m vllm_metal.server"

0 commit comments

Comments
 (0)