Add CUDA 13.3 / DOCA multi-arch NCCL test image for GB300 fleets - #8
Open
sirajrauff wants to merge 1 commit into
Open
Add CUDA 13.3 / DOCA multi-arch NCCL test image for GB300 fleets#8sirajrauff wants to merge 1 commit into
sirajrauff wants to merge 1 commit into
Conversation
Successor to docker/Dockerfile for GB300/Grace fleets: builds for amd64 and arm64, takes libibverbs from the DOCA-OFED repo instead of the HPC-X tarball, and moves to CUDA 13 (sm_103 is rejected by ptxas in 12.9 and earlier). Bundles sshd so one image serves as both MPIJob launcher and worker. DOCA, NCCL and the nccl-tests ref are pinned by ARG so rebuilds are reproducible. Also raises the PAM open-files limit. pam_limits clamps sshd sessions to the Ubuntu default soft RLIMIT_NOFILE=1024, and NCCL's proxy service polls roughly one fd per rank, so jobs above 1024 ranks fail with poll() EINVAL and hang silently until the limit is lifted. Soft only: raising the hard limit needs CAP_SYS_RESOURCE, and sshd runs pam_limits as required, so a hard bump the runtime cannot satisfy would refuse the login outright.
Comment on lines
+1
to
+139
| # NCCL tests image — CUDA 13.3 / Ubuntu 24.04 / DOCA-OFED userspace / multi-arch. | ||
| # | ||
| # Successor to docker/Dockerfile (CUDA 12.6 / MLNX_OFED-era HPC-X, x86_64-only): | ||
| # - Multi-arch: amd64 + arm64 (GB300/Grace fleets are aarch64). All arch-specific | ||
| # paths derive from TARGETARCH / dpkg multiarch — no hardcoded x86_64. | ||
| # - DOCA-OFED userspace replaces the HPC-X tarball + Ubuntu rdma-core (the | ||
| # "upgrade to DOCA_OFED" note in the legacy Dockerfile; our fleets run | ||
| # DOCA host stacks, CX7 and CX8 alike). | ||
| # - CUDA 13.3 devel base: GB300 (sm_103) needs CUDA >= 13; ptxas in <= 12.9 | ||
| # rejects sm_103a. | ||
| # - NCCL from the CUDA 13 apt repo (>= 2.30; MNNVL-capable), pinned by | ||
| # default via LIBNCCL_VERSION. | ||
| # - openssh-server for Kubeflow MPIJob workers (mpi-operator v2 execs | ||
| # workers over ssh); mpirun from Ubuntu OpenMPI for the launcher. | ||
| # - limits.d nofile override (1048576 soft) so pam_limits stops clamping sshd | ||
| # sessions to 1024 fds — required for >1024-rank NCCL jobs. | ||
| # | ||
| # Build inputs pinned by ARG: DOCA_VERSION, LIBNCCL_VERSION, NCCL_TESTS_REF. | ||
| # Override any of them at build time. | ||
| # | ||
| # Build (multi-arch, push): | ||
| # docker buildx build -f docker/Dockerfile.cuda13 \ | ||
| # --platform linux/arm64,linux/amd64 \ | ||
| # -t ghcr.io/voltagepark/nccl-tests:cuda13.3.0-ubuntu24.04-doca-ssh-server \ | ||
| # --push docker/ | ||
|
|
||
| ARG CUDA_VERSION=13.3.0 | ||
| ARG UBUNTU_VERSION=24.04 | ||
| FROM nvcr.io/nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION} | ||
|
|
||
| # ARGs above the first FROM are visible only to FROM; re-declare the ones the | ||
| # build stage interpolates (the DOCA repo path carries the Ubuntu release). | ||
| ARG UBUNTU_VERSION | ||
| ARG TARGETARCH | ||
| ENV DEBIAN_FRONTEND=noninteractive | ||
|
|
||
| # Base tooling + OpenMPI + sshd. rdma/ibverbs come from the DOCA repo below, | ||
| # NOT Ubuntu's rdma-core, so keep them out of this layer. | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| ca-certificates curl git build-essential \ | ||
| libnuma1 libnuma-dev \ | ||
| openssh-server openssh-client \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # DOCA-OFED userspace (libibverbs/mlx5 provider/librdmacm from NVIDIA's DOCA | ||
| # repo). Repo arch dirs: x86_64 | arm64-sbsa. Pinned to an explicit release: | ||
| # userspace/host-driver skew is the failure class this image exists to | ||
| # diagnose, so a rebuild must not silently swap the verbs stack. Build with | ||
| # --build-arg DOCA_VERSION=latest to float deliberately. | ||
| ARG DOCA_VERSION=3.4.0 | ||
| RUN set -eux; \ | ||
| case "${TARGETARCH}" in \ | ||
| amd64) DOCA_ARCH=x86_64 ;; \ | ||
| arm64) DOCA_ARCH=arm64-sbsa ;; \ | ||
| *) echo "unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \ | ||
| esac; \ | ||
| DOCA_REPO="https://linux.mellanox.com/public/repo/doca/${DOCA_VERSION}/ubuntu${UBUNTU_VERSION}/${DOCA_ARCH}"; \ | ||
| curl -fsSL "${DOCA_REPO}/doca_keyring.gpg" \ | ||
| -o /usr/share/keyrings/doca.gpg; \ | ||
| echo "deb [signed-by=/usr/share/keyrings/doca.gpg] ${DOCA_REPO} ./" \ | ||
| > /etc/apt/sources.list.d/doca.list; \ | ||
| apt-get update; \ | ||
| apt-get install -y --no-install-recommends \ | ||
| libibverbs1 libibverbs-dev ibverbs-providers ibverbs-utils \ | ||
| librdmacm1 librdmacm-dev rdma-core infiniband-diags; \ | ||
| dpkg -s libibverbs1 | grep ^Version; \ | ||
| rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # OpenMPI AFTER the DOCA verbs stack so apt resolves against DOCA's libibverbs | ||
| # (the doca-ofed-userspace meta is deliberately NOT used: it hard-depends on | ||
| # DOCA's own OpenMPI rc + UCX builds, which NCCL does not need — NCCL drives | ||
| # libibverbs directly; MPI is only the test launcher). | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| openmpi-bin libopenmpi-dev && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # NCCL from the CUDA apt repo, pinned to the build validated at scale on GB300. | ||
| # Pass an empty string to take whatever is newest for CUDA 13 instead. | ||
| ARG LIBNCCL_VERSION=2.30.7-1+cuda13.3 | ||
| RUN set -eux; \ | ||
| apt-get update; \ | ||
| if [ -n "${LIBNCCL_VERSION}" ]; then \ | ||
| apt-get install -y --no-install-recommends "libnccl2=${LIBNCCL_VERSION}" "libnccl-dev=${LIBNCCL_VERSION}"; \ | ||
| else \ | ||
| apt-get install -y --no-install-recommends libnccl2 libnccl-dev; \ | ||
| fi; \ | ||
| apt-mark hold libnccl2 libnccl-dev; \ | ||
| dpkg -s libnccl2 | grep ^Version; \ | ||
| rm -f /etc/apt/sources.list.d/doca.list; \ | ||
| rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # MPI-enabled NCCL test binaries, built against a pinned upstream ref: the | ||
| # default NVCC_GENCODE list lives in the cloned tree's src/common.mk, so an | ||
| # unpinned clone would let an upstream edit drop the sm_100 cubin GB300 runs | ||
| # on. /opt/openmpi is an arch-independent symlink so MPI_HOME can be a fixed | ||
| # ENV for in-container rebuilds. | ||
| ARG NCCL_TESTS_REF=v2.19.6 | ||
| RUN set -eux; \ | ||
| ln -s "/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/openmpi" /opt/openmpi; \ | ||
| git clone --depth 1 --branch "${NCCL_TESTS_REF}" \ | ||
| https://github.com/NVIDIA/nccl-tests.git /opt/nccl-tests; \ | ||
| cd /opt/nccl-tests; \ | ||
| make -j"$(nproc)" MPI=1 MPI_HOME=/opt/openmpi | ||
|
|
||
| ENV MPI_HOME=/opt/openmpi | ||
|
|
||
| # sshd runtime prereqs for MPIJob workers (mpi-operator injects keys/config), | ||
| # plus non-interactive ssh client defaults for the launcher: pod hostnames are | ||
| # ephemeral, so host-key pinning is meaningless inside a job and the launcher | ||
| # must never block on verification. | ||
| # The greps assert the substitutions landed: sed exits 0 on zero matches, so a | ||
| # future openssh package that renames these directives would otherwise ship an | ||
| # image where StrictModes silently reverts to yes and every worker rejects the | ||
| # mpi-operator-mounted key on mode grounds. | ||
| RUN mkdir -p /run/sshd && \ | ||
| sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ | ||
| sed -i 's/^#\?StrictModes.*/StrictModes no/' /etc/ssh/sshd_config && \ | ||
| grep -qE '^PermitRootLogin yes' /etc/ssh/sshd_config && \ | ||
| grep -qE '^StrictModes no' /etc/ssh/sshd_config && \ | ||
| printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n LogLevel ERROR\n' >> /etc/ssh/ssh_config | ||
|
|
||
| # Raise the PAM open-files limit for ssh sessions. pam_limits clamps sshd | ||
| # sessions (mpirun -> sshd -> orted) to the Ubuntu default soft | ||
| # RLIMIT_NOFILE=1024, and NCCL's proxy service needs ~one fd per rank — | ||
| # >1024-rank jobs fail with proxy poll() EINVAL without this. | ||
| # | ||
| # Soft only, deliberately. Raising the HARD limit needs CAP_SYS_RESOURCE, which | ||
| # pods do not get; sshd's PAM stack runs pam_limits as `required`, so a | ||
| # setrlimit that fails on a runtime whose hard ceiling is below this value | ||
| # returns PAM_PERM_DENIED and every worker login is refused. A soft-only entry | ||
| # is clamped to the runtime's own hard limit instead, so it degrades to "as high | ||
| # as this host allows". Raise the hard ceiling in the CRI (default_ulimits). | ||
| RUN printf '* soft nofile 1048576\nroot soft nofile 1048576\n' > /etc/security/limits.d/99-nofile.conf | ||
|
|
||
| WORKDIR /opt/nccl-tests | ||
|
|
||
| # sshd by default so the image matches its -ssh-server tag: mpi-operator only | ||
| # injects the sshd command when the worker container declares neither command | ||
| # nor args, and the launcher overrides CMD with its own args either way. | ||
| CMD ["/usr/sbin/sshd", "-D", "-e"] |
There was a problem hiding this comment.
Docker container runs as default root user - medium severity
By default, containers are run with root privileges and also run as the root user inside the container. Running the app as root gives a hacker who was able to hack the application instant root access to the Docker host, which could help them to escalate a hack.
Show fix
Remediation: Add 'USER username' to the end of your file.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
docker/Dockerfile.cuda13, the image we use for NCCL testing on Grace-Blackwell (GB300, aarch64) hardware, plus adocker/README.mdsection describing it.It differs from
docker/Dockerfilein four ways:linux/amd64andlinux/arm64; every arch-specific path derives fromTARGETARCHordpkg-architecture, so there is no hardcodedx86_64.rdma-core, matching hosts that run a DOCA stack on CX7 and CX8. OpenMPI is installed after the DOCA repo so apt resolves it against DOCA's libibverbs.sm_103, andptxasin 12.9 and earlier rejects it.Build inputs are pinned by
ARG—DOCA_VERSION,LIBNCCL_VERSION,NCCL_TESTS_REF— so a rebuild reproduces the same image; each is overridable at build time.The open-files limit
The line worth reviewing closely:
pam_limitsclamps sshd sessions to Ubuntu's default softRLIMIT_NOFILEof 1024. NCCL's proxy service polls an fd array sized roughly one entry per rank, so above 1024 ranks thepoll()fails withEINVAL, the proxy thread exits, lazy transport connect never completes, and the job hangs silently — TCP bootstrap chatter continues, so it still looks alive. Sincempirunreaches workers asmpirun -> sshd -> orted, every rank inherits the clamped limit.It reproduces purely by scale: jobs at or below 1024 ranks pass, jobs above 1024 ranks hang indefinitely. With this override in place, the same job completes.
The entries are soft only, deliberately. Raising the hard limit requires
CAP_SYS_RESOURCE, which pods do not get, and sshd's PAM stack runspam_limitsasrequired— so on any runtime whose hard ceiling sits below the requested value,setrlimitfails and the module returnsPAM_PERM_DENIED, refusing every worker login. A soft-only entry is clamped to the runtime's own ceiling instead, so it degrades to "as high as this host allows" rather than failing closed. Raise the hard ceiling in the CRI (default_ulimits) where a host needs more.Testing
Built with
docker buildxforlinux/arm64and published asghcr.io/voltagepark/nccl-tests:cuda13.3.0-ubuntu24.04-doca-ssh-server.Exercised as a Kubeflow MPIJob (
all_reduce_perf, 512M–8G) across a scale ramp — single node, single NVL72 rack, multiple racks, then a full cluster of 1k+ GPUs. Every stage completed with zero out-of-bounds errors, and bus bandwidth at the largest scale stayed in the expected band relative to the single-rack baseline. The >1024-rank hang described above was the only failure mode encountered, and it disappeared once the limit override was added.Note that the published image was built from an earlier revision of this file; the pins, the soft-only limits change, and the sshd
CMDhave not themselves been rebuilt yet.