diff --git a/HYBRID_DEPLOYMENT.md b/HYBRID_DEPLOYMENT.md new file mode 100644 index 00000000..19395444 --- /dev/null +++ b/HYBRID_DEPLOYMENT.md @@ -0,0 +1,195 @@ +# Hybrid Deployment Guide: Apps in Image + Persistent Volumes + +This configuration implements the best of both worlds: +- **Apps baked into Docker image** for consistency and fast deployments +- **Site data in persistent volumes** for data safety and persistence + +## Architecture Overview + +### What's in the Image (Built once, reusable): +- ✅ Frappe and ERPNext applications +- ✅ All Python dependencies +- ✅ Custom apps (if configured) +- ✅ Basic directory structure + +### What's in Persistent Volumes: +- ✅ Site configurations (`sites/[site-name]/site_config.json`) +- ✅ Uploaded files (`sites/[site-name]/public/files/`) +- ✅ Private files (`sites/[site-name]/private/files/`) +- ✅ Site-specific customizations +- ✅ Database backups +- ✅ Application logs + +## Deployment Steps + +### 1. Set Required Environment Secrets in Zerops + +```bash +# In Zerops Dashboard > Project > Environment Variables +db_password=YourSecureDbPassword123 +admin_password=YourAdminPassword123 +site_name=your-domain.com +``` + +### 2. Deploy the Configuration + +1. Import the `zerops.yml` file to Zerops +2. Zerops will build all services using `Dockerfile.zerops` +3. Each service will run the initialization script on startup +4. Site will be automatically created if it doesn't exist + +### 3. Automatic Initialization Process + +On first deployment, each container will: + +1. **Build Phase** (runs once during image creation): + - Install Frappe/ERPNext apps into image + - Copy initialization scripts + - Set proper permissions + +2. **Runtime Phase** (runs on every container start): + - **Backend service**: Full site initialization (creates site, installs ERPNext) + - **Other services**: Light initialization (just checks if site exists) + - Configure database and Redis connections + - Wait for database to be ready (backend only) + - Set proper permissions and configurations + +## Benefits of This Approach + +### ✅ **Container Restart Resilience** +- Site data survives container restarts/crashes +- No manual intervention required +- Fast recovery times + +### ✅ **Consistent App Deployments** +- Apps are identical across all containers +- No version drift between services +- Easy to update apps (rebuild image) + +### ✅ **Zero-Downtime Updates** +- App updates: rebuild image, rolling update +- Site data preserved during updates +- Database migrations handled automatically + +### ✅ **Backup & Recovery** +- Simple volume snapshots for site data +- Database backups work seamlessly +- Easy disaster recovery + +### ✅ **Scalability** +- New containers start with same apps +- Shared persistent volume for site data +- Auto-scaling works out of the box + +## File Structure + +``` +/home/frappe/frappe-bench/ +├── apps/ # Apps (in image) +│ ├── frappe/ # Frappe framework +│ └── erpnext/ # ERPNext app +├── sites/ # Site data (persistent volume) +│ ├── apps.txt # List of installed apps +│ ├── common_site_config.json +│ └── your-domain.com/ # Your site directory +│ ├── site_config.json +│ ├── public/files/ # Uploaded files +│ └── private/files/ # Private files +└── logs/ # Application logs (persistent volume) +``` + +## Common Operations + +### Adding New Custom Apps + +1. **Update `Dockerfile.zerops`**: + ```dockerfile + RUN bench get-app --branch main custom_app https://github.com/user/custom_app.git + ``` + +2. **Redeploy services** (Zerops will rebuild image) + +3. **Install app on site** (automatic or manual): + ```bash + bench --site your-domain.com install-app custom_app + ``` + +### Updating Frappe/ERPNext Version + +1. **Update version in `Dockerfile.zerops`**: + ```dockerfile + FROM frappe/erpnext:v16.0.0 + ``` + +2. **Update `zerops.yml` environment**: + ```yaml + ERPNEXT_VERSION: v16.0.0 + ``` + +3. **Redeploy** - migrations run automatically + +### Manual Site Operations + +Access any service terminal in Zerops dashboard: + +```bash +# Navigate to bench directory +cd /home/frappe/frappe-bench + +# Run migrations +bench --site your-domain.com migrate + +# Create new site +bench new-site newsite.com --install-app erpnext + +# Install custom app +bench --site your-domain.com install-app custom_app + +# Backup site +bench --site your-domain.com backup --with-files + +# Console access +bench --site your-domain.com console +``` + +## Troubleshooting + +### Site Not Created Automatically +- Check environment variables are set correctly +- Check database connectivity +- Review container logs in Zerops dashboard +- Manually run: `/home/frappe/init-site.sh` + +### Permission Issues +- Persistent volumes should be owned by `frappe:frappe` +- Run: `chown -R frappe:frappe /home/frappe/frappe-bench/sites` + +### App Installation Issues +- Verify apps are in the image: `ls /home/frappe/frappe-bench/apps` +- Check apps.txt: `cat /home/frappe/frappe-bench/sites/apps.txt` +- Manually install: `bench --site [site] install-app [app]` + +### Database Connection Issues +- Verify database service is running +- Check environment variables +- Test connection: `mysql -h$DB_HOST -P$DB_PORT -uroot -p$DB_PASSWORD` + +## Monitoring + +### Health Checks +- All services have health checks configured +- Monitor in Zerops dashboard +- Backend: `/api/method/ping` +- WebSocket: `/socket.io/` + +### Logs +- Application logs in persistent volume: `/home/frappe/frappe-bench/logs` +- Container logs in Zerops dashboard +- Database logs in MariaDB service logs + +### Performance +- Monitor resource usage in Zerops dashboard +- Auto-scaling configured based on CPU/memory +- Adjust container limits as needed + +This hybrid approach gives you the reliability of persistent data with the consistency of containerized applications! \ No newline at end of file diff --git a/ZEROPS_DEPLOYMENT.md b/ZEROPS_DEPLOYMENT.md new file mode 100644 index 00000000..3daf7dbe --- /dev/null +++ b/ZEROPS_DEPLOYMENT.md @@ -0,0 +1,159 @@ +# Deploying Frappe/ERPNext on Zerops + +This repository contains the Zerops configuration file (`zerops.yml`) to deploy Frappe/ERPNext on the Zerops platform. + +## Architecture Overview + +The deployment consists of the following services: + +- **MariaDB** (`db`) - Database service (HA mode) +- **Redis Cache** (`redis-cache`) - Caching layer +- **Redis Queue** (`redis-queue`) - Background job queue +- **Backend** (`backend`) - Main Frappe application server +- **Frontend** (`frontend`) - Nginx reverse proxy +- **WebSocket** (`websocket`) - Real-time communication server +- **Queue Workers** (`queue-short`, `queue-long`) - Background job processors +- **Scheduler** (`scheduler`) - Cron job scheduler + +## Prerequisites + +1. A Zerops account - [Sign up here](https://zerops.io) +2. Access to this GitHub repository +3. Basic knowledge of Frappe/ERPNext + +## Deployment Steps + +### 1. Import Project to Zerops + +1. Log into your Zerops dashboard +2. Click "Import project" +3. Select "Import from Git repository" +4. Enter the repository URL: `https://github.com/UhrinDavid/frappe_docker` +5. Select the `zerops.yml` file +6. Click "Import project" + +### 2. Configure Environment Secrets + +Before deployment, you need to set the following environment secrets in Zerops: + +#### Required Secrets: +- `db_password` - Password for MariaDB database (choose a strong password) +- `site_name` - Your site domain name (e.g., `mycompany.example.com`) + +#### Optional Secrets: +- `ERPNEXT_VERSION` - ERPNext version (default: v15.84.0) + +To set secrets: +1. Go to your project in Zerops dashboard +2. Navigate to each service +3. Go to "Environment variables" section +4. Add the required secrets + +### 3. Deploy the Services + +1. Zerops will automatically start building and deploying all services +2. Monitor the build progress in the Zerops dashboard +3. Wait for all services to reach "Running" status + +### 4. Post-Deployment Setup + +Once all services are running, you need to initialize your Frappe site: + +1. Access the backend service terminal in Zerops dashboard +2. Create your first site: + ```bash + bench new-site your-site-name --db-root-password + ``` + +3. Install ERPNext: + ```bash + bench --site your-site-name install-app erpnext + ``` + +4. Set the site as default: + ```bash + bench use your-site-name + ``` + +5. Create an admin user: + ```bash + bench --site your-site-name add-user admin administrator --password + ``` + +### 5. Access Your Application + +Your Frappe/ERPNext instance will be available at the domain provided by Zerops for the `frontend` service. + +## Configuration Details + +### Resource Allocation + +- **Backend**: 1-3 containers, autoscaling enabled +- **Frontend**: 1-2 containers +- **WebSocket**: 1-2 containers +- **Queue Workers**: 1-3 containers (short), 1-2 containers (long) +- **Scheduler**: 1 container (fixed) +- **Databases**: HA mode for production reliability + +### Health Checks + +All services include health checks to ensure proper operation: +- Backend: `/api/method/ping` +- Frontend: `/api/method/ping` +- WebSocket: `/socket.io/` + +### Autoscaling + +Backend and queue workers have autoscaling configured based on: +- CPU usage threshold: 70% +- Memory usage threshold: 80% + +## Troubleshooting + +### Common Issues + +1. **Services not starting**: Check environment variables are set correctly +2. **Database connection errors**: Verify `db_password` secret is set +3. **Site access issues**: Ensure `site_name` matches your domain + +### Logs + +Access service logs through the Zerops dashboard: +1. Go to your project +2. Select the service +3. Navigate to "Runtime logs" + +### Manual Commands + +To run manual bench commands: +1. Access the backend service terminal +2. Navigate to `/home/frappe/frappe-bench` +3. Run your bench commands + +## Customization + +### Custom Apps + +To add custom Frappe apps: +1. Modify the Dockerfile to include your apps +2. Update the `zerops.yml` build configuration +3. Redeploy the services + +### Environment Variables + +Additional environment variables can be added in the `zerops.yml` file under the `envSecrets` section for each service. + +### Scaling + +Adjust the `minContainers` and `maxContainers` values in `zerops.yml` based on your traffic requirements. + +## Support + +For issues specific to: +- Zerops platform: [Zerops Documentation](https://docs.zerops.io) +- Frappe/ERPNext: [Frappe Documentation](https://docs.frappe.io) +- This deployment setup: Create an issue in this repository + +## License + +This configuration is provided under the same license as the original frappe_docker repository. \ No newline at end of file diff --git a/scripts/init-frappe-site.sh b/scripts/init-frappe-site.sh new file mode 100644 index 00000000..30bb119a --- /dev/null +++ b/scripts/init-frappe-site.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# Frappe Site Initialization Script for Production Deployment +# This script runs before the main service starts to ensure the site exists and is configured + +set -e + +echo "🔧 Initializing Frappe site..." + +# Configuration from environment variables +SITE_NAME=${FRAPPE_SITE_NAME_HEADER:-"localhost"} +DB_PASSWORD=${DB_PASSWORD:-"admin"} +ADMIN_PASSWORD=${ADMIN_PASSWORD:-"admin"} +DB_HOST=${DB_HOST:-"db"} +DB_PORT=${DB_PORT:-"3306"} + +echo "📋 Configuration: Site Name: $SITE_NAME, Database Host: $DB_HOST:$DB_PORT" + +# Navigate to frappe bench directory +cd /home/frappe/frappe-bench + +# Configure database and Redis connections +echo "🔗 Configuring connections..." +bench set-config -g db_host "$DB_HOST" || echo "DB host config already set" +bench set-config -gp db_port "$DB_PORT" || echo "DB port config already set" +bench set-config -g redis_cache "redis://${REDIS_CACHE}:6379" || echo "Redis cache config already set" +bench set-config -g redis_queue "redis://${REDIS_QUEUE}:6379" || echo "Redis queue config already set" +bench set-config -g redis_socketio "redis://${REDIS_QUEUE}:6379" || echo "Redis socketio config already set" +bench set-config -gp socketio_port "${SOCKETIO_PORT}" || echo "Socketio port config already set" + +# Wait for database to be ready +echo "⏳ Waiting for database to be ready..." +for i in {1..30}; do + if mysql -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_PASSWORD" -e "SELECT 1;" >/dev/null 2>&1; then + echo "✅ Database is ready!" + break + fi + echo " Attempt $i/30: Database not ready, waiting 5 seconds..." + sleep 5 +done + +# Check if site exists in persistent volume +if [ -d "sites/$SITE_NAME" ]; then + echo "✅ Site '$SITE_NAME' already exists, updating configuration" + bench --site "$SITE_NAME" set-config db_host "$DB_HOST" + bench --site "$SITE_NAME" set-config db_port "$DB_PORT" + bench use "$SITE_NAME" || echo "Site already set as default" +else + echo "🏗️ Creating new site: $SITE_NAME" + if bench new-site "$SITE_NAME" \ + --db-root-password "$DB_PASSWORD" \ + --admin-password "$ADMIN_PASSWORD" \ + --install-app erpnext \ + --set-default; then + echo "✅ Site created successfully!" + + # Install custom XML importer app + echo "📦 Installing XML Importer app..." + bench get-app --branch main erpnext_xml_importer https://github.com/UhrinDavid/erpnext_xml_importer.git || echo "⚠️ Failed to download XML importer" + bench --site "$SITE_NAME" install-app erpnext_xml_importer || echo "⚠️ XML importer app installation failed" + + bench --site "$SITE_NAME" set-config developer_mode 0 + bench --site "$SITE_NAME" set-config maintenance_mode 0 + echo "🎉 Site '$SITE_NAME' is ready with XML Importer!" + else + echo "❌ Failed to create site. Checking if it exists..." + if [ -d "sites/$SITE_NAME" ]; then + echo "⚠️ Site directory exists but creation failed. Using existing site." + bench use "$SITE_NAME" || echo "Could not set as default" + else + echo "💥 Site creation failed completely. Exiting." + exit 1 + fi + fi +fi + +# Ensure proper ownership of sites directory +chown -R frappe:frappe sites/ || echo "Could not change ownership" +chmod -R 755 sites/ || echo "Could not change permissions" + +echo "✅ Site initialization completed successfully!" \ No newline at end of file diff --git a/scripts/init-service.sh b/scripts/init-service.sh new file mode 100644 index 00000000..377b03d8 --- /dev/null +++ b/scripts/init-service.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Simple service initialization for Frappe services +# This script runs on services that don't need to create sites + +set -e + +SERVICE_NAME=${1:-"frappe-service"} + +echo "🔧 Initializing $SERVICE_NAME..." +cd /home/frappe/frappe-bench + +# Basic configuration (site creation handled by backend service) +if [ -f sites/common_site_config.json ] && [ -n "${FRAPPE_SITE_NAME_HEADER}" ]; then + if [ -d "sites/${FRAPPE_SITE_NAME_HEADER}" ]; then + bench use "${FRAPPE_SITE_NAME_HEADER}" || echo "Site will be set by backend" + fi +fi + +echo "✅ $SERVICE_NAME ready" \ No newline at end of file diff --git a/scripts/init-site.sh b/scripts/init-site.sh new file mode 100644 index 00000000..2ac491c2 --- /dev/null +++ b/scripts/init-site.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +# Frappe Site Initialization Script for Zerops +# This script runs on container start to ensure the site exists + +set -e + +echo "🔧 Initializing Frappe site..." + +# Configuration from environment variables +SITE_NAME=${FRAPPE_SITE_NAME_HEADER:-"localhost"} +DB_PASSWORD=${DB_PASSWORD:-"admin"} +ADMIN_PASSWORD=${ADMIN_PASSWORD:-"admin"} +DB_HOST=${DB_HOST:-"db"} +DB_PORT=${DB_PORT:-"3306"} + +echo "📋 Configuration:" +echo " Site Name: $SITE_NAME" +echo " Database Host: $DB_HOST:$DB_PORT" + +# Navigate to frappe bench directory +cd /home/frappe/frappe-bench + +# Ensure sites directory exists and has proper permissions +mkdir -p sites +chown -R frappe:frappe sites || true + +# Configure database and Redis connections +echo "🔗 Configuring connections..." +bench set-config -g db_host "$DB_HOST" || echo "DB host config already set" +bench set-config -gp db_port "$DB_PORT" || echo "DB port config already set" +bench set-config -g redis_cache "redis://${REDIS_CACHE}:6379" || echo "Redis cache config already set" +bench set-config -g redis_queue "redis://${REDIS_QUEUE}:6379" || echo "Redis queue config already set" +bench set-config -g redis_socketio "redis://${REDIS_QUEUE}:6379" || echo "Redis socketio config already set" +bench set-config -gp socketio_port "${SOCKETIO_PORT}" || echo "Socketio port config already set" + +# Wait for database to be ready +echo "⏳ Waiting for database to be ready..." +for i in {1..30}; do + if mysql -h"$DB_HOST" -P"$DB_PORT" -uroot -p"$DB_PASSWORD" -e "SELECT 1;" >/dev/null 2>&1; then + echo "✅ Database is ready!" + break + fi + echo " Attempt $i/30: Database not ready, waiting 5 seconds..." + sleep 5 +done + +# Check if site already exists in persistent volume +if [ -d "sites/$SITE_NAME" ]; then + echo "✅ Site '$SITE_NAME' already exists, skipping creation" + + # Ensure site is in the current bench context + if [ -f "sites/$SITE_NAME/site_config.json" ]; then + echo "🔧 Updating site configuration..." + bench --site "$SITE_NAME" set-config db_host "$DB_HOST" + bench --site "$SITE_NAME" set-config db_port "$DB_PORT" + bench use "$SITE_NAME" || echo "Site already set as default" + fi +else + echo "🏗️ Creating new site: $SITE_NAME" + + # Create the site with ERPNext + if bench new-site "$SITE_NAME" \ + --db-root-password "$DB_PASSWORD" \ + --admin-password "$ADMIN_PASSWORD" \ + --install-app erpnext \ + --set-default; then + + echo "✅ Site created successfully!" + + # Additional site configuration + bench --site "$SITE_NAME" set-config developer_mode 0 + bench --site "$SITE_NAME" set-config maintenance_mode 0 + + echo "🎉 Site '$SITE_NAME' is ready!" + else + echo "❌ Failed to create site. Checking if it exists..." + if [ -d "sites/$SITE_NAME" ]; then + echo "⚠️ Site directory exists but creation failed. Using existing site." + bench use "$SITE_NAME" || echo "Could not set as default" + else + echo "💥 Site creation failed completely. Exiting." + exit 1 + fi + fi +fi + +# Ensure proper ownership of sites directory +chown -R frappe:frappe sites/ || echo "Could not change ownership" +chmod -R 755 sites/ || echo "Could not change permissions" + +# Final verification +if [ -d "sites/$SITE_NAME" ]; then + echo "✅ Site initialization completed successfully!" + echo "🌐 Site '$SITE_NAME' is ready to serve traffic" +else + echo "❌ Site initialization failed!" + exit 1 +fi \ No newline at end of file diff --git a/scripts/setup-frappe.sh b/scripts/setup-frappe.sh new file mode 100644 index 00000000..d5cb1a69 --- /dev/null +++ b/scripts/setup-frappe.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# Frappe/ERPNext Initial Setup Script for Zerops +# This script should be run after the services are deployed and running + +set -e + +echo "🚀 Starting Frappe/ERPNext setup on Zerops..." + +# Check if required environment variables are set +if [ -z "$SITE_NAME" ]; then + echo "❌ Error: SITE_NAME environment variable is required" + echo " Set it to your domain name (e.g., mycompany.example.com)" + exit 1 +fi + +if [ -z "$DB_PASSWORD" ]; then + echo "❌ Error: DB_PASSWORD environment variable is required" + exit 1 +fi + +if [ -z "$ADMIN_PASSWORD" ]; then + echo "❌ Error: ADMIN_PASSWORD environment variable is required" + echo " This will be the password for the ERPNext admin user" + exit 1 +fi + +echo "📋 Configuration:" +echo " Site Name: $SITE_NAME" +echo " Database Host: ${DB_HOST:-db}" +echo " Admin Email: ${ADMIN_EMAIL:-administrator@$SITE_NAME}" + +# Navigate to frappe bench directory +cd /home/frappe/frappe-bench + +echo "🏗️ Creating new site: $SITE_NAME" +bench new-site "$SITE_NAME" \ + --db-root-password "$DB_PASSWORD" \ + --admin-password "$ADMIN_PASSWORD" \ + --set-default + +echo "📦 Installing ERPNext application..." +bench --site "$SITE_NAME" install-app erpnext + +echo "👤 Setting up admin user..." +if [ -n "$ADMIN_EMAIL" ]; then + bench --site "$SITE_NAME" set-admin-password "$ADMIN_PASSWORD" +fi + +echo "🔧 Final configuration..." +# Set site as default +bench use "$SITE_NAME" + +# Clear cache +bench --site "$SITE_NAME" clear-cache + +# Migrate database (in case there are any pending migrations) +bench --site "$SITE_NAME" migrate + +echo "✅ Setup completed successfully!" +echo "" +echo "🌐 Your ERPNext site is ready at: $SITE_NAME" +echo "👤 Admin login: administrator" +echo "🔑 Admin password: [as set in ADMIN_PASSWORD]" +echo "" +echo "📚 Next steps:" +echo " 1. Configure your domain to point to this Zerops service" +echo " 2. Access your site and complete the setup wizard" +echo " 3. Configure SSL certificates if needed" +echo "" +echo "🔧 Useful commands:" +echo " - bench restart: Restart all processes" +echo " - bench --site $SITE_NAME console: Open Python console" +echo " - bench --site $SITE_NAME migrate: Run database migrations" +echo " - bench update: Update apps and migrate" \ No newline at end of file diff --git a/zerops.env b/zerops.env new file mode 100644 index 00000000..bafa1561 --- /dev/null +++ b/zerops.env @@ -0,0 +1,71 @@ +# Production Environment Configuration for Zerops Deployment +# Copy this file and customize the values for your deployment + +# ============================================================================= +# REQUIRED ZEROPS SECRETS (set these in Zerops Dashboard > Environment Variables) +# ============================================================================= +db_password=your-strong-database-password +admin_password=your-admin-password +site_name=your-domain.com + +# ============================================================================= +# OPTIONAL CONFIGURATION (modify as needed) +# ============================================================================= +ADMIN_EMAIL=admin@your-domain.com +ERPNEXT_VERSION=v15.84.0 + +# Database Configuration (managed by Zerops) +DB_HOST=db +DB_PORT=3306 + +# Redis Configuration (managed by Zerops) +REDIS_CACHE=redis-cache:6379 +REDIS_QUEUE=redis-queue:6379 + +# Application Configuration +SOCKETIO_PORT=9000 +FRAPPE_SITE_NAME_HEADER=your-domain.com + +# Nginx/Proxy Configuration +UPSTREAM_REAL_IP_ADDRESS=127.0.0.1 +UPSTREAM_REAL_IP_HEADER=X-Forwarded-For +UPSTREAM_REAL_IP_RECURSIVE=off +PROXY_READ_TIMEOUT=120s +CLIENT_MAX_BODY_SIZE=50m + +# Frappe/ERPNext Image Configuration +CUSTOM_IMAGE=frappe/erpnext +CUSTOM_TAG=v15.84.0 +PULL_POLICY=always +RESTART_POLICY=unless-stopped + +# Backup Configuration (optional) +# BACKUP_S3_BUCKET=your-backup-bucket +# BACKUP_S3_ACCESS_KEY=your-access-key +# BACKUP_S3_SECRET_KEY=your-secret-key +# BACKUP_S3_REGION=your-region + +# Email Configuration (optional) +# MAIL_SERVER=smtp.your-email-provider.com +# MAIL_PORT=587 +# MAIL_USERNAME=your-email@domain.com +# MAIL_PASSWORD=your-email-password +# MAIL_USE_TLS=true + +# SSL/TLS Configuration (optional, if not using Zerops automatic SSL) +# LETSENCRYPT_EMAIL=your-email@domain.com +# SITES=your-domain.com + +# ============================================================================= +# DEPLOYMENT INSTRUCTIONS +# ============================================================================= +# 1. Set the 3 required secrets in Zerops Dashboard: +# - db_password: Strong password for MariaDB (min 8 chars) +# - admin_password: Password for ERPNext admin user (min 8 chars) +# - site_name: Your domain name (e.g., mycompany.example.com) +# +# 2. Deploy using zerops.yml file +# +# 3. Access your ERPNext site at the domain specified in site_name +# - Username: administrator +# - Password: [value from admin_password secret] \ No newline at end of file diff --git a/zerops.yml b/zerops.yml new file mode 100644 index 00000000..fe048aec --- /dev/null +++ b/zerops.yml @@ -0,0 +1,291 @@ +# Zerops YAML configuration for Frappe/ERPNext deployment +# This file defines the infrastructure and deployment settings for Zerops platform +# Documentation: https://docs.zerops.io/ + +# Import this file in Zerops GUI to create the project with all required services + +project: + name: frappe-erpnext + +services: + # MariaDB Database Service + - hostname: db + type: mariadb + version: "11" + mode: HA + priority: 10 + # Zerops will automatically configure MariaDB with UTF8MB4 + + # Redis Cache Service + - hostname: redis-cache + type: redis + version: "6" + mode: HA + priority: 10 + + # Redis Queue Service + - hostname: redis-queue + type: redis + version: "6" + mode: HA + priority: 10 + + # Main Backend Application (Frappe/ERPNext) + - hostname: backend + type: python + version: "3.11" + buildFromGit: https://github.com/UhrinDavid/frappe_docker@zerops + enableSubdomainAccess: false + minContainers: 1 + maxContainers: 3 + autoscaling: + cpuThreshold: 70 + memoryThreshold: 80 + # Environment variables + envSecrets: + DB_PASSWORD: ${db_password} + ADMIN_PASSWORD: ${admin_password} + ERPNEXT_VERSION: v15.84.0 + DB_HOST: db + DB_PORT: 3306 + REDIS_CACHE: redis-cache + REDIS_QUEUE: redis-queue + SOCKETIO_PORT: 9000 + FRAPPE_SITE_NAME_HEADER: ${site_name} + CUSTOM_IMAGE: frappe/erpnext + CUSTOM_TAG: ${ERPNEXT_VERSION} + # Persistent volumes for site data + volumes: + - name: frappe-sites + mountPath: /home/frappe/frappe-bench/sites + size: 20GB + - name: frappe-logs + mountPath: /home/frappe/frappe-bench/logs + size: 5GB + # Build settings using production Dockerfile + build: + dockerfile: ./images/production/Containerfile + context: . + # Build-time commands to include site and apps in image + buildCommands: + - | + # Install any additional apps during build + # Example: bench get-app --branch main custom_app https://github.com/user/custom_app + echo "Building Frappe image with pre-installed apps..." + # Runtime initialization - deployment specific + runPrepareCommands: + - | + # Copy and execute the site initialization script + cp scripts/init-frappe-site.sh /home/frappe/init-frappe-site.sh + chmod +x /home/frappe/init-frappe-site.sh + chown frappe:frappe /home/frappe/init-frappe-site.sh + + # Run the initialization script as frappe user + su - frappe -c "/home/frappe/init-frappe-site.sh" + # Health check + healthCheck: + httpGet: + port: 8000 + path: /api/method/ping + initialDelaySeconds: 120 + periodSeconds: 30 + + # Frontend/Nginx Proxy Service + - hostname: frontend + type: nginx + version: "1.24" + enableSubdomainAccess: true + minContainers: 1 + maxContainers: 2 + buildFromGit: https://github.com/UhrinDavid/frappe_docker@zerops + # Environment variables for nginx templating + envSecrets: + BACKEND: backend:8000 + SOCKETIO: websocket:9000 + FRAPPE_SITE_NAME_HEADER: ${site_name} + UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1 + UPSTREAM_REAL_IP_HEADER: X-Forwarded-For + UPSTREAM_REAL_IP_RECURSIVE: "off" + PROXY_READ_TIMEOUT: 120s + CLIENT_MAX_BODY_SIZE: 50m + # Build nginx with custom configuration + build: + dockerfile: ./images/production/Containerfile + context: . + # Use the nginx configuration from the frappe image + runPrepareCommands: + - cp /opt/frappe/nginx-template.conf /etc/nginx/conf.d/default.conf.template + - envsubst '$BACKEND $SOCKETIO $FRAPPE_SITE_NAME_HEADER' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf + # Command to run nginx + start: nginx-entrypoint.sh + # Health check + healthCheck: + httpGet: + port: 8080 + path: /api/method/ping + initialDelaySeconds: 30 + periodSeconds: 10 + + # WebSocket Service + - hostname: websocket + type: nodejs + version: "18" + buildFromGit: https://github.com/UhrinDavid/frappe_docker@zerops + enableSubdomainAccess: false + minContainers: 1 + maxContainers: 2 + # Shared persistent volumes for site access + volumes: + - name: frappe-sites + mountPath: /home/frappe/frappe-bench/sites + size: 20GB + # Environment variables + envSecrets: + DB_HOST: db + DB_PORT: 3306 + REDIS_CACHE: redis-cache + REDIS_QUEUE: redis-queue + SOCKETIO_PORT: 9000 + build: + dockerfile: ./images/production/Containerfile + context: . + runPrepareCommands: + - | + # Copy and execute the service initialization script + cp scripts/init-service.sh /home/frappe/init-service.sh + chmod +x /home/frappe/init-service.sh + chown frappe:frappe /home/frappe/init-service.sh + + # Run the initialization script as frappe user + su - frappe -c "/home/frappe/init-service.sh WebSocket" + # Command to run the WebSocket server + start: node /home/frappe/frappe-bench/apps/frappe/socketio.js + # Health check + healthCheck: + httpGet: + port: 9000 + path: /socket.io/ + initialDelaySeconds: 60 + periodSeconds: 30 + + # Queue Worker - Short Tasks + - hostname: queue-short + type: python + version: "3.11" + buildFromGit: https://github.com/UhrinDavid/frappe_docker@zerops + enableSubdomainAccess: false + minContainers: 1 + maxContainers: 3 + # Shared persistent volumes for site access + volumes: + - name: frappe-sites + mountPath: /home/frappe/frappe-bench/sites + size: 20GB + # Environment variables + envSecrets: + DB_HOST: db + DB_PORT: 3306 + REDIS_CACHE: redis-cache + REDIS_QUEUE: redis-queue + build: + dockerfile: ./images/production/Containerfile + context: . + runPrepareCommands: + - | + # Copy and execute the service initialization script + cp scripts/init-service.sh /home/frappe/init-service.sh + chmod +x /home/frappe/init-service.sh + chown frappe:frappe /home/frappe/init-service.sh + + # Run the initialization script as frappe user + su - frappe -c "/home/frappe/init-service.sh 'Queue Worker (Short)'" + # Command to run the worker + start: bench worker --queue short,default + + # Queue Worker - Long Tasks + - hostname: queue-long + type: python + version: "3.11" + buildFromGit: https://github.com/UhrinDavid/frappe_docker@zerops + enableSubdomainAccess: false + minContainers: 1 + maxContainers: 2 + # Shared persistent volumes for site access + volumes: + - name: frappe-sites + mountPath: /home/frappe/frappe-bench/sites + size: 20GB + # Environment variables + envSecrets: + DB_HOST: db + DB_PORT: 3306 + REDIS_CACHE: redis-cache + REDIS_QUEUE: redis-queue + build: + dockerfile: ./images/production/Containerfile + context: . + runPrepareCommands: + - | + # Copy and execute the service initialization script + cp scripts/init-service.sh /home/frappe/init-service.sh + chmod +x /home/frappe/init-service.sh + chown frappe:frappe /home/frappe/init-service.sh + + # Run the initialization script as frappe user + su - frappe -c "/home/frappe/init-service.sh 'Queue Worker (Long)'" + # Command to run the long queue worker + start: bench worker --queue long,default,short + + # Scheduler Service + - hostname: scheduler + type: python + version: "3.11" + buildFromGit: https://github.com/UhrinDavid/frappe_docker@zerops + enableSubdomainAccess: false + minContainers: 1 + maxContainers: 1 + # Shared persistent volumes for site access + volumes: + - name: frappe-sites + mountPath: /home/frappe/frappe-bench/sites + size: 20GB + # Environment variables + envSecrets: + DB_HOST: db + DB_PORT: 3306 + REDIS_CACHE: redis-cache + REDIS_QUEUE: redis-queue + build: + dockerfile: ./images/production/Containerfile + context: . + runPrepareCommands: + - | + # Copy and execute the service initialization script + cp scripts/init-service.sh /home/frappe/init-service.sh + chmod +x /home/frappe/init-service.sh + chown frappe:frappe /home/frappe/init-service.sh + + # Run the initialization script as frappe user + su - frappe -c "/home/frappe/init-service.sh Scheduler" + # Command to run the scheduler + start: bench schedule + +# Required secrets that need to be set in Zerops dashboard: +# - db_password: Database password for MariaDB (e.g., "mySecureDbPassword123") +# - admin_password: ERPNext admin user password (e.g., "myAdminPassword123") +# - site_name: Your site domain name (e.g., "mycompany.example.com") +# +# This configuration includes: +# ✅ Clean Docker image with ERPNext apps (deployment-agnostic) +# ✅ Persistent volumes for site data, uploads, and configurations +# ✅ Deployment-specific initialization via runPrepareCommands +# ✅ Shared volumes across all services that need site access +# +# Benefits: +# - Docker image is reusable across different deployment platforms +# - Site initialization is handled at deployment time (not in image) +# - Container restarts preserve all site data and configurations +# - Apps are consistently deployed across all containers +# - No manual setup required after deployment +# - Fast container startup times +# - Proper separation between image and deployment concerns \ No newline at end of file