-
Notifications
You must be signed in to change notification settings - Fork 3
Add UBI 9 container with vLLM and GuideLLM (OCTOET-1123) #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 4 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
211b77c
Add UBI 9 container with vLLM and GuideLLM (OCTOET-1123)
38749e7
Address code review feedback
ed03730
Fix YAML linting issues in workflow
0c54541
Fix invalid Docker tag in GitHub Actions workflow
445b656
Add Red Hat registry authentication to workflow
8dc4e94
Fix cosign to sign immutable digests instead of mutable tags
6b2cb7a
Update Quay organization from redhat-et to octo-et
3acdfd4
Copy repository files into container image
9ed3490
Fix manifest digest resolution to avoid null returns
77e8d1c
Add Ansible to container for test automation
3a3721f
Fix Ansible version to be compatible with Python 3.11
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| name: Build and Push vLLM CPU Perf Eval Container | ||
|
|
||
| "on": | ||
| push: | ||
| branches: | ||
| - "main" | ||
| paths: | ||
| - "Containerfile" | ||
| - ".github/workflows/build-and-push.yml" | ||
| pull_request: | ||
| branches: | ||
| - "main" | ||
| paths: | ||
| - "Containerfile" | ||
| - ".github/workflows/build-and-push.yml" | ||
| workflow_dispatch: | ||
| inputs: | ||
| tag: | ||
| description: "Image tag (default: latest)" | ||
| required: false | ||
| default: "latest" | ||
|
|
||
| env: | ||
| IMAGE_NAME: vllm-cpu-perf-eval | ||
| REGISTRY: quay.io | ||
| QUAY_ORG: redhat-et | ||
|
|
||
| jobs: | ||
| build-and-test: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| id-token: write | ||
|
|
||
| strategy: | ||
| matrix: | ||
| arch: [amd64, arm64] | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up QEMU | ||
| uses: docker/setup-qemu-action@v3 | ||
| with: | ||
| platforms: linux/amd64,linux/arm64 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| # Only login to Quay if we're going to push (not on PR) | ||
| - name: Log in to Quay.io | ||
| if: github.event_name != 'pull_request' | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ secrets.QUAY_USERNAME }} | ||
| password: ${{ secrets.QUAY_PASSWORD }} | ||
|
|
||
| - name: Extract metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.QUAY_ORG }}/${{ env.IMAGE_NAME }} | ||
| tags: | | ||
| type=ref,event=branch | ||
| type=ref,event=pr | ||
| type=semver,pattern={{version}} | ||
| type=semver,pattern={{major}}.{{minor}} | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
| type=sha | ||
| flavor: | | ||
| suffix=-${{ matrix.arch }} | ||
|
|
||
| - name: Build container image | ||
| id: build | ||
| uses: docker/build-push-action@v5 | ||
| with: | ||
| context: . | ||
| file: ./Containerfile | ||
| platforms: linux/${{ matrix.arch }} | ||
| # Only push to Quay if not a PR | ||
| push: ${{ github.event_name != 'pull_request' }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| cache-from: type=gha,scope=build-${{ matrix.arch }} | ||
| cache-to: type=gha,mode=max,scope=build-${{ matrix.arch }} | ||
| build-args: | | ||
| TARGETARCH=${{ matrix.arch }} | ||
| # Save to local tar for testing in PRs | ||
| outputs: ${{ github.event_name == 'pull_request' && 'type=docker,dest=/tmp/image.tar' || '' }} | ||
|
|
||
| # Test the image in PRs | ||
| - name: Load and test image (PR only) | ||
| if: github.event_name == 'pull_request' | ||
| run: | | ||
| docker load --input /tmp/image.tar | ||
| # Capture the first tag to a variable | ||
| image_tag=$(echo "${{ steps.meta.outputs.tags }}" | head -1) | ||
| echo "Testing image: $image_tag" | ||
| echo "Testing vLLM installation..." | ||
| docker run --rm "$image_tag" python -c "import vllm; print(f'vLLM version: {vllm.__version__}')" | ||
| echo "Testing GuideLLM installation..." | ||
| docker run --rm "$image_tag" python -c "import guidellm; print('GuideLLM installed successfully')" | ||
| echo "✅ Container tests passed!" | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # Only sign and push digest if not a PR | ||
| - name: Install Cosign | ||
| if: github.event_name != 'pull_request' | ||
| uses: sigstore/cosign-installer@v3 | ||
|
|
||
| - name: Sign the container image | ||
| if: github.event_name != 'pull_request' | ||
| env: | ||
| COSIGN_EXPERIMENTAL: "true" | ||
| run: | | ||
| echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes {}@${{ steps.build.outputs.digest }} | ||
|
|
||
| - name: Export digest | ||
| if: github.event_name != 'pull_request' | ||
| run: | | ||
| mkdir -p /tmp/digests | ||
| digest="${{ steps.build.outputs.digest }}" | ||
| touch "/tmp/digests/${digest#sha256:}" | ||
|
|
||
| - name: Upload digest | ||
| if: github.event_name != 'pull_request' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: digests-${{ matrix.arch }} | ||
| path: /tmp/digests/* | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
|
|
||
| # Only create manifest if not a PR | ||
| create-manifest: | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name != 'pull_request' | ||
| needs: build-and-test | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| id-token: write | ||
|
|
||
| steps: | ||
| - name: Download digests | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| path: /tmp/digests | ||
| pattern: digests-* | ||
| merge-multiple: true | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Log in to Quay.io | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ secrets.QUAY_USERNAME }} | ||
| password: ${{ secrets.QUAY_PASSWORD }} | ||
|
|
||
| - name: Extract metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.QUAY_ORG }}/${{ env.IMAGE_NAME }} | ||
| tags: | | ||
| type=ref,event=branch | ||
| type=semver,pattern={{version}} | ||
| type=raw,value=latest,enable={{is_default_branch}} | ||
|
|
||
| - name: Create manifest list and push | ||
| working-directory: /tmp/digests | ||
| run: | | ||
| docker buildx imagetools create \ | ||
| $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | ||
| $(printf '${{ env.REGISTRY }}/${{ env.QUAY_ORG }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) | ||
|
|
||
| - name: Install Cosign | ||
| uses: sigstore/cosign-installer@v3 | ||
|
|
||
| - name: Sign the manifest | ||
| env: | ||
| COSIGN_EXPERIMENTAL: "true" | ||
| run: | | ||
| echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes {} | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - name: Inspect image | ||
| run: | | ||
| docker buildx imagetools inspect \ | ||
| ${{ env.REGISTRY }}/${{ env.QUAY_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | ||
|
|
||
| - name: Comment on PR with image info | ||
| if: github.event_name == 'push' | ||
| run: | | ||
| echo "✅ Multi-arch container image published!" | ||
| echo "📦 Image: ${{ env.REGISTRY }}/${{ env.QUAY_ORG }}/${{ env.IMAGE_NAME }}:latest" | ||
| echo "🔐 Image signed with Cosign" | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # vLLM CPU Performance Evaluation Container | ||
| # Based on Red Hat Universal Base Image 9 | ||
|
|
||
| # Use UBI 9 with Python 3.11 (pinned by digest for reproducibility) | ||
| # Image: registry.redhat.io/ubi9/python-311:latest as of 2026-03-03 | ||
| FROM registry.redhat.io/ubi9/python-311@sha256:56193de31c185cebfb8a9f0a7624407f49b1cdf923403d5d777027b285701d78 | ||
|
|
||
| # Metadata | ||
| LABEL name="vllm-cpu-perf-eval" \ | ||
| version="1.0" \ | ||
| description="vLLM CPU Performance Evaluation Test Suite" \ | ||
| maintainer="Red Hat OCTO Edge Team" \ | ||
| io.k8s.description="Container for running vLLM CPU performance benchmarks" \ | ||
| io.k8s.display-name="vLLM CPU Performance Evaluator" | ||
|
|
||
| # Set working directory | ||
| WORKDIR /opt/vllm-perf | ||
|
|
||
| # Install system dependencies and create directories | ||
| USER root | ||
| RUN dnf install -y \ | ||
| gcc \ | ||
| gcc-c++ \ | ||
| git \ | ||
| numactl \ | ||
| && dnf clean all | ||
|
|
||
| # Create directories and set ownership for non-root user | ||
| RUN mkdir -p /opt/vllm-perf/models \ | ||
| /opt/vllm-perf/results \ | ||
| /opt/vllm-perf/scripts \ | ||
| && chown -R 1001:0 /opt/vllm-perf \ | ||
| && chmod -R g=u /opt/vllm-perf | ||
|
|
||
| # Switch to non-root user for pip installations | ||
| USER 1001 | ||
|
|
||
| # Upgrade pip and install build tools | ||
| RUN pip install --no-cache-dir --upgrade pip setuptools wheel | ||
|
|
||
| # Install vLLM with CPU support (pinned version for reproducibility) | ||
| RUN pip install --no-cache-dir \ | ||
| 'vllm>=0.16.0,<0.17.0' | ||
|
|
||
| # Install GuideLLM for benchmarking (pinned version for reproducibility) | ||
| RUN pip install --no-cache-dir \ | ||
| 'guidellm>=0.5.0,<0.6.0' | ||
|
|
||
| # Install additional performance tools (pinned versions for reproducibility) | ||
| RUN pip install --no-cache-dir \ | ||
| 'numpy>=2.0.0,<3.0.0' \ | ||
| 'pandas>=3.0.0,<4.0.0' \ | ||
| 'psutil>=7.0.0,<8.0.0' | ||
|
|
||
| # Set environment variables for optimal CPU performance | ||
| # Note: OMP_NUM_THREADS should be set at runtime based on available cores | ||
| ENV VLLM_CPU_KVCACHE_SPACE=40 | ||
|
|
||
| # Default command (can be overridden) | ||
| CMD ["/bin/bash"] | ||
|
|
||
| # Health check (optional) | ||
| HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ | ||
| CMD python -c "import vllm; import guidellm" || exit 1 |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # vLLM CPU Performance Evaluation Container | ||
|
|
||
| UBI 9-based container image for running vLLM CPU performance benchmarks. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```bash | ||
| # Pull the image | ||
| podman pull quay.io/redhat-et/vllm-cpu-perf-eval:latest | ||
|
|
||
| # Run interactively | ||
| podman run -it --rm quay.io/redhat-et/vllm-cpu-perf-eval:latest | ||
|
|
||
| # Run a benchmark | ||
| podman run --rm \ | ||
| -v $(pwd)/results:/opt/vllm-perf/results \ | ||
| quay.io/redhat-et/vllm-cpu-perf-eval:latest \ | ||
| guidellm --help | ||
| ``` | ||
|
|
||
| ## Supported Architectures | ||
|
|
||
| - linux/amd64 | ||
| - linux/arm64 | ||
|
|
||
| ## Included Tools | ||
|
|
||
| - vLLM (CPU-optimized) | ||
| - GuideLLM | ||
| - NumPy, Pandas, psutil | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| - `OMP_NUM_THREADS`: OpenMP thread count (not set by container; user must set at runtime based on available cores) | ||
| - `VLLM_CPU_KVCACHE_SPACE`: KV cache size in GB (default: 40) | ||
|
|
||
| ## Building Locally | ||
|
|
||
| ```bash | ||
| podman build -t vllm-cpu-perf-eval:local -f Containerfile . | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| ```bash | ||
| ./tests/test-container.sh | ||
| ``` |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| #!/bin/bash | ||
| # Test script for vllm-cpu-perf-eval container | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # Compute script directory for path-agnostic execution | ||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" | ||
|
|
||
| IMAGE_NAME="vllm-cpu-perf-eval" | ||
| IMAGE_TAG="test" | ||
|
|
||
| echo "=== Building Container ===" | ||
| echo "Build context: $SCRIPT_DIR" | ||
| podman build -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "${SCRIPT_DIR}/Containerfile" "${SCRIPT_DIR}" | ||
|
|
||
| echo "" | ||
| echo "=== Testing Python Version ===" | ||
| podman run --rm "${IMAGE_NAME}:${IMAGE_TAG}" python --version | ||
|
|
||
| echo "" | ||
| echo "=== Testing vLLM Installation ===" | ||
| podman run --rm "${IMAGE_NAME}:${IMAGE_TAG}" python -c "import vllm; print(f'vLLM version: {vllm.__version__}')" | ||
|
|
||
| echo "" | ||
| echo "=== Testing GuideLLM Installation ===" | ||
| podman run --rm "${IMAGE_NAME}:${IMAGE_TAG}" python -c "import guidellm; print('GuideLLM installed successfully')" | ||
|
|
||
| echo "" | ||
| echo "=== Testing System Info ===" | ||
| podman run --rm "${IMAGE_NAME}:${IMAGE_TAG}" bash -c " | ||
| echo 'OS Release:' | ||
| cat /etc/redhat-release | ||
| echo '' | ||
| echo 'CPU Info:' | ||
| lscpu | grep 'Model name' | ||
| echo '' | ||
| echo 'Memory:' | ||
| free -h | ||
| " | ||
|
|
||
| echo "" | ||
| echo "=== Testing vLLM CLI ===" | ||
| # Run vllm --help and capture output, then display first 20 lines | ||
| vllm_help_output=$(podman run --rm "${IMAGE_NAME}:${IMAGE_TAG}" vllm --help) | ||
| echo "$vllm_help_output" | head -20 | ||
|
|
||
| echo "" | ||
| echo "=== Testing GuideLLM CLI ===" | ||
| # Run guidellm --help and capture output, then display first 20 lines | ||
| guidellm_help_output=$(podman run --rm "${IMAGE_NAME}:${IMAGE_TAG}" guidellm --help) | ||
| echo "$guidellm_help_output" | head -20 | ||
|
|
||
| echo "" | ||
| echo "=== Container Size ===" | ||
| podman images "${IMAGE_NAME}:${IMAGE_TAG}" | ||
|
|
||
| echo "" | ||
| echo "✅ All tests passed!" | ||
| echo "" | ||
| echo "To run interactively:" | ||
| echo " podman run -it --rm ${IMAGE_NAME}:${IMAGE_TAG} /bin/bash" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.