mirror of
https://github.com/fsecada01/Pygentic-AI.git
synced 2026-08-18 15:45:49 +00:00
feat: modernize deployment pipeline for Komodo integration
Production Deployment Improvements: - Added .env.example template for secure credential management - Modernized Docker build workflow with branch sanitization - Created Komodo deployment trigger workflow - Updated compose.yaml with environment variable substitution GitHub Workflows: - Updated docker-image.yml: - Add branch name sanitization (replace / with -) - Generate both date-tagged and -latest Docker tags - Upgrade to actions/checkout@v4 - Add pull: true for layer caching - New komodo-deploy.yml: - Triggers after successful Docker Image CI - Sends signed webhook to Komodo service - Extracts and sanitizes branch names - Requires secrets: KOMODO_HOST, KOMODO_STACK_ID_OR_NAME, KOMODO_WEBHOOK_SECRET Docker Compose Modernization: - Dynamic IMAGE_TAG with sensible defaults (main-latest) - Configurable memory limits and reservations - Environment variable substitution for all configs - Added container names and restart policies - Improved healthcheck with Host header - Updated Traefik labels with Let's Encrypt cert resolver - Added loadbalancer server URL configuration - Explicit command paths for reliability Security: - .env.example provides safe template (no credentials) - Actual .env remains in .gitignore (not tracked) Pattern based on proven Formana deployment architecture. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# OpenAI Configuration
|
||||
OPENAI_API_KEY=sk-proj-your-openai-api-key-here
|
||||
OPENAI_MODEL=gpt-4o-mini
|
||||
# OPENAI_MODEL=gpt-4o
|
||||
|
||||
# Security
|
||||
HTTPS_ONLY=False
|
||||
SECRET_KEY=your-secret-key-here
|
||||
|
||||
# Local Database Configuration
|
||||
LOCAL_DB_UN=pygentic_ai
|
||||
LOCAL_DB_PW=your-local-db-password
|
||||
LOCAL_DB_DB=fsecada_server
|
||||
LOCAL_DB_HOST=localhost
|
||||
LOCAL_DB_PORT=5433
|
||||
|
||||
# Cloud Database Configuration
|
||||
CLOUD_DB_UN=pygentic_ai
|
||||
CLOUD_DB_PW=your-cloud-db-password
|
||||
CLOUD_DB_DB=fsecada_server
|
||||
CLOUD_DB_HOST=pgserver.example.com
|
||||
CLOUD_DB_PORT=5433
|
||||
|
||||
# Database Configuration
|
||||
SQL_DIALECT=postgresql
|
||||
|
||||
# Application Environment
|
||||
DEBUG=True
|
||||
SERVER_ENV=dev
|
||||
|
||||
# Reddit API Configuration (for intelligence gathering)
|
||||
REDDIT_MAX_INSIGHTS=5
|
||||
REDDIT_MAX_INSIGHT_LENGTH=400
|
||||
REDDIT_USER_AGENT=your-reddit-user-agent
|
||||
REDDIT_CLIENT_ID=your-reddit-client-id
|
||||
REDDIT_CLIENT_SECRET=your-reddit-client-secret
|
||||
REDDIT_SUBREDDIT=python,kubernetes,devops,rust,selfhosted,algorithms,typescript,programming,webdev,strategy,DigitalMarketing,Entrepreneur
|
||||
|
||||
# Celery Configuration (optional)
|
||||
# CELERY_PORT=5052
|
||||
@@ -24,13 +24,17 @@ jobs:
|
||||
shell: bash
|
||||
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
|
||||
id: extract_branch
|
||||
- name: Sanitize branch name for Docker tag
|
||||
shell: bash
|
||||
run: echo "sanitized_branch=$(echo '${{ steps.extract_branch.outputs.branch }}' | sed 's/\//-/g')" >> $GITHUB_OUTPUT
|
||||
id: sanitize_branch
|
||||
- name: Set SSH Agent
|
||||
uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
@@ -41,6 +45,9 @@ jobs:
|
||||
ssh: |
|
||||
default=${{ env.SSH_AUTH_SOCK }}
|
||||
build-args: |
|
||||
GIT_BRANCH=${{ steps.extract_branch.outputs.branch }}
|
||||
"GIT_BRANCH=${{ steps.extract_branch.outputs.branch }}"
|
||||
push: true
|
||||
tags: s3docker.francissecada.com/pygentic_ai:${{ steps.extract_branch.outputs.branch }}.${{ steps.date.outputs.date }}
|
||||
tags: |
|
||||
s3docker.francissecada.com/pygentic_ai:${{ steps.sanitize_branch.outputs.sanitized_branch }}.${{ steps.date.outputs.date }}
|
||||
s3docker.francissecada.com/pygentic_ai:${{ steps.sanitize_branch.outputs.sanitized_branch }}-latest
|
||||
pull: true
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Komodo Deployment Trigger
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Docker Image CI"]
|
||||
types:
|
||||
- completed
|
||||
branches: [ "**_deploy", "main" ]
|
||||
|
||||
jobs:
|
||||
trigger_komodo_deployment:
|
||||
runs-on: ubuntu-latest
|
||||
# Only run if the 'Docker Image CI' workflow was successful
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
steps:
|
||||
- name: Extract branch name from triggering workflow
|
||||
id: branch
|
||||
run: echo "BRANCH_NAME=$(echo ${{ github.event.workflow_run.head_branch }} | sed 's/\//-/g')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Trigger Komodo Stack Deployment
|
||||
env:
|
||||
# The webhook URL is constructed from secrets
|
||||
KOMODO_WEBHOOK_URL: "https://${{ secrets.KOMODO_HOST }}/listener/github/stack/${{ secrets.KOMODO_STACK_ID_OR_NAME }}/deploy"
|
||||
run: |
|
||||
# Get the branch name from the previous step's output
|
||||
branch_name="${{ steps.branch.outputs.BRANCH_NAME }}"
|
||||
|
||||
# Construct a JSON payload containing the branch name
|
||||
# This tells Komodo which specific branch/tag to deploy
|
||||
payload=$(printf '{"ref":"%s"}' "$branch_name")
|
||||
|
||||
# Generate the signature based on the payload
|
||||
signature=$(echo -n "$payload" | openssl dgst -sha256 -hmac "${{ secrets.KOMODO_WEBHOOK_SECRET }}" | sed 's/^.* //')
|
||||
|
||||
# Send the request to the Komodo webhook with the payload
|
||||
echo "Triggering Pygentic-AI deployment for branch: $branch_name"
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Hub-Signature-256: sha256=$signature" \
|
||||
-d "$payload" \
|
||||
--fail-with-body \
|
||||
"${KOMODO_WEBHOOK_URL}"
|
||||
+33
-23
@@ -1,58 +1,68 @@
|
||||
services:
|
||||
web:
|
||||
image: s3docker.francissecada.com/pygentic_ai:main.2024-11-30
|
||||
image: s3docker.francissecada.com/pygentic_ai:${IMAGE_TAG:-main-latest}
|
||||
container_name: pygentic_ai
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1024mb
|
||||
memory: ${MEMORY_LIMIT:-1024mb}
|
||||
reservations:
|
||||
memory: ${MEMORY_RESERVATION:-512mb}
|
||||
ports:
|
||||
- "5051:5051"
|
||||
- "0.0.0.0:${PORT:-5051}:${INTERNAL_PORT:-5051}"
|
||||
env_file:
|
||||
- ./stack.env
|
||||
environment:
|
||||
PORT: 5051
|
||||
SERVER_ENV: prod
|
||||
- PORT=${INTERNAL_PORT:-5051}
|
||||
- SERVER_ENV=${SERVER_ENV:-prod}
|
||||
volumes:
|
||||
- ./src/proxy_urls.db:/opt/pygentic_ai/src/proxy_urls.db
|
||||
command: bash -c "/opt/pygentic_ai/docker/pygentic_ai/python_start.sh"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "-H", "Host: pygenticai.francissecada.com", "http://localhost:${INTERNAL_PORT:-5051}/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.http.routers.pygentic_ai.entrypoints=websecure
|
||||
- traefik.http.routers.pygentic_ai.rule=Host(`pygenticai.francissecada.com`)
|
||||
- traefik.http.routers.pygentic_ai.tls=true
|
||||
healthcheck:
|
||||
test: curl --fail http://localhost:5051/ || exit 1
|
||||
interval: 40s
|
||||
timeout: 30s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
- traefik.http.routers.pygentic_ai.entrypoints=websecure
|
||||
- traefik.http.routers.pygentic_ai.tls.certresolver=letsencrypt
|
||||
- traefik.http.services.pygentic_ai.loadbalancer.server.url=http://${DOCKER_HOST_IP:-192.168.99.85}:${PORT:-5051}
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
celery_service:
|
||||
image: s3docker.francissecada.com/pygentic_ai:main.2024-11-30
|
||||
image: s3docker.francissecada.com/pygentic_ai:${IMAGE_TAG:-main-latest}
|
||||
container_name: pygentic_ai_celery
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512mb
|
||||
# build: .
|
||||
command: ./docker/celery/start.sh
|
||||
memory: ${CELERY_MEMORY_LIMIT:-512mb}
|
||||
reservations:
|
||||
memory: ${CELERY_MEMORY_RESERVATION:-256mb}
|
||||
command: bash -c "/opt/pygentic_ai/docker/celery/start.sh"
|
||||
env_file:
|
||||
- ./stack.env
|
||||
environment:
|
||||
PORT: ${CELERY_PORT}
|
||||
SERVER_ENV: staging
|
||||
C_FORCE_ROOT: true
|
||||
- PORT=${CELERY_PORT:-5052}
|
||||
- SERVER_ENV=${SERVER_ENV:-prod}
|
||||
- C_FORCE_ROOT=true
|
||||
ports:
|
||||
- "5052:5052"
|
||||
- "0.0.0.0:${CELERY_PORT:-5052}:${CELERY_PORT:-5052}"
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.http.routers.celery_pygentic_ai.entrypoints=websecure
|
||||
- traefik.http.routers.celery_pygentic_ai.rule=Host(`celery.pygenticai.francissecada.com`)
|
||||
- traefik.http.routers.celery_pygentic_ai.tls.certresolver=letsencrypt
|
||||
networks:
|
||||
- proxy
|
||||
depends_on:
|
||||
- web
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
|
||||
Reference in New Issue
Block a user