#!/usr/bin/env bash # onstart для Vast: разворачивает агента LLM-ноды и держит его запущенным. # # Сам скрипт намеренно тонкий: вся логика в agent.py, который качается # отдельно. Так починка ноды не требует пересоздания шаблона Vast — # шаблоны там неизменяемы, а agent.py достаточно перезалить. set -u LOG=/var/log/vllm-node.log STATE=/opt/vllm-node AGENT="$STATE/agent.py" AGENT_URL="${AGENT_URL:-https://huggingface.co/cloud19/vllm-vast-node/resolve/main/agent.py}" mkdir -p "$STATE" /var/log/vllm-node exec >>"$LOG" 2>&1 echo "=== bootstrap $(date -Is) ===" # Скрипты из README прода ходят в /workspace; на образе vllm рабочий каталог # другой, поэтому связываем, чтобы ручные команды работали как на проде. [ -e /workspace ] || ln -s /root /workspace # Переменные из `docker -e` достаются только процессу, которого Vast запустил # при старте контейнера. Если поднять bootstrap руками из ssh, их не будет, и # нода молча не зарегистрируется (менеджер ответит 403). Берём их у init. if [ -z "${MANAGER_API_KEY:-}" ] && [ -r /proc/1/environ ]; then while IFS= read -r -d '' kv; do case "$kv" in MODEL_ID=*|SERVED_MODEL_NAME=*|WEIGHTS_GIB=*|VLLM_API_KEY=*|HF_TOKEN=*|\ MANAGER_URL=*|MANAGER_API_KEY=*|NODE_POOLS=*|GPU_LAYOUT=*|PORTS=*|\ TENSOR_PARALLEL_SIZE=*|MAX_MODEL_LEN=*|MAX_NUM_SEQS=*|REGISTER=*|\ GPU_MEMORY_UTILIZATION=*|KV_CACHE_DTYPE=*|AGENT_URL=*|VLLM_EXTRA_ARGS=*) export "$kv" ;; esac done /usr/local/bin/vllm-node <<'CLI' #!/usr/bin/env bash set -u STATE=/opt/vllm-node case "${1:-status}" in status) if [ -f "$STATE/state.json" ]; then python3 -m json.tool "$STATE/state.json"; else echo "агент ещё не записал состояние"; fi ;; logs) if [ -n "${2:-}" ]; then tail -f "/var/log/vllm-node/gpu$2.log"; else tail -f /var/log/vllm-node.log; fi ;; vllm-logs) tail -f /var/log/vllm-node/gpu*.log ;; manual) # агент держит vLLM, но не трогает менеджер: удобно на отладке, # иначе снятая руками нода вернётся в пулы через минуту touch "$STATE/manual"; echo "ручной режим включён, нода снимется с пулов" ;; auto) rm -f "$STATE/manual"; echo "автоматический режим, нода вернётся в пулы" ;; stop) # мягко: агент сам снимет ноду с пулов менеджера pkill -TERM -f 'python3 .*agent\.py' && echo "агент получил TERM" ;; restart) touch "$STATE/restarting"; pkill -TERM -f 'python3 .*agent\.py'; echo "перезапуск, следи за vllm-node logs" ;; *) echo "использование: vllm-node {status|logs [N]|vllm-logs|manual|auto|stop|restart}" ;; esac CLI chmod +x /usr/local/bin/vllm-node # Перезапускаем агента, если он упал сам. Ручная остановка (`vllm-node stop`) # выходит с нулём — тогда цикл заканчивается и нода остаётся снятой с пулов. while true; do echo "--- запуск агента $(date -Is) ---" python3 "$AGENT" code=$? if [ -f "$STATE/restarting" ]; then rm -f "$STATE/restarting" echo "перезапуск по просьбе" sleep 5 fetch_agent continue fi if [ "$code" = "0" ]; then echo "агент остановлен штатно, выхожу" break fi echo "агент упал с кодом $code, перезапуск через 30 с" sleep 30 fetch_agent done