Skip to content

Commit 7291469

Browse files
Devops (#35)
* Adds initial Docker Compose setup Sets up Docker Compose for local development. Defines services for the API and database (PostgreSQL with pgvector). Configures environment variables, volumes, and health checks for both services. Also includes a Dockerfile that uses uv to manage the python environment and dependencies. * Add initial database setup with tables for documents, document chunks, and chat sessions * Refactor Docker setup: replace pgvector with new Dockerfiles for DocsManager and RAGManager, update docker-compose.yml for service configuration, and adjust Python version in RAGManager. * Adds CI/CD workflows for deployment and validation Sets up GitHub Actions workflows for continuous integration and continuous deployment. - Introduces a deployment workflow that builds and pushes Docker images to ACR, configures kubectl, and restarts deployments in a Kubernetes namespace. - Implements a pull request validation workflow that performs secret scanning with Gitleaks, builds Docker images for validation (without pushing), runs Trivy vulnerability scans, and uploads the results to GitHub Security. - Adds a PR summary workflow that posts a comment on the pull request with the results of the Gitleaks and build validation jobs, including a notice to check the security tab for any found vulnerabilities. * Refactors PR validation workflow for clarity Streamlines the PR validation workflow by removing the Gitleaks job and improving the presentation of Trivy results. The workflow now focuses on build validation and vulnerability scanning with clearer output in the PR summary. Trivy results are now displayed in a table format within the PR comment, and a direct link to the detailed results in the Actions tab is included. The Gitleaks check is removed. * Enhances deployment workflow with summaries Adds deployment summary to the workflow, providing detailed information about the deployed service, image, and pod status in the job summary. Also, it includes a success notification with links to deployed services and sets fail-fast to false to ensure all services are deployed. * Enhances deployment workflow with rollback Improves the deployment process by adding rollback capabilities on failure, enhanced logging, and deployment summaries in GitHub. The changes also include updating the deployment strategy from rolling restarts to image updates. It adds timeout configurations for deployments. Also adds live URL information to success summary. * Add GitHub Actions workflows for deployment and PR validation * Refactor Dockerfiles to streamline installation and add healthcheck * Refactor Dockerfiles to simplify file copying and improve build process * Fix CMD syntax in Dockerfiles for consistency * Fix CMD syntax in Dockerfiles for consistency * Update Python version to 3.13 and fix CMD syntax in Dockerfiles for consistency * Updates project dependencies Updates the project's dependencies in pyproject.toml to align with the current versions and includes 'langchain-text-splitters' to resolve the name change of 'langchain.text_splitter'. Adds a start script to `pyproject.toml`. Updates the poetry lock file. * Refactor import statement for clarity and add pdfplumber and minio dependencies * Remove rollback step from deployment workflow and adjust script section in pyproject.toml for clarity * Replace rollout status with wait for new pods to be ready in deployment workflow * Increase deployment timeout to 8 minutes and update rollout status check in deployment workflow * Remove redundant wait command from deployment rollout step in workflow * Refactor deployment workflow to improve rollout checks and update timeout settings * Add Discord notifications for successful and failed deployments, and new pull requests * Enhance Discord notifications with detailed deployment information for success and failure events * Update PR validation trigger to include opened event and adjust Python version requirement in uv.lock * Reduce rollout timeout to 30s and add debug steps for deployment status before and after rollout * Update rollout timeout to 60s and remove debug steps from deployment workflow * Add SonarQube scan step to PR validation workflow * Refactor configuration settings to use Pydantic Field for environment variables * Add env_map for PostgreSQL configuration in Settings * Refactor PostgreSQL and RabbitMQ configuration to remove env_map and use Field for environment variables * Update Dockerfile to include Python in CMD and improve uv sync command
1 parent 8f603e5 commit 7291469

File tree

9 files changed

+168
-54
lines changed

9 files changed

+168
-54
lines changed

.github/workflows/deploy.yml

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ on:
99
env:
1010
REGISTRY: crretoxmas2024.azurecr.io
1111
NAMESPACE: reto-xmas-2025-goland-ia-backend
12+
ROLLOUT_TIMEOUT: 60s
13+
READY_CHECK_RETRIES: 20
14+
READY_CHECK_SLEEP: 15
1215

1316
jobs:
1417
build-and-deploy:
1518
runs-on: ubuntu-latest
19+
timeout-minutes: 15
1620
strategy:
1721
fail-fast: false
1822
matrix:
@@ -25,7 +29,7 @@ jobs:
2529
path: ./RAGManager
2630
image: reto-xmas-2025-goland-ia-backend-rag-manager
2731
deployment: rag-manager
28-
32+
2933
steps:
3034
- name: Checkout code
3135
uses: actions/checkout@v4
@@ -51,6 +55,7 @@ jobs:
5155
${{ env.REGISTRY }}/${{ matrix.service.image }}:${{ github.sha }}
5256
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ matrix.service.image }}:buildcache
5357
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ matrix.service.image }}:buildcache,mode=max
58+
provenance: false
5459

