Skip to content

Commit 115655b

Browse files
committed
fix: address feedback
1 parent 0dcec9b commit 115655b

File tree

4 files changed

+827
-244
lines changed

4 files changed

+827
-244
lines changed

deps/0010-container-strategy.md

Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
# Dynamo Container Build Process Improvements
2+
3+
**Status**: Ready for Review
4+
5+
**Authors**: [nv-tusharma]
6+
7+
**Category**: Architecture
8+
9+
**Replaces**: N/A
10+
11+
**Replaced By**: N/A
12+
13+
**Sponsor**: saturley-hall, nv-anants
14+
15+
**Required Reviewers**: nnshah1, saturley-hall, nv-anants, nvda-mesharma, mc-nv, dmitry-tokarev-nv, pvijayakrish
16+
17+
**Review Date**: 2025-07-18
18+
19+
**Pull Request**: TBD
20+
21+
**Implementation PR / Tracking Issue**: TBD
22+
23+
# Summary
24+
25+
This document outlines a container build process optimization strategy for Dynamo to enhance the developer experience by re-organizing Dockerfiles along with defining a clear and maintainable structure for our Dockerfiles.
26+
27+
One of the goals for this document is to define a clear and maintainable structure for our Dockerfiles. Specifically, to determine how many Dockerfiles we need and clarify the relationships between base, runtime, and development images. The aim is to ensure each environment's Dockerfile builds upon the previous (as supersets), maximizing environment consistency and coverage during daily development and testing.
28+
29+
To achieve this goal, this document proposes certain optimizations to improve the current build process:
30+
- Restructuring the build process to provide a base container with a pre-built version of Dynamo + NIXL available on all distributions, enabling splitting of specific backends from the dynamo build process.
31+
- Defining a structure/template for all Dockerfiles to follow to ensure consistent and reproducible builds across backends along with specific roles/use cases targeted for each stage.
32+
- Implementing remote compiler caching strategies tools like sccache to significantly reduce rust compilation times across builds and CI/CD pipelines.
33+
34+
# Motivation
35+
36+
Dynamo's current container architecture consists of multiple Dockerfiles in the `/containers` directory of the [Dynamo repository](https://github.com/NVIDIA/Dynamo). These Dockerfiles are organized by backend (vLLM, sglang, TRT-LLM) and contain multiple stages (base, devel, ci, runtime) for different use cases. Each stage includes a Dynamo build, the specific backend, and NIXL - our high-throughput, low-latency point-to-point communication library for accelerating inference.
37+
38+
The current approach faces several challenges:
39+
40+
1. **Inefficient Build Process**: Components like Dynamo, NIXL, and backends are installed multiple times across stages instead of using a layered approach. Stages do not build upon each other which leads to repeated steps and inefficient build times.
41+
42+
2. **Developer Experience Issues**: The unclear organization of Dockerfiles makes it difficult for developers to choose the right build for their needs, often defaulting to the devel build regardless of use case.
43+
44+
3. **Build Reliability**: The complex layering and repeated steps across stages can lead to intermittent build failures.
45+
46+
4. **Inconsistent Standards**: Without a unified Dockerfile for building Dynamo, NIXL, and dependencies, code is duplicated or missing across backend-specific Dockerfiles, and optimizations aren't shared effectively.
47+
48+
This document proposes solutions to the build process challenges, aiming to improve overall container build efficiency and developer experience.
49+
50+
## Goals
51+
52+
* Remove duplicate code in current dockerfile implementations and define a single build base image which provides a pre-built container with Dynamo + NIXL.
53+
54+
This base image should operate as a single base container which can then be used as base containers for backend-specific images. By leveraging a base container, We can reduce the redundant code across Dockerfiles and establish a single-source of truth for all Dynamo-builds. This would also enable us to replace the current devel container with the base container for local development/public CI for faster validation of changes.
55+
56+
* Define the relationships between base, runtime, and development images for each Dockerfile and provide a structure/template to follow for Dockerfiles.
57+
58+
* Reduce build flakiness by pinning/fixing dependencies in the base image from package managers and squashing/reducing layers as necessary
59+
60+
Pinning/Fixing dependencies will ensure a unified build environment reducing "it works on my machine" problems or "this worked yesterday"
61+
62+
* Minimize effort for providing multi-arch support across various backends for Dynamo by leveraging manylinux to build for multiple distributions
63+
64+
* Implement remote compiler caching strategies to dramatically reduce build times across development and CI/CD environments
65+
66+
By integrating tools like sccache for remote compilation caching, we can avoid redundant compilation work across builds, significantly speeding up the container build process for both developers and CI pipelines.
67+
68+
### Non Goals
69+
70+
- Container release strategy and processes (covered in separate DEP)
71+
- Unified build environment
72+
73+
## Requirements
74+
75+
### REQ \<\#1\> \<Backend Integration with Base Container\>
76+
The build-base container must be designed such that backend-specific Dockerfiles can integrate with it with minimal changes to their existing build process. This includes:
77+
- Multi-arch support is a P0. The Base container should be able to support both x84_64 and arm64 builds.
78+
- Clear documentation on how to use the base container
79+
- Standardized environment variables and paths
80+
- Replace the current devel container with the base container for local development/public CI for faster validation of changes.
81+
82+
### REQ \<\#2\> \<Layered Container Structure\>
83+
Dockerfiles must follow a layered, super-set structure to optimize build efficiency:
84+
- Each stage should build upon the previous stage or use artifacts from the previous stage
85+
- Artifacts should be built only once and reused across stages
86+
- Clear separation between build-time and runtime dependencies
87+
- Minimal layer count to reduce build complexity
88+
89+
### REQ \<\#3\> \<Stage Purpose Definition\>
90+
Each build stage must have a clearly defined purpose and scope:
91+
- Base: NIXL + Dynamo build from a manylinux container (Enables support on multiple platforms)
92+
- Backend Build: Builds the specified backend along with any dependencies required for the backend
93+
- Runtime: Minimal production deployment requirements
94+
- CI: Testing tools and validation requirements built on runtime
95+
96+
# Proposal
97+
98+
In order to address the requirements, we propose the following changes to the Dynamo build process:
99+
100+
## Build-Base Container
101+
102+
The base container will be a pre-built container that will be used by the backends to build the final container image. This build base container will contain a Dynamo build for all backends to use for their framework-specific build. The base image will leverage a manylinux base image to enable support for multiple distributions (U22, U24, etc). The container will also include a NIXL build since this is common across all backends. This will be a new Dockerfile in the /containers directory. Multi-arch support is also a P0 Also, the base container can be used as a drop-in replacement for the current devel container used in public CI. This would significantly reduce public CI build times and enable faster validation of changes.
103+
104+
## Use-case of build stages along with relationship between stages (base, runtime, dev)
105+
106+
Each backend-specific Dockerfile should follow a specific format. The backend-specific Dockerfiles should be divided up into multiple stages, with each stage inheriting artifacts/leveraging the previous stage as the base container. The following stages should be defined in the backend-specific Dockerfile:
107+
108+
**Backend Build Stage:**
109+
- Targeted User: Developers
110+
- Base Image: Cuda base devel image
111+
- Functionality: Builds targeted backend along with backend-specific dependencies in editable mode.
112+
113+
**Runtime Stage:**
114+
- Targeted User: Customers/Production
115+
- Base Image: Cuda base runtime image
116+
- Functionality: Minimal image with only the dependencies required to deploy and run Dynamo w/backend from the backend build stage; intended for production deployments. Copies dynamo artifacts from base image and backend artifacts from backend build image.
117+
118+
**Development Stage:**
119+
- Targeted User: Developers/Internal CI Pipelines/Local Debugging
120+
- Base Image: Runtime image
121+
- Functionality: Adds development-specific tools, QA test scripts, internal models, and other dependencies needed for developers. We also want to integrate dev container features into this stage.
122+
123+
The CUDA base images will be used from the [NVIDIA CUDA Container Registry](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/cuda). Please refer to the Pros and Cons section for more details on why we chose to use the cuda runtime image instead of the Deep Learning CUDA image.
124+
125+
# Implementation Details
126+
127+
## Container Build Flow
128+
129+
```mermaid
130+
flowchart TD
131+
A[Manylinux build base image]
132+
B[NIXL Setup/Build NIXL Wheel]
133+
C[Build Dependencies]
134+
D[Build Dynamo]
135+
E[Build Base Container]
136+
F[Build Backend from source]
137+
G[Backend Build Image]
138+
J[Cuda Runtime<br/>nvcr.io/nvidia/cuda.XX.YY-runtime]
139+
K[Install NATS + ETCD]
140+
L[Runtime-specific dependencies]
141+
M[pip install dynamo + Backend && NIXL]
142+
N[Backend Runtime Image]
143+
O[Install CI/Test/Dev dependencies]
144+
P[Development image]
145+
146+
%% Main build flow (left)
147+
A --> B
148+
B --> C
149+
C --> D
150+
D --> E
151+
E --> F
152+
F --> G
153+
154+
%% Runtime flow (right)
155+
J --> K
156+
K --> L
157+
L --> M
158+
M --> N
159+
N --> O
160+
O --> P
161+
162+
%% Cross-links with text
163+
E -.->|Copy Dynamo & NIXL Build Wheels| M
164+
G -.->|Copy Backend build| M
165+
166+
%% Styling
167+
classDef gray fill:#e5e7eb,stroke:#333,stroke-width:1px;
168+
```
169+
170+
The diagram above illustrates the proposed container build strategy showing the relationships between:
171+
- Build Base Container with common dependencies
172+
- Backend-specific development containers
173+
- Runtime containers
174+
- Development containers
175+
176+
This layered approach ensures consistent builds, reduces duplication, and improves maintainability across all backend implementations.
177+
178+
## Dockerfile Structure Template
179+
180+
Each backend-specific Dockerfile will follow this standardized structure:
181+
182+
```dockerfile
183+
# Backend Build Stage
184+
FROM nvcr.io/nvidia/cuda:XX.YY-devel-ubuntuXX.XX as backend-build
185+
# Install backend-specific dependencies and build backend
186+
187+
# Runtime Stage
188+
FROM nvcr.io/nvidia/cuda:XX.YY-runtime-ubuntuXX.XX as runtime
189+
# Copy dynamo and NIXL wheels from base container
190+
# Copy backend artifacts from backend-build stage
191+
# Install runtime dependencies only
192+
193+
# Development Stage
194+
FROM runtime as dev
195+
# Add development-specific tools and test dependencies
196+
```
197+
198+
## Dependency Management
199+
200+
- **Pinned Dependencies**: All dependencies will be pinned to specific versions in the base container
201+
- **Multi-arch Support**: Base container will support both x86_64 and arm64 architectures
202+
- **Minimal Runtime**: Runtime images will only include necessary dependencies for production deployment
203+
- **Layered Caching**: Build layers will be optimized for Docker build cache efficiency
204+
205+
## Build Caching Strategy (Phase 3)
206+
207+
To further optimize build times after the initial Dockerfile restructuring, We will explore remote compiler caching strategies (further optimizations to be added in future):
208+
209+
### Remote Compiler Caching Strategies
210+
- **Compiler cache Integration**: Leverage compiler cache service like [sccache](https://github.com/mozilla/sccache) in the build-base container to cache compilation results for Dynamo, NIXL, and backend dependencies.
211+
- **Remote Cache Storage**: Use a remote cache storage service to store the cached compilation results in CI/CD pipelines.
212+
- **Cache Size Management**: Configure appropriate cache size limits and cleanup policies to balance storage usage with build performance.
213+
214+
215+
### Implementation Considerations
216+
- **Cache Invalidation**: Implement smart cache invalidation based on dependency changes and version updates
217+
- **Monitoring**: Add build time metrics to measure cache effectiveness and identify optimization opportunities
218+
- **CI Integration**: Configure CI/CD pipelines to properly utilize remote caching storage.
219+
220+
221+
# Implementation Phases
222+
223+
## Phase \<\#1\> \<Build Base Container Development\>
224+
225+
**Release Target**: v0.5.0
226+
227+
**Effort Estimate**: 1 engineer, 1 week
228+
229+
**Work Item(s):** N/A
230+
231+
**Supported API / Behavior:**
232+
233+
* Pre-built Build base container with multi-arch support containing Dynamo and NIXL
234+
* NIXL integration in base container
235+
* Manylinux base for broad distribution compatibility
236+
* Standardized environment variables and paths
237+
* Pinned dependencies for base container
238+
239+
**Not Supported:**
240+
241+
242+
## Phase \<\#2\> \<Restructure backend Dockerfiles to follow proposed structure\>
243+
244+
**Release Target**: v0.5.1
245+
246+
**Effort Estimate**: 1 engineer, 1 week
247+
248+
**Work Item(s):** \<one or more links to github issues\>
249+
250+
**Supported API / Behavior:**
251+
252+
* Updated vLLM, sglang, and TRT-LLM Dockerfiles following new structure
253+
* Clear separation between backend build, runtime, and CI stages
254+
* Integration with base container for Dynamo and NIXL dependencies
255+
* Reduced build times through improved layering
256+
* Backward compatibility with existing Dockerfiles
257+
* Pinned dependencies for backend builds
258+
259+
**Not Supported:**
260+
261+
## Phase \<\#3\> \<Build Caching Optimization\>
262+
263+
**Release Target**: v0.5.1
264+
265+
**Effort Estimate**: 1 engineer, 1 week
266+
267+
**Work Item(s):** N/A
268+
269+
**Supported API / Behavior:**
270+
271+
* Integration of sccache for rust compilation caching across container builds
272+
* Remote cache storage for CI/CD pipelines to reduce cold build times
273+
* Cache invalidation strategies for dependency updates and smart cache layer management
274+
275+
**Not Supported:**
276+
277+
* Advanced distributed caching mechanisms
278+
279+
# Related Proposals
280+
281+
**\[Optional \- if not applicable omit\]**
282+
283+
# Alternate Solutions
284+
285+
**\[Required, if not applicable write N/A\]**
286+
287+
List out solutions that were considered but ultimately rejected. Consider free form \- but a possible format shown below.
288+
289+
## Alt \<\# 2\> \<Provide a single container with multi-backend support instead of multiple backend-specific containers\>
290+
291+
**Pros:**
292+
293+
- Reduce overall complexity (less containers, less Dockerfiles)
294+
- No need foradditonal security scans and QA validation.
295+
- Simpler Open Source approval process.
296+
297+
**Cons:**
298+
299+
- Container size, if a user is only interested in one particular backend, we should remove the dependencies associated with other backends. We would need to provide tools for users to create backend-specific containers for their deployment.
300+
- It is expected that Backends can differ on performance, which could be a result of backend-specific dependencies.
301+
- Build times are expected to be longer for a single container with multi-backend support.
302+
- Is it feasible for a user to want deploy multiple inference engines at once with dynamo?
303+
304+
**Reason Rejected:**
305+
306+
- There are more cons than pros for this approach. Along with the cons, the Dynamo base container is a good drop-in replacement for the multi-backend container.
307+
308+
## Alt #3 Published Base Container with Pinned Dependencies
309+
310+
**Description:**
311+
312+
Instead of building NIXL, UCX, and other stable dependencies from source in each build, publish a pre-built base container with these pinned components. This would create a three-tier container hierarchy:
313+
314+
1. **Base Image (Published):** CUDA + NIXL + UCX + uv + cargo + other stable dependencies
315+
2. **Dynamo Image:** Base Image + Dynamo Rust/Python builds
316+
3. **Framework Image:** Dynamo Image + Framework builds (vLLM, sglang, TRT-LLM)
317+
318+
The base image would be published to a public registry (GitHub Container Registry or NGC) and updated infrequently when NIXL or other core dependencies change.
319+
320+
**Pros:**
321+
322+
- **Dramatically reduced build times:** Skip compilation of NIXL, UCX, and other stable components that rarely change
323+
- **Consistent environment:** All builds use the same pinned versions of core dependencies
324+
- **Simplified maintenance:** Base image updates are centralized and infrequent
325+
- **Better caching:** Base image can be cached across all builds and CI pipelines
326+
- **Reduced CI resource usage:** Less compilation work in CI/CD pipelines
327+
- **Public availability:** Base image could be made available to external users/partners
328+
329+
**Cons:**
330+
331+
- **Additional publishing workflow:** Need separate CI/CD pipeline to build and publish base images
332+
- **Registry management:** Need to manage storage and access for published base images
333+
- **Storage costs:** Published images consume registry storage space
334+
- **Security scanning:** Published base images need regular security scanning and updates
335+
- **Dependency on external registry:** Builds depend on availability of published base image
336+
337+
**Implementation Considerations:**
338+
339+
- **Publishing cadence:** Base image updates triggered by NIXL/UCX version changes or monthly schedule
340+
- **Versioning strategy:** Semantic versioning for base images (e.g., `nvidia/dynamo-base:v1.2.0`)
341+
- **Multi-arch support:** Publish both x86_64 and arm64 variants
342+
- **Registry choice:** GitHub Container Registry (ghcr.io) for open source, NGC for enterprise
343+
- **Fallback strategy:** Ability to build from source if published image unavailable
344+
345+
**Reason Rejected:**
346+
347+
N/A
348+
349+
# Background
350+
351+
**\[Optional \- if not applicable omit\]**
352+
353+
Add additional context and references as needed to help reviewers and authors understand the context of the problem and solution being proposed.
354+
355+
## References
356+
357+
**\[Optional \- if not applicable omit\]**
358+
359+
Add additional references as needed to help reviewers and authors understand the context of the problem and solution being proposed.
360+
361+
* \<hyper-linked title of an external reference resource\>
362+
363+
## Terminology & Definitions
364+
365+
**Base Container:** Pre-built container with Dynamo and NIXL that serves as foundation for backend-specific builds
366+
367+
**Backend Build:** Container stage that builds backend-specific code and dependencies
368+
369+
**sccache:** Compiler cache tool that speeds up recompilation by caching previous compilation results
370+
371+
**CI Stage:** Container stage with testing tools and validation requirements
372+
373+
**Manylinux:** PEP 513 standard for Linux wheel distribution compatibility
374+
375+
**NIXL:** High-throughput, low-latency point-to-point communication library for accelerating inference
376+
377+
**Runtime Stage:** Minimal container stage with only production deployment requirements
378+
379+
## Acronyms & Abbreviations
380+
381+
**CI:** Continuous Integration
382+
383+
**DEP:** Design Enhancement Proposal
384+
385+
**NIXL:** NVIDIA Inference Exchange Library
386+
387+

0 commit comments

Comments
 (0)