Delete AKS or ARO clusters on Azure with safety checks
Safely delete AKS or ARO clusters with comprehensive safety checks, backups, and resource cleanup. Use this before decommissioning to prevent accidental data loss and ensure proper resource removal.
/plugin marketplace add kcns008/cluster-code/plugin install kcns008-cloud-azure-plugins-cloud-azure@kcns008/cluster-codeSafely delete AKS or ARO clusters with comprehensive backup and safety checks.
You are responsible for safely decommissioning Azure Kubernetes clusters while:
Verify Azure authentication:
az account show || {
echo "โ Not authenticated to Azure"
echo "Run: az login"
exit 1
}
Auto-detect cluster type (if not specified):
if [[ -z "$CLUSTER_TYPE" ]]; then
# Try AKS
if az aks show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP &>/dev/null; then
CLUSTER_TYPE="aks"
# Try ARO
elif az aro show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP &>/dev/null; then
CLUSTER_TYPE="aro"
else
echo "โ Cluster not found: $CLUSTER_NAME"
exit 1
fi
fi
Get cluster information:
echo "๐ Cluster Information:"
echo ""
if [[ "$CLUSTER_TYPE" == "aks" ]]; then
CLUSTER_INFO=$(az aks show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP -o json)
LOCATION=$(echo $CLUSTER_INFO | jq -r '.location')
K8S_VERSION=$(echo $CLUSTER_INFO | jq -r '.kubernetesVersion')
NODE_COUNT=$(echo $CLUSTER_INFO | jq -r '.agentPoolProfiles[].count' | awk '{sum+=$1} END {print sum}')
PROVISIONING_STATE=$(echo $CLUSTER_INFO | jq -r '.provisioningState')
echo " Type: AKS"
echo " Name: $CLUSTER_NAME"
echo " Resource Group: $RESOURCE_GROUP"
echo " Location: $LOCATION"
echo " Kubernetes Version: $K8S_VERSION"
echo " Total Nodes: $NODE_COUNT"
echo " State: $PROVISIONING_STATE"
else
CLUSTER_INFO=$(az aro show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP -o json)
LOCATION=$(echo $CLUSTER_INFO | jq -r '.location')
OPENSHIFT_VERSION=$(echo $CLUSTER_INFO | jq -r '.clusterProfile.version')
PROVISIONING_STATE=$(echo $CLUSTER_INFO | jq -r '.provisioningState')
CONSOLE_URL=$(echo $CLUSTER_INFO | jq -r '.consoleProfile.url')
echo " Type: ARO"
echo " Name: $CLUSTER_NAME"
echo " Resource Group: $RESOURCE_GROUP"
echo " Location: $LOCATION"
echo " OpenShift Version: $OPENSHIFT_VERSION"
echo " State: $PROVISIONING_STATE"
echo " Console: $CONSOLE_URL"
fi
echo ""
Check for production indicators:
echo "๐ Running safety checks..."
echo ""
WARNINGS=0
# Check cluster tags
TAGS=$(echo $CLUSTER_INFO | jq -r '.tags // {}')
ENV_TAG=$(echo $TAGS | jq -r '.Environment // .environment // ""')
if [[ "$ENV_TAG" =~ ^(prod|production|prd)$ ]]; then
echo "โ ๏ธ WARNING: Cluster is tagged as PRODUCTION"
WARNINGS=$((WARNINGS + 1))
fi
# Check node count
if [[ "$CLUSTER_TYPE" == "aks" && $NODE_COUNT -gt 5 ]]; then
echo "โ ๏ธ WARNING: Large cluster ($NODE_COUNT nodes)"
WARNINGS=$((WARNINGS + 1))
fi
# Check for persistent volumes
PV_COUNT=$(kubectl get pv --no-headers 2>/dev/null | wc -l)
if [[ $PV_COUNT -gt 0 ]]; then
echo "โ ๏ธ WARNING: $PV_COUNT Persistent Volumes found (data will be lost)"
WARNINGS=$((WARNINGS + 1))
fi
# Check for load balancers
LB_COUNT=$(kubectl get svc --all-namespaces --no-headers 2>/dev/null | grep LoadBalancer | wc -l)
if [[ $LB_COUNT -gt 0 ]]; then
echo "โ ๏ธ INFO: $LB_COUNT Load Balancer services (will be deleted)"
fi
echo ""
List associated resources:
echo "๐ Associated Azure Resources:"
echo ""
# Get resources in the cluster's resource group
RESOURCES=$(az resource list --resource-group $RESOURCE_GROUP -o json)
RESOURCE_COUNT=$(echo $RESOURCES | jq 'length')
echo " Total resources in resource group: $RESOURCE_COUNT"
echo ""
echo " Resource types:"
echo $RESOURCES | jq -r '.[].type' | sort | uniq -c | awk '{printf " - %s: %d\n", $2, $1}'
echo ""
# Check for managed resource group (AKS creates additional RG)
if [[ "$CLUSTER_TYPE" == "aks" ]]; then
NODE_RG=$(echo $CLUSTER_INFO | jq -r '.nodeResourceGroup')
if [[ -n "$NODE_RG" && "$NODE_RG" != "null" ]]; then
echo " Managed Resource Group: $NODE_RG"
NODE_RG_RESOURCES=$(az resource list --resource-group $NODE_RG -o json | jq 'length')
echo " Resources in managed RG: $NODE_RG_RESOURCES"
echo ""
fi
fi
Create backup (if --backup enabled):
if [[ "$BACKUP" == "true" ]]; then
echo "๐พ Backing up cluster resources..."
echo ""
BACKUP_DIR="./cluster-backup-$CLUSTER_NAME-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
# Backup all namespaces
kubectl get namespaces -o yaml > "$BACKUP_DIR/namespaces.yaml"
# Backup all resources in each namespace
kubectl get namespaces --no-headers | awk '{print $1}' | while read NS; do
echo " ๐ Backing up namespace: $NS"
mkdir -p "$BACKUP_DIR/$NS"
# Skip system namespaces for full backup
if [[ ! "$NS" =~ ^(kube-|openshift-|default$) ]]; then
kubectl get all,cm,secret,pvc,ing -n $NS -o yaml > "$BACKUP_DIR/$NS/all-resources.yaml" 2>/dev/null
fi
done
# Backup cluster-scoped resources
echo " ๐ Backing up cluster-scoped resources"
kubectl get clusterrole,clusterrolebinding,sc,pv -o yaml > "$BACKUP_DIR/cluster-resources.yaml" 2>/dev/null
# Save cluster info
echo $CLUSTER_INFO | jq '.' > "$BACKUP_DIR/cluster-info.json"
# Create backup archive
tar -czf "$BACKUP_DIR.tar.gz" -C "$(dirname $BACKUP_DIR)" "$(basename $BACKUP_DIR)"
rm -rf "$BACKUP_DIR"
echo ""
echo "โ
Backup saved: $BACKUP_DIR.tar.gz"
echo ""
fi
Export important data:
# Export Helm releases
if command -v helm &>/dev/null; then
echo " ๐ฆ Exporting Helm releases"
helm list --all-namespaces -o json > "$BACKUP_DIR/helm-releases.json" 2>/dev/null
fi
# Export ArgoCD applications (if installed)
if kubectl get namespace argocd &>/dev/null; then
echo " ๐ Exporting ArgoCD applications"
kubectl get applications -n argocd -o yaml > "$BACKUP_DIR/argocd-apps.yaml" 2>/dev/null
fi
Show deletion summary:
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo "โ ๏ธ DELETION SUMMARY"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo ""
echo "Cluster to delete:"
echo " Name: $CLUSTER_NAME"
echo " Type: $CLUSTER_TYPE"
echo " Resource Group: $RESOURCE_GROUP"
echo ""
echo "What will be deleted:"
echo " โ Cluster control plane"
echo " โ All worker nodes ($NODE_COUNT nodes)"
echo " โ All pods and containers"
echo " โ All persistent volumes ($PV_COUNT PVs)"
echo " โ All load balancers ($LB_COUNT LBs)"
if [[ "$CLUSTER_TYPE" == "aks" ]]; then
echo " โ Managed resource group: $NODE_RG"
fi
if [[ "$DELETE_RESOURCE_GROUP" == "true" ]]; then
echo " โ Resource group: $RESOURCE_GROUP ($RESOURCE_COUNT resources)"
fi
echo ""
if [[ "$BACKUP" == "true" ]]; then
echo "โ
Backup created: $BACKUP_DIR.tar.gz"
else
echo "โ ๏ธ No backup created (use --backup to create backup)"
fi
echo ""
if [[ $WARNINGS -gt 0 ]]; then
echo "โ ๏ธ $WARNINGS warning(s) detected - review carefully before proceeding"
echo ""
fi
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
Request confirmation (unless --yes):
if [[ "$YES" != "true" ]]; then
echo ""
echo "โ ๏ธ THIS ACTION CANNOT BE UNDONE!"
echo ""
read -p "Type the cluster name to confirm deletion: " CONFIRM_NAME
if [[ "$CONFIRM_NAME" != "$CLUSTER_NAME" ]]; then
echo ""
echo "โ Cluster name does not match. Deletion cancelled."
exit 0
fi
echo ""
read -p "Are you absolutely sure you want to delete this cluster? [yes/NO]: " FINAL_CONFIRM
if [[ ! "$FINAL_CONFIRM" =~ ^[Yy][Ee][Ss]$ ]]; then
echo ""
echo "โ Deletion cancelled"
exit 0
fi
fi
Delete cluster:
echo ""
echo "๐๏ธ Deleting cluster..."
echo ""
START_TIME=$(date +%s)
if [[ "$CLUSTER_TYPE" == "aks" ]]; then
# Delete AKS cluster
az aks delete \
--name $CLUSTER_NAME \
--resource-group $RESOURCE_GROUP \
--yes \
--no-wait
echo " Deletion initiated for AKS cluster"
echo " This typically takes 5-10 minutes"
else
# Delete ARO cluster
az aro delete \
--name $CLUSTER_NAME \
--resource-group $RESOURCE_GROUP \
--yes \
--no-wait
echo " Deletion initiated for ARO cluster"
echo " This typically takes 15-20 minutes"
fi
echo ""
Monitor deletion progress:
echo "โณ Monitoring deletion progress..."
echo ""
while true; do
if [[ "$CLUSTER_TYPE" == "aks" ]]; then
STATUS=$(az aks show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP \
--query provisioningState -o tsv 2>/dev/null)
else
STATUS=$(az aro show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP \
--query provisioningState -o tsv 2>/dev/null)
fi
if [[ $? -ne 0 ]]; then
echo "โ
Cluster deleted successfully!"
break
fi
ELAPSED=$(($(date +%s) - START_TIME))
ELAPSED_MIN=$((ELAPSED / 60))
echo " Status: $STATUS (elapsed: ${ELAPSED_MIN}m)"
sleep 30
done
echo ""
Delete resource group (if --delete-resource-group):
if [[ "$DELETE_RESOURCE_GROUP" == "true" ]]; then
echo "๐๏ธ Deleting resource group: $RESOURCE_GROUP"
echo ""
az group delete \
--name $RESOURCE_GROUP \
--yes \
--no-wait
echo " Resource group deletion initiated"
echo " This may take additional time"
echo ""
fi
Clean up kubeconfig:
echo "๐งน Cleaning up local configuration..."
echo ""
# Remove context from kubeconfig
kubectl config delete-context $CLUSTER_NAME 2>/dev/null && \
echo " โ
Removed kubectl context"
kubectl config delete-cluster $CLUSTER_NAME 2>/dev/null && \
echo " โ
Removed cluster from kubeconfig"
kubectl config unset users.$CLUSTER_NAME 2>/dev/null && \
echo " โ
Removed user credentials"
echo ""
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo "โ
DELETION COMPLETE"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo ""
echo "Deleted:"
echo " โ Cluster: $CLUSTER_NAME"
echo " โ Type: $CLUSTER_TYPE"
echo " โ Resource Group: $RESOURCE_GROUP"
if [[ "$DELETE_RESOURCE_GROUP" == "true" ]]; then
echo " โ Resource Group deleted"
fi
echo ""
if [[ "$BACKUP" == "true" ]]; then
echo "Backup Location:"
echo " ๐ $BACKUP_DIR.tar.gz"
echo ""
echo "To restore from backup:"
echo " tar -xzf $BACKUP_DIR.tar.gz"
echo " kubectl apply -f $BACKUP_DIR/"
echo ""
fi
TOTAL_TIME=$(($(date +%s) - START_TIME))
TOTAL_MIN=$((TOTAL_TIME / 60))
echo "Total Time: ${TOTAL_MIN}m"
echo ""
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
Cluster not found:
โ Cluster not found
Verify cluster name and resource group:
az aks list --resource-group <rg>
az aro list --resource-group <rg>
Deletion failed:
โ Cluster deletion failed
Check Azure portal for errors
View activity log:
az monitor activity-log list --resource-group <rg>
Retry deletion:
az aks delete --name <name> --resource-group <rg> --yes
Resource group locked:
โ Resource group is locked
Check locks:
az lock list --resource-group <rg>
Remove lock:
az lock delete --name <lock-name> --resource-group <rg>