5560
- name: Set up kubectl
5661
uses: azure/setup-kubectl@v3
@@ -63,28 +68,78 @@ jobs:
6368
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
6469
chmod 600 $HOME/.kube/config
6570
66-
- name: Restart deployment
71+
- name: Update deployment image
6772
run: |
68-
kubectl rollout restart deployment/${{ matrix.service.deployment }} -n ${{ env.NAMESPACE }}
69-
kubectl rollout status deployment/${{ matrix.service.deployment }} -n ${{ env.NAMESPACE }} --timeout=5m
73+
kubectl set image deployment/${{ matrix.service.deployment }} \
74+
api=${{ env.REGISTRY }}/${{ matrix.service.image }}:${{ github.sha }} \
75+
-n ${{ env.NAMESPACE }}
7076
71-
- name: Verify deployment
77+
- name: Wait for deployment to be ready (robust)
7278
run: |
73-
echo "✅ Deployment successful for ${{ matrix.service.name }}"
74-
kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ matrix.service.deployment }}
79+
set -e
80+
81+
echo "Checking rollout status (non-blocking)..."
82+
kubectl rollout status deployment/${{ matrix.service.deployment }} \
83+
-n ${{ env.NAMESPACE }} \
84+
--timeout=${{ env.ROLLOUT_TIMEOUT }} || true
85+
86+
echo "Waiting for available replicas..."
87+
88+
for i in $(seq 1 $READY_CHECK_RETRIES); do
89+
DESIRED=$(kubectl get deployment/${{ matrix.service.deployment }} -n ${{ env.NAMESPACE }} -o jsonpath='{.spec.replicas}')
90+
AVAILABLE=$(kubectl get deployment/${{ matrix.service.deployment }} -n ${{ env.NAMESPACE }} -o jsonpath='{.status.availableReplicas}')
91+
92+
echo "Attempt $i: $AVAILABLE / $DESIRED replicas available"
93+
94+
if [ "$AVAILABLE" = "$DESIRED" ]; then
95+
echo "Deployment is ready"
96+
exit 0
97+
fi
98+
99+
sleep $READY_CHECK_SLEEP
100+
done
101+
102+
echo "Deployment did not become ready in time"
103+
kubectl describe deployment/${{ matrix.service.deployment }} -n ${{ env.NAMESPACE }}
104+
exit 1
105+
106+
- name: Verify pods
107+
if: success()
108+
run: |
109+
kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ matrix.service.deployment }} -o wide
110+
111+
- name: Get logs on failure
112+
if: failure()
113+
run: |
114+
echo "=== Deployment ==="
115+
kubectl describe deployment/${{ matrix.service.deployment }} -n ${{ env.NAMESPACE }}
116+
117+
echo "=== Pods ==="
118+
kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ matrix.service.deployment }} -o wide
119+
120+
echo "=== Pod Logs ==="
121+
kubectl logs -n ${{ env.NAMESPACE }} \
122+
-l app=${{ matrix.service.deployment }} \
123+
--tail=100 \
124+
--all-containers=true \
125+
--prefix=true || true
75126
76127
- name: Deployment Summary
77128
if: always()
78129
run: |
79-
echo "### 🚀 Deployment Summary" >> $GITHUB_STEP_SUMMARY
130+
STATUS="${{ job.status }}"
131+
132+
echo "### Deployment - ${{ matrix.service.name }}" >> $GITHUB_STEP_SUMMARY
80133
echo "" >> $GITHUB_STEP_SUMMARY
81-
echo "**Service:** ${{ matrix.service.name }}" >> $GITHUB_STEP_SUMMARY
82-
echo "**Image:** ${{ env.REGISTRY }}/${{ matrix.service.image }}:${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
83-
echo "**Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
134+
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
135+
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
136+
echo "| Image | \`${{ env.REGISTRY }}/${{ matrix.service.image }}:${{ github.sha }}\` |" >> $GITHUB_STEP_SUMMARY
137+
echo "| Status | $STATUS |" >> $GITHUB_STEP_SUMMARY
84138
echo "" >> $GITHUB_STEP_SUMMARY
139+
85140
echo "#### Pods:" >> $GITHUB_STEP_SUMMARY
86141
echo '```' >> $GITHUB_STEP_SUMMARY
87-
kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ matrix.service.deployment }} >> $GITHUB_STEP_SUMMARY
142+
kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ matrix.service.deployment }} >> $GITHUB_STEP_SUMMARY || true
88143
echo '```' >> $GITHUB_STEP_SUMMARY
89144
90145
notify-success:
@@ -95,8 +150,34 @@ jobs:
95150
steps:
96151
- name: Success Summary
97152
run: |
98-
echo "### ✅ Deployment Successful!" >> $GITHUB_STEP_SUMMARY
153+
echo "### All Services Deployed" >> $GITHUB_STEP_SUMMARY
99154
echo "" >> $GITHUB_STEP_SUMMARY
100-
echo "All services deployed successfully:" >> $GITHUB_STEP_SUMMARY
101-
echo "- 🌐 DocsManager: https://goland-ia-backend-docs-manager.reto-ucu.net" >> $GITHUB_STEP_SUMMARY
102-
echo "- 🌐 RAGManager: https://goland-ia-backend-rag-manager.reto-ucu.net" >> $GITHUB_STEP_SUMMARY
155+
echo "**Live URLs:**" >> $GITHUB_STEP_SUMMARY
156+
echo "- [DocsManager](https://goland-ia-backend-docs-manager.reto-ucu.net/docs)" >> $GITHUB_STEP_SUMMARY
157+
echo "- [RAGManager](https://goland-ia-backend-rag-manager.reto-ucu.net/docs)" >> $GITHUB_STEP_SUMMARY
158+
159+
- name: Notificar a Discord (deploy exitoso)
160+
run: |
161+
curl -H "Content-Type: application/json" \
162+
-X POST \
163+
-d "{\"content\": \"✅ **Deploy exitoso**\\n\\n**Servicio:** \\\\`${{ matrix.service.name }}\\\\`\\n**Imagen:** \\\\`${{ env.REGISTRY }}/${{ matrix.service.image }}:${{ github.sha }}\\\\`\\n**Namespace:** \\\\`${{ env.NAMESPACE }}\\\\`\\n**Autor:** ${{ github.actor }}\\n**Commit:** [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})\\n\\n[Ver ejecución en GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\\n\\n:rocket: ¡Todo salió bien!\"}" \
164+
https://discord.com/api/webhooks/1449147972330852463/sMs3QYOvQ6oiaPHR4PlBluwNrhWSsVmfm3_Miz6UAFrPxj1SsbqNnHXc5eK9h8ZSaumk
165+
166+
notify-failure:
167+
name: Deployment Failed
168+
runs-on: ubuntu-latest
169+
needs: [build-and-deploy]
170+
if: failure()
171+
steps:
172+
- name: Failure Summary
173+
run: |
174+
echo "### Deployment Failed" >> $GITHUB_STEP_SUMMARY
175+
echo "" >> $GITHUB_STEP_SUMMARY
176+
echo "Please check deployment logs above." >> $GITHUB_STEP_SUMMARY
177+
178+
- name: Notificar a Discord (deploy fallido)
179+
run: |
180+
curl -H "Content-Type: application/json" \
181+
-X POST \
182+
-d "{\"content\": \"❌ **Falló el deploy**\\n\\n**Servicio:** \\\\`${{ matrix.service.name }}\\\\`\\n**Imagen:** \\\\`${{ env.REGISTRY }}/${{ matrix.service.image }}:${{ github.sha }}\\\\`\\n**Namespace:** \\\\`${{ env.NAMESPACE }}\\\\`\\n**Autor:** ${{ github.actor }}\\n**Commit:** [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})\\n\\n[Ver ejecución en GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\\n\\n:warning: Revisa los logs para más detalles.\"}" \
183+
https://discord.com/api/webhooks/1449147972330852463/sMs3QYOvQ6oiaPHR4PlBluwNrhWSsVmfm3_Miz6UAFrPxj1SsbqNnHXc5eK9h8ZSaumk

