build.sh 11.4 KB
Newer Older
Carsten Csiky's avatar
Carsten Csiky committed
1
#!/usr/bin/env bash
Neelay Shah's avatar
Neelay Shah committed
2
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
# SPDX-License-Identifier: Apache-2.0
4
5
6
7
8
9
10
11
12
13
14
15
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
16

17
18
19
20
21
if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
    echo "Error: Bash version 4.0 or higher is required. Current version: ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"
    exit 1
fi

Carsten Csiky's avatar
Carsten Csiky committed
22
set -e
23

24
25
26
TAG=
RUN_PREFIX=
PLATFORM=linux/amd64
27
28
29
30

# Get short commit hash
commit_id=$(git rev-parse --short HEAD)

31
32
# if COMMIT_ID matches a TAG use that
current_tag=$(git describe --tags --exact-match 2>/dev/null | sed 's/^v//') || true
33

34
# Get latest TAG and add COMMIT_ID for dev
Carsten Csiky's avatar
Carsten Csiky committed
35
latest_tag=$(git describe --tags --abbrev=0 "$(git rev-list --tags --max-count=1 main)" | sed 's/^v//') || true
36
37
38
39
if [[ -z ${latest_tag} ]]; then
    latest_tag="0.0.1"
    echo "No git release tag found, setting to unknown version: ${latest_tag}"
fi
40

41
42
43
44
# Use tag if available, otherwise use latest_tag.dev.commit_id
VERSION=v${current_tag:-$latest_tag.dev.$commit_id}

PYTHON_PACKAGE_VERSION=${current_tag:-$latest_tag.dev+$commit_id}
45
46
47
48
49
50

# Frameworks
#
# Each framework has a corresponding base image.  Additional
# dependencies are specified in the /container/deps folder and
# installed within framework specific sections of the Dockerfile.
51

52
declare -A FRAMEWORKS=(["VLLM"]=1 ["TENSORRTLLM"]=2 ["NONE"]=3)
53
DEFAULT_FRAMEWORK=VLLM
54
55
56
57
58
59

SOURCE_DIR=$(dirname "$(readlink -f "$0")")
DOCKERFILE=${SOURCE_DIR}/Dockerfile
BUILD_CONTEXT=$(dirname "$(readlink -f "$SOURCE_DIR")")

# Base Images
60
TENSORRTLLM_BASE_IMAGE=tensorrt_llm/release
61
TENSORRTLLM_BASE_IMAGE_TAG=latest_squashed
62
TENSORRTLLM_PIP_WHEEL_PATH=""
63

64
VLLM_BASE_IMAGE="nvcr.io/nvidia/cuda-dl-base"
65
VLLM_BASE_IMAGE_TAG="25.03-cuda12.8-devel-ubuntu24.04"
66

67
68
69
NONE_BASE_IMAGE="ubuntu"
NONE_BASE_IMAGE_TAG="24.04"

70
NIXL_COMMIT=d247e88c72db75dc00e4e37aa21ed8d99e60c27d
71
72
NIXL_REPO=ai-dynamo/nixl.git

73
74
75
76
77
78
79
get_options() {
    while :; do
        case $1 in
        -h | -\? | --help)
            show_help
            exit
            ;;
80
        --platform)
81
82
83
84
            if [ "$2" ]; then
                PLATFORM=$2
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
85
                missing_requirement "$1"
86
87
            fi
            ;;
88
        --framework)
89
90
91
92
            if [ "$2" ]; then
                FRAMEWORK=$2
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
93
                missing_requirement "$1"
94
95
            fi
            ;;
96
        --tensorrtllm-pip-wheel-path)
97
            if [ "$2" ]; then
98
                TENSORRTLLM_PIP_WHEEL_PATH=$2
99
100
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
101
                missing_requirement "$1"
102
103
            fi
            ;;
104
105
106
107
108
        --base-image)
            if [ "$2" ]; then
                BASE_IMAGE=$2
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
109
                missing_requirement "$1"
110
111
            fi
            ;;
112
        --base-image-tag)
113
114
115
116
            if [ "$2" ]; then
                BASE_IMAGE_TAG=$2
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
117
                missing_requirement "$1"
118
119
120
121
122
123
124
            fi
            ;;
        --target)
            if [ "$2" ]; then
                TARGET=$2
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
125
                missing_requirement "$1"
