Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
aec5cb8
Update backend_ci.yml
himanshudhaka17 Sep 19, 2025
b63ec07
fix(ci): ACR login + dual tags; tests preserved
himanshudhaka17 Sep 19, 2025
1fb6720
chore: ignore azure_creds.json
himanshudhaka17 Sep 19, 2025
d395536
Update backend-cd.yml
himanshudhaka17 Sep 20, 2025
e6bc220
Update backend-cd.yml
himanshudhaka17 Sep 20, 2025
0887c11
frontend: point API to AKS backends
himanshudhaka17 Sep 20, 2025
ca42364
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
c18a4ee
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
e841c33
Update frontend_ci.yml
himanshudhaka17 Sep 20, 2025
1540699
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
498a71b
Update frontend.yaml
himanshudhaka17 Sep 20, 2025
c93a359
Update frontend.yaml
himanshudhaka17 Sep 20, 2025
1886b3f
Update frontend.yaml
himanshudhaka17 Sep 20, 2025
65020a2
frontend: use in-cluster service URLs (ClusterIP)
himanshudhaka17 Sep 20, 2025
9c47c68
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
d04c512
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
7b9c803
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
6a0a761
frontend: point API to backend public LB IPs
himanshudhaka17 Sep 20, 2025
d3929ff
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
33f3f6a
Update frontend-cd.yml
himanshudhaka17 Sep 20, 2025
1fe6ab6
Update frontend_ci.yml
himanshudhaka17 Sep 20, 2025
e2a06d6
Update config.js
himanshudhaka17 Sep 20, 2025
9b8aab3
Update frontend_ci.yml
himanshudhaka17 Sep 20, 2025
294ba18
fix: resolve merge conflict in frontend/src/config.js (keep remote)
himanshudhaka17 Oct 1, 2025
88ef428
test: trigger PR CI
himanshudhaka17 Oct 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ci-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ci test Wed 1 Oct 2025 23:20:42 AEST
260 changes: 193 additions & 67 deletions .github/workflows/backend-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,99 +3,225 @@ name: CD - Deploy Backend Services to AKS
on:
workflow_dispatch:
inputs:
aks_cluster_name:
description: 'Name of the AKS Cluster to deploy to'
required: true
default: '<aks_cluster_name>'
aks_resource_group:
description: 'Resource Group of the AKS Cluster'
required: true
default: '<resource_group_name>'
aks_acr_name:
description: 'Name of ACR'
required: true
default: '<acr_name>'
image_tag:
description: "Image tag to deploy (default: latest)"
required: false
default: "latest"

env:
# leave empty to use the default namespace
NAMESPACE: ""

jobs:
deploy_backend:
runs-on: ubuntu-latest
environment: Production