.github/workflows/pr-validation.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ name: PR Validation
22

33
on:
44
pull_request:
5+
types: [opened]
56
branches:
67
- main
78

@@ -66,6 +67,13 @@ jobs:
6667
severity: 'CRITICAL,HIGH'
6768
exit-code: '0'
6869

70+
- name: SonarQube Scan
71+
uses: sonarsource/sonarqube-scan-action@v2
72+
with:
73+
host: https://sonarqube.reto-ucu.net/
74+
login: ${{ secrets.SONAR_TOKEN }}
75+
projectKey: reto-xmas-2025-goland-ia-backend
76+
6977
pr-summary:
7078
name: PR Summary
7179
runs-on: ubuntu-latest
@@ -96,4 +104,16 @@ jobs:
96104
owner: context.repo.owner,
97105
repo: context.repo.repo,
98106
body: message
99-
});
107+
});
108+
109+
discord-pr-notify:
110+
name: Notificar PR en Discord
111+
runs-on: ubuntu-latest
112+
if: github.event_name == 'pull_request'
113+
steps:
114+
- name: Notificar a Discord (nuevo PR)
115+
run: |
116+
curl -H "Content-Type: application/json" \
117+
-X POST \
118+
-d "{\"content\": \"🔔 Nuevo Pull Request: [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }}) por ${{ github.event.pull_request.user.login }}\"}" \
119+
https://discord.com/api/webhooks/1449147972330852463/sMs3QYOvQ6oiaPHR4PlBluwNrhWSsVmfm3_Miz6UAFrPxj1SsbqNnHXc5eK9h8ZSaumk

