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:
Leonid Pershin
2026-08-21 08:19:37 +03:00
parent ccba40a228
commit 91d2ce0fab
7 changed files with 311 additions and 79 deletions
+19 -1
View File
@@ -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 (~30MB, 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
View File
@@ -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 — см. кейсы AH):
# 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
View File
@@ -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=
+32 -3
View File
@@ -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()
+157 -64
View File
@@ -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}, 515 мин)…"
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
+3 -1
View File
@@ -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)
+27
View File
@@ -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"}