Repository navigation
Build and Push Development Docker Images #31
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
| name: Build and Push Development Docker Images | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| pr_number: | |
| description: "PR number to build from (leave empty to use current branch)" | |
| required: false | |
| default: "" | |
| tag: | |
| description: "Custom tag suffix (overrides pr_number in tag). E.g. 'my-test' → dev-my-test, dev-cu13-my-test, etc." | |
| required: false | |
| default: "" | |
| image_repo: | |
| description: "Docker Hub repo to push to. Use lmsysorg/sglang-staging for testing." | |
| required: false | |
| default: "lmsysorg/sglang" | |
| build_only: | |
| description: "Build and validate one Linux AMD64 CUDA 13 image locally on the runner without logging in or pushing." | |
| required: false | |
| type: boolean | |
| default: false | |
| overlay_dockerfile: | |
| description: "Optional extra Dockerfile lines appended after FROM <base> to build a layered image (e.g. 'RUN pip install ...'). Note: this job has no repo checkout, so only FROM + RUN work — you cannot COPY files from this repo. Leave empty to skip overlay." | |
| required: false | |
| default: "" | |
| overlay_cudas: | |
| description: "Comma-separated cuda variants to overlay onto (cu12, cu13). Default 'cu13'." | |
| required: false | |
| default: "cu13" | |
| overlay_tag_suffix: | |
| description: "Overlay output suffix appended to the base tag. EMPTY = overwrite the base tag(s); non-empty = append (e.g. 'msa')." | |
| required: false | |
| default: "" | |
| schedule: | |
| - cron: "0 0 * * *" | |
| concurrency: | |
| group: release-docker-dev-${{ inputs.tag || inputs.pr_number || 'nightly' }} | |
| cancel-in-progress: true | |
| jobs: | |
| prepare: | |
| if: github.repository == 'sgl-project/sglang' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| checkout_ref: ${{ steps.config.outputs.checkout_ref }} | |
| extra_build_args: ${{ steps.config.outputs.extra_build_args }} | |
| tag_config: ${{ steps.config.outputs.tag_config }} | |
| overlay_cudas_json: ${{ steps.config.outputs.overlay_cudas_json }} | |
| overlay_tags_json: ${{ steps.config.outputs.overlay_tags_json }} | |
| steps: | |
| - name: Compute build configuration | |
| id: config | |
| env: | |
| # Inject multi-line/free-text inputs via env to avoid ${{ }} injection | |
| # breaking the bash script on quotes or $ in the Dockerfile snippet. | |
| OVERLAY_DOCKERFILE_INPUT: ${{ inputs.overlay_dockerfile }} | |
| OVERLAY_CUDAS_INPUT: ${{ inputs.overlay_cudas }} | |
| OVERLAY_SUFFIX_INPUT: ${{ inputs.overlay_tag_suffix }} | |
| run: | | |
| # Determine checkout ref | |
| if [ -n "${{ inputs.pr_number }}" ]; then | |
| echo "checkout_ref=refs/pull/${{ inputs.pr_number }}/head" >> $GITHUB_OUTPUT | |
| else | |
| echo "checkout_ref=" >> $GITHUB_OUTPUT | |
| fi | |
| # Determine extra build args | |
| if [ "${{ github.event_name }}" = "schedule" ]; then | |
| echo "extra_build_args=--build-arg BRANCH_TYPE=local --build-arg CMAKE_BUILD_PARALLEL_LEVEL=\$(nproc)" >> $GITHUB_OUTPUT | |
| else | |
| echo "extra_build_args=--build-arg BRANCH_TYPE=local --build-arg CMAKE_BUILD_PARALLEL_LEVEL=\$(nproc)" >> $GITHUB_OUTPUT | |
| fi | |
| # Determine tag suffix | |
| SUFFIX="" | |
| if [ -n "${{ inputs.tag }}" ]; then | |
| SUFFIX="-${{ inputs.tag }}" | |
| elif [ -n "${{ inputs.pr_number }}" ]; then | |
| SUFFIX="-pr-${{ inputs.pr_number }}" | |
| fi | |
| # Build tag config. dev-cu13 / nightly-dev-cu13 are published as | |
| # aliases on the cu130 image for backwards compatibility with | |
| # consumers pinned to the pre-flip names. | |
| if [ -z "${SUFFIX}" ]; then | |
| # Nightly: include dated tags | |
| TAG_CONFIG='[{"cuda":"cu129","tags":["dev-cu12","nightly-dev-cu12-{date}-{short_sha}"]},{"cuda":"cu130","tags":["dev","dev-cu13","nightly-dev-{date}-{short_sha}","nightly-dev-cu13-{date}-{short_sha}"]}]' | |
| else | |
| TAG_CONFIG="[{\"cuda\":\"cu129\",\"tags\":[\"dev-cu12${SUFFIX}\"]},{\"cuda\":\"cu130\",\"tags\":[\"dev${SUFFIX}\",\"dev-cu13${SUFFIX}\"]}]" | |
| fi | |
| echo "tag_config=${TAG_CONFIG}" >> $GITHUB_OUTPUT | |
| # Overlay configuration (optional). When overlay_dockerfile is set, | |
| # build one or more layered images on top of the just-built base. | |
| # SUFFIX was computed above from inputs.tag / inputs.pr_number. | |
| if [ -n "${OVERLAY_DOCKERFILE_INPUT}" ]; then | |
| # Refuse to overlay without a tag/pr_number: SUFFIX would be empty, | |
| # so base would point at the moving 'dev'/'dev-cu12'/'dev-cu13' | |
| # latest tags and overwrite mode would clobber them. | |
| if [ -z "${SUFFIX}" ]; then | |
| echo "overlay_dockerfile is set but neither 'tag' nor 'pr_number' was given." >&2 | |
| echo "Set one so the overlay targets a specific tag, not the moving 'dev' latest." >&2 | |
| exit 1 | |
| fi | |
| CUDAS_INPUT="${OVERLAY_CUDAS_INPUT}" | |
| [ -z "${CUDAS_INPUT}" ] && CUDAS_INPUT="cu13" | |
| OVERLAY_TAGS='{}' | |
| IFS=',' read -ra CUDAS <<< "${CUDAS_INPUT}" | |
| for C in "${CUDAS[@]}"; do | |
| C="$(echo "${C}" | xargs)" | |
| if [ "${C}" = "cu13" ]; then | |
| BASES='["dev'"${SUFFIX}"'","dev-cu13'"${SUFFIX}"'"]' | |
| elif [ "${C}" = "cu12" ]; then | |
| BASES='["dev-cu12'"${SUFFIX}"'"]' | |
| else | |
| echo "Unknown overlay cuda variant: ${C} (expected cu12 or cu13)" >&2 | |
| exit 1 | |
| fi | |
| if [ -n "${OVERLAY_SUFFIX_INPUT}" ]; then | |
| # Append mode: primary base tag + suffix. | |
| PRIMARY="$(echo "${BASES}" | jq -r '.[0]')" | |
| OUTS='["'"${PRIMARY}-${OVERLAY_SUFFIX_INPUT}"'"]' | |
| else | |
| # Overwrite mode: replace every base alias. | |
| OUTS="${BASES}" | |
| fi | |
| OVERLAY_TAGS="$(echo "${OVERLAY_TAGS}" | jq -c \ | |
| --arg c "${C}" --argjson b "${BASES}" --argjson o "${OUTS}" \ | |
| '.[$c] = {bases:$b, outs:$o}')" | |
| done | |
| CUDAS_JSON="$(echo "${CUDAS_INPUT}" | jq -c -R 'split(",") | map(gsub("^\\s+|\\s+$";""))')" | |
| echo "overlay_cudas_json=${CUDAS_JSON}" >> $GITHUB_OUTPUT | |
| echo "overlay_tags_json=${OVERLAY_TAGS}" >> $GITHUB_OUTPUT | |
| else | |
| echo "overlay_cudas_json=[]" >> $GITHUB_OUTPUT | |
| echo "overlay_tags_json={}" >> $GITHUB_OUTPUT | |
| fi | |
| build-and-publish: | |
| needs: prepare | |
| if: ${{ !inputs.build_only }} | |
| uses: ./.github/workflows/_docker-build-and-publish.yml | |
| with: | |
| docker_target: framework_final | |
| checkout_ref: ${{ needs.prepare.outputs.checkout_ref }} | |
| extra_build_args: ${{ needs.prepare.outputs.extra_build_args }} | |
| tag_config: ${{ needs.prepare.outputs.tag_config }} | |
| image_repo: ${{ inputs.image_repo || 'lmsysorg/sglang' }} | |
| secrets: inherit | |
| build-only: | |
| needs: prepare | |
| if: ${{ inputs.build_only && github.repository == 'sgl-project/sglang' }} | |
| runs-on: x64-docker-build-node | |
| env: | |
| IMAGE: sglang-diffusion-build-only:${{ github.run_id }}-${{ github.run_attempt }} | |
| SOURCE_DIR: source-${{ github.run_id }}-${{ github.run_attempt }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.prepare.outputs.checkout_ref || github.ref }} | |
| path: ${{ env.SOURCE_DIR }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build CUDA 13 diffusion image locally (no push) | |
| run: | | |
| cd "$SOURCE_DIR" | |
| docker buildx build \ | |
| --target framework_final \ | |
| --platform linux/amd64 \ | |
| --load \ | |
| -t "$IMAGE" \ | |
| -f docker/Dockerfile \ | |
| --build-arg CUDA_VERSION=13.0.3 \ | |
| --build-arg BUILD_TYPE=all \ | |
| --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ | |
| ${{ needs.prepare.outputs.extra_build_args }} \ | |
| --no-cache \ | |
| . | |
| - name: Verify diffusion dependencies | |
| run: | | |
| docker run --rm "$IMAGE" python3 -c ' | |
| import importlib | |
| modules = ( | |
| "av", | |
| "cache_dit", | |
| "cv2", | |
| "diffusers", | |
| "imageio_ffmpeg", | |
| "moviepy", | |
| "msgpack", | |
| "sglang.multimodal_gen", | |
| "soundfile", | |
| "trimesh", | |
| ) | |
| for module in modules: | |
| importlib.import_module(module) | |
| print("diffusion dependency smoke check passed") | |
| ' | |
| - name: Remove local test image | |
| if: always() | |
| run: docker image rm "$IMAGE" || true | |
| cleanup-nightly: | |
| needs: build-and-publish | |
| if: ${{ !inputs.build_only && !inputs.tag && !inputs.pr_number }} | |
| uses: ./.github/workflows/_docker-cleanup-nightly.yml | |
| with: | |
| tag_prefixes: '["nightly-dev", "nightly-dev-cu12", "nightly-dev-cu13"]' | |
| image_repo: ${{ inputs.image_repo || 'lmsysorg/sglang' }} | |
| secrets: inherit | |
| build-overlay: | |
| needs: [prepare, build-and-publish] | |
| if: ${{ !inputs.build_only && inputs.overlay_dockerfile != '' && github.repository == 'sgl-project/sglang' }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| cuda: ${{ fromJson(needs.prepare.outputs.overlay_cudas_json) }} | |
| steps: | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v2 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Build and push overlay image (amd64 + arm64) | |
| env: | |
| REPO: ${{ inputs.image_repo || 'lmsysorg/sglang' }} | |
| TAGS: ${{ needs.prepare.outputs.overlay_tags_json }} | |
| CUDA: ${{ matrix.cuda }} | |
| # Injected via env to keep Dockerfile quotes/$ verbatim. | |
| SNIPPET: ${{ inputs.overlay_dockerfile }} | |
| run: | | |
| set -euo pipefail | |
| BASE="$(printf '%s' "$TAGS" | jq -r --arg c "$CUDA" '.[$c].bases[0]')" | |
| mapfile -t OUTS < <(printf '%s' "$TAGS" | jq -r --arg c "$CUDA" '.[$c].outs[]') | |
| { | |
| printf 'FROM %s:%s\n' "$REPO" "$BASE" | |
| printf '%s\n' "$SNIPPET" | |
| } > Dockerfile.overlay | |
| echo "::group::overlay Dockerfile ($CUDA)" | |
| cat Dockerfile.overlay | |
| echo "::endgroup::" | |
| OUT_ARGS="" | |
| for o in "${OUTS[@]}"; do OUT_ARGS="$OUT_ARGS -t $REPO:$o"; done | |
| docker buildx build \ | |
| --platform linux/amd64,linux/arm64 \ | |
| -f Dockerfile.overlay \ | |
| $OUT_ARGS \ | |
| --push . |