126
127
128
129
130
131
132
            fi
            ;;
        --build-arg)
            if [ "$2" ]; then
                BUILD_ARGS+="--build-arg $2 "
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
133
                missing_requirement "$1"
134
135
136
137
            fi
            ;;
        --tag)
            if [ "$2" ]; then
138
                TAG="--tag $2"
139
140
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
141
                missing_requirement "$1"
142
143
144
145
146
147
148
149
150
151
            fi
            ;;
        --dry-run)
            RUN_PREFIX="echo"
            echo ""
            echo "=============================="
            echo "DRY RUN: COMMANDS PRINTED ONLY"
            echo "=============================="
            echo ""
            ;;
152
153
        --no-cache)
            NO_CACHE=" --no-cache"
154
            ;;
155
156
        --cache-from)
            if [ "$2" ]; then
157
158
159
                CACHE_FROM="--cache-from $2"
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
160
                missing_requirement "$1"
161
162
            fi
            ;;
163
164
165
166
167
        --cache-to)
            if [ "$2" ]; then
                CACHE_TO="--cache-to $2"
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
168
                missing_requirement "$1"
169
170
            fi
            ;;
ptarasiewiczNV's avatar
ptarasiewiczNV committed
171
172
173
174
175
        --build-context)
            if [ "$2" ]; then
                BUILD_CONTEXT_ARG="--build-context $2"
                shift
            else
Carsten Csiky's avatar
Carsten Csiky committed
176
                missing_requirement "$1"
ptarasiewiczNV's avatar
ptarasiewiczNV committed
177
178
            fi
            ;;
179
180
181
        --release-build)
            RELEASE_BUILD=true
            ;;
182
183
184
185
186
        --)
            shift
            break
            ;;
         -?*)
Carsten Csiky's avatar
Carsten Csiky committed
187
            error 'ERROR: Unknown option: ' "$1"
188
            ;;
189
         ?*)
Carsten Csiky's avatar
Carsten Csiky committed
190
            error 'ERROR: Unknown option: ' "$1"
191
192
193
194
195
196
197
198
199
            ;;
        *)
            break
            ;;
        esac
        shift
    done

    if [ -z "$FRAMEWORK" ]; then
200
        FRAMEWORK=$DEFAULT_FRAMEWORK
201
202
    fi

Carsten Csiky's avatar
Carsten Csiky committed
203
    if [ -n "$FRAMEWORK" ]; then
204
        FRAMEWORK=${FRAMEWORK^^}
205

Carsten Csiky's avatar
Carsten Csiky committed
206
207
        if [[ -z "${FRAMEWORKS[$FRAMEWORK]}" ]]; then
            error 'ERROR: Unknown framework: ' "$FRAMEWORK"
208
        fi
209

Carsten Csiky's avatar
Carsten Csiky committed
210
        if [ -z "$BASE_IMAGE_TAG" ]; then
211
212
213
            BASE_IMAGE_TAG=${FRAMEWORK}_BASE_IMAGE_TAG
            BASE_IMAGE_TAG=${!BASE_IMAGE_TAG}
        fi
214

Carsten Csiky's avatar
Carsten Csiky committed
215
        if [ -z "$BASE_IMAGE" ]; then
216
217
218
            BASE_IMAGE=${FRAMEWORK}_BASE_IMAGE
            BASE_IMAGE=${!BASE_IMAGE}
        fi
219

Carsten Csiky's avatar
Carsten Csiky committed
220
        if [ -z "$BASE_IMAGE" ]; then
221
222
            error "ERROR: Framework $FRAMEWORK without BASE_IMAGE"
        fi
223

224
225
        BASE_VERSION=${FRAMEWORK}_BASE_VERSION
        BASE_VERSION=${!BASE_VERSION}
226
227
228
229

    fi

    if [ -z "$TAG" ]; then
230
        TAG="--tag dynamo:${VERSION}-${FRAMEWORK,,}"
Carsten Csiky's avatar
Carsten Csiky committed
231
        if [ -n "${TARGET}" ]; then
232
233
            TAG="${TAG}-${TARGET}"
        fi
234
235
    fi

Carsten Csiky's avatar
Carsten Csiky committed
236
    if [ -n "$PLATFORM" ]; then
237
238
239
        PLATFORM="--platform ${PLATFORM}"
    fi

Carsten Csiky's avatar
Carsten Csiky committed
240
    if [ -n "$TARGET" ]; then
