From 4d4131e7a7d96669c783d01ea11fb8c34db44bd3 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 18:39:46 +0300 Subject: [PATCH 01/16] fix: Add PostgreSQL service to the test job --- .github/workflows/ci-cd.yml | 27 ++++++++++++++++++--------- entrypoint.sh | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 1ec9e50..de994c1 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -15,6 +15,21 @@ jobs: name: Run Django Tests runs-on: ubuntu-latest + services: + postgres: + image: postgres:14 + env: + POSTGRES_DB: ${{ secrets.DB_NAME }} + POSTGRES_USER: ${{ secrets.DB_USER }} + POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }} + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - name: Checkout Repository uses: actions/checkout@v3 @@ -41,18 +56,12 @@ jobs: DB_NAME: ${{ secrets.DB_NAME }} DB_USER: ${{ secrets.DB_USER }} DB_PASSWORD: ${{ secrets.DB_PASSWORD }} - DB_HOST: ${{ secrets.DB_HOST }} - DB_PORT: ${{ secrets.DB_PORT }} + DB_HOST: "localhost" + DB_PORT: "5432" SECRET_KEY: ${{ secrets.SECRET_KEY }} run: | source venv/bin/activate - # Debug: Check if variables are set (without exposing values) - echo "Checking database configuration..." - [ -z "$DB_NAME" ] && echo "DB_NAME is not set" || echo "DB_NAME is set" - [ -z "$DB_USER" ] && echo "DB_USER is not set" || echo "DB_USER is set" - [ -z "$DB_HOST" ] && echo "DB_HOST is not set" || echo "DB_HOST is set" - [ -z "$DB_PORT" ] && echo "DB_PORT is not set" || echo "DB_PORT is set" - pytest -v + pytest -v build-and-push: name: Build and Push Docker Image diff --git a/entrypoint.sh b/entrypoint.sh index 4448ab9..203baca 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/sh echo "Waiting for database to be ready..." -while ! nc -z "$DATABASE_HOST" "$DATABASE_PORT"; do +while ! nc -z "$DB_HOST" "$DB_PORT"; do sleep 2 done From 44850c876a764e0bb0746263e36e13e37c3e2594 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 20:17:43 +0300 Subject: [PATCH 02/16] fix: update ci-cd pipeline to fix deployment errors --- .github/workflows/ci-cd.yml | 63 ++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index de994c1..adc534a 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -83,39 +83,60 @@ jobs: docker push ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest deploy: - name: Deploy to Kubernetes + name: Deploy to Minikube runs-on: ubuntu-latest - needs: build-and-push + needs: test steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Set Up Kubectl - uses: azure/setup-kubectl@v3 + - name: Start Minikube + uses: medyagh/setup-minikube@latest with: - version: 'latest' + minikube-version: v1.35.0 + kubernetes-version: v1.32.0 + + - name: Wait for Minikube to be ready + run: | + minikube status + kubectl cluster-info + + - name: Create Kubernetes Secrets + run: | + kubectl create secret generic django-secrets \ + --from-literal=DB_NAME=${{ secrets.DB_NAME }} \ + --from-literal=DB_USER=${{ secrets.DB_USER }} \ + --from-literal=DB_PASSWORD=${{ secrets.DB_PASSWORD }} \ + --from-literal=DB_HOST=postgres-service \ + --from-literal=DB_PORT=5432 \ + --from-literal=SECRET_KEY=${{ secrets.SECRET_KEY }} - - name: Validate KUBECONFIG Secret + - name: Log in to Docker Hub + run: | + docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} + + - name: Deploy Postgres to Minikube run: | - if [ -z "${{ secrets.KUBECONFIG }}" ]; then - echo "Error: KUBECONFIG secret is missing!" - exit 1 - fi + kubectl apply -f k8s/postgres.yaml --validate=false + kubectl rollout status deployment/postgres --timeout=120s - - name: Configure Kubeconfig + - name: Wait for Postgres to be Ready run: | - echo "${{ secrets.KUBECONFIG }}" | base64 -d > kubeconfig.yaml - export KUBECONFIG=$(pwd)/kubeconfig.yaml - echo "KUBECONFIG=$(pwd)/kubeconfig.yaml" >> $GITHUB_ENV + kubectl wait --for=condition=Ready pod -l app=postgres --timeout=180s - - name: Deploy Postgres to Kubernetes + - name: Pull and Deploy Application to Minikube run: | - kubectl apply -f k8s/postgres.yaml - kubectl rollout status statefulset/postgres --timeout=120s + docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + minikube image load ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + kubectl apply -f k8s/deployment.yaml --validate=false + kubectl rollout status deployment/ecommerce-app --timeout=120s - - name: Deploy Application to Kubernetes + - name: Check Deployment Status run: | - kubectl apply -f k8s/deployment.yaml - kubectl set image deployment/ecommerce-app ecommerce-app=${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - kubectl rollout status deployment/ecommerce-app --timeout=120s + kubectl get pods + kubectl get services + kubectl describe pod ecommerce-app + kubectl logs deployment/ecommerce-app + + \ No newline at end of file From b8f4562d02d94088d4261337f72c8cee1533a4e5 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 20:34:36 +0300 Subject: [PATCH 03/16] fix: Adjust ci-cd workflow to locate Minikube on localhost --- .github/workflows/ci-cd.yml | 46 ++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index adc534a..a5fe996 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -91,16 +91,50 @@ jobs: - name: Checkout Repository uses: actions/checkout@v3 + - name: Check Minikube and Kubectl Installation + id: check-tools + run: | + MINIKUBE_INSTALLED=$(which minikube || echo "false") + KUBECTL_INSTALLED=$(which kubectl || echo "false") + + echo "Minikube installed: $MINIKUBE_INSTALLED" + echo "Kubectl installed: $KUBECTL_INSTALLED" + + echo "minikube_exists=$MINIKUBE_INSTALLED" >> $GITHUB_OUTPUT + echo "kubectl_exists=$KUBECTL_INSTALLED" >> $GITHUB_OUTPUT + + - name: Install Minikube (if needed) + if: steps.check-tools.outputs.minikube_exists == 'false' + run: | + curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 + sudo install minikube-linux-amd64 /usr/local/bin/minikube + + - name: Install Kubectl (if needed) + if: steps.check-tools.outputs.kubectl_exists == 'false' + run: | + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + - name: Start Minikube - uses: medyagh/setup-minikube@latest - with: - minikube-version: v1.35.0 - kubernetes-version: v1.32.0 - - - name: Wait for Minikube to be ready + run: | + minikube start \ + --driver=docker \ + --kubernetes-version=v1.27.1 \ + --wait=all \ + --force + + - name: Configure Kubectl Context + run: | + kubectl config use-context minikube + kubectl config set-cluster minikube --insecure-skip-tls-verify=true + + - name: Verify Minikube Setup run: | minikube status + minikube ip kubectl cluster-info + kubectl get nodes + kubectl version || true # Use || true to prevent failure if version command is incompatible - name: Create Kubernetes Secrets run: | From 55afe1e6c27c005104659a0543c167f50afc4e83 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 20:46:25 +0300 Subject: [PATCH 04/16] fix: Modify Create Kubernetes Secrets job in the ci-cd file --- .github/workflows/ci-cd.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a5fe996..dd0bd72 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -137,14 +137,24 @@ jobs: kubectl version || true # Use || true to prevent failure if version command is incompatible - name: Create Kubernetes Secrets - run: | - kubectl create secret generic django-secrets \ - --from-literal=DB_NAME=${{ secrets.DB_NAME }} \ - --from-literal=DB_USER=${{ secrets.DB_USER }} \ - --from-literal=DB_PASSWORD=${{ secrets.DB_PASSWORD }} \ - --from-literal=DB_HOST=postgres-service \ - --from-literal=DB_PORT=5432 \ - --from-literal=SECRET_KEY=${{ secrets.SECRET_KEY }} + env: + DB_NAME: ${{ secrets.DB_NAME }} + DB_USER: ${{ secrets.DB_USER }} + DB_PASSWORD: ${{ secrets.DB_PASSWORD }} + DB_HOST: postgres-service + DB_PORT: "5432" + SECRET_KEY: ${{ secrets.SECRET_KEY }} + + run: | + # Ensure environment variables are properly escaped + kubectl create secret generic django-secrets \ + --from-literal=DB_NAME="$DB_NAME" \ + --from-literal=DB_USER="$DB_USER" \ + --from-literal=DB_PASSWORD="$DB_PASSWORD" \ + --from-literal=DB_HOST="$DB_HOST" \ + --from-literal=DB_PORT="$DB_PORT" \ + --from-literal=SECRET_KEY="$SECRET_KEY" + - name: Log in to Docker Hub run: | From 4c63d7eda8cb6583800a5d3373b84e15a8bcb307 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 20:57:32 +0300 Subject: [PATCH 05/16] fix: fix ci-cd indentation --- .github/workflows/ci-cd.yml | 154 +++++++++++++++++------------------- 1 file changed, 73 insertions(+), 81 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index dd0bd72..74d072a 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -1,6 +1,5 @@ name: CI/CD Pipeline - -on: +'on': push: branches: - main @@ -9,60 +8,55 @@ on: branches: - main - master - jobs: test: name: Run Django Tests runs-on: ubuntu-latest - services: postgres: - image: postgres:14 + image: 'postgres:14' env: - POSTGRES_DB: ${{ secrets.DB_NAME }} - POSTGRES_USER: ${{ secrets.DB_USER }} - POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }} + POSTGRES_DB: '${{ secrets.DB_NAME }}' + POSTGRES_USER: '${{ secrets.DB_USER }}' + POSTGRES_PASSWORD: '${{ secrets.DB_PASSWORD }}' ports: - - 5432:5432 + - '5432:5432' options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s + --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Set up Python 3.8 uses: actions/setup-python@v4 with: - python-version: "3.8" - + python-version: '3.8' - name: Install Dependencies run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt - - name: Decode and set environment variables - run: | - echo "AT_USERNAME=$(echo '${{ secrets.AT_USERNAME }}' | base64 -d)" >> $GITHUB_ENV - echo "AT_SHORT_CODE=$(echo '${{ secrets.AT_SHORT_CODE }}' | base64 -d)" >> $GITHUB_ENV - echo "AT_API_KEY=$(echo '${{ secrets.AT_API_KEY }}' | base64 -d)" >> $GITHUB_ENV + run: > + echo "AT_USERNAME=$(echo '${{ secrets.AT_USERNAME }}' | base64 -d)" >> + $GITHUB_ENV + + echo "AT_SHORT_CODE=$(echo '${{ secrets.AT_SHORT_CODE }}' | base64 + -d)" >> $GITHUB_ENV + echo "AT_API_KEY=$(echo '${{ secrets.AT_API_KEY }}' | base64 -d)" >> + $GITHUB_ENV - name: Run Tests env: - DB_NAME: ${{ secrets.DB_NAME }} - DB_USER: ${{ secrets.DB_USER }} - DB_PASSWORD: ${{ secrets.DB_PASSWORD }} - DB_HOST: "localhost" - DB_PORT: "5432" - SECRET_KEY: ${{ secrets.SECRET_KEY }} + DB_NAME: '${{ secrets.DB_NAME }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASSWORD: '${{ secrets.DB_PASSWORD }}' + DB_HOST: localhost + DB_PORT: '5432' + SECRET_KEY: '${{ secrets.SECRET_KEY }}' run: | source venv/bin/activate pytest -v - build-and-push: name: Build and Push Docker Image runs-on: ubuntu-latest @@ -70,51 +64,50 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Log in to Docker Hub uses: docker/login-action@v2 with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - + username: '${{ secrets.DOCKER_USERNAME }}' + password: '${{ secrets.DOCKER_PASSWORD }}' - name: Build and Push Docker Image - run: | - docker build -t ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest . - docker push ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + run: > + docker build -t ${{ secrets.DOCKER_USERNAME + }}/e-commerce-service:latest . + docker push ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest deploy: name: Deploy to Minikube runs-on: ubuntu-latest needs: test - steps: - name: Checkout Repository uses: actions/checkout@v3 - - name: Check Minikube and Kubectl Installation id: check-tools run: | MINIKUBE_INSTALLED=$(which minikube || echo "false") KUBECTL_INSTALLED=$(which kubectl || echo "false") - + echo "Minikube installed: $MINIKUBE_INSTALLED" echo "Kubectl installed: $KUBECTL_INSTALLED" - + echo "minikube_exists=$MINIKUBE_INSTALLED" >> $GITHUB_OUTPUT echo "kubectl_exists=$KUBECTL_INSTALLED" >> $GITHUB_OUTPUT - - name: Install Minikube (if needed) if: steps.check-tools.outputs.minikube_exists == 'false' - run: | - curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 - sudo install minikube-linux-amd64 /usr/local/bin/minikube + run: > + curl -LO + https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 + sudo install minikube-linux-amd64 /usr/local/bin/minikube - name: Install Kubectl (if needed) if: steps.check-tools.outputs.kubectl_exists == 'false' - run: | - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" - sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + run: > + curl -LO "https://dl.k8s.io/release/$(curl -L -s + https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl + /usr/local/bin/kubectl - name: Start Minikube run: | minikube start \ @@ -122,65 +115,64 @@ jobs: --kubernetes-version=v1.27.1 \ --wait=all \ --force - - name: Configure Kubectl Context run: | kubectl config use-context minikube kubectl config set-cluster minikube --insecure-skip-tls-verify=true - - name: Verify Minikube Setup - run: | + run: > minikube status + minikube ip + kubectl cluster-info + kubectl get nodes - kubectl version || true # Use || true to prevent failure if version command is incompatible + kubectl version || true # Use || true to prevent failure if version + command is incompatible - name: Create Kubernetes Secrets - env: - DB_NAME: ${{ secrets.DB_NAME }} - DB_USER: ${{ secrets.DB_USER }} - DB_PASSWORD: ${{ secrets.DB_PASSWORD }} - DB_HOST: postgres-service - DB_PORT: "5432" - SECRET_KEY: ${{ secrets.SECRET_KEY }} - - run: | - # Ensure environment variables are properly escaped - kubectl create secret generic django-secrets \ - --from-literal=DB_NAME="$DB_NAME" \ - --from-literal=DB_USER="$DB_USER" \ - --from-literal=DB_PASSWORD="$DB_PASSWORD" \ - --from-literal=DB_HOST="$DB_HOST" \ - --from-literal=DB_PORT="$DB_PORT" \ - --from-literal=SECRET_KEY="$SECRET_KEY" - - - - name: Log in to Docker Hub + env: + DB_NAME: '${{ secrets.DB_NAME }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASSWORD: '${{ secrets.DB_PASSWORD }}' + DB_HOST: postgres-service + DB_PORT: '5432' + SECRET_KEY: '${{ secrets.SECRET_KEY }}' run: | - docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - + # Ensure environment variables are properly escaped + kubectl create secret generic django-secrets \ + --from-literal=DB_NAME="$DB_NAME" \ + --from-literal=DB_USER="$DB_USER" \ + --from-literal=DB_PASSWORD="$DB_PASSWORD" \ + --from-literal=DB_HOST="$DB_HOST" \ + --from-literal=DB_PORT="$DB_PORT" \ + --from-literal=SECRET_KEY="$SECRET_KEY" + - name: Log in to Docker Hub + run: > + docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ + secrets.DOCKER_PASSWORD }} - name: Deploy Postgres to Minikube run: | kubectl apply -f k8s/postgres.yaml --validate=false kubectl rollout status deployment/postgres --timeout=120s - - name: Wait for Postgres to be Ready - run: | - kubectl wait --for=condition=Ready pod -l app=postgres --timeout=180s - + run: > + kubectl wait --for=condition=Ready pod -l app=postgres + --timeout=180s - name: Pull and Deploy Application to Minikube - run: | + run: > docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - minikube image load ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + + minikube image load ${{ secrets.DOCKER_USERNAME + }}/e-commerce-service:latest + kubectl apply -f k8s/deployment.yaml --validate=false - kubectl rollout status deployment/ecommerce-app --timeout=120s + kubectl rollout status deployment/ecommerce-app --timeout=120s - name: Check Deployment Status run: | kubectl get pods kubectl get services kubectl describe pod ecommerce-app kubectl logs deployment/ecommerce-app - - \ No newline at end of file From 1cf19c86890ac2aeb9a83373a3a5af9ee8948ff5 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 21:48:02 +0300 Subject: [PATCH 06/16] fix: adjust ci-cd workflow to display postgres logs after deployment --- .github/workflows/ci-cd.yml | 31 +++++++++++++++++++++++++++++-- k8s/postgres.yaml | 24 ++++++++++++++++++++---- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 74d072a..0bade91 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -152,14 +152,41 @@ jobs: run: > docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} + - name: Deploy Postgres to Minikube run: | kubectl apply -f k8s/postgres.yaml --validate=false + echo "Checking Postgres Deployment Details:" + kubectl get deployments + kubectl get pods + kubectl describe deployment postgres + kubectl get events --sort-by='.metadata.creationTimestamp kubectl rollout status deployment/postgres --timeout=120s + + - name: Check Postgres Deployment Logs + run: | + POSTGRES_PODS=$(kubectl get pods -l app=postgres -o jsonpath='{.items[*].metadata.name}') + for pod in $POSTGRES_PODS; do + echo "Logs for pod: $pod" + kubectl logs $pod || true + echo "---" + done + + - name: Verify Persistent Volume and Claims + run: | + kubectl get pvc + kubectl describe pvc postgres-pvc + kubectl get storageclass + - name: Wait for Postgres to be Ready run: > - kubectl wait --for=condition=Ready pod -l app=postgres - --timeout=180s + kubectl wait --for=condition=Ready pod -l app=postgres --timeout=180s || { + echo "Postgres pod did not become ready in time" + kubectl get pods + kubectl describe pods + exit 1 + } + - name: Pull and Deploy Application to Minikube run: > docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest diff --git a/k8s/postgres.yaml b/k8s/postgres.yaml index 9860daf..09d607e 100644 --- a/k8s/postgres.yaml +++ b/k8s/postgres.yaml @@ -8,6 +8,8 @@ spec: resources: requests: storage: 1Gi + + storageClassName: standard --- apiVersion: apps/v1 @@ -29,9 +31,23 @@ spec: image: postgres:14 ports: - containerPort: 5432 - envFrom: - - secretRef: - name: django-secrets + env: + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: django-secrets + key: DATABASE_NAME + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: django-secrets + key: DATABASE_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: django-secrets + key: DATABASE_PASSWORD + volumeMounts: - mountPath: /var/lib/postgresql/data name: postgres-storage @@ -58,4 +74,4 @@ spec: ports: - protocol: TCP port: 5432 - targetPort: 5432 + targetPort: 5432 \ No newline at end of file From c8de04f750a49ddb014e73851800bcfee57dbc27 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 22:33:33 +0300 Subject: [PATCH 07/16] fix: Adjust workflow to reset minikube before deployment --- .github/workflows/ci-cd.yml | 45 ++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 0bade91..da097b8 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -107,18 +107,56 @@ jobs: https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl - /usr/local/bin/kubectl - - name: Start Minikube + /usr/local/bin/kubectl + + - name: Reset Kubernetes Cluster run: | + # Stop any running Minikube instance + minikube stop || true + + # Delete existing Minikube cluster + minikube delete || true + + # Restart Minikube with optimized resources minikube start \ --driver=docker \ --kubernetes-version=v1.27.1 \ + --cpus=2 \ + --memory=4g \ --wait=all \ --force + + # Wait for cluster to be fully ready + kubectl wait --for=condition=Ready nodes --all --timeout=300s + + - name: Clean Up Existing Resources + run: | + # Remove all existing resources + kubectl delete all --all || true + kubectl delete pvc --all || true + kubectl delete secrets --all || true + + # Wait for resources to be terminated + sleep 15 + - name: Configure Kubectl Context run: | kubectl config use-context minikube - kubectl config set-cluster minikube --insecure-skip-tls-verify=true + kubectl config set-cluster minikube --insecure-skip-tls-verify=true + + - name: Deploy Configuration + run: | + # Apply ConfigMaps + kubectl apply -f configmap.yaml + + # Apply Secrets + kubectl apply -f secrets.yaml + + # Verify resources + kubectl get configmaps + kubectl get secrets + + - name: Verify Minikube Setup run: > minikube status @@ -131,6 +169,7 @@ jobs: kubectl version || true # Use || true to prevent failure if version command is incompatible + - name: Create Kubernetes Secrets env: DB_NAME: '${{ secrets.DB_NAME }}' From c30066db7d220c3afb9c2fbd06fbe18082623d2d Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 22:44:13 +0300 Subject: [PATCH 08/16] fix: adjust workflow to create secrets only if they don't exist --- .github/workflows/ci-cd.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index da097b8..0122bb3 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -148,7 +148,7 @@ jobs: run: | # Apply ConfigMaps kubectl apply -f configmap.yaml - + # Apply Secrets kubectl apply -f secrets.yaml @@ -179,7 +179,8 @@ jobs: DB_PORT: '5432' SECRET_KEY: '${{ secrets.SECRET_KEY }}' run: | - # Ensure environment variables are properly escaped + # Create secret only if it doesn't exist + kubectl get secret django-secrets || \ kubectl create secret generic django-secrets \ --from-literal=DB_NAME="$DB_NAME" \ --from-literal=DB_USER="$DB_USER" \ From cced670da4d4648c6b4d62e9a1540f669c74a6e3 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 22:57:18 +0300 Subject: [PATCH 09/16] fix: adjust ci-cd workflow to fix missing closing quote --- .github/workflows/ci-cd.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 0122bb3..d17fa30 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -200,11 +200,12 @@ jobs: kubectl get deployments kubectl get pods kubectl describe deployment postgres - kubectl get events --sort-by='.metadata.creationTimestamp + kubectl get events --sort-by='.metadata.creationTimestamp' kubectl rollout status deployment/postgres --timeout=120s - name: Check Postgres Deployment Logs run: | + sleep 10 POSTGRES_PODS=$(kubectl get pods -l app=postgres -o jsonpath='{.items[*].metadata.name}') for pod in $POSTGRES_PODS; do echo "Logs for pod: $pod" From 3be44d6e245329421212909e2802c549bd31fc78 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 23:22:58 +0300 Subject: [PATCH 10/16] fix: add more resources to app container in the cluster --- .github/workflows/ci-cd.yml | 15 ++++++--------- k8s/deployment.yaml | 12 ++++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index d17fa30..1355d94 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -229,15 +229,12 @@ jobs: } - name: Pull and Deploy Application to Minikube - run: > - docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - - minikube image load ${{ secrets.DOCKER_USERNAME - }}/e-commerce-service:latest - - kubectl apply -f k8s/deployment.yaml --validate=false - - kubectl rollout status deployment/ecommerce-app --timeout=120s + run: | + docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + minikube image load ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + kubectl apply -f k8s/deployment.yaml + kubectl rollout status deployment/ecommerce-app --timeout=300s + - name: Check Deployment Status run: | kubectl get pods diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 65868a2..250825c 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -17,7 +17,7 @@ spec: initContainers: - name: wait-for-db image: busybox - command: ['sh', '-c', 'until nc -z postgres-service 5432; do echo waiting for db; sleep 2; done;'] + command: ['sh', '-c', 'until nc -z postgres-service 5432; do echo waiting for db; sleep 5; done;'] containers: - name: ecommerce-app image: ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest @@ -31,16 +31,16 @@ spec: name: django-secrets resources: requests: - memory: "128Mi" - cpu: "100m" - limits: memory: "256Mi" - cpu: "500m" + cpu: "200m" + limits: + memory: "512Mi" + cpu: "1000m" readinessProbe: httpGet: path: /api/v1/health/ port: 8000 - initialDelaySeconds: 30 + initialDelaySeconds: 60 periodSeconds: 10 failureThreshold: 3 timeoutSeconds: 5 From 308c0d7c43781f799bfb29090f9020e0d8c20ba9 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Wed, 26 Mar 2025 23:50:58 +0300 Subject: [PATCH 11/16] fix: change deployment strategy from recreate to RollingUpdate --- .github/workflows/ci-cd.yml | 5 ++++- k8s/deployment.yaml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 1355d94..2f7d951 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -230,8 +230,11 @@ jobs: - name: Pull and Deploy Application to Minikube run: | + eval $(minikube docker-env) docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - minikube image load ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + docker tag ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest ecommerce-app:latest + docker rmi ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + minikube image load ecommerce-app:latest kubectl apply -f k8s/deployment.yaml kubectl rollout status deployment/ecommerce-app --timeout=300s diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 250825c..85b8757 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -5,7 +5,10 @@ metadata: spec: replicas: 1 strategy: - type: Recreate + type: RollingUpdate + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 selector: matchLabels: app: ecommerce-app From 4cddb5f309f4b5c91c7c8ed9281e6b8f43350393 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Thu, 27 Mar 2025 00:04:15 +0300 Subject: [PATCH 12/16] fix: adjust imagePullPolicy to never --- .github/workflows/ci-cd.yml | 1 + k8s/deployment.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 2f7d951..43e5538 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -235,6 +235,7 @@ jobs: docker tag ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest ecommerce-app:latest docker rmi ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest minikube image load ecommerce-app:latest + minikube image ls | grep ecommerce-app kubectl apply -f k8s/deployment.yaml kubectl rollout status deployment/ecommerce-app --timeout=300s diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 85b8757..89655d1 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -24,7 +24,7 @@ spec: containers: - name: ecommerce-app image: ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - imagePullPolicy: Always + imagePullPolicy: Never ports: - containerPort: 8000 envFrom: From ed16870321b5964139e464870201dadc47cd7e16 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Thu, 27 Mar 2025 00:05:44 +0300 Subject: [PATCH 13/16] fix: output deployment timeout with verbose output --- .github/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 43e5538..73d9fe9 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -237,7 +237,7 @@ jobs: minikube image load ecommerce-app:latest minikube image ls | grep ecommerce-app kubectl apply -f k8s/deployment.yaml - kubectl rollout status deployment/ecommerce-app --timeout=300s + kubectl rollout status deployment/ecommerce-app --timeout=300s -v 6 - name: Check Deployment Status run: | From 5ecd05d54cac8c95de5a3dc76734063b1ed0149f Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Thu, 27 Mar 2025 00:23:46 +0300 Subject: [PATCH 14/16] revert: update deployment.yaml to always pull latest image from DockerHub --- .github/workflows/ci-cd.yml | 11 +++++------ k8s/deployment.yaml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 73d9fe9..9f29b8d 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -232,13 +232,12 @@ jobs: run: | eval $(minikube docker-env) docker pull ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - docker tag ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest ecommerce-app:latest - docker rmi ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - minikube image load ecommerce-app:latest - minikube image ls | grep ecommerce-app + minikube image load ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest + minikube image ls | grep e-commerce-service + sed -i 's|image: .*|image: ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest|' k8s/deployment.yaml kubectl apply -f k8s/deployment.yaml - kubectl rollout status deployment/ecommerce-app --timeout=300s -v 6 - + kubectl rollout status deployment/ecommerce-app --timeout=300s + - name: Check Deployment Status run: | kubectl get pods diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 89655d1..c7d725d 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -24,7 +24,7 @@ spec: containers: - name: ecommerce-app image: ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest - imagePullPolicy: Never + imagePullPolicy: Always ports: - containerPort: 8000 envFrom: From 0c0cb93482963787f10b0e72586156ac01dc6ddd Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Thu, 27 Mar 2025 00:38:56 +0300 Subject: [PATCH 15/16] fix: defer roll-out status to last step --- .github/workflows/ci-cd.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 9f29b8d..d8f2a44 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -236,11 +236,14 @@ jobs: minikube image ls | grep e-commerce-service sed -i 's|image: .*|image: ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest|' k8s/deployment.yaml kubectl apply -f k8s/deployment.yaml - kubectl rollout status deployment/ecommerce-app --timeout=300s - + - name: Check Deployment Status run: | kubectl get pods kubectl get services - kubectl describe pod ecommerce-app - kubectl logs deployment/ecommerce-app + kubectl describe deployment/ecommerce-app + kubectl describe pods + + - name: Verify Rollout + run: | + kubectl rollout status deployment/ecommerce-app --timeout=120s From 952aea93ee669f2b79b3ef6cb825e35a2ff8a899 Mon Sep 17 00:00:00 2001 From: JamesKibathi Date: Thu, 27 Mar 2025 01:01:58 +0300 Subject: [PATCH 16/16] fix: remove rollout status from ci workflow --- .github/workflows/ci-cd.yml | 3 --- k8s/deployment.yaml | 11 ++++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index d8f2a44..9e15b28 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -244,6 +244,3 @@ jobs: kubectl describe deployment/ecommerce-app kubectl describe pods - - name: Verify Rollout - run: | - kubectl rollout status deployment/ecommerce-app --timeout=120s diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index c7d725d..e32d0c8 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -20,7 +20,16 @@ spec: initContainers: - name: wait-for-db image: busybox - command: ['sh', '-c', 'until nc -z postgres-service 5432; do echo waiting for db; sleep 5; done;'] + command: + - 'sh' + - '-c' + - | + echo "Checking PostgreSQL connection..." + until nc -z -v -w5 postgres-service 5432; do + echo "Waiting for PostgreSQL to be ready..."; + sleep 5; + done + echo "PostgreSQL is ready!" containers: - name: ecommerce-app image: ${{ secrets.DOCKER_USERNAME }}/e-commerce-service:latest