1. Sistema Operativo y Controladores
- SO: Ubuntu 22.04 LTS o superior.
- Arquitectura: Grace Blackwell.
Verifica que los controladores de NVIDIA estén operativos:
nvidia-smi
2. Docker con NVIDIA Container Runtime
Docker debe estar instalado con NVIDIA Container Runtime configurado. Verifica el acceso utilizando CUDA 13 en Ubuntu 22.04:
docker run --rm --gpus all nvidia/cuda:13.0.1-base-ubuntu22.04 nvidia-smi
3. Cables de Interconexión Aprobados
Para la conexión directa de 200GbE entre los puertos CX-7, NVIDIA recomienda exclusivamente estos modelos:
- Amphenol: NJAAKK-N911 (QSFP to QSFP112, 400mm).
- Luxshare: LMTQF022-SD-R (QSFP112 400G DAC, 400mm).
4. Configuración de Red (Automatizada con Netplan)
NVIDIA proporciona un archivo de configuración para facilitar la asignación de IPs en las interfaces CX-7. Ejecuta esto en ambos nodos:
# Descargar y aplicar configuración de Netplansudo wget -O /etc/netplan/40-cx7.yaml https://github.com/NVIDIA/dgx-spark-playbooks/raw/main/nvidia/connect-two-sparks/assets/cx7-netplan.yaml
sudo chmod 600 /etc/netplan/40-cx7.yaml
sudo netplan apply
5. Script de Descubrimiento y SSH
Este paso identifica automáticamente los sistemas interconectados y configura el SSH sin contraseña. Ejecútalo en ambos nodos:
# Descargar y ejecutar script de descubrimiento
wget https://github.com/NVIDIA/dgx-spark-playbooks/raw/refs/heads/main/nvidia/connect-two-sparks/assets/discover-sparks
chmod +x discover-sparks
./discover-sparks
6. Verificación Detallada de Interfaces (ibdev2netdev)
Confirma que los puertos CX-7 están en estado "(Up)" tras aplicar la red. Es fundamental verificar la conexión física:
# Comprobar estado de los puertos de red
ibdev2netdev
Ejemplo de salida detallada:
roceP2p1s0f0 port 1 ==> enP2p1s0f0np0 (Down)
roceP2p1s0f1 port 1 ==> enP2p1s0f1np1 (Up)
rocep1s0f0 port 1 ==> enp1s0f0np0 (Down)
rocep1s0f1 port 1 ==> enp1s0f1np1 (Up)
enP2p... y priorizar siempre las que comienzan por
enp1.... Si nada aparece como "(Up)", revisa el cable QSFP.
7. Identificación de IPs ConnectX-7 (CX-7)
Localiza la IP de alta velocidad necesaria para la comunicación entre nodos. Ejecuta en ambos servidores:
# Ver IP de la interfaz ConnectX-7 activa
ip addr show enp1s0f1np1
ping <IP-CX7-DEL-OTRO-NODO>
MASTER_ADDR
para
garantizar los 200Gbps de ancho de banda.
Consulta la documentación adicional si es necesario:
Guía de NVIDIA8. Configuración del Firewall
Asegúrate de que los siguientes puertos estén abiertos entre ambos nodos:
- 6379 - Ray GCS
- 8265 - Ray Dashboard
- 8000 - vLLM API
Ejemplo de Configuración Práctica
Datos del ejemplo:
- Nodo A: 169.254.123.147
- Nodo B: 169.254.214.62
1. En el NODO A (IP ...147)
Debe dar permiso a la IP del B (...62):
# Permitir tráfico entrante DESDE el Nodo B
sudo ufw allow from 169.254.214.62 to any port 6379 proto tcp comment 'Ray GCS desde Nodo B'
sudo ufw allow from 169.254.214.62 to any port 8265 proto tcp comment 'Ray Dashboard desde Nodo B'
sudo ufw allow from 169.254.214.62 to any port 8000 proto tcp comment 'vLLM API desde Nodo B'
# Recargar firewall
sudo ufw reload
2. En el NODO B (IP ...62)
Debe dar permiso a la IP del A (...147):
# Permitir tráfico entrante DESDE el Nodo A
sudo ufw allow from 169.254.123.147 to any port 6379 proto tcp comment 'Ray GCS desde Nodo A'
sudo ufw allow from 169.254.123.147 to any port 8265 proto tcp comment 'Ray Dashboard desde Nodo A'
sudo ufw allow from 169.254.123.147 to any port 8000 proto tcp comment 'vLLM API desde Nodo A'
# Recargar firewall
sudo ufw reload
3. Comprobación final
Verifica que las reglas se han cargado correctamente en ambos nodos:
sudo ufw status
Deberías ver que el estado es active y que las reglas especifican la IP de origen correcta.
9. Autenticación Hugging Face
Modelos como Llama-3 o Gemma requieren autorización previa:
# Instalar la CLI de Hugging Face (ejecutar en ambos nodos)pip install huggingface_hub
hf auth login
Alternativamente, puedes establecer el token en tu entorno local:
HF_TOKEN="hf_your_token_here"
NCCL (NVIDIA Collective Communications Library) es fundamental para optimizar la transferencia de datos entre las GPUs de ambos nodos.
Paso 1: Configurar conectividad de red
Asegúrate de haber completado la conexión física mediante cable QSFP y de tener configurado el SSH sin contraseña entre ambos nodos.
Paso 2: Construir NCCL con soporte Blackwell
Ejecuta estos comandos en ambos nodos para compilar NCCL desde el código fuente con soporte para la arquitectura Blackwell:
# Instalar dependencias y clonar repositoriosudo apt-get update && sudo apt-get install -y libopenmpi-dev
git clone -b v2.28.9-1 https://github.com/NVIDIA/nccl.git ~/nccl/
cd ~/nccl/
make -j src.build NVCC_GENCODE="-gencode=arch=compute_121,code=sm_121"
export CUDA_HOME="/usr/local/cuda"
export MPI_HOME="/usr/lib/aarch64-linux-gnu/openmpi"
export NCCL_HOME="$HOME/nccl/build/"
export LD_LIBRARY_PATH="$NCCL_HOME/lib:$CUDA_HOME/lib64/:$MPI_HOME/lib:$LD_LIBRARY_PATH"
Paso 3: Construir suite de pruebas NCCL
Compila los tests de NCCL en ambos nodos para verificar el rendimiento:
git clone https://github.com/NVIDIA/nccl-tests.git ~/nccl-tests/
cd ~/nccl-tests/
make MPI=1
Paso 4: Identificar interfaz activa e IPs
Identifica qué puertos de red están activos (Up) utilizando ibdev2netdev e
inspecciona
su IP:
ibdev2netdev
ip addr show enp1s0f1np1
enp1.
# Configurar variables de la interfaz activa
export UCX_NET_DEVICES=enp1s0f1np1
export NCCL_SOCKET_IFNAME=enp1s0f1np1
export OMPI_MCA_btl_tcp_if_include=enp1s0f1np1
# Ejecutar test de ancho de banda estándar
mpirun -np 2 -H :1,:1 \
--mca plm_rsh_agent "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking =no" \
-x LD_LIBRARY_PATH=$LD_LIBRARY_PATH \
$HOME/nccl-tests/build/all_gather_perf
# Ejecutar test con buffer grande para maximizar los 200Gbps
mpirun -np 2 -H :1,:1 \
--mca plm_rsh_agent "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \
-x LD_LIBRARY_PATH=$LD_LIBRARY_PATH \
$HOME/nccl-tests/build/all_gather_perf -b 16G -e 16G -f 2
Una vez verificado NCCL, configuraremos vLLM para servir modelos de lenguaje a gran escala aprovechando la potencia de los dos nodos Spark.
Paso 1: Script de despliegue del cluster
Descarga el script que coordina la configuración del cluster Ray en ambos nodos:
wget https://raw.githubusercontent.com/vllm-project/vllm/refs/heads/main/examples/online_serving/run_cluster.sh
chmod +x run_cluster.sh
Paso 2: Imagen de vLLM desde NVIDIA NGC
Configura Docker y descarga la imagen oficial optimizada:
docker pull nvcr.io/nvidia/vllm:25.11-py3
export VLLM_IMAGE=nvcr.io/nvidia/vllm:25.11-py3
Paso 3: Iniciar el Nodo Maestro (Ray Head)
Ejecuta esto en el Nodo 1. Este nodo coordinará la inferencia distribuida y servirá el endpoint de la API.
# En el Nodo 1, iniciar nodo maestro
# Obtener la IP de la interfaz de alta velocidad
# Usa la interfaz que aparece como "(Up)" en ibdev2netdev
export MN_IF_NAME=enp1s0f1np1
export VLLM_HOST_IP=$(ip -4 addr show $MN_IF_NAME | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo "Usando interfaz $MN_IF_NAME con IP $VLLM_HOST_IP"
bash run_cluster.sh $VLLM_IMAGE $VLLM_HOST_IP --head ~/.cache/huggingface \
-e VLLM_HOST_IP=$VLLM_HOST_IP \
-e UCX_NET_DEVICES=$MN_IF_NAME \
-e NCCL_SOCKET_IFNAME=$MN_IF_NAME \
-e OMPI_MCA_btl_tcp_if_include=$MN_IF_NAME \
-e GLOO_SOCKET_IFNAME=$MN_IF_NAME \
-e TP_SOCKET_IFNAME=$MN_IF_NAME \
-e RAY_memory_monitor_refresh_ms=0 \
-e MASTER_ADDR=$VLLM_HOST_IP
Paso 4: Iniciar Nodo Trabajador (Ray Worker)
Conecta el Nodo 2 al cluster Ray como nodo trabajador para proporcionar recursos adicionales de GPU.
# En el Nodo 2, unirse como trabajador
# Establecer el nombre de la interfaz (la misma que en el Nodo 1)
export MN_IF_NAME=enp1s0f1np1
# Obtener la propia IP del Nodo 2
export VLLM_HOST_IP=$(ip -4 addr show $MN_IF_NAME | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
# IMPORTANTE: Establecer HEAD_NODE_IP a la IP del Nodo 1
# Debes obtener este valor del Nodo 1 (ejecuta: echo $VLLM_HOST_IP en Nodo 1)
export HEAD_NODE_IP=
echo "Worker IP: $VLLM_HOST_IP, conectando al nodo maestro en: $HEAD_NODE_IP"
bash run_cluster.sh $VLLM_IMAGE $HEAD_NODE_IP --worker ~/.cache/huggingface \
-e VLLM_HOST_IP=$VLLM_HOST_IP \
-e UCX_NET_DEVICES=$MN_IF_NAME \
-e NCCL_SOCKET_IFNAME=$MN_IF_NAME \
-e OMPI_MCA_btl_tcp_if_include=$MN_IF_NAME \
-e GLOO_SOCKET_IFNAME=$MN_IF_NAME \
-e TP_SOCKET_IFNAME=$MN_IF_NAME \
-e RAY_memory_monitor_refresh_ms=0 \
-e MASTER_ADDR=$HEAD_NODE_IP
Paso 5: Servir Llama 3.3 70B
Una vez que el cluster esté listo, localiza el contenedor e inicia el servidor de vLLM:
# En el Nodo 1, encontrar el nombre del contenedor (será node-)
export VLLM_CONTAINER=$(docker ps --format '{{.Names}}' | grep -E '^node-[0-9]+$')
echo "Contenedor encontrado: $VLLM_CONTAINER"
# Iniciar servidor dentro del contenedor
docker exec -it $VLLM_CONTAINER /bin/bash -c '
vllm serve meta-llama/Llama-3.3-70B-Instruct \
--tensor-parallel-size 2 --max_model_len 2048'
# Descargar modelo 405B cuantizado
huggingface-cli download hugging-quants/Meta-Llama-3.1-405B-Instruct-AWQ-INT4
echo "Modelo 405B cuantizado descargado."
# En el Nodo 1, lanzar con parámetros de memoria limitada
export VLLM_CONTAINER=$(docker ps --format '{{.Names}}' | grep -E '^node-[0-9]+$')
echo "Lanzando 405B en: $VLLM_CONTAINER"
docker exec -it $VLLM_CONTAINER /bin/bash -c '
vllm serve hugging-quants/Meta-Llama-3.1-405B-Instruct \
--tensor-parallel-size 2 --max_model_len 256 --gpu-memory-utilization 1.0 \
--max-num-seqs 1 --max_num_batched_tokens 256'
echo "Servidor vLLM para Llama 3.1 405B iniciado con parámetros restringidos."
Verificación y Pruebas
Para probar que el servidor está respondiendo correctamente a través de la red distribuida:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.3-70B-Instruct",
"prompt": "Escribe un haiku sobre una GPU",
"max_tokens": 32,
"temperature": 0.7
}'
Monitoreo y Validación
- Ray Dashboard:
http://<IP_NODO_MAESTRO>:8265 - Health Check:
curl http://localhost:8000/health - Uso de VRAM:
Bash
nvidia-smi --query-gpu=memory.used,memory.total --format=csv