Enhance LLM configuration and installation scripts for improved flexibility
- Added new environment variables in `env.example` and `gpu-rent.vars.example` for fine-tuning LLM settings, including CUDA build options and model version pinning. - Updated `llm.md` documentation to include detailed descriptions of new configuration options and usage cases for LLM setups. - Enhanced the `provision.py` script to forward new environment variables during remote installations, improving the installation process for LLM components. - Modified the `install_llamacpp.sh` script to support conditional CUDA builds and asset URL overrides, ensuring better compatibility with various environments. - Improved logging in the installation scripts to provide clearer feedback during the setup process.
This commit is contained in:
+19
-1
@@ -120,7 +120,22 @@ Unit `gpu-rent-ollama` читает `/mnt/swarm_data/.gpu-rent-gpu.json`:
|
|||||||
|
|
||||||
На `up`: скачать GGUF → `/mnt/swarm_data/llamacpp/models` → `llama-server` + systemd. Уже скачанные крупные файлы не трогает.
|
На `up`: скачать GGUF → `/mnt/swarm_data/llamacpp/models` → `llama-server` + systemd. Уже скачанные крупные файлы не трогает.
|
||||||
|
|
||||||
**Бинарник:** у upstream нет Linux CUDA в GitHub Releases (только Windows). `install_llamacpp.sh` собирает `llama-server` из исходников (`GGML_CUDA=ON`, arch из GPU probe). Если `nvcc` недоступен — fallback на Ubuntu Vulkan/CPU asset (без Windows). Pin: `LLAMACPP_TAG=b10545`. Override: `LLAMACPP_ASSET_URL` + `LLAMACPP_SHA256`.
|
**Бинарник (без compile по умолчанию):** официальные Releases **не** дают Linux CUDA — только Windows CUDA + Ubuntu CPU/Vulkan. `install_llamacpp.sh` берёт **Ubuntu Vulkan** prebuilt (~30 MB, GPU через Vulkan). CUDA-сборка из исходников — только крайний случай (prebuilt упал) или явно `LLAMACPP_BUILD_CUDA=1` (5–15 мин, тихий лог + heartbeat).
|
||||||
|
|
||||||
|
Переменные (`.env` или `gpu-rent.vars`, пробрасываются на VM при `up`):
|
||||||
|
|
||||||
|
| Var | Зачем |
|
||||||
|
| --- | --- |
|
||||||
|
| `LLAMACPP_TAG` | pin release (`b10545`) |
|
||||||
|
| `LLAMACPP_ASSET_URL` + `LLAMACPP_SHA256` | свой архив |
|
||||||
|
| `LLAMACPP_BUILD_CUDA=1` | сразу CUDA из исходников |
|
||||||
|
| `LLAMACPP_FORCE_REINSTALL=1` | снести бинарь и поставить заново |
|
||||||
|
| `LLAMACPP_NGL` / `LLAMACPP_CTX` | override GPU layers / context |
|
||||||
|
| `LLAMACPP_HOST` / `LLAMACPP_PORT` | bind (default `127.0.0.1:8080`) |
|
||||||
|
| `LLAMACPP_EXTRA_ARGS` | доп. флаги `llama-server` |
|
||||||
|
| `OLLAMA_VERSION` / `OLLAMA_SHA256` | pin Ollama |
|
||||||
|
|
||||||
|
Готовые кейсы A–H — в `gpu-rent.vars.example`.
|
||||||
|
|
||||||
### Пресеты (меню)
|
### Пресеты (меню)
|
||||||
|
|
||||||
@@ -158,4 +173,7 @@ OLLAMA_VERSION=0.6.5
|
|||||||
OLLAMA_SHA256=<sha256 of ollama-linux-amd64.tgz>
|
OLLAMA_SHA256=<sha256 of ollama-linux-amd64.tgz>
|
||||||
LLAMACPP_TAG=b10545
|
LLAMACPP_TAG=b10545
|
||||||
# или LLAMACPP_ASSET_URL=... + LLAMACPP_SHA256=...
|
# или LLAMACPP_ASSET_URL=... + LLAMACPP_SHA256=...
|
||||||
|
# CUDA из исходников (медленно): LLAMACPP_BUILD_CUDA=1
|
||||||
|
# Переустановка бинаря: LLAMACPP_FORCE_REINSTALL=1
|
||||||
|
# VRAM: LLAMACPP_NGL=40 LLAMACPP_CTX=4096 LLAMACPP_EXTRA_ARGS=--flash-attn on
|
||||||
```
|
```
|
||||||
|
|||||||
+11
@@ -46,6 +46,17 @@ OLLAMA_LOCAL_PORT=17811
|
|||||||
LLAMACPP_LOCAL_PORT=17812
|
LLAMACPP_LOCAL_PORT=17812
|
||||||
# OLLAMA_MODELS_MANIFEST=
|
# OLLAMA_MODELS_MANIFEST=
|
||||||
# LLAMACPP_MODELS_MANIFEST=
|
# LLAMACPP_MODELS_MANIFEST=
|
||||||
|
# Pin / тонкая настройка LLM (несecреты; удобнее в gpu-rent.vars — см. кейсы A–H):
|
||||||
|
# LLAMACPP_TAG=b10545
|
||||||
|
# LLAMACPP_BUILD_CUDA=1
|
||||||
|
# LLAMACPP_FORCE_REINSTALL=1
|
||||||
|
# LLAMACPP_ASSET_URL=
|
||||||
|
# LLAMACPP_SHA256=
|
||||||
|
# LLAMACPP_NGL=40
|
||||||
|
# LLAMACPP_CTX=4096
|
||||||
|
# LLAMACPP_EXTRA_ARGS=--flash-attn on
|
||||||
|
# OLLAMA_VERSION=0.6.5
|
||||||
|
# OLLAMA_SHA256=
|
||||||
# CIVITAI_API_TOKEN=
|
# CIVITAI_API_TOKEN=
|
||||||
# CIVITAI_API_HOST=civitai.red
|
# CIVITAI_API_HOST=civitai.red
|
||||||
# Hugging Face (GGUF / gated HF URLs / capture fallback metadata):
|
# Hugging Face (GGUF / gated HF URLs / capture fallback metadata):
|
||||||
|
|||||||
+62
-10
@@ -1,7 +1,7 @@
|
|||||||
# gpu-rent.vars — локальные параметры запуска (не секреты).
|
# gpu-rent.vars — локальные параметры запуска (не секреты).
|
||||||
# Скопируй в gpu-rent.vars и правь. Файл в .gitignore.
|
# Скопируй в gpu-rent.vars и правь. Файл в .gitignore.
|
||||||
# Читают: gpu-rent.ps1 / .bat / .sh и python -m gpu_rent (после .env).
|
# Читают: gpu-rent.ps1 / .bat / .sh и python -m gpu_rent (после .env).
|
||||||
# Секреты (OS_PASSWORD, CIVITAI_*) — только в .env.
|
# Секреты (OS_PASSWORD, CIVITAI_*, HF_TOKEN) — только в .env.
|
||||||
|
|
||||||
# Если запуск без аргументов (двойной клик / .\gpu-rent.ps1):
|
# Если запуск без аргументов (двойной клик / .\gpu-rent.ps1):
|
||||||
# GPU_RENT_DEFAULT_ARGS=up --yes
|
# GPU_RENT_DEFAULT_ARGS=up --yes
|
||||||
@@ -9,24 +9,76 @@
|
|||||||
# Доп. флаги ко ВСЕМ вызовам (после твоих аргументов):
|
# Доп. флаги ко ВСЕМ вызовам (после твоих аргументов):
|
||||||
# GPU_RENT_EXTRA_ARGS=
|
# GPU_RENT_EXTRA_ARGS=
|
||||||
|
|
||||||
# Те же имена, что в .env / env.example (несекретные дефолты):
|
# ---------------------------------------------------------------------------
|
||||||
|
# Базовые (несекретные дефолты; те же имена, что в env.example)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# UPDATE_GIT=true
|
# UPDATE_GIT=true
|
||||||
# DEFAULT_SPOT=true
|
# DEFAULT_SPOT=true
|
||||||
# SCAN_POOLS=ru-6,ru-7
|
# SCAN_POOLS=ru-6,ru-7
|
||||||
# FLAVOR_PREFERENCE=4090-24,4090-48,a5000,a100-40
|
# FLAVOR_PREFERENCE=4090-24,4090-48,a5000,a100-40
|
||||||
# SWARMUI_LOCAL_PORT=17801
|
# SWARMUI_LOCAL_PORT=17801
|
||||||
# DATA_VOLUME_SIZE_GB=100
|
# DATA_VOLUME_SIZE_GB=100
|
||||||
# DEFAULT_FLAVOR_ID=
|
|
||||||
# DEFAULT_SPOT=true
|
|
||||||
# ENABLE_SWARMUI=true
|
# ENABLE_SWARMUI=true
|
||||||
# WORKLOAD=llm # то же что ENABLE_SWARMUI=false (только LLM)
|
|
||||||
# LLM_RUNTIME=none
|
|
||||||
# OLLAMA_LOCAL_PORT=17811
|
|
||||||
# LLAMACPP_LOCAL_PORT=17812
|
|
||||||
# IDLE_MINUTES=60
|
# IDLE_MINUTES=60
|
||||||
# IDLE_GRACE_MINUTES=90
|
# IDLE_GRACE_MINUTES=90
|
||||||
# LOCAL_WATCHDOG_GRACE_MINUTES=10
|
|
||||||
# NOTIFY_READY=true
|
# NOTIFY_READY=true
|
||||||
# PULL_OUTPUT=false
|
|
||||||
# Prefer auto /32 (leave unset). Spike/WARP only:
|
# Prefer auto /32 (leave unset). Spike/WARP only:
|
||||||
# GPU_RENT_SSH_CIDR=0.0.0.0/0
|
# GPU_RENT_SSH_CIDR=0.0.0.0/0
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# LLM — кейсы тонкой настройки (раскомментируй один блок)
|
||||||
|
# Подробнее: docs/llm.md
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# --- A) Быстрый default: SwarmUI + llama.cpp, Ubuntu Vulkan prebuilt ---
|
||||||
|
# LLM_RUNTIME=llamacpp
|
||||||
|
# ENABLE_SWARMUI=true
|
||||||
|
# LLAMACPP_TAG=b10545
|
||||||
|
# (GGUF — llamacpp-models.yaml; бинарь без compile)
|
||||||
|
|
||||||
|
# --- B) Только LLM, без SwarmUI (дешевле по времени bootstrap / VRAM) ---
|
||||||
|
# WORKLOAD=llm
|
||||||
|
# LLM_RUNTIME=llamacpp
|
||||||
|
# LLAMACPP_TAG=b10545
|
||||||
|
|
||||||
|
# --- C) Максимальная скорость инференса: CUDA-сборка (5–15 мин первый раз) ---
|
||||||
|
# LLM_RUNTIME=llamacpp
|
||||||
|
# LLAMACPP_TAG=b10545
|
||||||
|
# LLAMACPP_BUILD_CUDA=1
|
||||||
|
# LLAMACPP_FORCE_REINSTALL=1
|
||||||
|
# (FORCE — снести старый Vulkan/битый бинарь и переустановить)
|
||||||
|
|
||||||
|
# --- D) Свой бинарь / pin URL (supply-chain) ---
|
||||||
|
# LLM_RUNTIME=llamacpp
|
||||||
|
# LLAMACPP_ASSET_URL=https://github.com/ggml-org/llama.cpp/releases/download/b10545/llama-b10545-bin-ubuntu-vulkan-x64.tar.gz
|
||||||
|
# LLAMACPP_SHA256=<sha256 архива>
|
||||||
|
# LLAMACPP_FORCE_REINSTALL=1
|
||||||
|
|
||||||
|
# --- E) Делим 4090 со SwarmUI: меньше слоёв / короче контекст ---
|
||||||
|
# LLM_RUNTIME=llamacpp
|
||||||
|
# LLAMACPP_NGL=40
|
||||||
|
# LLAMACPP_CTX=4096
|
||||||
|
# LLAMACPP_EXTRA_ARGS=--flash-attn on
|
||||||
|
|
||||||
|
# --- F) Длинный контекст / почти весь VRAM под LLM (llm-only) ---
|
||||||
|
# WORKLOAD=llm
|
||||||
|
# LLM_RUNTIME=llamacpp
|
||||||
|
# LLAMACPP_NGL=99
|
||||||
|
# LLAMACPP_CTX=32768
|
||||||
|
# LLAMACPP_EXTRA_ARGS=--parallel 1
|
||||||
|
|
||||||
|
# --- G) Ollama вместо llama.cpp + pin версии ---
|
||||||
|
# LLM_RUNTIME=ollama
|
||||||
|
# OLLAMA_VERSION=0.6.5
|
||||||
|
# OLLAMA_SHA256=<sha256 of ollama-linux-amd64.tgz>
|
||||||
|
# OLLAMA_LOCAL_PORT=17811
|
||||||
|
|
||||||
|
# --- H) Выключить LLM (гасит unit’ы на следующем up) ---
|
||||||
|
# LLM_RUNTIME=none
|
||||||
|
|
||||||
|
# Порты туннеля (localhost):
|
||||||
|
# OLLAMA_LOCAL_PORT=17811
|
||||||
|
# LLAMACPP_LOCAL_PORT=17812
|
||||||
|
# Свой путь к манифесту GGUF/pull:
|
||||||
|
# LLAMACPP_MODELS_MANIFEST=
|
||||||
|
# OLLAMA_MODELS_MANIFEST=
|
||||||
|
|||||||
@@ -29,6 +29,32 @@ from gpu_rent.sync_files import pull_tree, push_tree
|
|||||||
Log = Callable[[str], None]
|
Log = Callable[[str], None]
|
||||||
DATA = "/mnt/swarm_data"
|
DATA = "/mnt/swarm_data"
|
||||||
|
|
||||||
|
# Forwarded to remote install_*.sh (from .env / gpu-rent.vars → os.environ).
|
||||||
|
_OLLAMA_INSTALL_ENV = ("OLLAMA_VERSION", "OLLAMA_SHA256")
|
||||||
|
_LLAMACPP_INSTALL_ENV = (
|
||||||
|
"LLAMACPP_TAG",
|
||||||
|
"LLAMACPP_ASSET_URL",
|
||||||
|
"LLAMACPP_SHA256",
|
||||||
|
"LLAMACPP_BUILD_CUDA",
|
||||||
|
"LLAMACPP_FORCE_REINSTALL",
|
||||||
|
"LLAMACPP_NGL",
|
||||||
|
"LLAMACPP_CTX",
|
||||||
|
"LLAMACPP_HOST",
|
||||||
|
"LLAMACPP_PORT",
|
||||||
|
"LLAMACPP_EXTRA_ARGS",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _remote_llm_env(cfg: Config, *keys: str) -> dict[str, str]:
|
||||||
|
import os
|
||||||
|
|
||||||
|
env: dict[str, str] = {"SWARM_USER": cfg.ssh_user}
|
||||||
|
for key in keys:
|
||||||
|
value = (os.environ.get(key) or "").strip()
|
||||||
|
if value:
|
||||||
|
env[key] = value
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
def _pkg_text(name: str) -> str:
|
def _pkg_text(name: str) -> str:
|
||||||
return files("gpu_rent.remote").joinpath(name).read_text(encoding="utf-8")
|
return files("gpu_rent.remote").joinpath(name).read_text(encoding="utf-8")
|
||||||
@@ -442,7 +468,7 @@ def provision_llm(cfg: Config, host: str, log: Log) -> None:
|
|||||||
_pkg_text("install_ollama.sh"),
|
_pkg_text("install_ollama.sh"),
|
||||||
remote_path="/tmp/gpu-rent-install_ollama.sh",
|
remote_path="/tmp/gpu-rent-install_ollama.sh",
|
||||||
timeout=900,
|
timeout=900,
|
||||||
env={"SWARM_USER": cfg.ssh_user},
|
env=_remote_llm_env(cfg, *_OLLAMA_INSTALL_ENV),
|
||||||
log=log,
|
log=log,
|
||||||
)
|
)
|
||||||
entries = parse_ollama_models(cfg.ollama_models_manifest)
|
entries = parse_ollama_models(cfg.ollama_models_manifest)
|
||||||
@@ -516,13 +542,16 @@ def provision_llm(cfg: Config, host: str, log: Log) -> None:
|
|||||||
else:
|
else:
|
||||||
log("llamacpp-models.yaml пуст — GGUF skip (положи вручную)")
|
log("llamacpp-models.yaml пуст — GGUF skip (положи вручную)")
|
||||||
log("LLM: ставим/запускаем llama.cpp server")
|
log("LLM: ставим/запускаем llama.cpp server")
|
||||||
|
import os
|
||||||
|
|
||||||
|
build_cuda = (os.environ.get("LLAMACPP_BUILD_CUDA") or "").strip() == "1"
|
||||||
run_script_sudo(
|
run_script_sudo(
|
||||||
cfg,
|
cfg,
|
||||||
host,
|
host,
|
||||||
_pkg_text("install_llamacpp.sh"),
|
_pkg_text("install_llamacpp.sh"),
|
||||||
remote_path="/tmp/gpu-rent-install_llamacpp.sh",
|
remote_path="/tmp/gpu-rent-install_llamacpp.sh",
|
||||||
timeout=1200,
|
timeout=3600 if build_cuda else 1200,
|
||||||
env={"SWARM_USER": cfg.ssh_user},
|
env=_remote_llm_env(cfg, *_LLAMACPP_INSTALL_ENV),
|
||||||
log=log,
|
log=log,
|
||||||
)
|
)
|
||||||
st = load_state()
|
st = load_state()
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Install llama-server (CUDA) for OpenAI-compatible API on loopback :8080.
|
# Install llama-server for OpenAI-compatible API on loopback :8080.
|
||||||
# Official GitHub releases ship Windows CUDA only — on Linux we build from source.
|
#
|
||||||
|
# Default: official Linux release asset (Ubuntu Vulkan — GPU without compile).
|
||||||
|
# CUDA source build only as last resort (or LLAMACPP_BUILD_CUDA=1).
|
||||||
|
# Pin: LLAMACPP_TAG=b10545 LLAMACPP_ASSET_URL=... LLAMACPP_SHA256=...
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SWARM_USER="${SWARM_USER:-ubuntu}"
|
SWARM_USER="${SWARM_USER:-ubuntu}"
|
||||||
@@ -28,8 +31,21 @@ SERVER_BIN="${BIN_DIR}/llama-server"
|
|||||||
LLAMACPP_TAG="${LLAMACPP_TAG:-}"
|
LLAMACPP_TAG="${LLAMACPP_TAG:-}"
|
||||||
LLAMACPP_ASSET_URL="${LLAMACPP_ASSET_URL:-}"
|
LLAMACPP_ASSET_URL="${LLAMACPP_ASSET_URL:-}"
|
||||||
LLAMACPP_SHA256="${LLAMACPP_SHA256:-}"
|
LLAMACPP_SHA256="${LLAMACPP_SHA256:-}"
|
||||||
|
# 1 = force CUDA compile; 0/empty = prebuilt first, build only if prebuilt fails
|
||||||
|
LLAMACPP_BUILD_CUDA="${LLAMACPP_BUILD_CUDA:-}"
|
||||||
|
LLAMACPP_FORCE_REINSTALL="${LLAMACPP_FORCE_REINSTALL:-}"
|
||||||
|
LLAMACPP_NGL="${LLAMACPP_NGL:-}"
|
||||||
|
LLAMACPP_CTX="${LLAMACPP_CTX:-}"
|
||||||
|
LLAMACPP_HOST="${LLAMACPP_HOST:-127.0.0.1}"
|
||||||
|
LLAMACPP_PORT="${LLAMACPP_PORT:-8080}"
|
||||||
|
LLAMACPP_EXTRA_ARGS="${LLAMACPP_EXTRA_ARGS:-}"
|
||||||
|
|
||||||
# Pick a Linux release asset (never Windows/macOS). Prefer ubuntu CUDA → vulkan → cpu.
|
if [[ "${LLAMACPP_FORCE_REINSTALL}" == "1" ]]; then
|
||||||
|
log "LLAMACPP_FORCE_REINSTALL=1 — удаляю старый бинарь"
|
||||||
|
rm -f "$SERVER_BIN" "$STAMP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prefer ubuntu CUDA (rare) → vulkan → cpu. Never Windows/macOS/cudart-only.
|
||||||
pick_linux_asset_url() {
|
pick_linux_asset_url() {
|
||||||
python3 -c '
|
python3 -c '
|
||||||
import json,sys
|
import json,sys
|
||||||
@@ -107,7 +123,7 @@ ensure_build_deps() {
|
|||||||
export PATH="/usr/local/cuda/bin:${PATH}"
|
export PATH="/usr/local/cuda/bin:${PATH}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
log "ставлю nvidia-cuda-toolkit (нужен nvcc для сборки)…"
|
log "ставлю nvidia-cuda-toolkit (нужен nvcc)…"
|
||||||
apt-get install -y -qq nvidia-cuda-toolkit >/dev/null
|
apt-get install -y -qq nvidia-cuda-toolkit >/dev/null
|
||||||
if command -v nvcc >/dev/null 2>&1; then
|
if command -v nvcc >/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
@@ -119,14 +135,24 @@ ensure_build_deps() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_vulkan_runtime() {
|
||||||
|
if ldconfig -p 2>/dev/null | grep -q 'libvulkan\.so'; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
log "ставлю libvulkan1 (для Ubuntu Vulkan prebuilt)…"
|
||||||
|
apt-get install -y -qq libvulkan1 mesa-vulkan-drivers >/dev/null 2>&1 || \
|
||||||
|
apt-get install -y -qq libvulkan1 >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
install_from_archive_url() {
|
install_from_archive_url() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
local tmp
|
local tmp
|
||||||
tmp="$(mktemp -d)"
|
tmp="$(mktemp -d)"
|
||||||
(
|
(
|
||||||
cd "$tmp"
|
cd "$tmp"
|
||||||
log "asset $url"
|
log "скачиваю prebuilt: $url"
|
||||||
curl -fL "$url" -o pkg.bin
|
curl -fL --progress-bar "$url" -o pkg.bin
|
||||||
if [[ -n "$LLAMACPP_SHA256" ]]; then
|
if [[ -n "$LLAMACPP_SHA256" ]]; then
|
||||||
echo "${LLAMACPP_SHA256} pkg.bin" | sha256sum -c -
|
echo "${LLAMACPP_SHA256} pkg.bin" | sha256sum -c -
|
||||||
else
|
else
|
||||||
@@ -149,58 +175,19 @@ install_from_archive_url() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
install -m 755 "$found" "$SERVER_BIN"
|
install -m 755 "$found" "$SERVER_BIN"
|
||||||
chown "${SWARM_USER}:${SWARM_USER}" "$SERVER_BIN"
|
# Shared libs next to binary (release tarballs ship .so alongside).
|
||||||
|
find out -type f \( -name '*.so' -o -name '*.so.*' \) -print0 2>/dev/null \
|
||||||
|
| while IFS= read -r -d '' so; do
|
||||||
|
install -m 755 "$so" "${BIN_DIR}/$(basename "$so")"
|
||||||
|
done
|
||||||
|
chown -R "${SWARM_USER}:${SWARM_USER}" "$BIN_DIR"
|
||||||
)
|
)
|
||||||
local rc=$?
|
local rc=$?
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
return "$rc"
|
return "$rc"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_cuda_from_source() {
|
install_linux_release() {
|
||||||
local tag="$1"
|
|
||||||
local arch
|
|
||||||
arch="$(cuda_architectures)"
|
|
||||||
log "собираю llama-server CUDA из исходников (tag=${tag}, arch=${arch})…"
|
|
||||||
if ! ensure_build_deps; then
|
|
||||||
log "нет nvcc — CUDA-сборку пропускаем"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
log "nvcc $(nvcc --version 2>/dev/null | tail -n1 || echo '?')"
|
|
||||||
|
|
||||||
mkdir -p "$SRC_DIR"
|
|
||||||
if [[ -d "${SRC_DIR}/.git" ]]; then
|
|
||||||
git -C "$SRC_DIR" fetch --depth 1 origin tag "$tag" 2>/dev/null || true
|
|
||||||
if ! git -C "$SRC_DIR" checkout -f "$tag" 2>/dev/null; then
|
|
||||||
rm -rf "$SRC_DIR"
|
|
||||||
git clone --depth 1 --branch "$tag" "$REPO" "$SRC_DIR"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
rm -rf "$SRC_DIR"
|
|
||||||
git clone --depth 1 --branch "$tag" "$REPO" "$SRC_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmake -S "$SRC_DIR" -B "${SRC_DIR}/build" \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DGGML_CUDA=ON \
|
|
||||||
-DCMAKE_CUDA_ARCHITECTURES="${arch}" \
|
|
||||||
-DLLAMA_CURL=ON \
|
|
||||||
-DLLAMA_BUILD_SERVER=ON
|
|
||||||
cmake --build "${SRC_DIR}/build" -j"$(nproc)" --target llama-server
|
|
||||||
|
|
||||||
local built="${SRC_DIR}/build/bin/llama-server"
|
|
||||||
if [[ ! -x "$built" ]]; then
|
|
||||||
log "сборка не дала ${built}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
install -m 755 "$built" "$SERVER_BIN"
|
|
||||||
chown "${SWARM_USER}:${SWARM_USER}" "$SERVER_BIN"
|
|
||||||
echo "cuda:${tag}:${arch}" >"$STAMP"
|
|
||||||
chown "${SWARM_USER}:${SWARM_USER}" "$STAMP"
|
|
||||||
log "CUDA binary → ${SERVER_BIN}"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
install_linux_release_fallback() {
|
|
||||||
local tag="$1"
|
local tag="$1"
|
||||||
local api url
|
local api url
|
||||||
api="${API_BASE}/releases/tags/${tag}"
|
api="${API_BASE}/releases/tags/${tag}"
|
||||||
@@ -210,36 +197,134 @@ install_linux_release_fallback() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [[ "$url" == *vulkan* ]]; then
|
if [[ "$url" == *vulkan* ]]; then
|
||||||
log "WARN: официального Linux CUDA нет — беру Ubuntu Vulkan prebuilt"
|
log "беру Ubuntu Vulkan prebuilt (GPU без compile; CUDA-сборка — LLAMACPP_BUILD_CUDA=1)"
|
||||||
elif [[ "$url" != *cuda* ]]; then
|
ensure_vulkan_runtime
|
||||||
log "WARN: беру Linux prebuilt без CUDA (CPU) — лучше собрать с nvcc"
|
elif [[ "$url" == *cuda* ]]; then
|
||||||
|
log "беру Linux CUDA prebuilt"
|
||||||
|
else
|
||||||
|
log "WARN: Linux prebuilt без GPU backend (CPU) — ${url##*/}"
|
||||||
fi
|
fi
|
||||||
install_from_archive_url "$url"
|
install_from_archive_url "$url"
|
||||||
echo "asset:${tag}" >"$STAMP"
|
echo "asset:${tag}" >"$STAMP"
|
||||||
chown "${SWARM_USER}:${SWARM_USER}" "$STAMP"
|
chown "${SWARM_USER}:${SWARM_USER}" "$STAMP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Quiet CUDA build: no cmake spam; heartbeat every 30s with last %.
|
||||||
|
build_cuda_from_source() {
|
||||||
|
local tag="$1"
|
||||||
|
local arch build_log pid pct line
|
||||||
|
arch="$(cuda_architectures)"
|
||||||
|
build_log="${LLAMA_ROOT}/build-cuda.log"
|
||||||
|
log "крайний случай: сборка CUDA из исходников (tag=${tag}, arch=${arch}, 5–15 мин)…"
|
||||||
|
log "полный лог: ${build_log}"
|
||||||
|
if ! ensure_build_deps; then
|
||||||
|
log "нет nvcc — CUDA-сборку пропускаем"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
log "nvcc $(nvcc --version 2>/dev/null | tail -n1 || echo '?')"
|
||||||
|
|
||||||
|
mkdir -p "$SRC_DIR"
|
||||||
|
export GIT_TERMINAL_PROMPT=0
|
||||||
|
if [[ -d "${SRC_DIR}/.git" ]]; then
|
||||||
|
git -C "$SRC_DIR" -c advice.detachedHead=false fetch --depth 1 origin tag "$tag" 2>>"$build_log" || true
|
||||||
|
if ! git -C "$SRC_DIR" -c advice.detachedHead=false checkout -f "$tag" >>"$build_log" 2>&1; then
|
||||||
|
rm -rf "$SRC_DIR"
|
||||||
|
git -c advice.detachedHead=false clone --depth 1 --branch "$tag" "$REPO" "$SRC_DIR" >>"$build_log" 2>&1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
rm -rf "$SRC_DIR"
|
||||||
|
git -c advice.detachedHead=false clone --depth 1 --branch "$tag" "$REPO" "$SRC_DIR" >>"$build_log" 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmake -S "$SRC_DIR" -B "${SRC_DIR}/build" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DGGML_CUDA=ON \
|
||||||
|
-DCMAKE_CUDA_ARCHITECTURES="${arch}" \
|
||||||
|
-DLLAMA_BUILD_SERVER=ON \
|
||||||
|
-DLLAMA_BUILD_UI=OFF \
|
||||||
|
-DLLAMA_USE_PREBUILT_UI=OFF \
|
||||||
|
-DGGML_CCACHE=OFF \
|
||||||
|
>>"$build_log" 2>&1
|
||||||
|
|
||||||
|
# Background build + heartbeat (keeps SSH stream alive without 200 cmake lines).
|
||||||
|
cmake --build "${SRC_DIR}/build" -j"$(nproc)" --target llama-server \
|
||||||
|
>>"$build_log" 2>&1 &
|
||||||
|
pid=$!
|
||||||
|
while kill -0 "$pid" 2>/dev/null; do
|
||||||
|
pct="$(grep -oE '\[[[:space:]]*[0-9]+%\]' "$build_log" 2>/dev/null | tail -n1 || true)"
|
||||||
|
line="$(grep -E 'Building CUDA|Built target|Linking' "$build_log" 2>/dev/null | tail -n1 || true)"
|
||||||
|
if [[ -n "$pct" ]]; then
|
||||||
|
log "сборка CUDA ещё идёт… ${pct}${line:+ · ${line}}"
|
||||||
|
else
|
||||||
|
log "сборка CUDA ещё идёт… (cmake/nvcc, см. build.log)"
|
||||||
|
fi
|
||||||
|
sleep 30
|
||||||
|
done
|
||||||
|
if ! wait "$pid"; then
|
||||||
|
log "сборка упала — хвост ${build_log}:"
|
||||||
|
tail -n 40 "$build_log" >&2 || true
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local built="${SRC_DIR}/build/bin/llama-server"
|
||||||
|
if [[ ! -x "$built" ]]; then
|
||||||
|
log "сборка не дала ${built}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
install -m 755 "$built" "$SERVER_BIN"
|
||||||
|
# CUDA build may need libs from build/bin
|
||||||
|
find "${SRC_DIR}/build/bin" -maxdepth 1 -type f \( -name '*.so' -o -name '*.so.*' \) -print0 2>/dev/null \
|
||||||
|
| while IFS= read -r -d '' so; do
|
||||||
|
install -m 755 "$so" "${BIN_DIR}/$(basename "$so")"
|
||||||
|
done
|
||||||
|
chown -R "${SWARM_USER}:${SWARM_USER}" "$BIN_DIR"
|
||||||
|
echo "cuda:${tag}:${arch}" >"$STAMP"
|
||||||
|
chown "${SWARM_USER}:${SWARM_USER}" "$STAMP"
|
||||||
|
log "CUDA binary → ${SERVER_BIN}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_tag() {
|
||||||
|
printf '%s' "$1" | tr -d '\r' | head -n1 | awk 'NF{print; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
if [[ -x "$SERVER_BIN" ]]; then
|
if [[ -x "$SERVER_BIN" ]]; then
|
||||||
log "llama-server уже есть: ${SERVER_BIN}"
|
log "llama-server уже есть: ${SERVER_BIN}"
|
||||||
else
|
else
|
||||||
if [[ -n "$LLAMACPP_ASSET_URL" ]]; then
|
if [[ -n "$LLAMACPP_ASSET_URL" ]]; then
|
||||||
log "скачиваю llama-server по LLAMACPP_ASSET_URL…"
|
log "скачиваю по LLAMACPP_ASSET_URL…"
|
||||||
install_from_archive_url "$LLAMACPP_ASSET_URL"
|
install_from_archive_url "$LLAMACPP_ASSET_URL"
|
||||||
echo "asset-url" >"$STAMP"
|
echo "asset-url" >"$STAMP"
|
||||||
chown "${SWARM_USER}:${SWARM_USER}" "$STAMP"
|
chown "${SWARM_USER}:${SWARM_USER}" "$STAMP"
|
||||||
else
|
else
|
||||||
if [[ -z "$LLAMACPP_TAG" ]]; then
|
if [[ -z "$LLAMACPP_TAG" ]]; then
|
||||||
log "WARN: LLAMACPP_TAG/ASSET_URL не заданы — берём latest (нет pin). См. docs/llm.md"
|
log "WARN: LLAMACPP_TAG не задан — latest (см. docs/llm.md)"
|
||||||
fi
|
fi
|
||||||
tag="$(resolve_release_tag)"
|
tag="$(normalize_tag "$(resolve_release_tag)")"
|
||||||
tag="$(printf '%s' "$tag" | tr -d '\r' | head -n1 | awk 'NF{print; exit}')"
|
|
||||||
if [[ -z "$tag" || "$tag" == *" "* || "$tag" == *"["* ]]; then
|
if [[ -z "$tag" || "$tag" == *" "* || "$tag" == *"["* ]]; then
|
||||||
log "не удалось определить release tag (got: ${tag:-empty})"
|
log "не удалось определить release tag (got: ${tag:-empty})"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! build_cuda_from_source "$tag"; then
|
|
||||||
log "CUDA-сборка не удалась — fallback на Linux release asset"
|
installed=0
|
||||||
install_linux_release_fallback "$tag"
|
if [[ "${LLAMACPP_BUILD_CUDA}" == "1" ]]; then
|
||||||
|
log "LLAMACPP_BUILD_CUDA=1 — сразу CUDA-сборка"
|
||||||
|
if build_cuda_from_source "$tag"; then
|
||||||
|
installed=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if install_linux_release "$tag"; then
|
||||||
|
installed=1
|
||||||
|
else
|
||||||
|
log "prebuilt не вышел — крайний случай: CUDA из исходников"
|
||||||
|
if build_cuda_from_source "$tag"; then
|
||||||
|
installed=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ "$installed" != "1" ]]; then
|
||||||
|
log "не удалось поставить llama-server"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -292,7 +377,14 @@ else:
|
|||||||
PY
|
PY
|
||||||
)" || true
|
)" || true
|
||||||
fi
|
fi
|
||||||
log "llama.cpp -ngl ${NGL} -c ${CTX}"
|
# Explicit overrides from gpu-rent.vars / .env (forwarded by provision).
|
||||||
|
if [[ -n "$LLAMACPP_NGL" ]]; then
|
||||||
|
NGL="$LLAMACPP_NGL"
|
||||||
|
fi
|
||||||
|
if [[ -n "$LLAMACPP_CTX" ]]; then
|
||||||
|
CTX="$LLAMACPP_CTX"
|
||||||
|
fi
|
||||||
|
log "llama.cpp -ngl ${NGL} -c ${CTX} host=${LLAMACPP_HOST} port=${LLAMACPP_PORT}${LLAMACPP_EXTRA_ARGS:+ extra=${LLAMACPP_EXTRA_ARGS}}"
|
||||||
|
|
||||||
cat >/etc/systemd/system/${UNIT}.service <<EOF
|
cat >/etc/systemd/system/${UNIT}.service <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
@@ -305,7 +397,8 @@ Type=simple
|
|||||||
User=${SWARM_USER}
|
User=${SWARM_USER}
|
||||||
Group=${SWARM_USER}
|
Group=${SWARM_USER}
|
||||||
WorkingDirectory=${LLAMA_ROOT}
|
WorkingDirectory=${LLAMA_ROOT}
|
||||||
ExecStart=${SERVER_BIN} ${MODEL_ARG} ${MMPROJ_ARG} --host 127.0.0.1 --port 8080 -ngl ${NGL} -c ${CTX}
|
Environment=LD_LIBRARY_PATH=${BIN_DIR}
|
||||||
|
ExecStart=${SERVER_BIN} ${MODEL_ARG} ${MMPROJ_ARG} --host ${LLAMACPP_HOST} --port ${LLAMACPP_PORT} -ngl ${NGL} -c ${CTX} ${LLAMACPP_EXTRA_ARGS}
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=8
|
RestartSec=8
|
||||||
|
|
||||||
|
|||||||
@@ -323,7 +323,9 @@ def run_script_sudo(
|
|||||||
fh.write(script)
|
fh.write(script)
|
||||||
sftp.chmod(remote_path, 0o755)
|
sftp.chmod(remote_path, 0o755)
|
||||||
sftp.close()
|
sftp.close()
|
||||||
env_s = " ".join(f"{key}={value}" for key, value in (env or {}).items())
|
env_s = " ".join(
|
||||||
|
f"{key}={shlex.quote(str(value))}" for key, value in (env or {}).items()
|
||||||
|
)
|
||||||
prefix = f"sudo -n env {env_s} " if env_s else "sudo -n "
|
prefix = f"sudo -n env {env_s} " if env_s else "sudo -n "
|
||||||
command = f"{prefix}bash {remote_path}"
|
command = f"{prefix}bash {remote_path}"
|
||||||
_stdin, stdout, stderr = client.exec_command(command, timeout=timeout, get_pty=True)
|
_stdin, stdout, stderr = client.exec_command(command, timeout=timeout, get_pty=True)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
from gpu_rent.provision import _LLAMACPP_INSTALL_ENV, _remote_llm_env
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_llm_env_forwards_llamacpp_vars(monkeypatch):
|
||||||
|
monkeypatch.setenv("LLAMACPP_TAG", "b10545")
|
||||||
|
monkeypatch.setenv("LLAMACPP_BUILD_CUDA", "1")
|
||||||
|
monkeypatch.setenv("LLAMACPP_NGL", "40")
|
||||||
|
monkeypatch.setenv("LLAMACPP_ASSET_URL", "https://example/a.tar.gz")
|
||||||
|
monkeypatch.delenv("LLAMACPP_SHA256", raising=False)
|
||||||
|
cfg = SimpleNamespace(ssh_user="ubuntu")
|
||||||
|
env = _remote_llm_env(cfg, *_LLAMACPP_INSTALL_ENV)
|
||||||
|
assert env["SWARM_USER"] == "ubuntu"
|
||||||
|
assert env["LLAMACPP_TAG"] == "b10545"
|
||||||
|
assert env["LLAMACPP_BUILD_CUDA"] == "1"
|
||||||
|
assert env["LLAMACPP_NGL"] == "40"
|
||||||
|
assert env["LLAMACPP_ASSET_URL"] == "https://example/a.tar.gz"
|
||||||
|
assert "LLAMACPP_SHA256" not in env
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_llm_env_skips_empty(monkeypatch):
|
||||||
|
for key in _LLAMACPP_INSTALL_ENV:
|
||||||
|
monkeypatch.delenv(key, raising=False)
|
||||||
|
cfg = SimpleNamespace(ssh_user="ubuntu")
|
||||||
|
env = _remote_llm_env(cfg, *_LLAMACPP_INSTALL_ENV)
|
||||||
|
assert env == {"SWARM_USER": "ubuntu"}
|
||||||
Reference in New Issue
Block a user