130 строки
6.9 KiB
Docker
130 строки
6.9 KiB
Docker
### vLLM ROCm portable build (lemonade-sdk), con supporto GGUF nativo incluso
|
|
### Auto-detect dell'ultima release disponibile per il target GPU scelto.
|
|
###
|
|
### BUILD (gfx1151):
|
|
### podman build --build-arg GPU_TARGET=gfx1151 -t vllm:rocm -f vllm-rocm.Containerfile .
|
|
### BUILD (gfx1150):
|
|
### podman build --build-arg GPU_TARGET=gfx1150 -t vllm:rocm -f vllm-rocm.Containerfile .
|
|
FROM ubuntu:26.04
|
|
|
|
ARG GPU_TARGET=gfx1151
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -y curl ca-certificates jq python3-minimal libatomic1 libgomp1 libnuma1 patchelf \
|
|
&& apt-get clean \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
WORKDIR /opt
|
|
|
|
# Se i .tar.gz della release e/o librccl.so.1.0 (build TheRock, unica per tutti i target) sono gia' presenti accanto al Containerfile li usiamo cosi' come sono.
|
|
COPY vllm-rocm.Containerfile *.tar.gz librccl.so.1.0* /opt/build-context/
|
|
|
|
# Prende il tag dell'ultima release e lo adatta al target GPU richiesto (es. ...-gfx1151 -> ...-gfx1150).
|
|
RUN curl -s https://api.github.com/repos/lemonade-sdk/vllm-rocm/releases/latest -o /tmp/latest.json \
|
|
&& LATEST_TAG=$(jq -r '.tag_name' /tmp/latest.json) \
|
|
&& if [ -z "$LATEST_TAG" ] || [ "$LATEST_TAG" = "null" ]; then \
|
|
echo "ERRORE: impossibile recuperare il tag latest"; exit 1; \
|
|
fi \
|
|
&& echo "Tag latest: $LATEST_TAG" \
|
|
&& BASE_TAG=$(echo "$LATEST_TAG" | sed -E 's/-gfx[0-9X]+$//') \
|
|
&& TAG="${BASE_TAG}-${GPU_TARGET}" \
|
|
&& echo "Tag risolto per target ${GPU_TARGET}: $TAG" \
|
|
&& echo "$TAG" > /opt/vllm_rocm_tag.txt \
|
|
&& ENCODED_TAG=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=''))" "$TAG") \
|
|
&& echo "Tag URL-encoded: $ENCODED_TAG" \
|
|
&& curl -s "https://api.github.com/repos/lemonade-sdk/vllm-rocm/releases/tags/${ENCODED_TAG}" -o /tmp/release.json \
|
|
&& echo "--- Asset disponibili in questa release ---" \
|
|
&& jq -r '.assets[].name' /tmp/release.json \
|
|
&& echo "--- fine lista asset ---" \
|
|
&& jq -r '.assets[] | select(.name | test("part[0-9]+-of-[0-9]+\\.tar\\.gz$")) | [.name, .browser_download_url] | @tsv' /tmp/release.json \
|
|
| sort -k1,1 > /tmp/parts.tsv \
|
|
&& if [ ! -s /tmp/parts.tsv ]; then \
|
|
echo "ERRORE: release ${TAG} non trovata o senza asset part*-of-*.tar.gz (target ${GPU_TARGET} non ancora pubblicato per questa versione?)"; exit 1; \
|
|
fi \
|
|
&& echo "--- Parti trovate, in ordine ---" \
|
|
&& cat /tmp/parts.tsv \
|
|
&& mkdir -p /opt/vllm-rocm \
|
|
&& N=$(wc -l < /tmp/parts.tsv) \
|
|
&& i=1 \
|
|
&& while [ "$i" -le "$N" ]; do \
|
|
LINE=$(sed -n "${i}p" /tmp/parts.tsv); \
|
|
NAME=$(printf '%s' "$LINE" | cut -f1); \
|
|
URL=$(printf '%s' "$LINE" | cut -f2); \
|
|
if [ -f "/opt/build-context/$NAME" ]; then \
|
|
echo "Trovata localmente ($i/$N): $NAME, copio invece di scaricare"; \
|
|
cp "/opt/build-context/$NAME" "$NAME"; \
|
|
else \
|
|
echo "Scarico ($i/$N): $NAME"; \
|
|
curl -L -o "$NAME" "$URL"; \
|
|
fi; \
|
|
i=$((i + 1)); \
|
|
done \
|
|
&& cut -f1 /tmp/parts.tsv | xargs cat | tar xz -C /opt/vllm-rocm \
|
|
&& cut -f1 /tmp/parts.tsv | xargs rm -f
|
|
|
|
# L'archivio non preserva il bit di esecuzione sui binari/librerie
|
|
RUN chmod -R a+rX /opt/vllm-rocm/lib \
|
|
&& find /opt/vllm-rocm/bin -type f -exec chmod a+rx {} \;
|
|
|
|
# Correggiamo lo shebang degli script in bin/ (es. hipcc, pip), hardcodato con il path della macchina CI originale.
|
|
RUN for f in /opt/vllm-rocm/bin/*; do \
|
|
if [ -f "$f" ] && head -c 2 "$f" 2>/dev/null | grep -q '^#!'; then \
|
|
sed -i "1s|^#!.*python3[^ ]*|#!/opt/vllm-rocm/bin/python3|" "$f"; \
|
|
fi; \
|
|
done
|
|
|
|
ENV PATH=/opt/vllm-rocm/bin:$PATH
|
|
ENV LD_LIBRARY_PATH=/opt/vllm-rocm/lib:$LD_LIBRARY_PATH
|
|
|
|
# Symlink stabile lib/python3 verso la cartella versionata reale, la versione di Python cambia tra le release.
|
|
RUN PYDIR=$(find /opt/vllm-rocm/lib -maxdepth 1 -name 'python3.*' -type d | head -1) \
|
|
&& if [ -z "$PYDIR" ]; then echo "ERRORE: nessuna cartella lib/python3.* trovata"; exit 1; fi \
|
|
&& echo "Versione Python rilevata: $(basename "$PYDIR")" \
|
|
&& ln -s "$PYDIR" /opt/vllm-rocm/lib/python3
|
|
|
|
# La librccl.so della release e' uno stub senza kernel reali: se e' presente una build reale (TheRock, unica per tutti i target: librccl.so.1.0; oppure, per compatibilita' con vecchie build per-target: librccl.so.1.0-<target>) la usiamo al suo posto, correggendo il RPATH con patchelf verso _rocm_sdk_core/lib.
|
|
RUN RCCL_SRC=""; \
|
|
if [ -f "/opt/build-context/librccl.so.1.0" ]; then \
|
|
RCCL_SRC="/opt/build-context/librccl.so.1.0"; \
|
|
elif [ -f "/opt/build-context/librccl.so.1.0-${GPU_TARGET}" ]; then \
|
|
RCCL_SRC="/opt/build-context/librccl.so.1.0-${GPU_TARGET}"; \
|
|
fi; \
|
|
if [ -n "$RCCL_SRC" ]; then \
|
|
echo "Sostituisco librccl.so con la build reale: $RCCL_SRC"; \
|
|
cp "$RCCL_SRC" /opt/vllm-rocm/lib/python3/site-packages/_rocm_sdk_libraries/lib/librccl.so.1; \
|
|
chmod a+rx /opt/vllm-rocm/lib/python3/site-packages/_rocm_sdk_libraries/lib/librccl.so.1; \
|
|
patchelf --set-rpath '$ORIGIN/../../_rocm_sdk_core/lib' /opt/vllm-rocm/lib/python3/site-packages/_rocm_sdk_libraries/lib/librccl.so.1; \
|
|
echo "RPATH corretto: $(patchelf --print-rpath /opt/vllm-rocm/lib/python3/site-packages/_rocm_sdk_libraries/lib/librccl.so.1)"; \
|
|
else \
|
|
echo "Nessuna librccl.so.1.0 trovata in /opt/build-context, mantengo lo stub (niente RCCL multi-nodo)"; \
|
|
fi \
|
|
&& rm -rf /opt/build-context
|
|
|
|
# I gruppi paralleli del worker Ray (TP/PP/DP/EP) ricevono timeout=None (vllm_config non ancora disponibile) e finiscono sul default NCCL di PyTorch (600s): lo alziamo qui.
|
|
COPY patch-nccl-default-timeout.py /tmp/patch-nccl-default-timeout.py
|
|
RUN /opt/vllm-rocm/bin/python3 /tmp/patch-nccl-default-timeout.py /opt/vllm-rocm/lib/python3/site-packages/torch/distributed/distributed_c10d.py 3000 \
|
|
&& rm /tmp/patch-nccl-default-timeout.py
|
|
|
|
# amdsmi non e' importabile di default in questa build, serve nel PYTHONPATH (vedi lemonade-sdk/vllm-rocm#3).
|
|
ENV PYTHONPATH=/opt/vllm-rocm/lib/python3/site-packages/_rocm_sdk_core/share/amd_smi
|
|
|
|
# La build portable non include pip; ensurepip e' assente, quindi usiamo get-pip.py.
|
|
RUN (/opt/vllm-rocm/bin/python3 -m ensurepip --upgrade \
|
|
|| (curl -sSL https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py \
|
|
&& /opt/vllm-rocm/bin/python3 /tmp/get-pip.py)) \
|
|
&& /opt/vllm-rocm/bin/python3 -m pip install "ray[default]" sentencepiece tiktoken
|
|
|
|
# flash_attn qui e' solo metadata senza backend compilato: rotto e mai funzionante, va rimosso per far scattare il fallback nativo di vLLM.
|
|
RUN /opt/vllm-rocm/bin/python3 -m pip uninstall -y flash_attn
|
|
|
|
# XDG_RUNTIME_DIR scrivibile richiesto dal backend vLLM ROCm in ambienti containerizzati
|
|
ENV XDG_RUNTIME_DIR=/tmp/runtime-vllm
|
|
RUN mkdir -p /tmp/runtime-vllm && chmod 700 /tmp/runtime-vllm
|
|
|
|
WORKDIR /opt/vllm-rocm
|
|
|
|
COPY entrypoint.sh /opt/vllm-rocm/entrypoint.sh
|
|
RUN chmod +x /opt/vllm-rocm/entrypoint.sh
|
|
|
|
ENTRYPOINT ["/opt/vllm-rocm/entrypoint.sh"]
|