KAN-63: create and upload langchain image

This commit is contained in:
Gabos Levente 2025-06-27 10:11:21 +03:00
parent 5671dec923
commit e8e16b0e40
5 changed files with 306 additions and 124 deletions

View file

@ -1,65 +1,27 @@
# Frappe/ERPNext Environment Configuration
# Academy LMS Environment Configuration
# Database Configuration
DB_HOST=db
DB_PORT=3306
# REQUIRED: Database Configuration
MARIADB_ROOT_PASSWORD=changeme123
MARIADB_DATABASE=frappe
MARIADB_USER=frappe
MARIADB_PASSWORD=changeme456
# Redis Configuration
REDIS_CACHE=redis-cache:6379
REDIS_QUEUE=redis-queue:6379
REDIS_SOCKETIO=redis-socketio:6379
# Frappe Configuration
FRAPPE_SITE_NAME_HEADER=academy.example.com
FRAPPE_DEFAULT_SITE=academy.example.com
FRAPPE_SITES_DIR=/workspace/development/frappe-bench/sites
# Security
ADMIN_PASSWORD=changeme789
ENCRYPTION_KEY=changeme_32_character_encryption_key_here
# LangChain Service Configuration
LANGCHAIN_API_URL=http://langchain-service:8080
LANGCHAIN_API_KEY=changeme_langchain_api_key
# OpenAI Configuration (for AI Tutor)
# REQUIRED: AI Configuration
OPENAI_API_KEY=your_openai_api_key_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here # Optional, but recommended
# Anthropic Configuration (optional, for Claude models)
ANTHROPIC_API_KEY=your_anthropic_api_key_here
# LangChain Database Configuration
# REQUIRED: LangChain Database
LANGCHAIN_DB_NAME=langchain_db
LANGCHAIN_DB_USER=langchain_user
LANGCHAIN_DB_PASSWORD=changeme_langchain_db_password
# Service URLs (usually don't need to change)
AI_TUTOR_API_URL=http://langchain-service:8000
# Optional: Frappe Site Configuration
FRAPPE_SITE_NAME_HEADER=$$host # Use $$host for multi-site support
# Optional: Environment Settings
LANGCHAIN_ENV=production
LANGCHAIN_DEBUG=false
# AI Tutor API Configuration
AI_TUTOR_API_URL=http://langchain-service:8000
# Email Configuration (optional)
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
MAIL_USE_TLS=1
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
# Backup Configuration (optional)
BACKUP_RETENTION_DAYS=7
BACKUP_PATH=/backups
# Development/Production Mode
FRAPPE_ENV=production
DEVELOPER_MODE=0
# Network Configuration
COMPOSE_PROJECT_NAME=academy-lms
NETWORK_NAME=langchain-network
# Hetzner Specific (if needed)
EXTERNAL_IP=188.245.211.114
# Optional: Custom Image Tags (for development)
# CUSTOM_TAG=develop
# LANGCHAIN_TAG=develop

View file

