Repository navigation
AKS SSH Quickstart #8
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
| # Copyright (c) Microsoft Corporation. | |
| # Licensed under the MIT License. | |
| name: AKS SSH Quickstart | |
| "on": | |
| push: | |
| branches: | |
| - ismille/** | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| id-token: write | |
| concurrency: | |
| group: aks-ssh-quickstart-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| azure-setup: | |
| runs-on: ubuntu-latest | |
| environment: azure-ci | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Set up Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: go.mod | |
| cache-dependency-path: go.sum | |
| - name: Azure login | |
| uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| - name: Show Azure context | |
| run: | | |
| set -euo pipefail | |
| az account show --output jsonc | |
| - name: Build kubectl-unbounded | |
| run: | | |
| set -euo pipefail | |
| mkdir -p bin | |
| go build -o bin/kubectl-unbounded ./cmd/kubectl-unbounded | |
| echo "$PWD/bin" >> "$GITHUB_PATH" | |
| - name: Generate ephemeral SSH keypair | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .tmp/aks-ssh | |
| ssh-keygen -q -t ed25519 -N '' -f .tmp/aks-ssh/id_ed25519 | |
| chmod 600 .tmp/aks-ssh/id_ed25519 | |
| - name: Derive run-scoped names | |
| run: | | |
| set -euo pipefail | |
| mkdir -p workflow-artifacts/metadata | |
| suffix="${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" | |
| cat > workflow-artifacts/metadata/aks-metadata.env <<EOF | |
| AKS_NAME=ssh-quickstart-${suffix} | |
| AKS_RG=ssh-quickstart-${suffix} | |
| SITE_NAME=remote | |
| REMOTE_NODE_CIDR=10.10.100.0/24 | |
| REMOTE_POD_CIDR=10.245.0.0/16 | |
| EOF | |
| - name: Load metadata into environment | |
| run: | | |
| set -euo pipefail | |
| cat workflow-artifacts/metadata/aks-metadata.env >> "$GITHUB_ENV" | |
| - name: Upload metadata artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: aks-quickstart-metadata | |
| path: workflow-artifacts/metadata/aks-metadata.env | |
| retention-days: 1 | |
| - name: Validate remote CIDRs against AKS defaults | |
| run: | | |
| set -euo pipefail | |
| aks_service_cidr="10.0.0.0/16" | |
| aks_pod_cidr="10.244.0.0/16" | |
| if [[ "$REMOTE_NODE_CIDR" == "$aks_service_cidr" || "$REMOTE_NODE_CIDR" == "$aks_pod_cidr" ]]; then | |
| printf 'REMOTE_NODE_CIDR (%s) collides with AKS default CIDR (%s or %s)\n' "$REMOTE_NODE_CIDR" "$aks_service_cidr" "$aks_pod_cidr" >&2 | |
| exit 1 | |
| fi | |
| if [[ "$REMOTE_POD_CIDR" == "$aks_service_cidr" || "$REMOTE_POD_CIDR" == "$aks_pod_cidr" ]]; then | |
| printf 'REMOTE_POD_CIDR (%s) collides with AKS default CIDR (%s or %s)\n' "$REMOTE_POD_CIDR" "$aks_service_cidr" "$aks_pod_cidr" >&2 | |
| exit 1 | |
| fi | |
| - name: Create Azure resource group | |
| run: | | |
| set -euo pipefail | |
| az group create \ | |
| --name "$AKS_RG" \ | |
| --location eastus2 \ | |
| --output jsonc | |
| - name: Create AKS cluster via quickstart | |
| env: | |
| WORKFLOW_KUBECONFIG: ${{ github.workspace }}/.tmp/aks-quickstart.kubeconfig | |
| KUBECONFIG: ${{ github.workspace }}/.tmp/aks-quickstart.kubeconfig | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .tmp | |
| rm -f "$WORKFLOW_KUBECONFIG" | |
| bash hack/scripts/aks-quickstart.sh create \ | |
| --name "$AKS_NAME" \ | |
| --resource-group "$AKS_RG" \ | |
| --location eastus2 \ | |
| --site-name "$SITE_NAME" \ | |
| --remote-node-cidr "$REMOTE_NODE_CIDR" \ | |
| --remote-pod-cidr "$REMOTE_POD_CIDR" \ | |
| --ssh-key .tmp/aks-ssh/id_ed25519.pub | |
| - name: Refresh workflow kubeconfig | |
| env: | |
| WORKFLOW_KUBECONFIG: ${{ github.workspace }}/.tmp/aks-quickstart.kubeconfig | |
| run: | | |
| set -euo pipefail | |
| az aks get-credentials \ | |
| --resource-group "$AKS_RG" \ | |
| --name "$AKS_NAME" \ | |
| --file "$WORKFLOW_KUBECONFIG" \ | |
| --overwrite-existing \ | |
| --output none | |
| - name: Stage workflow artifacts | |
| run: | | |
| set -euo pipefail | |
| mkdir -p workflow-artifacts/kubeconfig workflow-artifacts/ssh | |
| cp .tmp/aks-quickstart.kubeconfig workflow-artifacts/kubeconfig/aks-quickstart.kubeconfig | |
| cp .tmp/aks-ssh/id_ed25519 workflow-artifacts/ssh/id_ed25519 | |
| cp .tmp/aks-ssh/id_ed25519.pub workflow-artifacts/ssh/id_ed25519.pub | |
| - name: Upload kubeconfig artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: aks-kubeconfig | |
| path: workflow-artifacts/kubeconfig/aks-quickstart.kubeconfig | |
| retention-days: 1 | |
| - name: Upload SSH material artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: aks-ssh-material | |
| path: workflow-artifacts/ssh/ | |
| retention-days: 1 | |
| - name: Collect Azure setup diagnostics | |
| if: failure() | |
| run: | | |
| set -euo pipefail | |
| printf 'Azure account context:\n' | |
| az account show --output jsonc || true | |
| if [[ -z "${AKS_RG:-}" ]]; then | |
| printf 'AKS_RG is not set; skipping resource-group diagnostics\n' | |
| exit 0 | |
| fi | |
| printf 'Azure resource group state for %s:\n' "$AKS_RG" | |
| az group show --name "$AKS_RG" --output jsonc || true | |
| if [[ "$(az group exists --name "$AKS_RG")" != "true" ]]; then | |
| printf 'resource group %s does not exist; skipping activity-log lookup\n' "$AKS_RG" | |
| exit 0 | |
| fi | |
| printf 'Recent Azure activity log entries for %s:\n' "$AKS_RG" | |
| az monitor activity-log list \ | |
| --resource-group "$AKS_RG" \ | |
| --offset 2h \ | |
| --max-events 20 \ | |
| --output table || true | |
| proxmox-bootstrap: | |
| needs: | |
| - azure-setup | |
| runs-on: | |
| - self-hosted | |
| - pve | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Set up Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: go.mod | |
| cache-dependency-path: go.sum | |
| - name: Verify runner dependencies | |
| run: | | |
| set -euo pipefail | |
| for tool in kubectl jq pvesh pvesm qm ip ssh ssh-keygen curl cksum grep; do | |
| if ! command -v "$tool" >/dev/null 2>&1; then | |
| printf 'missing required runner dependency: %s\n' "$tool" >&2 | |
| exit 1 | |
| fi | |
| done | |
| - name: Download kubeconfig artifact | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: aks-kubeconfig | |
| path: workflow-artifacts/kubeconfig | |
| - name: Download SSH material artifact | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: aks-ssh-material | |
| path: workflow-artifacts/ssh | |
| - name: Download metadata artifact | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: aks-quickstart-metadata | |
| path: workflow-artifacts/metadata | |
| - name: Restore metadata and kubeconfig environment | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .tmp .tmp/aks-ssh | |
| cp workflow-artifacts/kubeconfig/aks-quickstart.kubeconfig .tmp/aks-quickstart.kubeconfig | |
| cp workflow-artifacts/ssh/id_ed25519 .tmp/aks-ssh/id_ed25519 | |
| cp workflow-artifacts/ssh/id_ed25519.pub .tmp/aks-ssh/id_ed25519.pub | |
| chmod 600 .tmp/aks-ssh/id_ed25519 | |
| cat workflow-artifacts/metadata/aks-metadata.env >> "$GITHUB_ENV" | |
| echo "WORKFLOW_KUBECONFIG=$PWD/.tmp/aks-quickstart.kubeconfig" >> "$GITHUB_ENV" | |
| echo "KUBECONFIG=$PWD/.tmp/aks-quickstart.kubeconfig" >> "$GITHUB_ENV" | |
| echo "SSH_PRIVATE_KEY=$PWD/.tmp/aks-ssh/id_ed25519" >> "$GITHUB_ENV" | |
| - name: Build kubectl-unbounded | |
| run: | | |
| set -euo pipefail | |
| mkdir -p bin | |
| go build -o bin/kubectl-unbounded ./cmd/kubectl-unbounded | |
| echo "$PWD/bin" >> "$GITHUB_PATH" | |
| - name: Create Proxmox VMs | |
| run: | | |
| set -euo pipefail | |
| hack/scripts/proxmox-ssh-quickstart-vms.sh create \ | |
| --state-file .tmp/proxmox-vms.env \ | |
| --ssh-public-key .tmp/aks-ssh/id_ed25519.pub \ | |
| --vm-prefix "$AKS_NAME" | |
| - name: Load Proxmox VM state | |
| run: | | |
| set -euo pipefail | |
| hack/scripts/proxmox-ssh-quickstart-vms.sh print-env \ | |
| --state-file .tmp/proxmox-vms.env >> "$GITHUB_ENV" | |
| - name: Bootstrap first Proxmox VM | |
| run: | | |
| set -euo pipefail | |
| kubectl unbounded machine manual-bootstrap "${SITE_NAME}-worker-1" \ | |
| --kubeconfig "$WORKFLOW_KUBECONFIG" \ | |
| --site "$SITE_NAME" \ | |
| | ssh -o StrictHostKeyChecking=no \ | |
| -o BatchMode=yes \ | |
| -o UserKnownHostsFile=/dev/null \ | |
| -o ConnectTimeout=10 \ | |
| -i "$SSH_PRIVATE_KEY" \ | |
| "$SSH_USERNAME@$VM1_IP" sudo -n bash | |
| - name: Bootstrap second Proxmox VM | |
| run: | | |
| set -euo pipefail | |
| kubectl unbounded machine manual-bootstrap "${SITE_NAME}-worker-2" \ | |
| --kubeconfig "$WORKFLOW_KUBECONFIG" \ | |
| --site "$SITE_NAME" \ | |
| | ssh -o StrictHostKeyChecking=no \ | |
| -o BatchMode=yes \ | |
| -o UserKnownHostsFile=/dev/null \ | |
| -o ConnectTimeout=10 \ | |
| -i "$SSH_PRIVATE_KEY" \ | |
| "$SSH_USERNAME@$VM2_IP" sudo -n bash | |
| - name: Wait for both nodes to become Ready | |
| run: | | |
| set -euo pipefail | |
| for machine in "${SITE_NAME}-worker-1" "${SITE_NAME}-worker-2"; do | |
| node="" | |
| for attempt in $(seq 1 60); do | |
| node=$(KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl get nodes -l "unbounded-kube.io/machine=$machine" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) | |
| if [[ -n "$node" ]]; then | |
| break | |
| fi | |
| if [[ "$attempt" -eq 60 ]]; then | |
| printf 'node for machine %s did not appear after %s attempts\n' "$machine" "$attempt" >&2 | |
| exit 1 | |
| fi | |
| sleep 10 | |
| done | |
| KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl wait --for=condition=Ready "node/$node" --timeout=20m | |
| done | |
| - name: Cleanup Proxmox resources | |
| if: always() | |
| run: | | |
| set -euo pipefail | |
| proxmox_state_file=.tmp/proxmox-vms.env | |
| cleanup_failed=0 | |
| mkdir -p logs | |
| cp "$proxmox_state_file" logs/proxmox-vms.env 2>/dev/null || true | |
| destroy_proxmox_vms() { | |
| if [[ ! -f "$proxmox_state_file" ]]; then | |
| return 0 | |
| fi | |
| if ! hack/scripts/proxmox-ssh-quickstart-vms.sh destroy --state-file "$proxmox_state_file"; then | |
| printf 'failed to destroy Proxmox VMs recorded in %s\n' "$proxmox_state_file" >&2 | |
| cleanup_failed=1 | |
| return 0 | |
| fi | |
| rm -f "$proxmox_state_file" | |
| } | |
| destroy_proxmox_vms | |
| if [[ "$cleanup_failed" -ne 0 ]]; then | |
| exit 1 | |
| fi | |
| - name: Collect cluster diagnostics | |
| if: failure() | |
| run: | | |
| set -euo pipefail | |
| mkdir -p logs | |
| cp .tmp/proxmox-vms.env logs/proxmox-vms.env 2>/dev/null || true | |
| KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl get nodes -o wide > logs/nodes.txt 2>&1 || true | |
| KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl get machines -o wide > logs/machines.txt 2>&1 || true | |
| KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl get machines -o yaml > logs/machines.yaml 2>&1 || true | |
| KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl describe machines > logs/machines-describe.txt 2>&1 || true | |
| KUBECONFIG="$WORKFLOW_KUBECONFIG" kubectl -n unbounded-kube logs deploy/machina-controller > logs/machina.log 2>&1 || true | |
| - name: Upload diagnostics | |
| if: failure() | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: aks-ssh-quickstart-logs | |
| path: logs/ | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| azure-cleanup: | |
| needs: | |
| - azure-setup | |
| - proxmox-bootstrap | |
| if: always() | |
| runs-on: ubuntu-latest | |
| environment: azure-ci | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Download metadata artifact | |
| continue-on-error: true | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: aks-quickstart-metadata | |
| path: workflow-artifacts/metadata | |
| - name: Restore cleanup metadata | |
| run: | | |
| set -euo pipefail | |
| if [[ -f workflow-artifacts/metadata/aks-metadata.env ]]; then | |
| cat workflow-artifacts/metadata/aks-metadata.env >> "$GITHUB_ENV" | |
| fi | |
| - name: Azure login | |
| if: ${{ env.AKS_RG != '' }} | |
| uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| - name: Delete Azure resource group | |
| if: ${{ env.AKS_RG != '' }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$(az group exists --name "$AKS_RG")" != "true" ]]; then | |
| printf 'resource group %s does not exist; skipping delete\n' "$AKS_RG" | |
| exit 0 | |
| fi | |
| az group delete --yes --no-wait --name "$AKS_RG" |