outputs:
PRODUCT_API_IP: ${{ steps.get_product_ip.outputs.external_ip }}
ORDER_API_IP: ${{ steps.get_order_ip.outputs.external_ip }}
PRODUCT_API_IP: ${{ steps.capture_ips.outputs.product_ip }}
ORDER_API_IP: ${{ steps.capture_ips.outputs.order_ip }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to Azure
uses: azure/login@v1
- name: Azure login
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
enable-AzPSSession: true

- name: Set Kubernetes context (get AKS credentials)
- name: Derive ACR + tag
run: |
echo "ACR_LOGIN_SERVER=${{ secrets.ACR_LOGIN_SERVER }}" >> $GITHUB_ENV
echo "ACR_NAME=$(echo '${{ secrets.ACR_LOGIN_SERVER }}' | cut -d. -f1)" >> $GITHUB_ENV
echo "TAG=${{ github.event.inputs.image_tag || 'latest' }}" >> $GITHUB_ENV

- name: Set AKS context
uses: azure/aks-set-context@v4
with:
resource-group: ${{ secrets.AKS_RG }}
cluster-name: ${{ secrets.AKS_CLUSTER }}

# harmless if already attached; won't fail the job
- name: Attach ACR permissions (best effort)
run: |
az aks update -n "${{ secrets.AKS_CLUSTER }}" -g "${{ secrets.AKS_RG }}" --attach-acr "$ACR_NAME" || true

- name: Ensure namespace (optional)
if: env.NAMESPACE != ''
run: |
kubectl get ns "$NAMESPACE" || kubectl create ns "$NAMESPACE"

# --- Ensure Postgres backends exist (creates or updates) ---
- name: Ensure product-db
run: |
az aks get-credentials --resource-group ${{ github.event.inputs.aks_resource_group }} --name ${{ github.event.inputs.aks_cluster_name }} --overwrite-existing
kubectl ${NAMESPACE:+-n $NAMESPACE} apply -f - <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata: { name: product-db }
spec:
replicas: 1
selector: { matchLabels: { app: product-db } }
template:
metadata: { labels: { app: product-db } }
spec:
containers:
- name: postgres
image: postgres:15
env:
- { name: POSTGRES_PASSWORD, value: "postgres" }
- { name: POSTGRES_DB, value: "products" }
ports: [ { containerPort: 5432 } ]
---
apiVersion: v1
kind: Service
metadata: { name: product-db }
spec:
selector: { app: product-db }
ports: [ { port: 5432, targetPort: 5432 } ]
YAML

- name: Attach ACR
- name: Ensure order-db
run: |
az aks update --name ${{ github.event.inputs.aks_cluster_name }} --resource-group ${{ github.event.inputs.aks_resource_group }} --attach-acr ${{ github.event.inputs.aks_acr_name }}
kubectl ${NAMESPACE:+-n $NAMESPACE} apply -f - <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata: { name: order-db }
spec:
replicas: 1
selector: { matchLabels: { app: order-db } }
template:
metadata: { labels: { app: order-db } }
spec:
containers:
- name: postgres
image: postgres:15
env:
- { name: POSTGRES_PASSWORD, value: "postgres" }
- { name: POSTGRES_DB, value: "orders" }
ports: [ { containerPort: 5432 } ]
---
apiVersion: v1
kind: Service
metadata: { name: order-db }
spec:
selector: { app: order-db }
ports: [ { port: 5432, targetPort: 5432 } ]
YAML

- name: Deploy Backend Infrastructure (Namespace, ConfigMaps, Secrets, Databases)
# --- Ensure product-service + order-service exist (creates or updates) ---
- name: Ensure product-service deployment & service
run: |
echo "Deploying backend infrastructure..."
cd k8s/
kubectl apply -f configmaps.yaml
kubectl apply -f secrets.yaml
kubectl apply -f product-db.yaml
kubectl apply -f order-db.yaml

- name: Deploy Backend Microservices (Product, Order)
kubectl ${NAMESPACE:+-n $NAMESPACE} apply -f - <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata: { name: product-service }
spec:
replicas: 1
selector: { matchLabels: { app: product-service } }
template:
metadata: { labels: { app: product-service } }
spec:
containers:
- name: product-service
image: replace-later
imagePullPolicy: Always
env:
- { name: POSTGRES_HOST, value: "product-db" }
- { name: POSTGRES_PORT, value: "5432" }
- { name: POSTGRES_DB, value: "products" }
- { name: POSTGRES_USER, value: "postgres" }
- { name: POSTGRES_PASSWORD, value: "postgres" }
ports: [ { containerPort: 3000 } ]
readinessProbe: { httpGet: { path: /health, port: 3000 }, initialDelaySeconds: 5, periodSeconds: 10 }
livenessProbe: { httpGet: { path: /health, port: 3000 }, initialDelaySeconds: 10, periodSeconds: 20 }
---
apiVersion: v1
kind: Service
metadata: { name: product-service }
spec:
type: LoadBalancer
selector: { app: product-service }
ports: [ { port: 80, targetPort: 3000 } ]
YAML

- name: Ensure order-service deployment & service
run: |
kubectl ${NAMESPACE:+-n $NAMESPACE} apply -f - <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata: { name: order-service }
spec:
replicas: 1
selector: { matchLabels: { app: order-service } }
template:
metadata: { labels: { app: order-service } }
spec:
containers:
- name: order-service
image: replace-later
imagePullPolicy: Always
env:
- { name: POSTGRES_HOST, value: "order-db" }
- { name: POSTGRES_PORT, value: "5432" }
- { name: POSTGRES_DB, value: "orders" }
- { name: POSTGRES_USER, value: "postgres" }
- { name: POSTGRES_PASSWORD, value: "postgres" }
ports: [ { containerPort: 3001 } ]
readinessProbe: { httpGet: { path: /health, port: 3001 }, initialDelaySeconds: 5, periodSeconds: 10 }
livenessProbe: { httpGet: { path: /health, port: 3001 }, initialDelaySeconds: 10, periodSeconds: 20 }
---
apiVersion: v1
kind: Service
metadata: { name: order-service }
spec:
type: LoadBalancer
selector: { app: order-service }
ports: [ { port: 80, targetPort: 3001 } ]
YAML

- name: Set images to ACR tag and rollout
run: |
echo "Deploying backend microservices..."
cd k8s/
kubectl apply -f product-service.yaml
kubectl apply -f order-service.yaml

- name: Wait for Backend LoadBalancer IPs
ns_flag=""
[ -n "$NAMESPACE" ] && ns_flag="-n $NAMESPACE"
PRODUCT_IMG="${ACR_LOGIN_SERVER}/product_service:${TAG}"
ORDER_IMG="${ACR_LOGIN_SERVER}/order_service:${TAG}"

kubectl $ns_flag set image deploy/product-service product-service="$PRODUCT_IMG" --record || true
kubectl $ns_flag set image deploy/order-service order-service="$ORDER_IMG" --record || true

kubectl $ns_flag rollout status deploy/product-service --timeout=240s || true
kubectl $ns_flag rollout status deploy/order-service --timeout=240s || true

- name: Wait for LoadBalancer IPs (up to 6 minutes)
id: capture_ips
run: |
echo "Waiting for Product, Order LoadBalancer IPs to be assigned (up to 5 minutes)..."
ns_flag=""
[ -n "$NAMESPACE" ] && ns_flag="-n $NAMESPACE"

PRODUCT_IP=""
ORDER_IP=""

for i in $(seq 1 60); do
echo "Attempt $i/60 to get IPs..."
PRODUCT_IP=$(kubectl get service product-service-w08e1 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
ORDER_IP=$(kubectl get service order-service-w08e1 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

if [[ -n "$PRODUCT_IP" && -n "$ORDER_IP" ]]; then
echo "All backend LoadBalancer IPs assigned!"
for i in $(seq 1 72); do
echo "Attempt $i/72 to get external IPs ..."
PRODUCT_IP=$(kubectl $ns_flag get svc product-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || true)
ORDER_IP=$(kubectl $ns_flag get svc order-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || true)
if [ -n "$PRODUCT_IP" ] && [ -n "$ORDER_IP" ]; then
echo "Product Service IP: $PRODUCT_IP"
echo "Order Service IP: $ORDER_IP"
echo "Order Service IP: $ORDER_IP"
break
fi
sleep 5 # Wait 5 seconds before next attempt
sleep 5
done
if [[ -z "$PRODUCT_IP" || -z "$ORDER_IP" ]]; then
echo "Error: One or more LoadBalancer IPs not assigned after timeout."
exit 1 # Fail the job if IPs are not obtained

if [ -z "$PRODUCT_IP" ] || [ -z "$ORDER_IP" ]; then
echo "::error::One or more LoadBalancer IPs not assigned after timeout."
exit 1
fi
# These are environment variables for subsequent steps in the *same job*
# And used to set the job outputs

echo "product_ip=$PRODUCT_IP" >> $GITHUB_OUTPUT
echo "order_ip=$ORDER_IP" >> $GITHUB_OUTPUT
echo "PRODUCT_IP=$PRODUCT_IP" >> $GITHUB_ENV
echo "ORDER_IP=$ORDER_IP" >> $GITHUB_ENV

- name: Capture Product Service IP for Workflow Output
id: get_product_ip
run: echo "external_ip=${{ env.PRODUCT_IP }}" >> $GITHUB_OUTPUT

- name: Capture Order Service IP for Workflow Output
id: get_order_ip
run: echo "external_ip=${{ env.ORDER_IP }}" >> $GITHUB_OUTPUT

- name: Logout from Azure
run: az logout
echo "ORDER_IP=$ORDER_IP" >> $GITHUB_ENV

- name: Show services
run: kubectl ${NAMESPACE:+-n $NAMESPACE} get svc -o wide
Loading