@ -9,6 +9,14 @@ on:
required: false
default: 'false'
type: boolean
environment:
description: 'Deployment environment'
required: false
default: 'production'
type: choice
options:
- production
- test
# Webhook triggers from watched repositories
repository_dispatch:
@ -32,6 +40,8 @@ env:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
# Use environment for secrets management
environment: ${{ github.event.inputs.environment || 'production' }}
permissions:
contents: read
packages: write
@ -54,7 +64,7 @@ jobs:
id: meta-frappe
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/exarlabs/academy-frappe
images: ${{ env.REGISTRY }}/exarlabs/ignis-academy-lms
tags: |
type=ref,event=branch
type=ref,event=pr
@ -75,77 +85,107 @@ jobs:
LMS_REPO_URL=https://github.com/ExarLabs/academy-lms
AI_TUTOR_REPO_URL=https://github.com/ExarLabs/academy-ai-tutor-chat
- name: Setup SSH key
uses: webfactory/ssh-agent@v0.8.0
- name: Clone and prepare LangChain service
run: |
git clone https://github.com/ExarLabs/academy-LangChain.git langchain-temp
- name: Extract metadata for LangChain image
id: meta-langchain
uses: docker/metadata-action@v5
with:
ssh-private-key: ${{ secrets.HETZNER_SSH_KEY }}
images: ${{ env.REGISTRY }}/exarlabs/academy-langchain
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Add Hetzner server to known hosts
run: |
ssh-keyscan -H ${{ env.HETZNER_HOST }} >> ~/.ssh/known_hosts
- name: Build and push LangChain image
uses: docker/build-push-action@v5
with:
context: ./langchain-temp
push: true
tags: ${{ steps.meta-langchain.outputs.tags }}
labels: ${{ steps.meta-langchain.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Deploy to Hetzner
run: |
# Copy deployment files to server
scp -r compose.yaml nginx/ scripts/ ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }}:${{ env.DEPLOY_PATH }}/
# - name: Setup SSH key
# uses: webfactory/ssh-agent@v0.8.0
# with:
# ssh-private-key: ${{ secrets.HETZNER_SSH_KEY }}
# - name: Add Hetzner server to known hosts
# run: |
# ssh-keyscan -H ${{ env.HETZNER_HOST }} >> ~/.ssh/known_hosts
# - name: Deploy to Hetzner
# run: |
# # Copy deployment files to server
# scp -r compose.yaml nginx/ scripts/ ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }}:${{ env.DEPLOY_PATH }}/
# Copy environment file if it doesn't exist
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
cd ${{ env.DEPLOY_PATH }}
if [ ! -f .env ]; then
cp .env.example .env
echo 'Please update .env file with your configuration'
fi
"
- name: Update and restart services
run: |
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
cd ${{ env.DEPLOY_PATH }}
# Pull latest images
docker compose pull
# Stop services gracefully
docker compose down --timeout 30
# Start services
docker compose up -d
# Wait for services to be ready
sleep 30
# Run migrations on all sites
./scripts/migrate-all-sites.sh
# Show status
docker compose ps
"
- name: Health check
run: |
# Wait a bit more for services to fully start
sleep 60
# # Copy environment file if it doesn't exist
# ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
# cd ${{ env.DEPLOY_PATH }}
# if [ ! -f .env ]; then
# cp .env.example .env
# echo 'Please update .env file with your configuration'
# fi
# "
# Check if nginx-proxy is responding
if curl -f http://${{ env.HETZNER_HOST }}/health; then
echo "✅ Deployment successful - Health check passed"
else
echo "❌ Health check failed"
# Show logs for debugging
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
cd ${{ env.DEPLOY_PATH }}
docker compose logs --tail=50
"
exit 1
fi
# # Login to private registry
# ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
# echo '${{ secrets.GITHUB_TOKEN }}' | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
# "
- name: Notify deployment status
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "🚀 Deployment to Hetzner completed successfully!"
echo "🌐 Access your application at: http://${{ env.HETZNER_HOST }}"
else
echo "💥 Deployment failed. Check the logs above for details."
fi
# - name: Update and restart services
# run: |
# ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
# cd ${{ env.DEPLOY_PATH }}
# # Pull latest images
# docker compose pull
# # Stop services gracefully
# docker compose down --timeout 30
# # Start services
# docker compose up -d
# # Wait for services to be ready
# sleep 30
# # Run migrations on all sites
# ./scripts/migrate-all-sites.sh
# # Show status
# docker compose ps
# "
# - name: Health check
# run: |
# # Wait a bit more for services to fully start
# sleep 60
# # Check if nginx-proxy is responding
# if curl -f http://${{ env.HETZNER_HOST }}/health; then
# echo "✅ Deployment successful - Health check passed"
# else
# echo "❌ Health check failed"
# # Show logs for debugging
# ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
# cd ${{ env.DEPLOY_PATH }}
# docker compose logs --tail=50
# "
# exit 1
# fi
# - name: Notify deployment status
# if: always()
# run: |
# if [ "${{ job.status }}" == "success" ]; then
# echo "🚀 Deployment to Hetzner completed successfully!"
# echo "🌐 Access your application at: http://${{ env.HETZNER_HOST }}"
# else
# echo "💥 Deployment failed. Check the logs above for details."
# fi

View file

@ -56,6 +56,16 @@ Configure the following secrets in this repository:
- `HETZNER_SSH_KEY`: Private SSH key for accessing the Hetzner server
- `ACADEMY_DOCKER_PAT`: GitHub Personal Access Token with `repo` and `write:packages` permissions
For environment variables, you can either:
- Use a `.env` file on the server (default approach)
- Use GitHub Secrets for sensitive values (recommended for production)
If using GitHub Secrets, add these:
- `MARIADB_ROOT_PASSWORD`: Strong password for MariaDB root user
- `OPENAI_API_KEY`: Your OpenAI API key for AI features
- `ANTHROPIC_API_KEY`: Your Anthropic API key (optional)
- `LANGCHAIN_DB_PASSWORD`: Password for LangChain PostgreSQL database
### 3. Webhook Setup
Add the webhook workflow files to each watched repository:
@ -203,6 +213,7 @@ cd /opt/frappe-deployment
- Never commit `.env` file
- Use strong passwords
- Rotate credentials regularly
- Consider using GitHub Secrets for production deployments
2. **Network Security**:
- Configure firewall rules on Hetzner
@ -212,6 +223,36 @@ cd /opt/frappe-deployment
- Regular database backups
- Store backups off-site
### Private Registry Setup
By default, images are pushed to GitHub Container Registry (ghcr.io). To use private images:
1. **Make packages private in GitHub**:
- Go to your repository settings
- Navigate to "Packages" in the sidebar
- Find your package (e.g., `ignis-academy-lms`, `academy-langchain`)
- Click on "Package settings"
- Change visibility to "Private"
2. **Enable registry authentication in deployment**:
- The workflow already includes code for private registry login
- Uncomment the "Login to private registry" section in `.github/workflows/deploy.yml`
- The `GITHUB_TOKEN` automatically has `packages:read` permission for private packages in the same org
3. **Manual registry login on Hetzner** (if needed):
```bash
# For GitHub Container Registry
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Or use a Personal Access Token
echo $PAT | docker login ghcr.io -u USERNAME --password-stdin
```
4. **Alternative private registries**:
- Docker Hub: Update `REGISTRY` to `docker.io`
- Harbor: Update `REGISTRY` to your Harbor URL
- GitLab: Update `REGISTRY` to `registry.gitlab.com`
## SSL/TLS Setup (Production)
For production, set up SSL certificates:

