Files
AFC-Demo/.github/workflows/deploy-azure.yml
T
cbazzaandClaude Opus 4.5 fddc78618e
Build and Deploy to Synology NAS / test (push) Failing after 15m0s
Build and Deploy to Synology NAS / build (push) Has been cancelled
Build and Deploy to Synology NAS / deploy (push) Has been cancelled
Build and Deploy to Synology NAS / notify (push) Has been cancelled
feat: add Azure AKS deployment infrastructure with Terraform
- Add Terraform configuration for AKS cluster deployment
- Add Kubernetes manifests for Laravel app (deployment, services, secrets)
- Add PostgreSQL on Kubernetes with multi-schema support
- Add Nginx Ingress Controller configuration
- Add GitHub Actions workflow for Azure deployment
- Add HTTP Basic Authentication for production
- Add database restore functionality via Kubernetes jobs
- Update Dockerfile and nginx config for production
- Update database.php for multi-schema connections
- Add deployment documentation and quickstart guides

Deployed version: 1.0.7 at http://72.144.113.194/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 09:43:08 +01:00

243 lines
8.2 KiB
YAML

name: Deploy to Azure AKS
on:
push:
branches:
- main
- production
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
required: true
type: choice
options:
- staging
- production
default: staging
env:
REGISTRY: mylaravelregistry.azurecr.io
IMAGE_NAME: laravel-app
TERRAFORM_VERSION: 1.9.0
jobs:
build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Azure Container Registry
uses: azure/docker-login@v1
with:
login-server: ${{ env.REGISTRY }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
terraform-deploy:
name: Terraform Deploy
runs-on: ubuntu-latest
needs: build-and-push
environment: ${{ github.event.inputs.environment || 'staging' }}
defaults:
run:
working-directory: terraform
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TERRAFORM_VERSION }}
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Create terraform.tfvars
run: |
cat > terraform.tfvars <<EOF
subscription_id = "${{ secrets.AZURE_SUBSCRIPTION_ID }}"
resource_group_name = "trusted_ai_demo_rg"
location = "germanywestcentral"
aks_cluster_name = "trai_k8s_cluster"
app_name = "laravel-app"
app_namespace = "laravel-app"
app_env = "${{ github.event.inputs.environment || 'staging' }}"
app_debug = ${{ github.event.inputs.environment == 'production' && 'false' || 'true' }}
app_replicas = ${{ github.event.inputs.environment == 'production' && '3' || '2' }}
docker_image = "${{ needs.build-and-push.outputs.image_tag }}"
app_key = "${{ secrets.LARAVEL_APP_KEY }}"
postgresql_admin_username = "${{ secrets.POSTGRESQL_ADMIN_USERNAME }}"
postgresql_admin_password = "${{ secrets.POSTGRESQL_ADMIN_PASSWORD }}"
postgresql_sku_name = "${{ github.event.inputs.environment == 'production' && 'GP_Standard_D2s_v3' || 'B_Standard_B1ms' }}"
postgresql_storage_mb = ${{ github.event.inputs.environment == 'production' && '131072' || '32768' }}
ingress_enabled = true
ingress_host = "${{ secrets.INGRESS_HOST }}"
ssl_enabled = ${{ github.event.inputs.environment == 'production' && 'true' || 'false' }}
ssl_issuer_email = "${{ secrets.SSL_ISSUER_EMAIL }}"
db_restore_enabled = false
alert_email_address = "${{ secrets.ALERT_EMAIL }}"
EOF
- name: Terraform Init
run: terraform init
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
run: terraform plan -out=tfplan
- name: Terraform Apply
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production'
run: terraform apply -auto-approve tfplan
- name: Get kubectl credentials
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production'
run: |
az aks get-credentials \
--resource-group trusted_ai_demo_rg \
--name trai_k8s_cluster \
--overwrite-existing
- name: Wait for deployment
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production'
run: |
kubectl wait --for=condition=ready pod \
-l app=laravel-app \
-n laravel-app \
--timeout=300s || true
- name: Get Application URL
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production'
id: get-url
run: |
APP_URL=$(terraform output -raw app_url)
echo "url=$APP_URL" >> $GITHUB_OUTPUT
echo "### Deployment Complete! 🚀" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Application URL: $APP_URL" >> $GITHUB_STEP_SUMMARY
- name: Upload Terraform Plan
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/production'
uses: actions/upload-artifact@v4
with:
name: terraform-plan
path: terraform/tfplan
smoke-tests:
name: Smoke Tests
runs-on: ubuntu-latest
needs: terraform-deploy
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production'
steps:
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Get kubectl credentials
run: |
az aks get-credentials \
--resource-group trusted_ai_demo_rg \
--name trai_k8s_cluster \
--overwrite-existing
- name: Check pod health
run: |
kubectl get pods -n laravel-app
READY_PODS=$(kubectl get pods -n laravel-app -l app=laravel-app -o jsonpath='{.items[*].status.conditions[?(@.type=="Ready")].status}' | grep -o "True" | wc -l)
if [ "$READY_PODS" -lt 1 ]; then
echo "Error: No ready pods found"
exit 1
fi
echo "✓ $READY_PODS pod(s) are ready"
- name: Check service endpoint
run: |
LOADBALANCER_IP=$(kubectl get svc ingress-nginx-controller -n ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
if [ -z "$LOADBALANCER_IP" ]; then
echo "Warning: LoadBalancer IP not yet assigned"
else
echo "✓ LoadBalancer IP: $LOADBALANCER_IP"
# Try to reach the application
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://$LOADBALANCER_IP --max-time 10)
if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 302 ]; then
echo "✓ Application is responding (HTTP $HTTP_CODE)"
else
echo "Warning: Application returned HTTP $HTTP_CODE"
fi
fi
- name: Check database connectivity
run: |
DB_SECRET=$(kubectl get secret laravel-app-db-credentials -n laravel-app -o jsonpath='{.data.DB_HOST}' | base64 -d)
echo "✓ Database host configured: $DB_SECRET"
notify:
name: Notify Deployment Status
runs-on: ubuntu-latest
needs: [build-and-push, terraform-deploy, smoke-tests]
if: always()
steps:
- name: Deployment Success
if: ${{ needs.terraform-deploy.result == 'success' && needs.smoke-tests.result == 'success' }}
run: |
echo "### ✅ Deployment Successful!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Environment: ${{ github.event.inputs.environment || 'staging' }}" >> $GITHUB_STEP_SUMMARY
echo "Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
- name: Deployment Failed
if: ${{ needs.terraform-deploy.result == 'failure' || needs.smoke-tests.result == 'failure' }}
run: |
echo "### ❌ Deployment Failed!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Please check the logs for details." >> $GITHUB_STEP_SUMMARY
exit 1