241
        TARGET_STR="--target ${TARGET}"
242
    else
243
        TARGET_STR="--target dev"
244
    fi
245
246
247
248
249
}


show_image_options() {
    echo ""
250
    echo "Building Dynamo Image: '${TAG}'"
251
252
253
254
    echo ""
    echo "   Base: '${BASE_IMAGE}'"
    echo "   Base_Image_Tag: '${BASE_IMAGE_TAG}'"
    if [[ $FRAMEWORK == "TENSORRTLLM" ]]; then
255
        echo "   Tensorrtllm_Pip_Wheel_Path: '${TENSORRTLLM_PIP_WHEEL_PATH}'"
256
257
258
259
260
261
262
263
264
265
    fi
    echo "   Build Context: '${BUILD_CONTEXT}'"
    echo "   Build Arguments: '${BUILD_ARGS}'"
    echo "   Framework: '${FRAMEWORK}'"
    echo ""
}

show_help() {
    echo "usage: build.sh"
    echo "  [--base base image]"
Carsten Csiky's avatar
Carsten Csiky committed
266
    echo "  [--base-image-tag base image tag]"
267
    echo "  [--platform platform for docker build"
Carsten Csiky's avatar
Carsten Csiky committed
268
    echo "  [--framework framework one of ${!FRAMEWORKS[*]}]"
269
    echo "  [--tensorrtllm-pip-wheel-path path to tensorrtllm pip wheel]"
270
    echo "  [--build-arg additional build args to pass to docker build]"
271
272
    echo "  [--cache-from cache location to start from]"
    echo "  [--cache-to location where to cache the build output]"
273
274
275
    echo "  [--tag tag for image]"
    echo "  [--no-cache disable docker build cache]"
    echo "  [--dry-run print docker commands without running]"
ptarasiewiczNV's avatar
ptarasiewiczNV committed
276
    echo "  [--build-context name=path to add build context]"
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    exit 0
}

missing_requirement() {
    error "ERROR: $1 requires an argument."
}

error() {
    printf '%s %s\n' "$1" "$2" >&2
    exit 1
}

get_options "$@"

291
292
293
294
295
# Automatically set ARCH and ARCH_ALT if PLATFORM is linux/arm64
if [[ "$PLATFORM" == *"linux/arm64"* ]]; then
    BUILD_ARGS+=" --build-arg ARCH=arm64 --build-arg ARCH_ALT=aarch64 "
fi

296
297
298
# Update DOCKERFILE if framework is VLLM
if [[ $FRAMEWORK == "VLLM" ]]; then
    DOCKERFILE=${SOURCE_DIR}/Dockerfile.vllm
299
300
elif [[ $FRAMEWORK == "TENSORRTLLM" ]]; then
    DOCKERFILE=${SOURCE_DIR}/Dockerfile.tensorrt_llm
301
302
elif [[ $FRAMEWORK == "NONE" ]]; then
    DOCKERFILE=${SOURCE_DIR}/Dockerfile.none
303
304
fi

305
if [[ $FRAMEWORK == "VLLM" ]]; then
306
    NIXL_DIR="/tmp/nixl/nixl_src"
307
308

    # Clone original NIXL to temp directory
309
310
    if [ -d "$NIXL_DIR" ]; then
        echo "Warning: $NIXL_DIR already exists, skipping clone"
311
    else
Carsten Csiky's avatar
Carsten Csiky committed
312
313
        if [ -n "${GITHUB_TOKEN}" ]; then
            git clone "https://oauth2:${GITHUB_TOKEN}@github.com/${NIXL_REPO}" "$NIXL_DIR"
314
315
316
317
318
319
        else
            # Try HTTPS first with credential prompting disabled, fall back to SSH if it fails
            if ! GIT_TERMINAL_PROMPT=0 git clone https://github.com/${NIXL_REPO} "$NIXL_DIR"; then
                echo "HTTPS clone failed, falling back to SSH..."
                git clone git@github.com:${NIXL_REPO} "$NIXL_DIR"
            fi
320
321
322
        fi
    fi

Carsten Csiky's avatar
Carsten Csiky committed
323
    cd "$NIXL_DIR" || exit
