Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
165 changes: 85 additions & 80 deletions .github/workflows/backend-cd.yml
Original file line number Diff line number Diff line change
@@ -1,101 +1,106 @@
name: CD - Deploy Backend Services to AKS
name: CD - Deploy Backend Services to AKS

on:
workflow_dispatch:
inputs:
aks_cluster_name:
description: 'Name of the AKS Cluster to deploy to'
description: Name of the AKS Cluster
required: true
default: '<aks_cluster_name>'
aks_resource_group:
description: 'Resource Group of the AKS Cluster'
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>'

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 }}

runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/checkout@v4

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

- name: Set Kubernetes context (get AKS credentials)
- name: Azure CLI login (service principal)
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
run: |
az aks get-credentials --resource-group ${{ github.event.inputs.aks_resource_group }} --name ${{ github.event.inputs.aks_cluster_name }} --overwrite-existing
set -euxo pipefail
az cloud set -n azurecloud
az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID"
az account set --subscription "$AZURE_SUBSCRIPTION_ID"

- name: Attach ACR
- name: Set Kubernetes context (get AKS credentials)
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 }}
az aks get-credentials \
--resource-group ${{ github.event.inputs.aks_resource_group }} \
--name ${{ github.event.inputs.aks_cluster_name }} \
--overwrite-existing

