Arquivos
bdi_podman_serverconf/containers/vllm/vllm-rocm.Containerfile
T

130 linhas
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"]