CD - Deploy Backend (then Frontend) #12
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: CD - Deploy Backend (then Frontend) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| aks_cluster_name: { description: 'AKS name', required: false, default: '' } | |
| aks_resource_group: { description: 'RG name', required: false, default: '' } | |
| image_tag: { description: 'Image tag to deploy (optional)', required: false, default: '' } | |
| workflow_run: | |
| workflows: ["CI - Test, Build & Push (Backend + Frontend)"] | |
| types: [completed] | |
| branches: [main] | |
| permissions: | |
| id-token: write | |
| contents: read | |
| concurrency: | |
| group: deploy-backend-prod | |
| cancel-in-progress: false | |
| jobs: | |
| deploy_backend: | |
| # Run if manual OR CI completed successfully | |
| if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' | |
| runs-on: ubuntu-latest | |
| environment: Production | |
| outputs: | |
| PRODUCT_API_IP: ${{ steps.capture.outputs.product_ip }} | |
| ORDER_API_IP: ${{ steps.capture.outputs.order_ip }} | |
| IMAGE_TAG: ${{ steps.compute_tag.outputs.val }} | |
| AKS_NAME: ${{ steps.compute_aks.outputs.name }} | |
| AKS_RG: ${{ steps.compute_aks.outputs.rg }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Decide which image tag to deploy | |
| - name: Compute IMAGE_TAG | |
| id: compute_tag | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_run" ]; then | |
| echo "val=${{ github.event.workflow_run.head_sha }}" >> $GITHUB_OUTPUT | |
| elif [ -n "${{ github.event.inputs.image_tag }}" ]; then | |
| echo "val=${{ github.event.inputs.image_tag }}" >> $GITHUB_OUTPUT | |
| else | |
| echo "val=${{ github.sha }}" >> $GITHUB_OUTPUT | |
| fi | |
| # Compute AKS name/RG (inputs override secrets) | |
| - name: Compute AKS values | |
| id: compute_aks | |
| run: | | |
| NAME="${{ github.event.inputs.aks_cluster_name }}" | |
| RG="${{ github.event.inputs.aks_resource_group }}" | |
| if [ -z "$NAME" ]; then NAME="${{ secrets.AKS_NAME }}"; fi | |
| if [ -z "$RG" ]; then RG="${{ secrets.AKS_RG }}"; fi | |
| echo "name=$NAME" >> $GITHUB_OUTPUT | |
| echo "rg=$RG" >> $GITHUB_OUTPUT | |
| echo "AKS_NAME=$NAME" >> $GITHUB_ENV | |
| echo "AKS_RG=$RG" >> $GITHUB_ENV | |
| # Azure login | |
| - name: Azure Login | |
| uses: azure/login@v1 | |
| with: | |
| creds: ${{ secrets.AZURE_CREDENTIALS }} | |
| enable-AzPSSession: true | |
| - name: Set AKS context | |
| run: | | |
| az aks get-credentials \ | |
| --resource-group "$AKS_RG" \ | |
| --name "$AKS_NAME" \ | |
| --overwrite-existing | |
| - name: Attach ACR | |
| run: | | |
| az aks update \ | |
| --resource-group "$AKS_RG" \ | |
| --name "$AKS_NAME" \ | |
| --attach-acr "${{ secrets.AZURE_ACR_NAME }}" | |
| - name: Deploy Config & Databases | |
| working-directory: k8s | |
| run: | | |
| kubectl apply -f configmaps.yaml | |
| kubectl apply -f secrets.yaml | |
| kubectl apply -f product-db.yaml | |
| kubectl apply -f order-db.yaml | |
| - name: Deploy Services (apply manifests and pin images) | |
| env: | |
| REGISTRY_LOGIN_SERVER: ${{ secrets.AZURE_ACR_LOGIN_SERVER }} | |
| IMAGE_TAG: ${{ steps.compute_tag.outputs.val }} | |
| run: | | |
| kubectl apply -f k8s/product-service.yaml | |
| kubectl apply -f k8s/order-service.yaml | |
| kubectl set image deploy/product-service-w08e1 product-service-container="${REGISTRY_LOGIN_SERVER}/product_service:${IMAGE_TAG}" --record=true || true | |
| kubectl set image deploy/order-service-w08e1 order-service-container="${REGISTRY_LOGIN_SERVER}/order_service:${IMAGE_TAG}" --record=true || true | |
| echo "Waiting for product-service rollout..." | |
| kubectl rollout status deploy/product-service-w08e1 --timeout=180s || exit 1 | |
| echo "Waiting for order-service rollout..." | |
| kubectl rollout status deploy/order-service-w08e1 --timeout=180s || exit 1 | |
| - name: Capture LoadBalancer IPs | |
| id: capture | |
| run: | | |
| for i in {1..60}; do | |
| PRODUCT_IP=$(kubectl get svc product-service-w08e1 -o jsonpath='{.status.loadBalancer.ingress[0].ip}') | |
| ORDER_IP=$(kubectl get svc order-service-w08e1 -o jsonpath='{.status.loadBalancer.ingress[0].ip}') | |
| if [[ -n "$PRODUCT_IP" && -n "$ORDER_IP" ]]; then | |
| echo "product_ip=$PRODUCT_IP" >> $GITHUB_OUTPUT | |
| echo "order_ip=$ORDER_IP" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| sleep 5 | |
| done | |
| echo "Timed out waiting for IPs"; exit 1 | |
| deploy_frontend: | |
| needs: deploy_backend | |
| uses: ./.github/workflows/frontend-cd.yml | |
| with: | |
| product_api_ip: "http://${{ needs.deploy_backend.outputs.PRODUCT_API_IP }}:8000" | |
| order_api_ip: "http://${{ needs.deploy_backend.outputs.ORDER_API_IP }}:8001" | |
| aks_cluster_name: ${{ needs.deploy_backend.outputs.AKS_NAME }} | |
| aks_resource_group: ${{ needs.deploy_backend.outputs.AKS_RG }} | |
| image_tag: ${{ needs.deploy_backend.outputs.IMAGE_TAG }} | |
| secrets: inherit | |
| # update |