- name: Deploy Backend Infrastructure (Namespace, ConfigMaps, Secrets, Databases)
- name: Ensure namespace and image pull secret
env:
REGISTRY_LOGIN_SERVER: ${{ secrets.REGISTRY_LOGIN_SERVER }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
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
set -euxo pipefail
kubectl create namespace sit722-w08 --dry-run=client -o yaml | kubectl apply -f -
kubectl create secret docker-registry acr-pull \
--docker-server="$REGISTRY_LOGIN_SERVER" \
--docker-username="$REGISTRY_USERNAME" \
--docker-password="$REGISTRY_PASSWORD" \
-n sit722-w08 --dry-run=client -o yaml | kubectl apply -f -
kubectl patch sa default -n sit722-w08 --type merge -p '{"imagePullSecrets":[{"name":"acr-pull"}]}' || true

- name: Deploy Backend Microservices (Product, Order)
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
- name: Deploy backend services (product & order)
env:
REGISTRY_LOGIN_SERVER: ${{ secrets.REGISTRY_LOGIN_SERVER }}
run: |
echo "Waiting for Product, Order LoadBalancer IPs to be assigned (up to 5 minutes)..."
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!"
echo "Product Service IP: $PRODUCT_IP"
echo "Order Service IP: $ORDER_IP"
break
fi
sleep 5 # Wait 5 seconds before next attempt
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
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_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
cat <<'YAML' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata: { name: product-service, namespace: sit722-w08 }
spec:
replicas: 1
selector: { matchLabels: { app: product } }
template:
metadata: { labels: { app: product } }
spec:
containers:
- name: product
image: ${REGISTRY_LOGIN_SERVER}/product_service:latest
imagePullPolicy: Always
ports: [{ containerPort: 8000 }]
---
apiVersion: v1
kind: Service
metadata: { name: product-svc, namespace: sit722-w08 }
spec:
type: LoadBalancer
selector: { app: product }
ports: [{ port: 8000, targetPort: 8000 }]
---
apiVersion: apps/v1
kind: Deployment
metadata: { name: order-service, namespace: sit722-w08 }
spec:
replicas: 1
selector: { matchLabels: { app: order } }
template:
metadata: { labels: { app: order } }
spec:
containers:
- name: order
image: ${REGISTRY_LOGIN_SERVER}/order_service:latest
imagePullPolicy: Always
ports: [{ containerPort: 8002 }]
---
apiVersion: v1
kind: Service
metadata: { name: order-svc, namespace: sit722-w08 }
spec:
type: LoadBalancer
selector: { app: order }
ports: [{ port: 8002, targetPort: 8002 }]
YAML

- name: Logout from Azure
run: az logout
- name: Verify rollout
run: kubectl get deploy,svc -n sit722-w08 -o wide
6 changes: 3 additions & 3 deletions .github/workflows/backend_ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# week08/.github/workflows/backend_ci.yml
# week08/.github/workflows/backend_ci.yml

name: Backend CI - Test, Build and Push Images to ACR

Expand All @@ -20,7 +20,7 @@ on:
env:
# ACR Login Server (e.g., myregistry.azurecr.io)
# This needs to be set as a GitHub Repository Secret
ACR_LOGIN_SERVER: ${{ secrets.AZURE_CONTAINER_REGISTRY }}
ACR_LOGIN_SERVER: ${{ secrets.REGISTRY_LOGIN_SERVER }}
# Dynamically generate image tags based on Git SHA and GitHub Run ID
# This provides unique, traceable tags for each image build
IMAGE_TAG: ${{ github.sha }}-${{ github.run_id }}
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:

# Login to Azure Container Registry (ACR)
- name: Login to Azure Container Registry
run: az acr login --name ${{ env.ACR_LOGIN_SERVER }}
run: az acr login --name ${{ secrets.AZURE_CONTAINER_REGISTRY }}

# Build and Push Docker image for Product Service
- name: Build and Push Product Service Image
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/frontend-cd.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# week08/.github/workflows/frontend-cd.yml
# week08/.github/workflows/frontend-cd.yml

name: CD - Deploy Frontend to AKS

Expand Down Expand Up @@ -73,8 +73,8 @@ jobs:
# Build and Push Docker image for Frontend
- name: Build and Push Frontend Image
run: |
docker build -t ${{ secrets.AZURE_CONTAINER_REGISTRY }}/frontend:latest ./frontend/
docker push ${{ secrets.AZURE_CONTAINER_REGISTRY }}/frontend:latest
docker build -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/frontend:latest ./frontend/
docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/frontend:latest

- name: Set Kubernetes context (get AKS credentials)
uses: azure/aks-set-context@v3
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/frontend_ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# week08/.github/workflows/frontend_ci.yml
# week08/.github/workflows/frontend_ci.yml

name: Frontend CI - Build & Push Image

Expand All @@ -18,7 +18,7 @@ on:
env:
# ACR Login Server (e.g., myregistry.azurecr.io)
# This needs to be set as a GitHub Repository Secret
ACR_LOGIN_SERVER: ${{ secrets.AZURE_CONTAINER_REGISTRY }}
ACR_LOGIN_SERVER: ${{ secrets.REGISTRY_LOGIN_SERVER }}
# Dynamically generate image tags based on Git SHA and GitHub Run ID
# This provides unique, traceable tags for each image build
IMAGE_TAG: ${{ github.sha }}-${{ github.run_id }}
Expand All @@ -39,7 +39,7 @@ jobs:

# Login to Azure Container Registry (ACR)
- name: Login to Azure Container Registry
run: az acr login --name ${{ env.ACR_LOGIN_SERVER }}
run: az acr login --name ${{ secrets.AZURE_CONTAINER_REGISTRY }}

# Build and Push Docker image for Frontend
- name: Build and Push Frontend Image
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ image: <YOUR_ACR_NAME>.azurecr.io/<image_name>:<image_tag>
### 2. Update Backend Pipeline (`.github/workflows/backend-cd.yml`) & Frontend Pipeline (`.github/workflows/frontend-cd.yml`)

Ensure you replace all placeholders value to actual values.
trigger backend ci/cd
10 changes: 7 additions & 3 deletions frontend/main.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// week08/frontend/main.js
// week08/frontend/main.js

document.addEventListener('DOMContentLoaded', () => {
// API endpoints for the Product and Order services.
// These ports (30000 for Product, 30001 for Order) are mapped
// from the Docker containers to the host machine in docker-compose.yml for Example 2.
const PRODUCT_API_BASE_URL = '_PRODUCT_API_URL_';
const ORDER_API_BASE_URL = '_ORDER_API_URL_';
const PRODUCT_API_BASE_URL = 'http://4.198.148.230:8000';
const ORDER_API_BASE_URL = 'http://20.11.234.69:8002';

// Product Service is named 'product-service-w04e2' and exposes port 8000 internally.
//const PRODUCT_API_BASE_URL = 'http://product-service-w04e2:8000';
Expand Down Expand Up @@ -426,3 +426,7 @@ document.addEventListener('DOMContentLoaded', () => {
fetchProducts();
fetchOrders();
});