Skip to content

Commit ba42b0b

Browse files
authored
Merge branch 'main' into add-new-hf-dlcs-tags
2 parents fd1e87c + c49cf2e commit ba42b0b

513 files changed

Lines changed: 37868 additions & 17337 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/rules/ci-architecture.md

Lines changed: 264 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
______________________________________________________________________
2-
3-
## inclusion: always description: Test strategy and guidelines for the deep-learning-containers repository.
1+
---
2+
description: Test strategy, conventions, and guidelines for DLC integration and unit tests
3+
paths:
4+
- "test/**/*"
5+
---
46

57
# Test Strategy & Guidelines
68

Lines changed: 190 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,220 @@
11
name: 'Build Docker Image'
2-
description: 'Build and push Docker images for different frameworks and targets'
2+
description: 'Build and push a Docker image using config-file-driven build args, with pre/post build hooks.'
33

44
inputs:
5-
framework:
6-
description: 'Framework name'
7-
required: true
8-
target:
9-
description: 'Docker build target'
10-
required: true
11-
base-image:
12-
description: 'Base Docker image'
13-
required: true
14-
framework-version:
15-
description: 'Framework version'
16-
required: true
17-
container-type:
18-
description: 'Container type (e.g., general)'
5+
config-file:
6+
description: 'Path to the image config YAML file'
197
required: true
208
aws-account-id:
219
description: 'AWS account ID for ECR'
2210
required: true
2311
aws-region:
24-
description: 'AWS region'
12+
description: 'AWS region for ECR'
2513
required: true
26-
tag-pr:
27-
description: 'Pull request image tag'
14+
tag-suffix:
15+
description: 'Suffix for the CI image tag (e.g., github.run_id or pr-NUMBER)'
2816
required: true
29-
dockerfile-path:
30-
description: 'Path to the Dockerfile'
31-
required: true
32-
arch-type:
33-
description: 'Architecture type (e.g., x86, arm64)'
34-
required: false
35-
default: 'x86'
36-
device-type:
37-
description: 'Device type (e.g., gpu, cpu)'
38-
required: false
39-
default: 'gpu'
40-
cuda-version:
41-
description: 'CUDA version (e.g., cu129)'
42-
required: false
43-
default: ''
44-
python-version:
45-
description: 'Python version (e.g., py312)'
46-
required: false
47-
default: ''
48-
os-version:
49-
description: 'OS version (e.g., ubuntu24.04)'
50-
required: false
51-
default: ''
52-
contributor:
53-
description: 'Contributor name'
54-
required: false
55-
default: 'None'
56-
customer-type:
57-
description: 'Customer type (e.g., sagemaker, ec2)'
58-
required: false
59-
default: ''
60-
inference-toolkit-version:
61-
description: 'Inference toolkit version (e.g., 2.0.25)'
62-
required: false
63-
default: ''
64-
torchserve-version:
65-
description: 'TorchServe version (e.g., 0.12.0)'
66-
required: false
67-
default: ''
68-
transformers-version:
69-
description: 'Transformers library version (e.g., 4.28.1)'
70-
required: false
71-
default: ''
7217

7318
outputs:
7419
image-uri:
75-
description: 'Built image URI'
76-
value: ${{ steps.image-uri-build.outputs.CI_IMAGE_URI }}
20+
description: 'Full ECR image URI that was built and pushed'
21+
value: ${{ steps.build.outputs.image-uri }}
22+
ci-tag:
23+
description: 'Computed CI image tag'
24+
value: ${{ steps.ci-tag.outputs.ci-tag }}
7725

