Dockerfile 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. # The host agent for a GB10 node. Holds the privileged tools so the container
  2. # running the model does not have to.
  3. #
  4. # Small on purpose: stdlib Python plus py-spy. nvidia-smi is not installed
  5. # here, the NVIDIA container runtime injects it along with the driver
  6. # libraries when the compose file reserves a GPU.
  7. # Pulled registry-qualified: a bare `mentat-artifacts:<ver>` tag resolves to a
  8. # local image, and those have been mislabelled before.
  9. ARG MENTAT_VERSION=0.12.0
  10. FROM mmastrac/mentat-artifacts:${MENTAT_VERSION} AS mentat
  11. FROM python:3.12-slim
  12. # pciutils/usbutils carry pci.ids and usb.ids, without which lspci and lsusb
  13. # report bare hex vendor:device pairs. iproute2 backs the network tool.
  14. RUN apt-get update && apt-get install -y --no-install-recommends \
  15. iproute2 pciutils usbutils procps \
  16. && rm -rf /var/lib/apt/lists/* \
  17. && command -v ip && command -v lspci && command -v lsusb && command -v ps
  18. # py-spy reads another process's Python stack without stopping it. Container
  19. # processes are visible through the host's PID namespace, which the compose
  20. # file shares, so this reaches the engine without the model container holding
  21. # any tracing capability itself.
  22. RUN pip install --no-cache-dir py-spy && py-spy --version
  23. # The accounting helper runs live rather than reading the periodic snapshot,
  24. # because pid: host lets this container see every process and nvidia-smi gives
  25. # the GPU figure that process RSS never shows. The host's own memory timer
  26. # runs the same script.
  27. COPY spark-memory.py /usr/local/bin/spark-memory.py
  28. # The mentat shim, for ray.register only: the agent announces its MCP endpoint
  29. # to the local mentatd, and mentat-serve merges it. --no-deps, because the
  30. # shim installs as `ray` and must not pull real ray in.
  31. COPY --from=mentat /out/ /tmp/mentat-out/
  32. RUN pip install --no-cache-dir --no-deps /tmp/mentat-out/mentatd-*-py3-none-any.whl \
  33. && rm -rf /tmp/mentat-out \
  34. && python3 -c "from ray import register; register.connect, register.parse_args"
  35. COPY spark-agent.py /usr/local/bin/spark-agent.py
  36. RUN chmod +x /usr/local/bin/spark-agent.py /usr/local/bin/spark-memory.py \
  37. && python3 -c "import ast; ast.parse(open('/usr/local/bin/spark-agent.py').read()); \
  38. ast.parse(open('/usr/local/bin/spark-memory.py').read())"
  39. # 8090 = MCP and the node status endpoint. The compose file decides which
  40. # addresses it is reachable on.
  41. EXPOSE 8090
  42. ENTRYPOINT ["python3", "/usr/local/bin/spark-agent.py"]
  43. CMD ["--port", "8090"]