ci: add docker build in the pipeline to use with a basic k8s install test #4
Workflow file for this run
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: Docker CPU smoke-test images | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - ".github/workflows/docker-cpu-smoketest.yaml" | |
| - "docker-bake.hcl" | |
| - "docker/**" | |
| - "e2e/k8s/**" | |
| - "k8s/helm/**" | |
| - "Makefile" | |
| - "packages/**" | |
| - "plugins/**" | |
| - "sdk/**" | |
| - "services/**" | |
| - "src/**" | |
| - "uv.lock" | |
| - "pyproject.toml" | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - ".github/workflows/docker-cpu-smoketest.yaml" | |
| - "docker-bake.hcl" | |
| - "docker/**" | |
| - "e2e/k8s/**" | |
| - "k8s/helm/**" | |
| - "Makefile" | |
| - "packages/**" | |
| - "plugins/**" | |
| - "sdk/**" | |
| - "services/**" | |
| - "src/**" | |
| - "uv.lock" | |
| - "pyproject.toml" | |
| workflow_dispatch: | |
| inputs: | |
| image_tag: | |
| description: Optional image tag. Defaults to the commit SHA. | |
| required: false | |
| type: string | |
| default: "" | |
| publish: | |
| description: Publish images to GHCR. | |
| required: false | |
| type: boolean | |
| default: true | |
| permissions: | |
| contents: read | |
| packages: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| build-cpu-images: | |
| name: Build CPU images | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| permissions: | |
| contents: read | |
| packages: write | |
| outputs: | |
| image_registry: ${{ steps.bake-vars.outputs.image_registry }} | |
| image_tag: ${{ steps.bake-vars.outputs.image_tag }} | |
| publish_images: ${{ steps.bake-vars.outputs.publish_images }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Free disk space | |
| uses: ./.github/actions/free-disk-space | |
| with: | |
| disable_swap: "true" | |
| remove_haskell: "true" | |
| remove_java: "true" | |
| remove_ruby: "true" | |
| remove_swift: "true" | |
| prune_docker: "true" | |
| - name: Set up Docker Buildx | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| docker buildx create --name nmp-builder --driver docker-container --use | |
| docker buildx inspect --bootstrap | |
| - name: Configure bake variables | |
| id: bake-vars | |
| shell: bash | |
| env: | |
| HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name || github.repository }} | |
| INPUT_IMAGE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.image_tag || '' }} | |
| INPUT_PUBLISH: ${{ inputs.publish }} | |
| SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | |
| run: | | |
| set -euo pipefail | |
| image_registry="ghcr.io/${GITHUB_REPOSITORY,,}" | |
| source_sha="${SOURCE_SHA:-$GITHUB_SHA}" | |
| bake_tag="${INPUT_IMAGE_TAG:-$source_sha}" | |
| publish_images="false" | |
| if [ "$GITHUB_EVENT_NAME" = "push" ] && [ "$GITHUB_REF" = "refs/heads/main" ]; then | |
| publish_images="true" | |
| fi | |
| if [ "$GITHUB_EVENT_NAME" = "pull_request" ] && [ "$HEAD_REPOSITORY" = "$GITHUB_REPOSITORY" ]; then | |
| publish_images="true" | |
| fi | |
| if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ] && [ "$INPUT_PUBLISH" = "true" ]; then | |
| publish_images="true" | |
| fi | |
| { | |
| printf 'IMAGE_REGISTRY=%s\n' "$image_registry" | |
| printf 'BASE_REGISTRY=%s\n' "$image_registry" | |
| printf 'CACHE_REGISTRY=%s\n' "$image_registry" | |
| printf 'BAKE_TAG=%s\n' "$bake_tag" | |
| printf 'CI_COMMIT_SHA=%s\n' "$source_sha" | |
| printf 'PUBLISH_IMAGES=%s\n' "$publish_images" | |
| } >> "$GITHUB_ENV" | |
| { | |
| printf 'image_registry=%s\n' "$image_registry" | |
| printf 'image_tag=%s\n' "$bake_tag" | |
| printf 'publish_images=%s\n' "$publish_images" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Log in to GHCR | |
| if: env.PUBLISH_IMAGES == 'true' | |
| shell: bash | |
| env: | |
| GHCR_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| echo "$GHCR_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin | |
| - name: Print Docker bake graph | |
| shell: bash | |
| run: make docker-print TARGET=docker-cpu | |
| - name: Build CPU images | |
| if: env.PUBLISH_IMAGES != 'true' | |
| shell: bash | |
| run: make docker-load TARGET=docker-cpu | |
| - name: Build and publish CPU images | |
| if: env.PUBLISH_IMAGES == 'true' | |
| shell: bash | |
| run: make docker-push TARGET=docker-cpu | |
| kind-smoke: | |
| name: Set up kind CPU environment | |
| needs: [build-cpu-images] | |
| if: needs.build-cpu-images.outputs.publish_images == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| permissions: | |
| contents: read | |
| packages: read | |
| env: | |
| BUSYBOX_IMAGE: docker.io/library/busybox | |
| HELM_CHART: k8s/helm | |
| K8S_E2E_SCRIPTS: e2e/k8s/scripts | |
| K8S_E2E_VALUES: e2e/k8s/values | |
| KIND_CLUSTER_NAME: gha-${{ github.run_id }}-${{ github.run_attempt }}-kind-smoke | |
| KUBE_GATEWAY_NAME: nmp-e2e-gateway | |
| KUBE_NAMESPACE: nemo-platform | |
| NAMESPACE: nemo-platform | |
| CORE_STORAGE_BINDER_ENABLED: "false" | |
| NMP_E2E_CLUSTER_URL: "" | |
| NMP_E2E_INTERNAL_HOST: nemo-platform-api:8080 | |
| NMP_E2E_REGISTRY: ${{ needs.build-cpu-images.outputs.image_registry }} | |
| NMP_E2E_TAG: ${{ needs.build-cpu-images.outputs.image_tag }} | |
| POSTGRES_IMAGE: docker.io/library/postgres | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - name: Free disk space | |
| uses: ./.github/actions/free-disk-space | |
| with: | |
| disable_swap: "true" | |
| remove_haskell: "true" | |
| remove_java: "true" | |
| remove_ruby: "true" | |
| remove_swift: "true" | |
| prune_docker: "true" | |
| - name: Install kind | |
| shell: bash | |
| env: | |
| KIND_VERSION: v0.32.0 | |
| run: | | |
| set -euo pipefail | |
| case "$(uname -m)" in | |
| x86_64) arch=amd64 ;; | |
| aarch64|arm64) arch=arm64 ;; | |
| *) | |
| echo "Unsupported architecture: $(uname -m)" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| kind_url="https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-linux-${arch}" | |
| curl -fsSLo "${RUNNER_TEMP}/kind" "${kind_url}" | |
| curl -fsSLo "${RUNNER_TEMP}/kind.sha256sum" "${kind_url}.sha256sum" | |
| sed "s# kind-linux-${arch}# ${RUNNER_TEMP}/kind#" "${RUNNER_TEMP}/kind.sha256sum" | sha256sum -c - | |
| sudo install -m 0755 "${RUNNER_TEMP}/kind" /usr/local/bin/kind | |
| - name: Install kubectl | |
| shell: bash | |
| env: | |
| KUBECTL_VERSION: v1.33.7 | |
| run: | | |
| set -euo pipefail | |
| case "$(uname -m)" in | |
| x86_64) arch=amd64 ;; | |
| aarch64|arm64) arch=arm64 ;; | |
| *) | |
| echo "Unsupported architecture: $(uname -m)" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| kubectl_url="https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${arch}/kubectl" | |
| curl -fsSLo "${RUNNER_TEMP}/kubectl" "${kubectl_url}" | |
| curl -fsSLo "${RUNNER_TEMP}/kubectl.sha256" "${kubectl_url}.sha256" | |
| echo "$(cat "${RUNNER_TEMP}/kubectl.sha256") ${RUNNER_TEMP}/kubectl" | sha256sum -c - | |
| sudo install -m 0755 "${RUNNER_TEMP}/kubectl" /usr/local/bin/kubectl | |
| - name: Install Helm | |
| uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 | |
| - name: Start kind cluster | |
| shell: bash | |
| env: | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| NGC_API_KEY: not-used-for-ghcr-cpu-smoke | |
| run: bash "${K8S_E2E_SCRIPTS}/setup_local_kind_cpu.sh" | |
| - name: Set default kubectl namespace | |
| shell: bash | |
| run: kubectl config set-context --current --namespace="${NAMESPACE}" | |
| - name: Verify Gateway API setup | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| kubectl wait --for=condition=Established crd/gateways.gateway.networking.k8s.io --timeout=2m | |
| kubectl wait --for=condition=Established crd/httproutes.gateway.networking.k8s.io --timeout=2m | |
| kubectl get gatewayclass cloud-provider-kind | |
| kubectl -n "${NAMESPACE}" get gateway "${KUBE_GATEWAY_NAME}" | |
| - name: Pre-pull GHCR images into kind | |
| shell: bash | |
| env: | |
| KIND_IMAGE_PULL_TOKEN: ${{ github.token }} | |
| KIND_IMAGE_PULL_USER: ${{ github.actor }} | |
| run: | | |
| "${K8S_E2E_SCRIPTS}/prepull_kind_images.sh" \ | |
| "${NMP_E2E_REGISTRY}/nmp-api:${NMP_E2E_TAG}" \ | |
| "${NMP_E2E_REGISTRY}/nmp-core:${NMP_E2E_TAG}" \ | |
| "${NMP_E2E_REGISTRY}/nmp-cpu-tasks:${NMP_E2E_TAG}" | |
| - name: Build Helm dependencies | |
| shell: bash | |
| run: | | |
| helm repo add nvidia https://helm.ngc.nvidia.com/nvidia | |
| helm repo update | |
| helm dependency build "${HELM_CHART}" | |
| - name: Install NeMo Platform | |
| shell: bash | |
| run: | | |
| if ! HELM_VALUES="${K8S_E2E_VALUES}/kind.yaml" "${K8S_E2E_SCRIPTS}/install_nmp_e2e.sh"; then | |
| echo "--- helm list -A ---" | |
| helm list -A || true | |
| echo "--- helm status ${NAMESPACE}/nemo-platform ---" | |
| helm status -n "${NAMESPACE}" nemo-platform || true | |
| echo "--- kubectl get all -n ${NAMESPACE} ---" | |
| kubectl get all -n "${NAMESPACE}" || true | |
| exit 1 | |
| fi | |
| - name: Wait for API | |
| shell: bash | |
| run: | | |
| test -n "${NMP_E2E_CLUSTER_URL}" | |
| "${K8S_E2E_SCRIPTS}/wait_for_api.sh" "${NMP_E2E_CLUSTER_URL}/cluster-info" 120 | |
| - name: Collect Kubernetes logs | |
| if: always() | |
| shell: bash | |
| run: | | |
| "${K8S_E2E_SCRIPTS}/collect_k8s_logs.sh" | |
| - name: Disk usage summary | |
| if: always() | |
| shell: bash | |
| run: | | |
| echo "=== Host disk ===" | |
| df -h / | |
| echo "=== Docker system ===" | |
| docker system df | |
| echo "=== kind node storage ===" | |
| for node in $(kind get nodes --name "${KIND_CLUSTER_NAME}" 2>/dev/null); do | |
| echo "--- ${node} ---" | |
| docker exec "${node}" sh -c "du -sh /var/lib/containerd /var/lib/kubelet /var/log 2>/dev/null | sort -h" || true | |
| done | |
| - name: Upload Kubernetes artifacts | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: kind-smoke-kubernetes-artifacts | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| path: k8s-logs/ | |
| - name: Delete kind cluster | |
| if: always() | |
| shell: bash | |
| run: | | |
| docker rm -f "cloud-provider-kind-${KIND_CLUSTER_NAME}" || true | |
| kind delete cluster --name "${KIND_CLUSTER_NAME}" || true |