7826
runs:
7927
using: 'composite'
8028
steps:
29+
- name: Compute CI tag
30+
id: ci-tag
31+
shell: bash
32+
run: bash "${{ github.action_path }}/compute_ci_tag.sh" --config-file "${{ inputs.config-file }}" --tag-suffix "${{ inputs.tag-suffix }}"
33+
34+
- name: Resolve build args
35+
shell: bash
36+
run: python3 "${{ github.action_path }}/resolve_build_args.py" --config-file "${{ inputs.config-file }}"
37+
38+
- name: Extract build metadata
39+
id: metadata
40+
shell: bash
41+
run: |
42+
CONFIG_FILE="${{ inputs.config-file }}"
43+
echo "framework=$(yq '.metadata.framework' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
44+
echo "framework-version=$(yq '.metadata.framework_version' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
45+
echo "customer-type=$(yq '.metadata.customer_type' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
46+
echo "job-type=$(yq '.metadata.job_type' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
47+
echo "arch-type=$(yq '.metadata.arch_type' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
48+
echo "device-type=$(yq '.metadata.device_type' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
49+
echo "os-version=$(yq '.metadata.os_version' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
50+
echo "python-version=$(yq '.build.python_version // ""' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
51+
echo "cuda-version=$(yq '.build.cuda_version // ""' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
52+
echo "contributor=$(yq '.metadata.contributor // ""' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
53+
echo "transformers-version=$(yq '.build.transformers_version // ""' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
54+
echo "dockerfile=$(yq '.build.dockerfile' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
55+
echo "target=$(yq '.build.target // ""' "$CONFIG_FILE")" >> $GITHUB_OUTPUT
56+
57+
- name: Run pre-build hook
58+
shell: bash
59+
run: |
60+
FRAMEWORK="${{ steps.metadata.outputs.framework }}"
61+
HOOK="scripts/ci/build/${FRAMEWORK}/pre_build.sh"
62+
if [[ -f "$HOOK" ]]; then
63+
echo "Running pre-build hook: $HOOK"
64+
bash "$HOOK" --config-file "${{ inputs.config-file }}"
65+
else
66+
echo "No pre-build hook for ${FRAMEWORK}"
67+
fi
68+
8169
- name: Setup buildkitd
8270
shell: bash
83-
run: .github/scripts/buildkitd.sh
71+
run: bash "${{ github.action_path }}/buildkitd.sh"
8472

8573
- name: ECR login
8674
uses: ./.github/actions/ecr-authenticate
8775
with:
8876
aws-account-id: ${{ inputs.aws-account-id }}
8977
aws-region: ${{ inputs.aws-region }}
9078

