Skip to content

Terraform Destroy Workflow #25

Terraform Destroy Workflow

Terraform Destroy Workflow #25

Workflow file for this run

name: Terraform Destroy Workflow
on:
workflow_dispatch:
permissions:
id-token: write
contents: read
actions: read
jobs:
terraform-destroy:
name: Terraform Destroy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout Repository
uses: actions/checkout@v5
- name: Verify Variables Available
run: |
echo "CLUSTER_NAME: ${{ vars.CLUSTER_NAME }}"
echo "NAMESPACE: ${{ vars.APP_NAMESPACE }}"
echo "MONITORING_NAMESPACE: ${{ vars.MONITORING_NAMESPACE }}"
echo "ARGOCD_NAMESPACE: ${{ vars.ARGOCD_NAMESPACE }}"
echo "APP_NAME: ${{ vars.APP_NAME }}"
echo "KARPENTER_NODEPOOL_NAME: ${{ vars.KARPENTER_NODEPOOL_NAME }}"
echo "KARPENTER_NODECLASS_NAME: ${{ vars.KARPENTER_NODECLASS_NAME }}"
echo "KARPENTER_NODE_ROLE: ${{ vars.KARPENTER_NODE_ROLE }}"
echo "KARPENTER_INSTANCE_PROFILE: ${{ vars.KARPENTER_INSTANCE_PROFILE }}"
echo "KARPENTER_NAMESPACE: ${{ vars.KARPENTER_NAMESPACE }}"
if [[ -z "${{ vars.KARPENTER_NODEPOOL_NAME }}" ]]; then
echo "WARNING: KARPENTER_NODEPOOL_NAME variable not found. Karpenter resources may not be deployed."
fi
if [[ -z "${{ vars.KARPENTER_NODE_ROLE }}" ]]; then
echo "WARNING: KARPENTER_NODE_ROLE variable not found. Karpenter resources may not be deployed."
fi
if [[ -z "${{ vars.KARPENTER_INSTANCE_PROFILE }}" ]]; then
echo "WARNING: KARPENTER_INSTANCE_PROFILE variable not found. Karpenter resources may not be deployed."
fi
if [[ -z "${{ vars.KARPENTER_NAMESPACE }}" ]]; then
echo "WARNING: KARPENTER_NAMESPACE variable not found. Karpenter resources may not be deployed."
fi
if [[ -z "${{ vars.CLUSTER_NAME }}" ]]; then
echo "ERROR: CLUSTER_NAME variable not found. Infrastructure may not be deployed."
exit 1
fi
if [[ -z "${{ vars.APP_NAMESPACE }}" ]]; then
echo "ERROR: APP_NAMESPACE variable not found. Infrastructure may not be deployed."
exit 1
fi
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/GitHubActionsInfraRole
aws-region: us-east-1
- name: Setup Terraform
uses: hashicorp/[email protected]
with:
terraform_version: 1.5.7
- name: Update kubeconfig
run: aws eks update-kubeconfig --name ${{ vars.CLUSTER_NAME }} --region us-east-1
continue-on-error: true
- name: Install Helm
uses: azure/[email protected]
with:
version: v3.14.0
continue-on-error: true
# ---------------------------
# Delete ArgoCD Applications
# ---------------------------
- name: Delete ArgoCD Applications
run: |
kubectl delete application ${{ vars.APP_NAME }} -n ${{ vars.ARGOCD_NAMESPACE }} --ignore-not-found
kubectl delete application kube-prometheus-stack -n ${{ vars.ARGOCD_NAMESPACE }} --ignore-not-found
continue-on-error: true
# ---------------------------
# Delete Karpenter Resources (Updated)
# ---------------------------
- name: Scale down to release nodes first
run: |
kubectl scale deployment --all --replicas=0 --all-namespaces || true
sleep 30 # Let Karpenter scale down naturally
continue-on-error: true
- name: Delete Karpenter Provisioners and AWSNodeTemplates
run: |
echo "Deleting Karpenter Provisioners..."
kubectl delete provisioner ${{ vars.KARPENTER_NODEPOOL_NAME }} --ignore-not-found -n ${{ vars.KARPENTER_NAMESPACE }} || true
kubectl delete provisioner --all -n ${{ vars.KARPENTER_NAMESPACE }} --ignore-not-found || true
echo "Deleting Karpenter AWSNodeTemplates..."
kubectl delete awsnodetemplate ${{ vars.KARPENTER_NODECLASS_NAME }} --ignore-not-found -n ${{ vars.KARPENTER_NAMESPACE }} || true
kubectl delete awsnodetemplate --all -n ${{ vars.KARPENTER_NAMESPACE }} --ignore-not-found || true
echo "Waiting for resources to be cleaned up..."
sleep 10
continue-on-error: true
- name: Clean up Karpenter CRDs and Webhooks
run: |
echo "Deleting Karpenter CRDs..."
kubectl delete crd provisioners.karpenter.sh --ignore-not-found || true
kubectl delete crd awsnodetemplates.karpenter.k8s.aws --ignore-not-found || true
echo "Deleting Karpenter webhooks..."
kubectl delete validatingwebhookconfiguration defaulting.webhook.karpenter.sh --ignore-not-found || true
kubectl delete validatingwebhookconfiguration validation.webhook.karpenter.sh --ignore-not-found || true
kubectl delete mutatingwebhookconfiguration defaulting.webhook.karpenter.sh --ignore-not-found || true
echo "Deleting Karpenter finalizers if stuck..."
kubectl patch crd provisioners.karpenter.sh -p '{"metadata":{"finalizers":[]}}' --type=merge || true
kubectl patch crd awsnodetemplates.karpenter.k8s.aws -p '{"metadata":{"finalizers":[]}}' --type=merge || true
continue-on-error: true
- name: Uninstall Karpenter Helm Release
run: |
echo "Uninstalling Karpenter Helm release..."
helm uninstall karpenter -n ${{ vars.KARPENTER_NAMESPACE }} || true
echo "Waiting for pods to terminate..."
kubectl wait --for=delete pod -l app.kubernetes.io/name=karpenter -n ${{ vars.KARPENTER_NAMESPACE }} --timeout=120s || true
echo "Force deleting any remaining pods..."
kubectl delete pods --all -n ${{ vars.KARPENTER_NAMESPACE }} --force --grace-period=0 || true
continue-on-error: true
- name: Clean up Karpenter CRDs and Webhooks
run: |
echo "Deleting Karpenter CRDs..."
kubectl delete crd nodepools.karpenter.sh --ignore-not-found || true
kubectl delete crd provisioners.karpenter.sh --ignore-not-found || true
kubectl delete crd awsnodetemplates.karpenter.k8s.aws --ignore-not-found || true
kubectl delete crd ec2nodeclasses.karpenter.k8s.aws --ignore-not-found || true
echo "Deleting Karpenter webhooks..."
kubectl delete validatingwebhookconfiguration defaulting.webhook.karpenter.sh --ignore-not-found || true
kubectl delete validatingwebhookconfiguration validation.webhook.karpenter.sh --ignore-not-found || true
kubectl delete mutatingwebhookconfiguration defaulting.webhook.karpenter.sh --ignore-not-found || true
echo "Deleting Karpenter finalizers if stuck..."
kubectl patch crd nodepools.karpenter.sh -p '{"metadata":{"finalizers":[]}}' --type=merge || true
kubectl patch crd ec2nodeclasses.karpenter.k8s.aws -p '{"metadata":{"finalizers":[]}}' --type=merge || true
continue-on-error: true
# ---------------------------
# Uninstall Other Helm Releases
# ---------------------------
- name: Uninstall Helm Releases
run: |
helm uninstall ${{ vars.APP_NAME }} -n ${{ vars.APP_NAMESPACE }} || true
helm uninstall kube-prometheus-stack -n ${{ vars.MONITORING_NAMESPACE }} || true
helm uninstall ingress-nginx -n ingress-nginx || true
helm uninstall argocd -n ${{ vars.ARGOCD_NAMESPACE }} || true
continue-on-error: true
# ---------------------------
# Delete Namespaces
# ---------------------------
- name: Delete Namespaces
run: |
kubectl delete namespace ${{ vars.APP_NAMESPACE }} --ignore-not-found
kubectl delete namespace ${{ vars.MONITORING_NAMESPACE }} --ignore-not-found
kubectl delete namespace ${{ vars.ARGOCD_NAMESPACE }} --ignore-not-found
kubectl delete namespace ingress-nginx --ignore-not-found
# Delete Karpenter namespace last and force if needed
kubectl delete namespace ${{ vars.KARPENTER_NAMESPACE }} --ignore-not-found --timeout=60s || true
kubectl delete namespace ${{ vars.KARPENTER_NAMESPACE }} --force --grace-period=0 --ignore-not-found || true
continue-on-error: true
# ---------------------------
# Delete CRDs (Prometheus & Grafana)
# ---------------------------
- name: Delete Monitoring CRDs
run: |
kubectl get crd -o name | grep -E 'prometheus|grafana|alertmanager|servicemonitor|prometheusrule' | xargs -r kubectl delete || true
continue-on-error: true
# ---------------------------
# Cleanup PVCs & PVs
# ---------------------------
- name: Cleanup Persistent Storage
run: |
kubectl delete pvc --all -A || true
kubectl delete pv --all || true
continue-on-error: true
# ---------------------------
# Final cleanup verification
# ---------------------------
- name: Verify Karpenter cleanup
run: |
echo "Verifying Karpenter cleanup..."
kubectl get pods -n ${{ vars.KARPENTER_NAMESPACE }} || echo "Karpenter namespace not found (expected)"
kubectl get crd | grep karpenter || echo "No Karpenter CRDs found (expected)"
kubectl get validatingwebhookconfiguration | grep karpenter || echo "No Karpenter webhooks found (expected)"
kubectl get mutatingwebhookconfiguration | grep karpenter || echo "No Karpenter webhooks found (expected)"
helm list -n ${{ vars.KARPENTER_NAMESPACE }} || echo "No Helm releases in karpenter namespace (expected)"
continue-on-error: true
# ---------------------------
# Wait for cleanup to complete
# ---------------------------
- name: Wait for cleanup
run: sleep 30
# ---------------------------
# Terraform Destroy
# ---------------------------
- name: Terraform Init
run: terraform init
working-directory: ./Terraform
- name: Terraform Destroy Plan
run: terraform plan -destroy
working-directory: ./Terraform
- name: Terraform Destroy
run: terraform destroy -auto-approve
working-directory: ./Terraform
# ---------------------------
# Clean up GitHub Variables
# ---------------------------
- name: Remove GitHub repository variables
run: |
gh variable delete CLUSTER_NAME --repo $GITHUB_REPOSITORY || true
gh variable delete APP_NAMESPACE --repo $GITHUB_REPOSITORY || true
gh variable delete MONITORING_NAMESPACE --repo $GITHUB_REPOSITORY || true
gh variable delete ARGOCD_NAMESPACE --repo $GITHUB_REPOSITORY || true
gh variable delete APP_NAME --repo $GITHUB_REPOSITORY || true
gh variable delete KARPENTER_NODEPOOL_NAME --repo $GITHUB_REPOSITORY || true
gh variable delete KARPENTER_NODECLASS_NAME --repo $GITHUB_REPOSITORY || true
gh variable delete KARPENTER_NODE_ROLE --repo $GITHUB_REPOSITORY || true
gh variable delete KARPENTER_INSTANCE_PROFILE --repo $GITHUB_REPOSITORY || true
gh variable delete KARPENTER_NAMESPACE --repo $GITHUB_REPOSITORY || true
env:
GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }}
continue-on-error: true