gpu-llamacpp: Compose auf P2000 per device_ids, Rolle und Playbook (Task 6.1)
ci / test (push) Successful in 27s

- Build-Pin wie im Benchmark (b6000 = 4762ad7, CUDA 12.4, sm_52;61), Host-Netz,
  Log-Rotation, /slots und Web-Oberfläche aus, Qwen3 ohne Denkphase.
- Exporter aus dem Compose entfernt (laufen nativ, Rolle gpu-exporters).
- Rolle gpu-llamacpp: Karten-UUID über den Namen, Modelle mit Prüfsumme,
  ufw-Regeln nur vorgemerkt. Inventargruppe gpu_llamacpp (ohne gpu-pve52).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Rapp
2026-10-12 21:28:33 +02:00
co-authored by Claude Opus 5.5
parent d8797a9433
commit 5c790cc8d4
6 changed files with 233 additions and 39 deletions
+6
View File
@@ -1,4 +1,6 @@
COMPOSE_PROFILES=embed
LLAMACPP_REF=b6000
LLAMACPP_COMMIT=4762ad7316dcdec20016ab5985fb46a27902204d
CUDA_VERSION=12.4.0
CUDA_DOCKER_ARCH=52;61
MODELS_DIR=/srv/models
@@ -6,3 +8,7 @@ EMBED_GGUF=Qwen3-Embedding-0.6B-Q8_0.gguf
EMBED_POOLING=last
RERANK_GGUF=bge-reranker-v2-m3-Q8_0.gguf
CHAT_GGUF=Qwen3-4B-Q4_K_M.gguf
# Karte je Dienst: Index oder UUID aus `nvidia-smi -L` (Rolle gpu-llamacpp setzt die UUID der P2000)
EMBED_GPU=1
RERANK_GPU=1
CHAT_GPU=1
+52 -39
View File
@@ -1,25 +1,37 @@
# Rollen "gpu-embed" und "gpu-small" (VMs mit Quadro P2000 / M4000): llama.cpp-Server.
# Maxwell (sm_52) und Pascal (sm_61) brauchen CUDA 12.x – daher eigener Build mit festen Architekturen.
# Profile: embed (Embedding + Rerank), chat (Verifier/Signatur), z. B. `docker compose --profile embed up -d`
# Rollen "gpu-embed" und "gpu-small" (GPU-VMs mit Quadro P2000 + M4000): llama.cpp-Server (Task 6.1).
# Maxwell (sm_52) und Pascal (sm_61) brauchen CUDA 12.x – daher eigener Build mit festen Architekturen,
# derselbe Stand wie im Benchmark (ADR-0006): b6000 = Commit 4762ad7, CUDA 12.4.0, sm_52;61.
# Profile: embed (Embedding + Rerank, gpu-pve44/46), chat (verifier-small/signature-extractor, gpu-pve48).
# Ausgerollt von der Ansible-Rolle gpu-llamacpp (.env mit COMPOSE_PROFILES und Karten-UUIDs).
#
# Kartenwahl: je Dienst device_ids (UUID oder Index aus `nvidia-smi -L`). Ohne Angabe Index 1 = P2000
# (in gpu-pve44/46/48 ist Index 0 die M4000, sie bleibt frei). `count: 1` griffe die M4000.
# Netz: Host-Netz wie nex-speech. Veröffentlichte Docker-Ports liefen über DNAT und umgingen ufw;
# so gelten spätere ufw-Regeln der VM (Task 4.4).
# Datenschutz: kein --verbose (der loggt Prompts), /slots aus (zeigt Prompt-Inhalte), keine Web-Oberfläche.
name: knaster-gpu-llamacpp
x-logging: &logging
driver: local
options: {max-size: "5m", max-file: "2"}
x-llamacpp: &llamacpp
build:
context: https://github.com/ggml-org/llama.cpp.git#${LLAMACPP_REF:-b6000}
context: https://github.com/ggml-org/llama.cpp.git#${LLAMACPP_COMMIT:-4762ad7316dcdec20016ab5985fb46a27902204d}
dockerfile: .devops/cuda.Dockerfile
target: server
args:
CUDA_VERSION: ${CUDA_VERSION:-12.4.0}
CUDA_DOCKER_ARCH: ${CUDA_DOCKER_ARCH:-52;61}
image: knaster/llamacpp-server:${LLAMACPP_REF:-b6000}-cu12
image: knaster/llamacpp-server:${LLAMACPP_REF:-b6000}-cu${CUDA_VERSION:-12.4.0}
restart: unless-stopped
network_mode: host
read_only: true
tmpfs: [/tmp:size=64m]
labels: {autoheal: "true"}
volumes:
- ${MODELS_DIR:-/srv/models}:/models:ro
deploy:
resources:
reservations:
devices: [{driver: nvidia, count: 1, capabilities: [gpu]}]
logging: *logging
services:
llamacpp-embed:
@@ -27,60 +39,61 @@ services:
container_name: llamacpp-embed
profiles: ["embed"]
command: ["-m", "/models/${EMBED_GGUF:-Qwen3-Embedding-0.6B-Q8_0.gguf}", "--embedding",
"--pooling", "${EMBED_POOLING:-last}", "-c", "8192", "-ub", "8192", "-ngl", "99",
"--alias", "embed-default", "--metrics", "--host", "0.0.0.0", "--port", "8081"]
ports: ["8081:8081"]
"--pooling", "${EMBED_POOLING:-last}", "-c", "8192", "-b", "8192", "-ub", "8192", "-np", "1",
"-ngl", "99", "--alias", "embed-default", "--metrics", "--no-slots", "--no-webui",
"--host", "0.0.0.0", "--port", "8081"]
deploy:
resources:
reservations:
devices: [{driver: nvidia, device_ids: ["${EMBED_GPU:-1}"], capabilities: [gpu]}]
healthcheck: &hc
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8081/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 60s
start_period: 120s
llamacpp-rerank:
<<: *llamacpp
container_name: llamacpp-rerank
profiles: ["embed"]
command: ["-m", "/models/${RERANK_GGUF:-bge-reranker-v2-m3-Q8_0.gguf}", "--reranking", "-c", "8192",
"-ub", "8192", "-ngl", "99", "--alias", "rerank-default", "--metrics", "--host", "0.0.0.0",
"--port", "8082"]
ports: ["8082:8082"]
command: ["-m", "/models/${RERANK_GGUF:-bge-reranker-v2-m3-Q8_0.gguf}", "--reranking",
"-c", "8192", "-b", "8192", "-ub", "8192", "-np", "1", "-ngl", "99", "--alias", "rerank-default",
"--metrics", "--no-slots", "--no-webui", "--host", "0.0.0.0", "--port", "8082"]
deploy:
resources:
reservations:
devices: [{driver: nvidia, device_ids: ["${RERANK_GPU:-1}"], capabilities: [gpu]}]
healthcheck:
<<: *hc
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8082/health"]
# Qwen3 ohne Denkphase (enable_thinking=false): Verifier und Signatur brauchen kurze, direkte Antworten,
# und der Canary-Prober fragt mit max_tokens=5 nach "OK".
llamacpp-chat:
<<: *llamacpp
container_name: llamacpp-chat
profiles: ["chat"]
command: ["-m", "/models/${CHAT_GGUF:-Qwen3-4B-Q4_K_M.gguf}", "-c", "8192", "-ngl", "99",
"--alias", "verifier-small", "--metrics", "--host", "0.0.0.0", "--port", "8080"]
ports: ["8080:8080"]
command: ["-m", "/models/${CHAT_GGUF:-Qwen3-4B-Q4_K_M.gguf}", "-c", "8192", "-np", "1", "-ngl", "99",
"--jinja", "--chat-template-kwargs", "{\"enable_thinking\": false}",
"--alias", "verifier-small", "--metrics", "--no-slots", "--no-webui",
"--host", "0.0.0.0", "--port", "8080"]
deploy:
resources:
reservations:
devices: [{driver: nvidia, device_ids: ["${CHAT_GPU:-1}"], capabilities: [gpu]}]
healthcheck:
<<: *hc
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8080/health"]
gpu-exporter:
image: utkuozdemir/nvidia_gpu_exporter:1.2.1
restart: unless-stopped
ports: ["9835:9835"]
deploy:
resources:
reservations:
devices: [{driver: nvidia, count: all, capabilities: [gpu, utility]}]
node-exporter:
image: prom/node-exporter:v1.8.1
restart: unless-stopped
command: ["--path.rootfs=/host", "--collector.textfile.directory=/textfile"]
pid: host
volumes:
- /:/host:ro,rslave
- /var/lib/node_exporter/textfile:/textfile:ro
ports: ["9100:9100"]
# Startet Container mit Label autoheal=true neu, wenn ihr Healthcheck dauerhaft scheitert
# (restart: unless-stopped greift nur beim Absturz). Läuft in jedem Profil mit.
autoheal:
image: willfarrell/autoheal:1.2.0
container_name: llamacpp-autoheal
restart: unless-stopped
environment: {AUTOHEAL_CONTAINER_LABEL: autoheal}
volumes: ["/var/run/docker.sock:/var/run/docker.sock"]
logging: *logging
# Exporter (node_exporter 9100, nvidia_gpu_exporter 9835) laufen nativ in der VM (Rolle gpu-exporters).