91-
- name: Resolve image URI for build
92-
id: image-uri-build
79+
- name: Build and push image
80+
id: build
9381
shell: bash
9482
run: |
95-
CI_IMAGE_URI=${{ inputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/ci:${{ inputs.tag-pr }}
96-
echo "Image URI to build: ${CI_IMAGE_URI}"
97-
echo "CI_IMAGE_URI=${CI_IMAGE_URI}" >> ${GITHUB_ENV}
98-
echo "CI_IMAGE_URI=${CI_IMAGE_URI}" >> ${GITHUB_OUTPUT}
83+
CI_TAG="${{ steps.ci-tag.outputs.ci-tag }}"
84+
CI_IMAGE_URI="${{ inputs.aws-account-id }}.dkr.ecr.${{ inputs.aws-region }}.amazonaws.com/ci:${CI_TAG}"
85+
DOCKERFILE="${{ steps.metadata.outputs.dockerfile }}"
86+
TARGET="${{ steps.metadata.outputs.target }}"
87+
FRAMEWORK="${{ steps.metadata.outputs.framework }}"
88+
FRAMEWORK_VERSION="${{ steps.metadata.outputs.framework-version }}"
89+
CUSTOMER_TYPE="${{ steps.metadata.outputs.customer-type }}"
90+
JOB_TYPE="${{ steps.metadata.outputs.job-type }}"
91+
92+
# Build --build-arg flags from EXTRA_BUILD_ARGS (use array for space-safe values)
93+
BUILD_ARGS=()
94+
for var in ${EXTRA_BUILD_ARGS:-}; do
95+
if [[ -n "${!var:-}" ]]; then
96+
BUILD_ARGS+=("--build-arg" "${var}=${!var}")
97+
fi
98+
done
9999
100-
- name: Build image
100+
# Always pass framework metadata as build-args
101+
BUILD_ARGS+=("--build-arg" "FRAMEWORK=${FRAMEWORK}")
102+
BUILD_ARGS+=("--build-arg" "FRAMEWORK_VERSION=${FRAMEWORK_VERSION}")
103+
BUILD_ARGS+=("--build-arg" "CONTAINER_TYPE=${JOB_TYPE}")
104+
BUILD_ARGS+=("--build-arg" "CACHE_REFRESH=$(date +%Y-%m-%d)")
105+
106+
# Pass hook-injected env vars (set by pre_build hooks via GITHUB_ENV)
107+
if [[ -n "${USE_PREBUILT_WHEEL:-}" ]]; then
108+
BUILD_ARGS+=("--build-arg" "USE_PREBUILT_WHEEL=${USE_PREBUILT_WHEEL}")
109+
fi
110+
if [[ -n "${FRAMEWORK_SHORT_VERSION:-}" ]]; then
111+
BUILD_ARGS+=("--build-arg" "FRAMEWORK_SHORT_VERSION=${FRAMEWORK_SHORT_VERSION}")
112+
fi
113+
if [[ -n "${PYTHON_VERSION:-}" ]]; then
114+
PYTHON_SHORT_VERSION=$(echo "${PYTHON_VERSION}" | cut -d. -f1,2)
115+
BUILD_ARGS+=("--build-arg" "PYTHON_SHORT_VERSION=${PYTHON_SHORT_VERSION}")
116+
fi
117+
118+
# SageMaker labels
119+
LABEL_ARGS=()
120+
if [[ "$CUSTOMER_TYPE" == "sagemaker" ]]; then
121+
LABEL_FRAMEWORK=$(echo "${FRAMEWORK}" | tr '_' '-')
122+
LABEL_FRAMEWORK_VERSION=$(echo "${FRAMEWORK_VERSION}" | tr '.' '-')
123+
LABEL_ARCH="${{ steps.metadata.outputs.arch-type }}"
124+
LABEL_DEVICE_TYPE="${{ steps.metadata.outputs.device-type }}"
125+
126+
# Convert raw cuda version (13.0.2) to short form (cu130)
127+
CUDA_RAW="${{ steps.metadata.outputs.cuda-version }}"
128+
if [[ -n "$CUDA_RAW" ]]; then
129+
CUDA_MAJOR=$(echo "$CUDA_RAW" | cut -d. -f1)
130+
CUDA_MINOR=$(echo "$CUDA_RAW" | cut -d. -f2)
131+
LABEL_CUDA="cu${CUDA_MAJOR}${CUDA_MINOR}"
132+
else
133+
LABEL_CUDA=""
134+
fi
135+
if [[ "$LABEL_DEVICE_TYPE" == "gpu" && -n "$LABEL_CUDA" ]]; then
136+
LABEL_DEVICE_TYPE="gpu.${LABEL_CUDA}"
137+
fi
138+
139+
# Convert raw python version (3.12) to short form (py312)
140+
PYTHON_RAW="${{ steps.metadata.outputs.python-version }}"
141+
if [[ -n "$PYTHON_RAW" ]]; then
142+
PY_MAJOR=$(echo "$PYTHON_RAW" | cut -d. -f1)
143+
PY_MINOR=$(echo "$PYTHON_RAW" | cut -d. -f2)
144+
LABEL_PYTHON="py${PY_MAJOR}${PY_MINOR}"
145+
else
146+
LABEL_PYTHON=""
147+
fi
148+
149+
LABEL_OS=$(echo "${{ steps.metadata.outputs.os-version }}" | tr '.' '-')
150+
151+
LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.arch.${LABEL_ARCH}=true")
152+
LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.device.${LABEL_DEVICE_TYPE}=true")
153+
LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.framework.${LABEL_FRAMEWORK}.${LABEL_FRAMEWORK_VERSION}=true")
154+
LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.job.${JOB_TYPE}=true")
155+
[[ -n "$LABEL_OS" ]] && LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.os.${LABEL_OS}=true")
156+
[[ -n "$LABEL_PYTHON" ]] && LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.python.${LABEL_PYTHON}=true")
157+
158+
CONTRIBUTOR="${{ steps.metadata.outputs.contributor }}"
159+
if [[ -n "$CONTRIBUTOR" && "$CONTRIBUTOR" != "None" ]]; then
160+
LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.contributor.${CONTRIBUTOR}=true")
161+
fi
162+
163+
TRANSFORMERS_VER="${{ steps.metadata.outputs.transformers-version }}"
164+
if [[ -n "$TRANSFORMERS_VER" ]]; then
165+
LABEL_TRANSFORMERS=$(echo "${TRANSFORMERS_VER}" | tr '.' '-')
166+
LABEL_ARGS+=("--label" "com.amazonaws.ml.engines.sagemaker.dlc.lib.transformers.${LABEL_TRANSFORMERS}=true")
167+
fi
168+
fi
169+
170+
# Target flag (optional)
171+
TARGET_ARGS=()
172+
if [[ -n "$TARGET" ]]; then
173+
TARGET_ARGS+=("--target" "${TARGET}")
174+
fi
175+
176+
# Export intermediate stages if requested (wheel cache miss)
177+
if [[ -n "${EXPORT_TARGETS:-}" ]]; then
178+
IFS=',' read -ra EXPORTS <<< "${EXPORT_TARGETS}"
179+
for EXPORT in "${EXPORTS[@]}"; do
180+
EXPORT_TARGET="${EXPORT%%:*}"
181+
EXPORT_DEST="${EXPORT##*:}"
182+
echo "Exporting stage '${EXPORT_TARGET}' to ${EXPORT_DEST}..."
183+
docker buildx build --progress plain \
184+
"${BUILD_ARGS[@]}" \
185+
--target "${EXPORT_TARGET}" \
186+
--output "type=local,dest=${EXPORT_DEST}" \
187+
-f "${DOCKERFILE}" . || echo "Export ${EXPORT_TARGET} failed (non-fatal)"
188+
done
189+
fi
190+
191+
# Main build
192+
docker buildx use default 2>/dev/null || true
193+
echo "Building ${CI_IMAGE_URI}"
194+
docker buildx build --progress plain \
195+
"${BUILD_ARGS[@]}" \
196+
"${LABEL_ARGS[@]}" \
197+
--cache-to=type=inline \
198+
--cache-from=type=registry,ref="${CI_IMAGE_URI}" \
199+
--tag "${CI_IMAGE_URI}" \
200+
--push \
201+
"${TARGET_ARGS[@]}" \
202+
-f "${DOCKERFILE}" .
203+
204+
echo "image-uri=${CI_IMAGE_URI}" >> $GITHUB_OUTPUT
205+
echo "CI_IMAGE_URI=${CI_IMAGE_URI}" >> $GITHUB_ENV
206+
207+
# Cleanup local image
208+
docker rmi ${CI_IMAGE_URI} 2>/dev/null || true
209+
210+
- name: Run post-build hook
101211
shell: bash
102-
run: .github/scripts/build_image.sh
103-
env:
104-
FRAMEWORK: ${{ inputs.framework }}
105-
TARGET: ${{ inputs.target }}
106-
BASE_IMAGE: ${{ inputs.base-image }}
107-
FRAMEWORK_VERSION: ${{ inputs.framework-version }}
108-
CONTAINER_TYPE: ${{ inputs.container-type }}
109-
AWS_ACCOUNT_ID: ${{ inputs.aws-account-id }}
110-
AWS_REGION: ${{ inputs.aws-region }}
111-
TAG_PR: ${{ inputs.tag-pr }}
112-
DOCKERFILE_PATH: ${{ inputs.dockerfile-path }}
113-
ARCH_TYPE: ${{ inputs.arch-type }}
114-
DEVICE_TYPE: ${{ inputs.device-type }}
115-
CUDA_VERSION: ${{ inputs.cuda-version }}
116-
PYTHON_VERSION: ${{ inputs.python-version }}
117-
OS_VERSION: ${{ inputs.os-version }}
118-
CONTRIBUTOR: ${{ inputs.contributor }}
119-
CUSTOMER_TYPE: ${{ inputs.customer-type }}
120-
INFERENCE_TOOLKIT_VERSION: ${{ inputs.inference-toolkit-version }}
121-
TORCHSERVE_VERSION: ${{ inputs.torchserve-version }}
122-
TRANSFORMERS_VERSION: ${{ inputs.transformers-version }}
212+
run: |
213+
FRAMEWORK="${{ steps.metadata.outputs.framework }}"
214+
HOOK="scripts/ci/build/${FRAMEWORK}/post_build.sh"
215+
if [[ -f "$HOOK" ]]; then
216+
echo "Running post-build hook: $HOOK"
217+
bash "$HOOK" --config-file "${{ inputs.config-file }}"
218+
else
219+
echo "No post-build hook for ${FRAMEWORK}"
220+
fi
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env bash
2+
# Compute the CI image tag from a config file.
3+
#
4+
# Format: {image.name}-{framework_version}-{device_type}-{py_short}-{cu_short}-{tag_suffix}
5+
# Example: sglang-ec2-amzn2023-0.5.12.dlc1-gpu-py312-cu130-pr-123
6+
#
7+
# Usage:
8+
# bash compute_ci_tag.sh --config-file <path> --tag-suffix <suffix>
9+
#
10+
# Output: writes ci-tag=<value> to $GITHUB_OUTPUT
11+
#
12+
# Requires: yq
13+
14+
set -euo pipefail
15+
16+
CONFIG_FILE=""
17+
TAG_SUFFIX=""
18+
19+
while [[ $# -gt 0 ]]; do
20+
case "$1" in
21+
--config-file) CONFIG_FILE="$2"; shift 2 ;;
22+
--tag-suffix) TAG_SUFFIX="$2"; shift 2 ;;
23+
*) echo "Unknown argument: $1" >&2; exit 1 ;;
24+
esac
25+
done
26+
27+
[[ -n "$CONFIG_FILE" ]] || { echo "ERROR: --config-file is required" >&2; exit 1; }
28+
[[ -n "$TAG_SUFFIX" ]] || { echo "ERROR: --tag-suffix is required" >&2; exit 1; }
29+
[[ -f "$CONFIG_FILE" ]] || { echo "ERROR: Config file not found: $CONFIG_FILE" >&2; exit 1; }
30+
31+
IMAGE_NAME=$(yq '.image.name' "$CONFIG_FILE")
32+
FRAMEWORK_VERSION=$(yq '.metadata.framework_version' "$CONFIG_FILE")
33+
DEVICE_TYPE=$(yq '.metadata.device_type' "$CONFIG_FILE")
34+
35+
PYTHON_RAW=$(yq '.build.python_version // ""' "$CONFIG_FILE")
36+
if [[ -n "$PYTHON_RAW" ]]; then
37+
MAJOR=$(echo "$PYTHON_RAW" | cut -d. -f1)
38+
MINOR=$(echo "$PYTHON_RAW" | cut -d. -f2)
39+
PYTHON_SHORT="py${MAJOR}${MINOR}"
40+
else
41+
PYTHON_SHORT=""
42+
fi
43+
44+
CUDA_RAW=$(yq '.build.cuda_version // ""' "$CONFIG_FILE")
45+
if [[ -n "$CUDA_RAW" ]]; then
46+
CUDA_MAJOR=$(echo "$CUDA_RAW" | cut -d. -f1)
47+
CUDA_MINOR=$(echo "$CUDA_RAW" | cut -d. -f2)
48+
CUDA_SHORT="cu${CUDA_MAJOR}${CUDA_MINOR}"
49+
else
50+
CUDA_SHORT=""
51+
fi
52+
53+
SEGMENTS=("${IMAGE_NAME}" "${FRAMEWORK_VERSION}" "${DEVICE_TYPE}")
54+
[[ -n "${PYTHON_SHORT}" ]] && SEGMENTS+=("${PYTHON_SHORT}")
55+
[[ -n "${CUDA_SHORT}" ]] && SEGMENTS+=("${CUDA_SHORT}")
56+
SEGMENTS+=("${TAG_SUFFIX}")
57+
58+
CI_TAG=$(IFS='-'; echo "${SEGMENTS[*]}")
59+
60+
# Replace + with . for OCI tag compliance
61+
CI_TAG="${CI_TAG//+/.}"
62+
63+
echo "CI_TAG=${CI_TAG}"
64+
65+
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
66+
echo "ci-tag=${CI_TAG}" >> "$GITHUB_OUTPUT"
67+
fi

0 commit comments

Comments
 (0)