324
325
326
327
328
    if ! git checkout ${NIXL_COMMIT}; then
        echo "ERROR: Failed to checkout NIXL commit ${NIXL_COMMIT}. The cached directory may be out of date."
        echo "Please delete $NIXL_DIR and re-run the build script."
        exit 1
    fi
329

330
    BUILD_CONTEXT_ARG+=" --build-context nixl=$NIXL_DIR"
331

332
333
    # Add NIXL_COMMIT as a build argument to enable caching
    BUILD_ARGS+=" --build-arg NIXL_COMMIT=${NIXL_COMMIT} "
334
335
fi

336
337
338
339
if [[ $TARGET == "local-dev" ]]; then
    BUILD_ARGS+=" --build-arg USER_UID=$(id -u) --build-arg USER_GID=$(id -g) "
fi

340
341
# BUILD DEV IMAGE

342
BUILD_ARGS+=" --build-arg BASE_IMAGE=$BASE_IMAGE --build-arg BASE_IMAGE_TAG=$BASE_IMAGE_TAG --build-arg FRAMEWORK=$FRAMEWORK --build-arg ${FRAMEWORK}_FRAMEWORK=1 --build-arg VERSION=$VERSION --build-arg PYTHON_PACKAGE_VERSION=$PYTHON_PACKAGE_VERSION"
343

Carsten Csiky's avatar
Carsten Csiky committed
344
if [ -n "${GITHUB_TOKEN}" ]; then
345
346
347
    BUILD_ARGS+=" --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} "
fi

Carsten Csiky's avatar
Carsten Csiky committed
348
if [ -n "${GITLAB_TOKEN}" ]; then
349
350
351
    BUILD_ARGS+=" --build-arg GITLAB_TOKEN=${GITLAB_TOKEN} "
fi

352
if [[ $FRAMEWORK == "TENSORRTLLM" ]]; then
Carsten Csiky's avatar
Carsten Csiky committed
353
    if [ -n "${TENSORRTLLM_PIP_WHEEL_PATH}" ]; then
354
355
        BUILD_ARGS+=" --build-arg TENSORRTLLM_PIP_WHEEL_PATH=${TENSORRTLLM_PIP_WHEEL_PATH} "
    fi
356
357
fi

Carsten Csiky's avatar
Carsten Csiky committed
358
if [ -n "${HF_TOKEN}" ]; then
359
360
    BUILD_ARGS+=" --build-arg HF_TOKEN=${HF_TOKEN} "
fi
361
362
363
364
if [  ! -z ${RELEASE_BUILD} ]; then
    echo "Performing a release build!"
    BUILD_ARGS+=" --build-arg RELEASE_BUILD=${RELEASE_BUILD} "
fi
365

366
LATEST_TAG="--tag dynamo:latest-${FRAMEWORK,,}"
Carsten Csiky's avatar
Carsten Csiky committed
367
if [ -n "${TARGET}" ]; then
368
369
    LATEST_TAG="${LATEST_TAG}-${TARGET}"
fi
370

371
372
373
374
375
376
show_image_options

if [ -z "$RUN_PREFIX" ]; then
    set -x
fi

377
378
379
380
381
382
383
384
385
386
387
388
389
# Check if the TensorRT-LLM base image exists
if [[ $FRAMEWORK == "TENSORRTLLM" ]]; then
    if docker inspect --type=image "$BASE_IMAGE:$BASE_IMAGE_TAG" > /dev/null 2>&1; then
        echo "Image '$BASE_IMAGE:$BASE_IMAGE_TAG' is found."
    else
        echo "Image '$BASE_IMAGE:$BASE_IMAGE_TAG' is not found." >&2
        echo "Please build the TensorRT-LLM base image first. Run ./build_trtllm_base_image.sh" >&2
        echo "or use --base-image and --base-image-tag to an existing TensorRT-LLM base image." >&2
        echo "See https://nvidia.github.io/TensorRT-LLM/installation/build-from-source-linux.html for more information." >&2
        exit 1
    fi
fi

390
$RUN_PREFIX docker build -f $DOCKERFILE $TARGET_STR $PLATFORM $BUILD_ARGS $CACHE_FROM $CACHE_TO $TAG $LATEST_TAG $BUILD_CONTEXT_ARG $BUILD_CONTEXT $NO_CACHE
391
392
393
394
395
396
397

{ set +x; } 2>/dev/null

if [ -z "$RUN_PREFIX" ]; then
    set -x
fi

398
{ set +x; } 2>/dev/null