From dcd16121235c00bcba1bd0a3fb580eb5206bf1ff Mon Sep 17 00:00:00 2001 From: Cincaiplay Date: Thu, 2 Oct 2025 11:19:03 +1000 Subject: [PATCH 1/4] new update --- .github/workflows/backend-cd.yml | 130 +++++++++++++------------- .github/workflows/backend_ci.yml | 146 ------------------------------ .github/workflows/ci.yml | 141 +++++++++++++++++++++++++++++ .github/workflows/frontend-cd.yml | 98 ++++++++++++++------ .github/workflows/frontend_ci.yml | 53 ----------- 5 files changed, 273 insertions(+), 295 deletions(-) delete mode 100644 .github/workflows/backend_ci.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/frontend_ci.yml diff --git a/.github/workflows/backend-cd.yml b/.github/workflows/backend-cd.yml index 6035ed15..6f5f1f67 100644 --- a/.github/workflows/backend-cd.yml +++ b/.github/workflows/backend-cd.yml @@ -1,101 +1,99 @@ -name: CD - Deploy Backend Services to AKS +name: CD - Deploy Backend (then Frontend) on: workflow_dispatch: inputs: - aks_cluster_name: - description: 'Name of the AKS Cluster to deploy to' - required: true - default: '' - aks_resource_group: - description: 'Resource Group of the AKS Cluster' - required: true - default: '' - aks_acr_name: - description: 'Name of ACR' - required: true - default: '' + aks_cluster_name: { description: 'AKS name', required: true } + aks_resource_group: { description: 'RG name', required: true } + workflow_run: + workflows: ["CI - Test, Build & Push (Backend + Frontend)"] + types: [completed] + branches: [main] + +env: + REGISTRY_LOGIN_SERVER: ${{ secrets.AZURE_ACR_LOGIN_SERVER }} + IMAGE_TAG: ${{ github.event.workflow_run?.outputs.image_tag || github.sha }} + +permissions: + id-token: write + contents: read + +concurrency: + group: deploy-backend-prod + cancel-in-progress: false jobs: deploy_backend: + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' 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.outputs.product_ip }} + ORDER_API_IP: ${{ steps.capture.outputs.order_ip }} steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Log in to Azure - uses: azure/login@v1 + - name: Azure Login (OIDC) + uses: azure/login@v2 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} enable-AzPSSession: true - - name: Set Kubernetes context (get AKS credentials) + - name: Set AKS context run: | - az aks get-credentials --resource-group ${{ github.event.inputs.aks_resource_group }} --name ${{ github.event.inputs.aks_cluster_name }} --overwrite-existing + az aks get-credentials \ + --resource-group "${{ github.event.inputs.aks_resource_group || secrets.AKS_RG }}" \ + --name "${{ github.event.inputs.aks_cluster_name || secrets.AKS_NAME }}" \ + --overwrite-existing - name: Attach ACR 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 update \ + --resource-group "${{ github.event.inputs.aks_resource_group || secrets.AKS_RG }}" \ + --name "${{ github.event.inputs.aks_cluster_name || secrets.AKS_NAME }}" \ + --attach-acr "${{ secrets.AZURE_ACR_NAME }}" - - name: Deploy Backend Infrastructure (Namespace, ConfigMaps, Secrets, Databases) + - name: Deploy Config & Databases + working-directory: k8s 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) + - name: Deploy Services with pinned images + working-directory: k8s run: | - echo "Deploying backend microservices..." - cd k8s/ + # Patch images to the exact CI-built tag + kubectl set image deploy/product-service-w08e1 product-service-container="${{ env.REGISTRY_LOGIN_SERVER }}/product_service:${{ env.IMAGE_TAG }}" --record=true || true + kubectl set image deploy/order-service-w08e1 order-service-container="${{ env.REGISTRY_LOGIN_SERVER }}/order_service:${{ env.IMAGE_TAG }}" --record=true || true + # If first time apply: kubectl apply -f product-service.yaml kubectl apply -f order-service.yaml - - - name: Wait for Backend LoadBalancer IPs - 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}') + - name: Wait for 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 "All backend LoadBalancer IPs assigned!" - echo "Product Service IP: $PRODUCT_IP" - echo "Order Service IP: $ORDER_IP" - break + echo "product_ip=$PRODUCT_IP" >> $GITHUB_OUTPUT + echo "order_ip=$ORDER_IP" >> $GITHUB_OUTPUT + exit 0 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 - 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 + echo "Timed out waiting for IPs"; exit 1 - - name: Logout from Azure - run: az logout + 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: ${{ github.event.inputs.aks_cluster_name || secrets.AKS_NAME }} + aks_resource_group: ${{ github.event.inputs.aks_resource_group || secrets.AKS_RG }} diff --git a/.github/workflows/backend_ci.yml b/.github/workflows/backend_ci.yml deleted file mode 100644 index d69725aa..00000000 --- a/.github/workflows/backend_ci.yml +++ /dev/null @@ -1,146 +0,0 @@ -# week08/.github/workflows/backend_ci.yml - -name: Backend CI - Test, Build and Push Images to ACR - -# Trigger the workflow on pushes to the 'main' branch -# You can also add 'pull_request:' to run on PRs -on: - # Manual trigger - workflow_dispatch: - - # Automatically on pushes to main branch - push: - branches: - - main - paths: # Only trigger if changes are in backend directories - - 'backend/**' - - '.github/workflows/backend_ci.yml' # Trigger if this workflow file changes - -# Define global environment variables that can be used across jobs -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 }} - # 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 }} - -jobs: - # Job 1: Run tests and linting for all backend services - test_and_lint_backends: - runs-on: ubuntu-latest # Use a GitHub-hosted runner - - services: - # Product DB container - product_db: - image: postgres:15 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: products - # Make pg_isready available so the service is healthy before tests run - options: >- - --health-cmd "pg_isready -U postgres" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - # Order DB - order_db: - image: postgres:15 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: orders - ports: - - 5433:5432 - options: >- - --health-cmd "pg_isready -U postgres" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - # 1. Checkout the repository code to the runner - - name: Checkout repository - uses: actions/checkout@v4 # Action to check out your repository code - - # 2. Set up Python environment - - name: Set up Python 3.10 - uses: actions/setup-python@v5 # Action to set up Python environment - with: - python-version: '3.10' - - # 3. Install dependencies and run code quality checks - - name: Install dependencies - run: | # Use a multi-line script to install pip dependencies - pip install --upgrade pip - # Loop through each backend service folder - for req in backend/*/requirements.txt; do - echo "Installing $req" - pip install -r "$req" - done - # Install CI tools - pip install pytest httpx - - # 5. Run tests for product service - - name: Run product_service tests - working-directory: backend/product_service - env: - POSTGRES_HOST: localhost - POSTGRES_PORT: 5432 - POSTGRES_DB: products - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - run: | - pytest tests --maxfail=1 --disable-warnings -q - - # 6. Run tests for order service - - name: Run order_service tests - working-directory: backend/order_service - env: - POSTGRES_HOST: localhost - POSTGRES_PORT: 5433 - POSTGRES_DB: orders - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - run: | - pytest tests --maxfail=1 --disable-warnings -q - - # Job 2: Build and Push Docker Images (runs only if tests pass) - build_and_push_images: - runs-on: ubuntu-latest - needs: test_and_lint_backends - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Azure login using a Service Principal secret - - name: Azure Login - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} # Needs to be set as a GitHub Secret (Service Principal JSON) - - # Login to Azure Container Registry (ACR) - - name: Login to Azure Container Registry - run: az acr login --name ${{ env.ACR_LOGIN_SERVER }} - - # Build and Push Docker image for Product Service - - name: Build and Push Product Service Image - run: | - docker build -t ${{ env.ACR_LOGIN_SERVER }}/product_service:latest ./backend/product_service/ - docker push ${{ env.ACR_LOGIN_SERVER }}/product_service:latest - - # Build and Push Docker image for Order Service - - name: Build and Push Order Service Image - run: | - docker build -t ${{ env.ACR_LOGIN_SERVER }}/order_service:latest ./backend/order_service/ - docker push ${{ env.ACR_LOGIN_SERVER }}/order_service:latest - - # Logout from Azure for security (runs even if image push fails) - - name: Logout from Azure - run: az logout - if: always() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..8f893f06 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,141 @@ +name: CI - Test, Build & Push (Backend + Frontend) + +on: + workflow_dispatch: + pull_request: + branches: [development, main] + paths: + - 'backend/**' + - 'frontend/**' + - '.github/workflows/ci.yml' + push: + branches: [development, main] + paths: + - 'backend/**' + - 'frontend/**' + - '.github/workflows/ci.yml' + +env: + REGISTRY_NAME: ${{ secrets.AZURE_ACR_NAME }} # e.g. myregistry (NOT myregistry.azurecr.io) + REGISTRY_LOGIN_SERVER: ${{ secrets.AZURE_ACR_LOGIN_SERVER }} # e.g. myregistry.azurecr.io + IMAGE_TAG: ${{ github.sha }} + DOCKER_BUILDKIT: 1 + +permissions: + id-token: write # for OIDC + contents: read + packages: write + +jobs: + test_backends: + if: contains(github.event.head_commit.message, '[skip-ci]') == false + runs-on: ubuntu-latest + services: + product_db: + image: postgres:15 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: products + options: >- + --health-cmd "pg_isready -U postgres" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: ["5432:5432"] + order_db: + image: postgres:15 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: orders + options: >- + --health-cmd "pg_isready -U postgres" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: ["5433:5432"] + steps: + - uses: actions/checkout@v4 + + - name: Setup Python 3.10 (with pip cache) + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: 'pip' # built-in caching for requirements + - name: Install deps + run: | + pip install -U pip pytest httpx ruff + for req in backend/*/requirements.txt; do + echo "Installing $req" + pip install -r "$req" + done + - name: Lint (ruff) + run: ruff check backend/ + - name: Test product_service + working-directory: backend/product_service + env: + POSTGRES_HOST: localhost + POSTGRES_PORT: 5432 + POSTGRES_DB: products + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + run: pytest -q + - name: Test order_service + working-directory: backend/order_service + env: + POSTGRES_HOST: localhost + POSTGRES_PORT: 5433 + POSTGRES_DB: orders + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + run: pytest -q + + build_and_push: + needs: test_backends + runs-on: ubuntu-latest + # Only push images on pushes (not PRs) + if: github.event_name == 'push' + steps: + - uses: actions/checkout@v4 + + - name: Login to Azure via OIDC + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: ACR login (registry name, not FQDN) + run: az acr login --name ${{ env.REGISTRY_NAME }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build & push (matrix over apps) + uses: docker/build-push-action@v6 + with: + context: ${{ matrix.context }} + push: true + tags: | + ${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:latest + ${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:${{ env.IMAGE_TAG }} + cache-from: type=registry,ref=${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:buildcache,mode=max + strategy: + matrix: + include: + - name: product_service + context: ./backend/product_service + - name: order_service + context: ./backend/order_service + - name: frontend + context: ./frontend + + - name: Output image tags + id: out + run: | + echo "tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT + + outputs: + image_tag: ${{ steps.out.outputs.tag }} diff --git a/.github/workflows/frontend-cd.yml b/.github/workflows/frontend-cd.yml index 0a0879c8..16a54401 100644 --- a/.github/workflows/frontend-cd.yml +++ b/.github/workflows/frontend-cd.yml @@ -1,29 +1,28 @@ -# week08/.github/workflows/frontend-cd.yml - name: CD - Deploy Frontend to AKS -# This workflow can be called by other workflows and takes inputs. -# Or it can be run manually if you provide the IPs. on: workflow_dispatch: inputs: product_api_ip: - description: 'External IP of Product Service' + description: 'External URL of Product Service (e.g., http://X.X.X.X:8000)' required: true default: 'http://:8000' order_api_ip: - description: 'External IP of Order Service (e.g., http://Y.Y.Y.Y:8001)' + description: 'External URL of Order Service (e.g., http://Y.Y.Y.Y:8001)' required: true default: 'http://:8001' aks_cluster_name: - description: 'Name of the AKS Cluster to deploy to' + description: 'AKS cluster name' required: true default: '' aks_resource_group: - description: 'Resource Group of the AKS Cluster' + description: 'AKS resource group' required: true - default: '<' - + default: '' + image_tag: + description: 'Image tag to deploy (defaults to current commit SHA)' + required: false + default: '' workflow_call: inputs: product_api_ip: @@ -38,6 +37,32 @@ on: aks_resource_group: required: true type: string + image_tag: + required: false + type: string + +# Required secrets: +# - AZURE_CLIENT_ID +# - AZURE_TENANT_ID +# - AZURE_SUBSCRIPTION_ID +# - AZURE_ACR_NAME (e.g., myregistry) +# - AZURE_ACR_LOGIN_SERVER (e.g., myregistry.azurecr.io) + +permissions: + id-token: write + contents: read + packages: write + +env: + REGISTRY_NAME: ${{ secrets.AZURE_ACR_NAME }} + REGISTRY_LOGIN_SERVER: ${{ secrets.AZURE_ACR_LOGIN_SERVER }} + # default to the commit SHA when not provided via inputs + IMAGE_TAG: ${{ inputs.image_tag != '' && inputs.image_tag || github.sha }} + DOCKER_BUILDKIT: 1 + +concurrency: + group: deploy-frontend-prod + cancel-in-progress: false jobs: deploy_frontend: @@ -54,40 +79,53 @@ jobs: with: creds: ${{ secrets.AZURE_CREDENTIALS }} - # Login to Azure Container Registry (ACR) + # ACR login - name: Login to Azure Container Registry - run: az acr login --name ${{ secrets.AZURE_CONTAINER_REGISTRY }} + run: az acr login --name ${{ env.REGISTRY_NAME }} - - name: Inject Backend IPs into Frontend main.js + - name: Inject Backend IPs into frontend/main.js run: | - echo "Injecting IPs into frontend/static/js/main.js" - # Ensure frontend/main.js is directly in the path for sed + echo "Injecting API URLs into frontend/main.js..." sed -i "s|_PRODUCT_API_URL_|${{ inputs.product_api_ip }}|g" frontend/main.js sed -i "s|_ORDER_API_URL_|${{ inputs.order_api_ip }}|g" frontend/main.js - - # Display the modified file content for debugging - echo "--- Modified main.js content ---" - cat frontend/main.js + echo "--- Modified frontend/main.js ---" + sed -n '1,120p' frontend/main.js echo "---------------------------------" - # 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 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build & Push Frontend Image (tagged) + uses: docker/build-push-action@v6 + with: + context: ./frontend + push: true + tags: | + ${{ env.REGISTRY_LOGIN_SERVER }}/frontend:latest + ${{ env.REGISTRY_LOGIN_SERVER }}/frontend:${{ env.IMAGE_TAG }} + cache-from: type=registry,ref=${{ env.REGISTRY_LOGIN_SERVER }}/frontend:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY_LOGIN_SERVER }}/frontend:buildcache,mode=max - - name: Set Kubernetes context (get AKS credentials) + - name: Set AKS context uses: azure/aks-set-context@v3 with: resource-group: ${{ inputs.aks_resource_group }} cluster-name: ${{ inputs.aks_cluster_name }} - - name: Deploy Frontend to AKS + - name: Deploy Frontend to AKS (apply manifests) + working-directory: k8s run: | - echo "Deploying frontend with latest tag to AKS cluster: ${{ inputs.aks_cluster_name }}" - cd k8s/ - # Ensure frontend-service.yaml is configured with your ACR + # Ensure k8s/frontend.yaml references the correct Deployment and container names kubectl apply -f frontend.yaml - - name: Logout from Azure (AKS deployment) + - name: Pin Frontend image to built tag + run: | + # Adjust Deployment and container names if different in your YAML + # Example assumes: kind: Deployment, metadata.name: frontend-w08e1, container name: frontend-container + kubectl set image deployment/frontend-w08e1 frontend-container=${{ env.REGISTRY_LOGIN_SERVER }}/frontend:${{ env.IMAGE_TAG }} --record=true + echo "Waiting for rollout..." + kubectl rollout status deployment/frontend-w08e1 --timeout=180s + + - name: Logout from Azure + if: always() run: az logout diff --git a/.github/workflows/frontend_ci.yml b/.github/workflows/frontend_ci.yml deleted file mode 100644 index 9f9e76d9..00000000 --- a/.github/workflows/frontend_ci.yml +++ /dev/null @@ -1,53 +0,0 @@ -# week08/.github/workflows/frontend_ci.yml - -name: Frontend CI - Build & Push Image - -on: - # Manual trigger - workflow_dispatch: - - # Automatically on pushes to main branch - push: - branches: - - main - paths: # Only trigger if changes are in the frontend directory - - 'frontend/**' - - '.github/workflows/frontend_ci.yml' # Trigger if this workflow file changes - -# Define global environment variables that can be used across jobs -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 }} - # 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 }} - -jobs: - build_and_push_frontend: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Azure login using a Service Principal secret - - name: Azure Login - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - # Login to Azure Container Registry (ACR) - - name: Login to Azure Container Registry - run: az acr login --name ${{ env.ACR_LOGIN_SERVER }} - - # Build and Push Docker image for Frontend - - name: Build and Push Frontend Image - run: | - docker build -t ${{ env.ACR_LOGIN_SERVER }}/frontend:latest ./frontend/ - docker push ${{ env.ACR_LOGIN_SERVER }}/frontend:latest - - # Logout from Azure for security (runs even if image push fails) - - name: Logout from Azure - run: az logout - if: always() From b7df7ed27ae5150fdcb147941b141c0cbb01faac Mon Sep 17 00:00:00 2001 From: Cincaiplay Date: Fri, 3 Oct 2025 18:12:45 +1000 Subject: [PATCH 2/4] new update --- .github/workflows/ci.yml | 55 ++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f893f06..6a6c9ae8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,19 +16,18 @@ on: - '.github/workflows/ci.yml' env: - REGISTRY_NAME: ${{ secrets.AZURE_ACR_NAME }} # e.g. myregistry (NOT myregistry.azurecr.io) + REGISTRY_NAME: ${{ secrets.AZURE_ACR_NAME }} # e.g. myregistry REGISTRY_LOGIN_SERVER: ${{ secrets.AZURE_ACR_LOGIN_SERVER }} # e.g. myregistry.azurecr.io IMAGE_TAG: ${{ github.sha }} DOCKER_BUILDKIT: 1 permissions: - id-token: write # for OIDC + id-token: write contents: read packages: write jobs: test_backends: - if: contains(github.event.head_commit.message, '[skip-ci]') == false runs-on: ubuntu-latest services: product_db: @@ -62,7 +61,8 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.10' - cache: 'pip' # built-in caching for requirements + cache: 'pip' + - name: Install deps run: | pip install -U pip pytest httpx ruff @@ -70,8 +70,10 @@ jobs: echo "Installing $req" pip install -r "$req" done + - name: Lint (ruff) run: ruff check backend/ + - name: Test product_service working-directory: backend/product_service env: @@ -81,6 +83,7 @@ jobs: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres run: pytest -q + - name: Test order_service working-directory: backend/order_service env: @@ -94,25 +97,34 @@ jobs: build_and_push: needs: test_backends runs-on: ubuntu-latest - # Only push images on pushes (not PRs) - if: github.event_name == 'push' + if: github.event_name == 'push' # don’t push images on PRs + strategy: + fail-fast: false + matrix: + include: + - name: product_service + context: ./backend/product_service + - name: order_service + context: ./backend/order_service + - name: frontend + context: ./frontend + steps: - uses: actions/checkout@v4 - - name: Login to Azure via OIDC - uses: azure/login@v2 + # Azure login using a Service Principal secret + - name: Azure Login + uses: azure/login@v1 with: - client-id: ${{ secrets.AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + creds: ${{ secrets.AZURE_CREDENTIALS }} # Needs to be set as a GitHub Secret (Service Principal JSON) - - name: ACR login (registry name, not FQDN) + - name: ACR login (use registry NAME with --name) run: az acr login --name ${{ env.REGISTRY_NAME }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Build & push (matrix over apps) + - name: Build & push ${{ matrix.name }} uses: docker/build-push-action@v6 with: context: ${{ matrix.context }} @@ -122,20 +134,3 @@ jobs: ${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:${{ env.IMAGE_TAG }} cache-from: type=registry,ref=${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:buildcache cache-to: type=registry,ref=${{ env.REGISTRY_LOGIN_SERVER }}/${{ matrix.name }}:buildcache,mode=max - strategy: - matrix: - include: - - name: product_service - context: ./backend/product_service - - name: order_service - context: ./backend/order_service - - name: frontend - context: ./frontend - - - name: Output image tags - id: out - run: | - echo "tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT - - outputs: - image_tag: ${{ steps.out.outputs.tag }} From 351d67963dc6fa999d76cd122dac19bb0220b0b9 Mon Sep 17 00:00:00 2001 From: Cincaiplay Date: Fri, 3 Oct 2025 18:16:54 +1000 Subject: [PATCH 3/4] new update --- .github/workflows/ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a6c9ae8..6596dc3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,15 +65,12 @@ jobs: - name: Install deps run: | - pip install -U pip pytest httpx ruff + pip install -U pip pytest httpx for req in backend/*/requirements.txt; do echo "Installing $req" pip install -r "$req" done - - name: Lint (ruff) - run: ruff check backend/ - - name: Test product_service working-directory: backend/product_service env: From b2211fa03eeb60c39473b9e67b1bd8d14db035e6 Mon Sep 17 00:00:00 2001 From: Cincaiplay Date: Fri, 3 Oct 2025 18:33:25 +1000 Subject: [PATCH 4/4] update --- docker-compose.yml | 4 ++-- k8s/frontend.yaml | 2 +- k8s/order-service.yaml | 2 +- k8s/product-service.yaml | 2 +- k8s/secrets.yaml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1b255409..95842905 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,8 +53,8 @@ services: - "8000:8000" environment: POSTGRES_HOST: product_db # Connects to the 'product_db' service within Docker network - AZURE_STORAGE_ACCOUNT_NAME: cyweek08storage # Replace with your Azure Storage account name - AZURE_STORAGE_ACCOUNT_KEY: 3riV5/osgjy9btAzeQVo7UG0dmNZ2pgFjsozBnIqvYSkqkOglxTjtWffZ0pEd1P1tXFAOSKx6Z3/+AStsyuOKQ== # Replace with your Azure Storage account key + AZURE_STORAGE_ACCOUNT_NAME: cyweek09storage # Replace with your Azure Storage account name + AZURE_STORAGE_ACCOUNT_KEY: UA4lJKlDxxoawtB3W2mzSLc822nuENr4zjTtpTlytaxM6b3d8UtitQpPg8P3s9Ach2WENF+cQhbV+AStZ0Q6aw== # Replace with your Azure Storage account key AZURE_STORAGE_CONTAINER_NAME: product-images # Replace with your Azure Storage container name AZURE_SAS_TOKEN_EXPIRY_HOURS: 24 depends_on: diff --git a/k8s/frontend.yaml b/k8s/frontend.yaml index 177b6e48..983d9d3a 100644 --- a/k8s/frontend.yaml +++ b/k8s/frontend.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: frontend-container - image: cheeyuweek08.azurecr.io/frontend:latest + image: cyweek09acr.azurecr.io/frontend:351d67963dc6fa999d76cd122dac19bb0220b0b9 imagePullPolicy: Always ports: - containerPort: 80 diff --git a/k8s/order-service.yaml b/k8s/order-service.yaml index 016d90ac..04441e06 100644 --- a/k8s/order-service.yaml +++ b/k8s/order-service.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: order-service-container - image: cheeyuweek08.azurecr.io/order_service:latest + image: cyweek09acr.azurecr.io/order_service:351d67963dc6fa999d76cd122dac19bb0220b0b9 imagePullPolicy: Always ports: - containerPort: 8000 diff --git a/k8s/product-service.yaml b/k8s/product-service.yaml index 573e37d9..0a938a1c 100644 --- a/k8s/product-service.yaml +++ b/k8s/product-service.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: product-service-container - image: cheeyuweek08.azurecr.io/product_service:latest + image: cyweek09acr.azurecr.io/product_service:351d67963dc6fa999d76cd122dac19bb0220b0b9 imagePullPolicy: Always ports: - containerPort: 8000 diff --git a/k8s/secrets.yaml b/k8s/secrets.yaml index 8674fc86..ed2cf581 100644 --- a/k8s/secrets.yaml +++ b/k8s/secrets.yaml @@ -13,6 +13,6 @@ data: # Azure Storage Account Credentials for Product Service image uploads # REPLACE WITH YOUR ACTUAL BASE64 ENCODED VALUES from your Azure Storage Account # Example: echo -n 'myblobstorageaccount' | base64 - AZURE_STORAGE_ACCOUNT_NAME: "Y3l3ZWVrMDhzdG9yYWdl" + AZURE_STORAGE_ACCOUNT_NAME: "Y3l3ZWVrMDlzdG9yYWdl" # Example: echo -n 'your_storage_account_key_string' | base64 - AZURE_STORAGE_ACCOUNT_KEY: "M3JpVjUvb3Nnank5YnRBemVRVm83VUcwZG1OWjJwZ0Zqc296Qm5JcXZZU2txa09nbHhUanRXZmZaMHBFZDFQMXRYRkFPU0t4NlozLytBU3RzeXVPS1E9PQ==" + AZURE_STORAGE_ACCOUNT_KEY: "VUE0bEpLbER4eG9hd3RCM1cybXpTTGM4MjJudUVOcjR6alR0cFRseXRheE02YjNkOFV0aXRRcFBnOFAzczlBY2gyV0VORitjUWhiVitBU3RaMFE2YXc9PQ=="