DocsManager/.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.14
1+
3.13

DocsManager/Dockerfile

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
1+
FROM python:3.12-slim
22

33
WORKDIR /app
44

5-
COPY pyproject.toml uv.lock* ./
5+
RUN apt-get update && apt-get install -y \
6+
curl \
7+
&& rm -rf /var/lib/apt/lists/*
8+
9+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
10+
mv /root/.local/bin/uv /usr/local/bin/uv && \
11+
mv /root/.local/bin/uvx /usr/local/bin/uvx
12+
613

7-
RUN uv sync --frozen --no-cache || uv sync --no-cache
814

915
COPY . .
1016

17+
RUN uv sync --no-dev --no-cache \
18+
&& uv pip list \
19+
&& uv pip show fastapi uvicorn
20+
1121
EXPOSE 8000
1222

13-
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
23+
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
24+
CMD curl -f http://localhost:8000/health || exit 1
25+
26+
CMD ["uv", "run", "--no-sync", "python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

DocsManager/app/core/config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pydantic_settings import BaseSettings, SettingsConfigDict
2-
from pydantic import field_validator, model_validator
2+
from pydantic import field_validator, model_validator, Field
33
from typing import Optional
44
from urllib.parse import quote_plus
55
import logging
@@ -29,7 +29,6 @@ class Settings(BaseSettings):
2929
minio_access_key: str
3030
minio_secret_key: str
3131
minio_bucket: str = "documents"
32-
minio_folder: str = "rag-docs"
3332
minio_use_ssl: bool = True
3433

3534
# Database Configuration (for SQLAlchemy)

DocsManager/pyproject.toml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ name = "goland-ia"
33
version = "0.1.0"
44
description = "Add your description here"
55
readme = "README.md"
6-
requires-python = ">=3.14"
6+
requires-python = ">=3.12,<3.14"
7+
78
dependencies = [
89
"fastapi>=0.124.2",
9-
"ipython>=9.8.0",
10+
"sqlalchemy>=2.0.35",
11+
"asyncpg>=0.29.0",
12+
"psycopg2-binary>=2.9.9",
13+
"langgraph>=1.0.4",
1014
"typing-extensions>=4.15.0",
1115
"uvicorn>=0.38.0",
1216
"sqlalchemy>=2.0.0",
@@ -18,14 +22,17 @@ dependencies = [
1822
"python-multipart>=0.0.6",
1923
]
2024

25+
[project.scripts]
26+
start = "uvicorn main:app --reload --host 0.0.0.0 --port 8000"
27+
2128
[project.optional-dependencies]
2229
dev = [
2330
"ruff>=0.14.0",
2431
]
2532

2633
[tool.ruff]
2734
# Enable pyproject.toml support
28-
target-version = "py314"
35+
target-version = "py313"
2936
line-length = 120
3037

3138
# Enable auto-fix

DocsManager/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RAGManager/Dockerfile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1-
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
1+
FROM python:3.12-slim
22

33
WORKDIR /app
44

5-
COPY pyproject.toml uv.lock* ./
5+
RUN apt-get update && apt-get install -y \
6+
curl \
7+
&& rm -rf /var/lib/apt/lists/*
68

7-
RUN uv sync --frozen --no-cache || uv sync --no-cache
9+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && \
10+
mv /root/.local/bin/uv /usr/local/bin/uv && \
11+
mv /root/.local/bin/uvx /usr/local/bin/uvx
812

913
COPY . .
1014

15+
RUN uv sync --no-dev --no-cache
16+
1117
EXPOSE 8000
1218

13-
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
19+
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
20+
CMD curl -f http://localhost:8000/health || exit 1
21+
22+
CMD ["uv", "run", "--no-sync", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

0 commit comments

Comments
 (0)