{# # SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 #} # === BEGIN templates/sglang_runtime.Dockerfile === ################################## ########## Runtime Image ######### ################################## FROM ${RUNTIME_IMAGE}:${RUNTIME_IMAGE_TAG} AS runtime WORKDIR /workspace # Install NATS and ETCD COPY --from=dynamo_base /usr/bin/nats-server /usr/bin/nats-server COPY --from=dynamo_base /usr/local/bin/etcd/ /usr/local/bin/etcd/ ENV PATH=/usr/local/bin/etcd:$PATH # Create dynamo user with group 0 for OpenShift compatibility RUN userdel -r ubuntu > /dev/null 2>&1 || true \ && useradd -m -s /bin/bash -g 0 dynamo \ && [ `id -u dynamo` -eq 1000 ] \ && mkdir -p /home/dynamo/.cache /opt/dynamo \ # Non-recursive chown - only the directories themselves, not contents && chown dynamo:0 /home/dynamo /home/dynamo/.cache /opt/dynamo /workspace \ # No chmod needed: umask 002 handles new files, COPY --chmod handles copied content # Set umask globally for all subsequent RUN commands (must be done as root before USER dynamo) # NOTE: Setting ENV UMASK=002 does NOT work - umask is a shell builtin, not an environment variable && mkdir -p /etc/profile.d && echo 'umask 002' > /etc/profile.d/00-umask.sh {% if context.sglang.enable_media_ffmpeg == "true" %} # Copy ffmpeg RUN --mount=type=bind,from=wheel_builder,source=/usr/local/,target=/tmp/usr/local/ \ mkdir -p /usr/local/lib/pkgconfig && \ cp -rnL /tmp/usr/local/include/libav* /tmp/usr/local/include/libsw* /usr/local/include/ && \ cp -nL /tmp/usr/local/lib/libav*.so /tmp/usr/local/lib/libsw*.so /usr/local/lib/ && \ cp -nL /tmp/usr/local/lib/pkgconfig/libav*.pc /tmp/usr/local/lib/pkgconfig/libsw*.pc /usr/local/lib/pkgconfig/ && \ cp -r /tmp/usr/local/src/ffmpeg /usr/local/src/ {% endif %} {% if target not in ("dev", "local-dev") %} # Runtime target installs only the prebuilt Dynamo wheels. SGLang and its NIXL # packages come from the upstream lmsysorg/sglang runtime image; --no-deps keeps # pip from replacing that stack. Dev/local-dev build from source later in the # shared dev stage after the workspace is bind-mounted. COPY --chmod=775 --chown=dynamo:0 --from=wheel_builder /opt/dynamo/dist/*.whl /opt/dynamo/wheelhouse/ RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \ export PIP_CACHE_DIR=/root/.cache/pip && \ pip install --break-system-packages --no-deps \ /opt/dynamo/wheelhouse/ai_dynamo_runtime*.whl \ /opt/dynamo/wheelhouse/ai_dynamo*any.whl # Install accelerate for diffusion/video worker pipelines (diffusers requires it # for enable_model_cpu_offload but the upstream SGLang runtime image omits it) RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \ export PIP_CACHE_DIR=/root/.cache/pip && \ pip install --break-system-packages --no-deps "accelerate==1.13.0" # Install gpu_memory_service wheel if enabled (all targets) ARG ENABLE_GPU_MEMORY_SERVICE RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \ if [ "${ENABLE_GPU_MEMORY_SERVICE}" = "true" ]; then \ export PIP_CACHE_DIR=/root/.cache/pip && \ GMS_WHEEL=$(ls /opt/dynamo/wheelhouse/gpu_memory_service*.whl 2>/dev/null | head -1); \ if [ -n "$GMS_WHEEL" ]; then pip install --no-cache-dir --break-system-packages "$GMS_WHEEL"; fi; \ fi {% endif %} # Install nvtx pinned in container/deps/requirements.common.txt so DYN_NVTX=1 # profiling works in all targets (runtime, dev, local-dev) — see # components/src/dynamo/common/utils/nvtx_utils.py. --no-deps preserves the # upstream lmsysorg/sglang Python stack. RUN --mount=type=bind,source=./container/deps/requirements.common.txt,target=/tmp/requirements.common.txt \ --mount=type=cache,target=/root/.cache/pip,sharing=locked \ export PIP_CACHE_DIR=/root/.cache/pip && \ pip install --break-system-packages --no-deps $(grep -E '^nvtx==' /tmp/requirements.common.txt) # The upstream lmsysorg/sglang v0.5.10.post1 runtime image bundles the mooncake # python engine (`.so`) but does not declare its runtime apt dep libjsoncpp25, # so `from mooncake.engine import TransferEngine` fails with # `ImportError: libjsoncpp.so.25: cannot open shared object file`. # TODO: re-check whether this apt install is still needed after upgrading sglang # past v0.5.10.post1 — upstream may fix the packaging. RUN apt-get update && \ apt-get install -y --no-install-recommends libjsoncpp25 && \ rm -rf /var/lib/apt/lists/* # Copy tests, deploy and components for CI with correct ownership COPY --chmod=775 --chown=dynamo:0 tests /workspace/tests COPY --chmod=775 --chown=dynamo:0 examples /workspace/examples COPY --chmod=775 --chown=dynamo:0 deploy /workspace/deploy COPY --chmod=775 --chown=dynamo:0 components/src/dynamo/common /workspace/components/src/dynamo/common COPY --chmod=775 --chown=dynamo:0 components/src/dynamo/sglang /workspace/components/src/dynamo/sglang COPY --chmod=775 --chown=dynamo:0 components/src/dynamo/mocker /workspace/components/src/dynamo/mocker COPY --chmod=775 --chown=dynamo:0 recipes/ /workspace/recipes/ COPY --chmod=664 --chown=dynamo:0 ATTRIBUTION* LICENSE /workspace/ # Enable forceful shutdown of inflight requests ENV SGLANG_FORCE_SHUTDOWN=1 # Setup launch banner in common directory accessible to all users RUN --mount=type=bind,source=./container/launch_message/runtime.txt,target=/opt/dynamo/launch_message.txt \ sed '/^#\s/d' /opt/dynamo/launch_message.txt > /opt/dynamo/.launch_screen RUN chmod 755 /opt/dynamo/.launch_screen && \ echo 'cat /opt/dynamo/.launch_screen' >> /etc/bash.bashrc && \ ln -s /workspace /sgl-workspace/dynamo && \ NSYS_BIN=$(find /opt/nvidia/nsight-compute -maxdepth 6 -type f -name nsys -executable 2>/dev/null | head -n1) && \ if [ -n "$NSYS_BIN" ]; then ln -sf "$NSYS_BIN" /usr/local/bin/nsys; \ else echo "WARNING: no bundled nsys found under /opt/nvidia/nsight-compute"; fi USER dynamo ARG DYNAMO_COMMIT_SHA ENV DYNAMO_COMMIT_SHA=${DYNAMO_COMMIT_SHA} ENTRYPOINT ["/opt/nvidia/nvidia_entrypoint.sh"] CMD []