139
LOCAL_TESTING.md Normal file
View file

@ -0,0 +1,139 @@
# Local Testing Guide for Pre-built Images
This guide explains how to run the Academy LMS stack locally using images from GitHub Container Registry.
## Prerequisites
1. Docker and Docker Compose installed
2. Access to the GitHub Container Registry (for private images)
## Quick Start
### 1. Clone this repository
```bash
git clone https://github.com/ExarLabs/academy_docker.git
cd academy_docker
```
### 2. Set up environment variables
```bash
# Copy the example environment file
cp .env.example .env
# Edit the .env file with your actual values
nano .env
```
**Required variables to update:**
- `MARIADB_ROOT_PASSWORD` - Set a secure password
- `OPENAI_API_KEY` - Your OpenAI API key
- `ANTHROPIC_API_KEY` - Your Anthropic API key (optional)
- `LANGCHAIN_DB_PASSWORD` - Password for LangChain database
### 3. Login to GitHub Container Registry (if images are private)
```bash
# Using GitHub Personal Access Token
echo $GITHUB_PAT | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
# Or using GitHub CLI
gh auth token | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
```
### 4. Pull and run the services
```bash
# Pull the latest images
docker compose pull
# Start all services
docker compose up -d
# Check status
docker compose ps
# View logs
docker compose logs -f
```
### 5. Create your first site (after services are running)
```bash
# Create a new site
docker compose exec backend bench new-site academy.local \
--admin-password admin \
--db-root-password $MARIADB_ROOT_PASSWORD
# Install the LMS app
docker compose exec backend bench --site academy.local install-app lms
# Install the AI Tutor Chat app
docker compose exec backend bench --site academy.local install-app academy_ai_tutor_chat
# Set the site as default
docker compose exec backend bench use academy.local
```
### 6. Access the application
1. Add to your hosts file:
- Windows: `C:\Windows\System32\drivers\etc\hosts`
- Linux/Mac: `/etc/hosts`
Add this line:
```
127.0.0.1 academy.local
```
2. Open in browser: http://academy.local
## What's included?
The `compose.yaml` file includes:
- **Frappe/ERPNext** with Academy LMS and AI Tutor apps (single image: `ghcr.io/exarlabs/ignis-academy-lms`)
- **LangChain service** for AI functionality (image: `ghcr.io/exarlabs/academy-langchain`)
- **MariaDB** for Frappe database
- **PostgreSQL** for LangChain database
- **Redis** for caching and queues
- **Nginx** reverse proxy
## Troubleshooting
### "manifest unknown" error
This means the image hasn't been built yet. Either:
1. Wait for GitHub Actions to build and push the images
2. Build locally (see development guide)
### Environment variable warnings
Ensure your `.env` file exists and contains all required variables. Use `.env.example` as reference.
### Cannot access the site
1. Check if all services are running: `docker compose ps`
2. Ensure you've added the hostname to your hosts file
3. Check nginx logs: `docker compose logs nginx-proxy`
### Database connection errors
1. Ensure MariaDB is fully started before creating sites
2. Check the password in `.env` matches what you use in commands
## Stopping the services
```bash
# Stop all services
docker compose down
# Stop and remove all data (careful!)
docker compose down -v
```
## Next Steps
- For production deployment, see [DEPLOYMENT.md](DEPLOYMENT.md)
- For development setup, see [README.md](README.md)
- For environment configuration, see [docs/environment-secrets-explained.md](docs/environment-secrets-explained.md)

View file

@ -1,7 +1,7 @@
x-customizable-image:
# Custom Academy LMS image with all required apps
&customizable_image
image: ${CUSTOM_IMAGE:-ghcr.io/exarlabs/academy-frappe}:${CUSTOM_TAG:-latest}
image: ${CUSTOM_IMAGE:-ghcr.io/exarlabs/ignis-academy-lms}:${CUSTOM_TAG:-latest}
pull_policy: ${PULL_POLICY:-always}
restart: ${RESTART_POLICY:-unless-stopped}