Simplification radicale : moteur pris de l'image officielle llama.cpp

Plus aucune compilation CUDA : le runtime part de
ghcr.io/ggml-org/llama.cpp:server-cuda (llama-server précompilé et maintenu
par l'équipe amont, backends .so chargés dynamiquement, archs GPU courantes,
repli CPU fonctionnel). Le build complet passe de ~40 min à ~4 min et tous
les pièges du build CUDA sans GPU (stubs libcuda, espace disque du runner,
choix des architectures) disparaissent.

- Dockerfile : 2 étapes (Go + image officielle), build-arg LLAMACPP_IMAGE
  pour épingler une version ou passer en CPU/Vulkan
- entrypoint : BIN=/app/llama-server
- workflow GHCR : purge disque et CUDA_ARCHS supprimés, cache max
- compose/.env/README à l'avenant

Validé : build 3 min 55, UI HTTP 200, healthcheck healthy, superviseur PID
OK, llama-server démarre (repli CPU) et n'échoue que sur un modèle factice.
This commit is contained in:
Loki committed 2026-08-14 22:59:35 +00:00
1 parent 0846a70eb0
commit 1e232a7ff3
6 files changed
+49 -89

No files matched your search

-5
View File
@@ -4,11 +4,6 @@
# Port de l'interface web (identique dedans/dehors). # Port de l'interface web (identique dedans/dehors).
LOKI_WEB_PORT=8090 LOKI_WEB_PORT=8090
# Architectures CUDA compilées (build local uniquement).
# 75=Turing (GTX 16xx / RTX 20xx), 86=Ampere (RTX 30xx), 89=Ada (RTX 40xx).
# Restreindre à sa carte divise le temps de compilation.
CUDA_ARCHS=75;86;89
# Optionnel — semé au PREMIER démarrage seulement (modifiable ensuite dans # Optionnel — semé au PREMIER démarrage seulement (modifiable ensuite dans
# l'UI, qui garde la main) : # l'UI, qui garde la main) :
# Modèle initial : nom d'un .gguf présent dans ./models ou chemin complet. # Modèle initial : nom d'un .gguf présent dans ./models ou chemin complet.
+1 -15
View File
@@ -16,16 +16,6 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
# L'étape llama.cpp CUDA a besoin de place : l'image devel pèse ~8 Go et
# un runner ubuntu-latest n'offre que ~14 Go libres. On purge ce qui est
# préinstallé et inutile ici (SDK Android, .NET, Haskell…).
- name: Libérer l'espace disque du runner
run: |
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache/CodeQL
sudo docker image prune -af
df -h /
- name: Setup Buildx - name: Setup Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
@@ -53,11 +43,7 @@ jobs:
push: true push: true
build-args: | build-args: |
LOKI_VERSION=${{ github.sha }} LOKI_VERSION=${{ github.sha }}
CUDA_ARCHS=75;86;89
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
# Cache limité : les couches CUDA (plusieurs Go) satureraient le
# plafond de 10 Go du cache GitHub Actions — on ne cache que le mode
# min (couches finales), le gain principal restant le cache apt/go.
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=min cache-to: type=gha,mode=max
+22 -54
View File
@@ -1,54 +1,20 @@
# ── Loki — image GPU autonome (fork d'AJEAN, https://github.com/nathaninline/ajean) # ── Loki — image GPU (fork d'AJEAN, https://github.com/nathaninline/ajean)
# #
# Trois étapes : # Deux étapes seulement :
# 1. compilation de llama.cpp avec CUDA (mêmes flags que backend_build.go, # 1. compilation du binaire Go `loki` (UI embarquée via go:embed) ;
# sauf GGML_NATIVE=OFF : l'image est bâtie sur un runner GitHub, pas sur # 2. runtime = l'image serveur CUDA OFFICIELLE de llama.cpp — llama-server
# la machine qui l'exécutera — des instructions CPU « natives » du runner # y est précompilé et maintenu par l'équipe amont (base nvidia/cuda
# provoqueraient un Illegal instruction ailleurs) ; # runtime, backends .so dans /app, architectures GPU courantes).
# 2. compilation du binaire Go `loki` (UI embarquée via go:embed) ; # Aucune compilation CUDA ici : le build complet prend quelques minutes.
# 3. runtime CUDA léger : llama-server + loki + entrypoint.
# #
# Pré-requis d'exécution : NVIDIA Container Toolkit sur l'hôte. # Épingler une version : --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda-b10423
# docker build -t loki --build-arg CUDA_ARCHS=86 . # Variante CPU (test sans GPU) : --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server
# CUDA_ARCHS : 75=Turing, 86=Ampere, 89=Ada — restreindre à sa carte divise # Pré-requis d'exécution GPU : NVIDIA Container Toolkit sur l'hôte.
# le temps de build et la taille de l'image.
# ── Étape 1 : llama.cpp CUDA ──────────────────────────────────────────── # Déclaré avant le premier FROM : requis pour être utilisable dans un FROM.
FROM nvidia/cuda:12.6.3-devel-ubuntu24.04 AS llamacpp ARG LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda
RUN apt-get update && apt-get install -y --no-install-recommends \ # ── Étape 1 : binaire Go loki ───────────────────────────────────────────
git cmake build-essential ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Épingler LLAMACPP_REF sur un tag (ex. b4991) pour des builds reproductibles.
ARG LLAMACPP_REF=master
ARG CUDA_ARCHS=75;86;89
RUN git clone --depth 1 --branch "${LLAMACPP_REF}" \
https://github.com/ggml-org/llama.cpp /src/llama.cpp
# --allow-shlib-undefined : pas de GPU (donc pas de libcuda.so.1) sur le
# builder — l'API driver (cuMemCreate…) reste non résolue au link et sera
# fournie à l'exécution par le runtime NVIDIA. Même parade que le
# cuda.Dockerfile officiel de llama.cpp.
RUN cmake -S /src/llama.cpp -B /src/llama.cpp/build \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_CUDA=ON \
-DGGML_CUDA_F16=ON \
-DGGML_NATIVE=OFF \
-DCMAKE_CUDA_ARCHITECTURES="${CUDA_ARCHS}" \
-DLLAMA_CURL=OFF \
-DLLAMA_BUILD_TESTS=OFF \
-DLLAMA_BUILD_EXAMPLES=OFF \
-DLLAMA_BUILD_UI=OFF \
-DLLAMA_USE_PREBUILT_UI=OFF \
-DCMAKE_EXE_LINKER_FLAGS=-Wl,--allow-shlib-undefined \
&& cmake --build /src/llama.cpp/build --target llama-server -j"$(nproc)" \
&& mkdir -p /opt/llama.cpp \
&& find /src/llama.cpp/build -name 'llama-server' -type f -exec cp {} /opt/llama.cpp/ \; \
&& find /src/llama.cpp/build -name '*.so*' -exec cp -P {} /opt/llama.cpp/ \;
# ── Étape 2 : binaire Go loki ───────────────────────────────────────────
FROM golang:1.25 AS gobuild FROM golang:1.25 AS gobuild
WORKDIR /src WORKDIR /src
COPY go.mod go.sum ./ COPY go.mod go.sum ./
@@ -58,8 +24,8 @@ COPY internal/ internal/
COPY tools/ tools/ COPY tools/ tools/
RUN CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o /out/loki ./cmd/loki RUN CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o /out/loki ./cmd/loki
# ── Étape 3 : runtime ─────────────────────────────────────────────────── # ── Étape 2 : runtime sur l'image serveur CUDA officielle ───────────────
FROM nvidia/cuda:12.6.3-runtime-ubuntu24.04 AS runtime FROM ${LLAMACPP_IMAGE} AS runtime
# Marqueur de build (sha court), injecté par le workflow GitHub. # Marqueur de build (sha court), injecté par le workflow GitHub.
ARG LOKI_VERSION=dev ARG LOKI_VERSION=dev
@@ -67,21 +33,21 @@ LABEL org.opencontainers.image.revision="${LOKI_VERSION}" \
org.opencontainers.image.source="https://github.com/R0m1k3/Loki" \ org.opencontainers.image.source="https://github.com/R0m1k3/Loki" \
org.opencontainers.image.description="Loki — fork conteneurisé d'AJEAN (github.com/nathaninline/ajean, MIT)" org.opencontainers.image.description="Loki — fork conteneurisé d'AJEAN (github.com/nathaninline/ajean, MIT)"
# curl pour le HEALTHCHECK ; git pour les outils de l'agent ; nodejs/npm pour # git pour les outils de l'agent ; nodejs/npm pour les serveurs MCP lancés
# les serveurs MCP lancés via npx ; libgomp1 pour llama-server ; tini en PID 1. # via npx ; tini en PID 1. curl et libgomp1 sont déjà dans l'image amont.
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl git libgomp1 tini nodejs npm \ git nodejs npm tini \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
COPY --from=llamacpp /opt/llama.cpp /opt/llama.cpp
COPY --from=gobuild /out/loki /usr/local/bin/loki COPY --from=gobuild /out/loki /usr/local/bin/loki
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh && mkdir -p /data /models RUN chmod +x /usr/local/bin/docker-entrypoint.sh && mkdir -p /data /models
# llama-server et ses .so vivent dans /app (convention de l'image amont).
ENV LOKI_CONTAINER=1 \ ENV LOKI_CONTAINER=1 \
LOKI_HOME=/data \ LOKI_HOME=/data \
LOKI_MODEL_DIRS=/models \ LOKI_MODEL_DIRS=/models \
LD_LIBRARY_PATH=/opt/llama.cpp \ LD_LIBRARY_PATH=/app \
NVIDIA_VISIBLE_DEVICES=all \ NVIDIA_VISIBLE_DEVICES=all \
NVIDIA_DRIVER_CAPABILITIES=compute,utility NVIDIA_DRIVER_CAPABILITIES=compute,utility
@@ -89,8 +55,10 @@ ENV LOKI_CONTAINER=1 \
# conteneur — il n'est pas authentifié par défaut. # conteneur — il n'est pas authentifié par défaut.
EXPOSE 8090 EXPOSE 8090
# Remplace le HEALTHCHECK de l'image amont (qui vise le moteur sur :8080).
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsS "http://localhost:${LOKI_WEB_PORT:-8090}/" >/dev/null || exit 1 CMD curl -fsS "http://localhost:${LOKI_WEB_PORT:-8090}/" >/dev/null || exit 1
WORKDIR /data WORKDIR /data
# Remplace l'ENTRYPOINT de l'image amont (/app/llama-server).
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"] ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
+19 -8
View File
@@ -38,8 +38,9 @@ chiffré — serveur d'inférence llama.cpp compris, dans une seule image.
Pré-requis : pilote NVIDIA + [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Pré-requis : pilote NVIDIA + [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html).
```bash ```bash
cp .env.example .env # CUDA_ARCHS=86 pour une RTX 30xx, etc. cp .env.example .env
docker compose up --build # 30-45 min : compilation CUDA de llama.cpp docker compose up --build # quelques minutes : llama-server vient précompilé
# de l'image officielle llama.cpp (server-cuda)
``` ```
Interface : http://localhost:8090 — télécharge un modèle depuis le catalogue Interface : http://localhost:8090 — télécharge un modèle depuis le catalogue
@@ -96,7 +97,7 @@ En CLI dans le conteneur : `docker exec -it loki loki status` (aussi :
| | AJEAN (amont) | Loki (ce fork) | | | AJEAN (amont) | Loki (ce fork) |
|---|---|---| |---|---|---|
| Installation | binaire + `sudo ajean install` (systemd) | `docker compose up` | | Installation | binaire + `sudo ajean install` (systemd) | `docker compose up` |
| Moteur llama.cpp | compilé sur la machine (`ajean llamacpp install`) | précompilé CUDA dans l'image | | Moteur llama.cpp | compilé sur la machine (`ajean llamacpp install`) | image officielle llama.cpp (`server-cuda`), précompilée |
| Supervision moteur | systemd / launchd / PID (Windows) | fichier PID (`LOKI_CONTAINER=1`) | | Supervision moteur | systemd / launchd / PID (Windows) | fichier PID (`LOKI_CONTAINER=1`) |
| Configuration initiale | `ajean edit` ($EDITOR) | entrypoint + `loki config set` | | Configuration initiale | `ajean edit` ($EDITOR) | entrypoint + `loki config set` |
| Mise à jour | `ajean update` (binaire GitHub) | `docker compose pull` | | Mise à jour | `ajean update` (binaire GitHub) | `docker compose pull` |
@@ -108,12 +109,22 @@ les évolutions de l'amont :
git fetch upstream && git merge upstream/main # conflits de renommage à arbitrer git fetch upstream && git merge upstream/main # conflits de renommage à arbitrer
``` ```
## Build sans GPU / autres accélérateurs ## Build sans GPU / autres accélérateurs / version épinglée
L'image par défaut cible CUDA. Pour un essai CPU, remplace dans le L'image Loki se construit **au-dessus de l'image serveur officielle de
`Dockerfile` les bases `nvidia/cuda:*` par `ubuntu:24.04` et retire les flags llama.cpp**, choisie par le build-arg `LLAMACPP_IMAGE` :
`-DGGML_CUDA=*` (llama.cpp bascule en CPU). Vulkan/ROCm : adapter les flags
comme le fait l'amont (`internal/loki/backend_build.go`). ```bash
# CPU seul (test sans GPU)
docker build --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server .
# Vulkan (GPU AMD/Intel/NVIDIA sans CUDA)
docker build --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-vulkan .
# Version de llama.cpp épinglée (reproductible)
docker build --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda-b10423 .
```
Aucune compilation de llama.cpp n'a lieu : le moteur est maintenu et
précompilé par l'équipe amont (toutes architectures GPU courantes).
## Licence ## Licence
+4 -5
View File
@@ -2,7 +2,8 @@
# Un seul service : le conteneur embarque le moteur llama.cpp (CUDA) ET l'UI. # Un seul service : le conteneur embarque le moteur llama.cpp (CUDA) ET l'UI.
# #
# cp .env.example .env # ajuste si besoin # cp .env.example .env # ajuste si besoin
# docker compose up --build # build local (30-45 min : compilation CUDA) # docker compose up --build # build local en quelques minutes (llama-server
# # vient précompilé de l'image officielle llama.cpp)
# #
# Interface : http://localhost:8090 # Interface : http://localhost:8090
# Pré-requis GPU : NVIDIA Container Toolkit sur l'hôte. # Pré-requis GPU : NVIDIA Container Toolkit sur l'hôte.
@@ -10,10 +11,8 @@ services:
loki: loki:
build: build:
context: . context: .
args: # Pour épingler la version du moteur ou passer en CPU/Vulkan :
# Restreins à ta carte pour un build plus court : 75=Turing (GTX 16xx/RTX 20xx), # args: { LLAMACPP_IMAGE: "ghcr.io/ggml-org/llama.cpp:server-cuda-b10423" }
# 86=Ampere (RTX 30xx), 89=Ada (RTX 40xx).
CUDA_ARCHS: ${CUDA_ARCHS:-75;86;89}
container_name: loki container_name: loki
ports: ports:
- "${LOKI_WEB_PORT:-8090}:${LOKI_WEB_PORT:-8090}" - "${LOKI_WEB_PORT:-8090}:${LOKI_WEB_PORT:-8090}"
+3 -2
View File
@@ -6,9 +6,10 @@ set -eu
: "${LOKI_HOME:=/data}" : "${LOKI_HOME:=/data}"
mkdir -p "$LOKI_HOME" mkdir -p "$LOKI_HOME"
# Le chemin du moteur est imposé par l'image : on le (re)pose à chaque boot, # Le chemin du moteur est imposé par l'image (llama-server précompilé de
# l'image officielle llama.cpp, dans /app) : on le (re)pose à chaque boot,
# une mise à jour de l'image ne doit pas laisser un BIN obsolète en base. # une mise à jour de l'image ne doit pas laisser un BIN obsolète en base.
loki config set "BIN=/opt/llama.cpp/llama-server" loki config set "BIN=/app/llama-server"
# Les autres clés ne sont semées QUE si absentes : ce que l'utilisateur règle # Les autres clés ne sont semées QUE si absentes : ce que l'utilisateur règle
# ensuite dans l'UI (modèle, contexte…) est conservé d'un redémarrage à l'autre. # ensuite dans l'UI (modèle, contexte…) est conservé d'un redémarrage à l'autre.