Build & Push RKE2-HAMi Warewulf Image #11
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 & Push RKE2-HAMi Warewulf Image | |
| # Every version knob defaults to "0" (latest). Override per-run via the inputs | |
| # below, or set a persistent default as a repository Variable (Settings -> | |
| # Secrets and variables -> Actions -> Variables) using the same names with an | |
| # _OVERRIDE suffix (e.g. RKE2_VERSION_OVERRIDE, HAMI_VERSION_OVERRIDE). | |
| on: | |
| push: | |
| branches: | |
| - latest | |
| workflow_dispatch: | |
| inputs: | |
| RKE2_VERSION_OVERRIDE: | |
| description: 'RKE2 version (e.g. v1.31.5+rke2r1). "0" = latest.' | |
| required: false | |
| default: '0' | |
| KERNEL_VERSION_OVERRIDE: | |
| description: 'Kernel version (e.g. 6.8.0-31-generic). "0" = latest, "none" = no kernel.' | |
| required: false | |
| default: '0' | |
| NVIDIA_INSTALL_ENABLED: | |
| description: 'Bake NVIDIA driver into the image (1=Yes, 0=No).' | |
| required: true | |
| type: choice | |
| options: ['1', '0'] | |
| default: '1' | |
| NVIDIA_DRIVER_VERSION_OVERRIDE: | |
| description: 'NVIDIA driver version (e.g. 570.148.08). "0" = latest production branch.' | |
| required: false | |
| default: '0' | |
| NVIDIA_CONTAINER_TOOLKIT_VERSION_OVERRIDE: | |
| description: 'nvidia-container-toolkit version (e.g. 1.17.8). "0" = latest.' | |
| required: false | |
| default: '0' | |
| HELM_VERSION_OVERRIDE: | |
| description: 'Helm version (e.g. v3.16.2). "0" = latest.' | |
| required: false | |
| default: '0' | |
| SSG_VERSION_OVERRIDE: | |
| description: 'SCAP Security Guide tag (e.g. v0.1.76). "0" = latest.' | |
| required: false | |
| default: '0' | |
| HAMI_VERSION_OVERRIDE: | |
| description: 'HAMi Helm chart version (e.g. 2.6.0). "0" = latest.' | |
| required: false | |
| default: '0' | |
| FIRSTBOOT_ENABLED: | |
| description: 'Enable firstboot Ansible service (1=Yes, 0=No).' | |
| required: true | |
| type: choice | |
| options: ['1', '0'] | |
| default: '1' | |
| STABLE_TAG: | |
| description: 'Stable moving Docker tag. Empty = "<branch>-hami" (e.g. latest-hami).' | |
| required: false | |
| default: '' | |
| COMMIT_OVERLAY: | |
| description: 'Commit the rendered HAMi overlay back to the repo (1=Yes, 0=No).' | |
| required: true | |
| type: choice | |
| options: ['1', '0'] | |
| default: '1' | |
| schedule: | |
| - cron: '0 3 * * 1' # Every Monday at 3:00 AM UTC | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-and-push: | |
| name: Build & Push RKE2-HAMi Node Image | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: π οΈ Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref_name }} | |
| - name: π§ Resolve Versions & Verify Dependencies | |
| id: config | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| INPUT_RKE2_VERSION: ${{ github.event.inputs.RKE2_VERSION_OVERRIDE }} | |
| VAR_RKE2_VERSION: ${{ vars.RKE2_VERSION_OVERRIDE }} | |
| INPUT_KERNEL_VERSION: ${{ github.event.inputs.KERNEL_VERSION_OVERRIDE }} | |
| VAR_KERNEL_VERSION: ${{ vars.KERNEL_VERSION_OVERRIDE }} | |
| INPUT_NVIDIA_ENABLED: ${{ github.event.inputs.NVIDIA_INSTALL_ENABLED }} | |
| VAR_NVIDIA_ENABLED: ${{ vars.NVIDIA_INSTALL_ENABLED }} | |
| INPUT_NVIDIA_VERSION: ${{ github.event.inputs.NVIDIA_DRIVER_VERSION_OVERRIDE }} | |
| VAR_NVIDIA_VERSION: ${{ vars.NVIDIA_DRIVER_VERSION_OVERRIDE }} | |
| INPUT_TOOLKIT_VERSION: ${{ github.event.inputs.NVIDIA_CONTAINER_TOOLKIT_VERSION_OVERRIDE }} | |
| VAR_TOOLKIT_VERSION: ${{ vars.NVIDIA_CONTAINER_TOOLKIT_VERSION_OVERRIDE }} | |
| INPUT_HELM_VERSION: ${{ github.event.inputs.HELM_VERSION_OVERRIDE }} | |
| VAR_HELM_VERSION: ${{ vars.HELM_VERSION_OVERRIDE }} | |
| INPUT_SSG_VERSION: ${{ github.event.inputs.SSG_VERSION_OVERRIDE }} | |
| VAR_SSG_VERSION: ${{ vars.SSG_VERSION_OVERRIDE }} | |
| INPUT_HAMI_VERSION: ${{ github.event.inputs.HAMI_VERSION_OVERRIDE }} | |
| VAR_HAMI_VERSION: ${{ vars.HAMI_VERSION_OVERRIDE }} | |
| INPUT_FIRSTBOOT_ENABLED: ${{ github.event.inputs.FIRSTBOOT_ENABLED }} | |
| VAR_FIRSTBOOT_ENABLED: ${{ vars.FIRSTBOOT_ENABLED }} | |
| run: | | |
| set -e | |
| lower() { echo "$1" | tr '[:upper:]' '[:lower:]'; } | |
| # pick(): input wins, else repo var, else default ("0") | |
| pick() { if [ -n "$1" ] && [ "$1" != "0" ]; then echo "$1"; elif [ -n "$2" ] && [ "$2" != "0" ]; then echo "$2"; else echo "0"; fi; } | |
| echo "## Firstboot (default ON; only an explicit 0 disables it) ##" | |
| if [ "$INPUT_FIRSTBOOT_ENABLED" = "0" ] || [ "$VAR_FIRSTBOOT_ENABLED" = "0" ]; then FB="false"; else FB="true"; fi | |
| echo "FIRSTBOOT_ENABLED=$FB" >> $GITHUB_OUTPUT | |
| echo "## RKE2 version (always resolved to a concrete version) ##" | |
| RKE2_VER="$(pick "$INPUT_RKE2_VERSION" "$VAR_RKE2_VERSION")" | |
| if [ "$RKE2_VER" = "0" ]; then | |
| RKE2_VER=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" https://api.github.com/repos/rancher/rke2/releases/latest | jq -r .tag_name) | |
| fi | |
| [ -z "$RKE2_VER" ] || [ "$RKE2_VER" = "null" ] && { echo "β Could not resolve RKE2 version"; exit 1; } | |
| K8S_VERSION="${RKE2_VER%%+*}" # v1.31.5+rke2r1 -> v1.31.5 | |
| echo "INSTALL_RKE2_VERSION=$RKE2_VER" >> $GITHUB_OUTPUT | |
| echo "K8S_VERSION=$K8S_VERSION" >> $GITHUB_OUTPUT | |
| echo "π― RKE2=$RKE2_VER K8s=$K8S_VERSION" | |
| echo "## Kernel ##" | |
| KVER="$(pick "$INPUT_KERNEL_VERSION" "$VAR_KERNEL_VERSION")" | |
| if [ "$(lower "$KVER")" = "none" ]; then | |
| echo "KERNEL_INSTALL_ENABLED=false" >> $GITHUB_OUTPUT | |
| echo "KERNEL_VERSION=none" >> $GITHUB_OUTPUT | |
| elif [ "$KVER" != "0" ]; then | |
| sudo apt-get update -qq | |
| apt-cache policy "linux-image-${KVER}" | grep -q "Candidate:" || { echo "β linux-image-${KVER} not found"; exit 1; } | |
| apt-cache policy "linux-headers-${KVER}" | grep -q "Candidate:" || { echo "β linux-headers-${KVER} not found"; exit 1; } | |
| echo "KERNEL_INSTALL_ENABLED=true" >> $GITHUB_OUTPUT | |
| echo "KERNEL_VERSION=$KVER" >> $GITHUB_OUTPUT | |
| else | |
| sudo apt-get update -qq | |
| GENERIC_VERSION=$(apt-cache policy linux-image-generic | grep Candidate | awk '{print $2}') | |
| KERNEL_PKG=$(apt-cache show "linux-image-generic=$GENERIC_VERSION" | grep -E '^Depends:' | sed -E 's/.*linux-image-([0-9]+\.[0-9]+\.[0-9]+-[0-9]+-generic).*/\1/' | head -n1) | |
| [ -z "$KERNEL_PKG" ] && { echo "β Could not parse latest kernel"; exit 1; } | |
| echo "KERNEL_INSTALL_ENABLED=true" >> $GITHUB_OUTPUT | |
| echo "KERNEL_VERSION=$KERNEL_PKG" >> $GITHUB_OUTPUT | |
| KVER="$KERNEL_PKG" | |
| fi | |
| echo "π― Kernel=$KVER" | |
| echo "## NVIDIA driver ##" | |
| NV_ON=true | |
| if [ "$INPUT_NVIDIA_ENABLED" = "0" ] || [ "$VAR_NVIDIA_ENABLED" = "0" ]; then NV_ON=false; fi | |
| KIE="$(grep '^KERNEL_INSTALL_ENABLED=' $GITHUB_OUTPUT | cut -d= -f2)" | |
| if [ "$NV_ON" = "true" ] && [ "$KIE" != "true" ]; then | |
| echo "β οΈ NVIDIA needs a kernel; disabling NVIDIA install."; NV_ON=false | |
| fi | |
| NV_URL="0" | |
| if [ "$NV_ON" = "true" ]; then | |
| NV_VER="$(pick "$INPUT_NVIDIA_VERSION" "$VAR_NVIDIA_VERSION")" | |
| RJSON=$(curl -fsSL https://docs.nvidia.com/datacenter/tesla/drivers/releases.json) | |
| if [ "$NV_VER" != "0" ]; then | |
| NV_URL=$(echo "$RJSON" | jq -r --arg v "$NV_VER" '.[] | .driver_info[] | select(.release_version==$v) | .runfile_url["x86_64"]' | head -n1) | |
| else | |
| NV_URL=$(echo "$RJSON" | jq -r 'first(.[] | select(.type=="production branch")) | .driver_info[0].runfile_url["x86_64"]') | |
| fi | |
| { [ -z "$NV_URL" ] || [ "$NV_URL" = "null" ]; } && { echo "β Could not resolve NVIDIA driver URL"; exit 1; } | |
| fi | |
| echo "NVIDIA_INSTALL_ENABLED=$NV_ON" >> $GITHUB_OUTPUT | |
| echo "NVIDIA_DRIVER_URL=$NV_URL" >> $GITHUB_OUTPUT | |
| echo "π― NVIDIA=$NV_ON URL=$NV_URL" | |
| echo "## nvidia-container-toolkit / Helm / SSG (empty = latest) ##" | |
| TK="$(pick "$INPUT_TOOLKIT_VERSION" "$VAR_TOOLKIT_VERSION")"; [ "$TK" = "0" ] && TK="" | |
| HV="$(pick "$INPUT_HELM_VERSION" "$VAR_HELM_VERSION")"; [ "$HV" = "0" ] && HV="" | |
| SV="$(pick "$INPUT_SSG_VERSION" "$VAR_SSG_VERSION")"; [ "$SV" = "0" ] && SV="" | |
| echo "NVIDIA_CONTAINER_TOOLKIT_VERSION=$TK" >> $GITHUB_OUTPUT | |
| echo "HELM_VERSION=$HV" >> $GITHUB_OUTPUT | |
| echo "SSG_VERSION=$SV" >> $GITHUB_OUTPUT | |
| echo "## HAMi chart version (empty = latest chart from repo) ##" | |
| HAMI="$(pick "$INPUT_HAMI_VERSION" "$VAR_HAMI_VERSION")"; [ "$HAMI" = "0" ] && HAMI="" | |
| echo "HAMI_VERSION=$HAMI" >> $GITHUB_OUTPUT | |
| echo "π― HAMi chart=${HAMI:-latest}" | |
| echo "===== Resolved configuration =====" | |
| cat $GITHUB_OUTPUT | |
| - name: π§© Render HAMi overlay (hami.yaml) | |
| run: | | |
| set -e | |
| OUT=overlays/rke2-gpu/rootfs/etc/rancher/manifests/hami.yaml | |
| K8S="${{ steps.config.outputs.K8S_VERSION }}" | |
| HAMI="${{ steps.config.outputs.HAMI_VERSION }}" | |
| { | |
| echo "apiVersion: helm.cattle.io/v1" | |
| echo "kind: HelmChart" | |
| echo "metadata:" | |
| echo " name: hami" | |
| echo " namespace: kube-system" | |
| echo "spec:" | |
| echo " targetNamespace: kube-system" | |
| echo " chart: hami" | |
| echo " repo: https://project-hami.github.io/HAMi/" | |
| if [ -n "$HAMI" ]; then echo " version: \"$HAMI\""; fi | |
| echo " valuesContent: |-" | |
| echo " # kubeScheduler.imageTag is auto-set to the cluster Kubernetes version by CI." | |
| echo " scheduler:" | |
| echo " kubeScheduler:" | |
| echo " imageTag: \"$K8S\"" | |
| echo " # Host provides the NVIDIA driver + toolkit; rke2-gpu overlay sets the" | |
| echo " # containerd default runtime to \"nvidia\"." | |
| echo " devicePlugin:" | |
| echo " runtimeClassName: \"nvidia\"" | |
| } > "$OUT" | |
| echo "----- rendered $OUT -----"; cat "$OUT" | |
| - name: π·οΈ Generate Docker Tag Name | |
| id: taggen | |
| run: | | |
| K8S="${{ steps.config.outputs.K8S_VERSION }}" | |
| KERNEL_VER_RAW="${{ steps.config.outputs.KERNEL_VERSION }}" | |
| KERNEL_INSTALL_ENABLED="${{ steps.config.outputs.KERNEL_INSTALL_ENABLED }}" | |
| NVIDIA_ENABLED="${{ steps.config.outputs.NVIDIA_INSTALL_ENABLED }}" | |
| NVIDIA_URL="${{ steps.config.outputs.NVIDIA_DRIVER_URL }}" | |
| K8S_SLUG=$(echo "$K8S" | tr '.' '-' | tr '[:upper:]' '[:lower:]') | |
| if [ "$KERNEL_INSTALL_ENABLED" = "false" ]; then | |
| TAG_NAME="hami-${K8S_SLUG}-no-kernel" | |
| else | |
| KERNEL_VER=$(echo "u24.04-$KERNEL_VER_RAW" | tr '.' '-' | tr '[:upper:]' '[:lower:]') | |
| TAG_NAME="${KERNEL_VER}-${K8S_SLUG}-hami" | |
| if [ "$NVIDIA_ENABLED" = "true" ]; then | |
| NVIDIA_VER=$(basename "$NVIDIA_URL" | grep -oP '[0-9]+\.[0-9]+\.[0-9]+' | tr '.' '-') | |
| TAG_NAME="${TAG_NAME}-${NVIDIA_VER}" | |
| fi | |
| fi | |
| # Stable moving tag so you can point Warewulf at one predictable name. | |
| # Defaults to "<branch>-hami" (e.g. latest-hami); override via the | |
| # STABLE_TAG input or a STABLE_TAG repo Variable. | |
| STABLE_TAG="${INPUT_STABLE_TAG}" | |
| [ -z "$STABLE_TAG" ] && STABLE_TAG="${VAR_STABLE_TAG}" | |
| [ -z "$STABLE_TAG" ] && STABLE_TAG="${TAG_NAME_REF}-hami" | |
| echo "Generated descriptive TAG_NAME: $TAG_NAME" | |
| echo "Generated stable STABLE_TAG: $STABLE_TAG" | |
| echo "TAG_NAME=$TAG_NAME" >> $GITHUB_OUTPUT | |
| echo "STABLE_TAG=$STABLE_TAG" >> $GITHUB_OUTPUT | |
| env: | |
| TAG_NAME_REF: ${{ github.ref_name }} | |
| INPUT_STABLE_TAG: ${{ github.event.inputs.STABLE_TAG }} | |
| VAR_STABLE_TAG: ${{ vars.STABLE_TAG }} | |
| - name: π³ Build Docker Image | |
| run: | | |
| docker build \ | |
| --build-arg NVIDIA_INSTALL_ENABLED=${{ steps.config.outputs.NVIDIA_INSTALL_ENABLED }} \ | |
| --build-arg NVIDIA_DRIVER_URL=${{ steps.config.outputs.NVIDIA_DRIVER_URL }} \ | |
| --build-arg KERNEL_VERSION=${{ steps.config.outputs.KERNEL_VERSION }} \ | |
| --build-arg KERNEL_INSTALL_ENABLED=${{ steps.config.outputs.KERNEL_INSTALL_ENABLED }} \ | |
| --build-arg FIRSTBOOT_ENABLED=${{ steps.config.outputs.FIRSTBOOT_ENABLED }} \ | |
| --build-arg INSTALL_RKE2_VERSION=${{ steps.config.outputs.INSTALL_RKE2_VERSION }} \ | |
| --build-arg NVIDIA_CONTAINER_TOOLKIT_VERSION=${{ steps.config.outputs.NVIDIA_CONTAINER_TOOLKIT_VERSION }} \ | |
| --build-arg HELM_VERSION=${{ steps.config.outputs.HELM_VERSION }} \ | |
| --build-arg SSG_VERSION=${{ steps.config.outputs.SSG_VERSION }} \ | |
| -t ${{ secrets.DOCKER_HUB_REPO }}:${{ steps.taggen.outputs.TAG_NAME }} \ | |
| -t ${{ secrets.DOCKER_HUB_REPO }}:${{ steps.taggen.outputs.STABLE_TAG }} . | |
| - name: π Login to DockerHub | |
| run: | | |
| echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u "${{ secrets.DOCKER_HUB_USER }}" --password-stdin | |
| - name: π Push Image to DockerHub | |
| run: | | |
| # Descriptive, immutable tag (provenance) + stable moving tag (easy pointer) | |
| docker push ${{ secrets.DOCKER_HUB_REPO }}:${{ steps.taggen.outputs.TAG_NAME }} | |
| docker push ${{ secrets.DOCKER_HUB_REPO }}:${{ steps.taggen.outputs.STABLE_TAG }} | |
| - name: π Commit rendered HAMi overlay | |
| if: ${{ github.event.inputs.COMMIT_OVERLAY != '0' }} | |
| run: | | |
| set -e | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| if git diff --quiet -- overlays/rke2-gpu/rootfs/etc/rancher/manifests/hami.yaml; then | |
| echo "No overlay changes to commit." | |
| else | |
| git add overlays/rke2-gpu/rootfs/etc/rancher/manifests/hami.yaml | |
| git commit -m "ci: sync HAMi overlay (chart=${{ steps.config.outputs.HAMI_VERSION }} k8s=${{ steps.config.outputs.K8S_VERSION }}) [skip ci]" | |
| git push origin HEAD:${{ github.ref_name }} | |
| fi |