diff --git a/.github/workflows/03-staging-test.yml b/.github/workflows/03-staging-test.yml index 01daf5fa..91610044 100644 --- a/.github/workflows/03-staging-test.yml +++ b/.github/workflows/03-staging-test.yml @@ -1,4 +1,4 @@ -name: 03 - Test Staging +name: 03 - Test Staging and Deploy Production on: workflow_run: @@ -47,7 +47,6 @@ jobs: fi echo "Waiting for staging frontend IP..." - sleep 10 done @@ -60,4 +59,142 @@ jobs: --fail \ --retry 10 \ --retry-delay 5 \ - http://${{ env.FRONTEND_IP }} \ No newline at end of file + http://${{ env.FRONTEND_IP }} + + deploy-production: + name: Deploy to Production + needs: smoke-test + runs-on: ubuntu-latest + + environment: + name: production + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.workflow_run.head_sha }} + + - name: Login to Azure + uses: azure/login@v3 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Get AKS credentials + run: | + az aks get-credentials \ + --resource-group ${{ vars.AKS_RESOURCE_GROUP }} \ + --name ${{ vars.AKS_CLUSTER_NAME }} \ + --overwrite-existing + + - name: Create production namespace + run: | + kubectl create namespace production \ + --dry-run=client \ + -o yaml | kubectl apply -f - + + - name: Create PostgreSQL secret + run: | + kubectl create secret generic postgres-secret \ + --namespace production \ + --from-literal=POSTGRES_USER="${{ secrets.POSTGRES_USER }}" \ + --from-literal=POSTGRES_PASSWORD="${{ secrets.POSTGRES_PASSWORD }}" \ + --dry-run=client \ + -o yaml | kubectl apply -f - + + - name: Create application secret + run: | + kubectl create secret generic application-secret \ + --namespace production \ + --from-literal=POSTGRES_USER="${{ secrets.POSTGRES_USER }}" \ + --from-literal=POSTGRES_PASSWORD="${{ secrets.POSTGRES_PASSWORD }}" \ + --from-literal=JWT_SECRET_KEY="${{ secrets.JWT_SECRET_KEY }}" \ + --from-literal=DEFAULT_ADMIN_USERNAME="${{ secrets.DEFAULT_ADMIN_USERNAME }}" \ + --from-literal=DEFAULT_ADMIN_EMAIL="${{ secrets.DEFAULT_ADMIN_EMAIL }}" \ + --from-literal=DEFAULT_ADMIN_PASSWORD="${{ secrets.DEFAULT_ADMIN_PASSWORD }}" \ + --from-literal=AZURE_STORAGE_CONNECTION_STRING="${{ secrets.AZURE_STORAGE_CONNECTION_STRING }}" \ + --dry-run=client \ + -o yaml | kubectl apply -f - + + - name: Apply Kubernetes manifests + run: | + kubectl apply \ + -f kubernetes/production/ + + - name: Update frontend image + run: | + kubectl set image deployment/frontend \ + frontend=${{ vars.ACR_LOGIN_SERVER }}/koalatech-frontend:${{ github.event.workflow_run.head_sha }} \ + -n production + + - name: Update user-service image + run: | + kubectl set image deployment/user-service \ + user-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-user-service:${{ github.event.workflow_run.head_sha }} \ + -n production + + - name: Update student-service image + run: | + kubectl set image deployment/student-service \ + student-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-student-service:${{ github.event.workflow_run.head_sha }} \ + -n production + + - name: Update lecturer-service image + run: | + kubectl set image deployment/lecturer-service \ + lecturer-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-lecturer-service:${{ github.event.workflow_run.head_sha }} \ + -n production + + - name: Update course-service image + run: | + kubectl set image deployment/course-service \ + course-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-course-service:${{ github.event.workflow_run.head_sha }} \ + -n production + + - name: Update enrollment-service image + run: | + kubectl set image deployment/enrollment-service \ + enrollment-service=${{ vars.ACR_LOGIN_SERVER }}/koalatech-enrollment-service:${{ github.event.workflow_run.head_sha }} \ + -n production + + - name: Wait for frontend rollout + run: | + kubectl rollout status deployment/frontend \ + -n production \ + --timeout=300s + + - name: Wait for user-service rollout + run: | + kubectl rollout status deployment/user-service \ + -n production \ + --timeout=300s + + - name: Wait for student-service rollout + run: | + kubectl rollout status deployment/student-service \ + -n production \ + --timeout=300s + + - name: Wait for lecturer-service rollout + run: | + kubectl rollout status deployment/lecturer-service \ + -n production \ + --timeout=300s + + - name: Wait for course-service rollout + run: | + kubectl rollout status deployment/course-service \ + -n production \ + --timeout=300s + + - name: Wait for enrollment-service rollout + run: | + kubectl rollout status deployment/enrollment-service \ + -n production \ + --timeout=300s + + - name: Show production resources + run: | + kubectl get pods -n production + kubectl get services -n production + kubectl get pvc -n production \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4299cd1a..2001a367 100644 --- a/.gitignore +++ b/.gitignore @@ -196,4 +196,6 @@ cython_debug/ .cursorignore .cursorindexingignore -node_modules/ \ No newline at end of file +node_modules/ +# Local Week 08 Terraform working files +terraform/ diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx index c42604a5..3da4cfcd 100644 --- a/frontend/src/pages/Dashboard.jsx +++ b/frontend/src/pages/Dashboard.jsx @@ -199,7 +199,7 @@ const Dashboard = () => { - Welcome to KoalaTech University + Welcome to KoalaTech University - Continuous Deployment diff --git a/user-service/app/main.py b/user-service/app/main.py index 1b4769a6..0fe9f65a 100644 --- a/user-service/app/main.py +++ b/user-service/app/main.py @@ -1,3 +1,4 @@ +# Week 08 CI/CD pipeline trigger change import logging import os import time diff --git a/.github/workflows/04-deploy-production.yml b/week08-backup/04-deploy-production.yml similarity index 100% rename from .github/workflows/04-deploy-production.yml rename to week08-backup/04-deploy-production.yml