frappe_docker

repository·main·Indexed 25 days ago

https://github.com/frappe/frappe_docker

Official Docker images, Compose configurations, and orchestration tools for running Frappe applications such as ERPNext, CRM, and Helpdesk. It provides a multi-service architecture including a configurator, backend (Gunicorn), frontend (Nginx), websocket (Socket.IO), and background workers. The repository offers various deployment methods ranging from disposable demo setups via pwd.yml and VS Code Devcontainers for development to manual production deployments using compose.yaml with overrides for MariaDB, PostgreSQL, Redis, and proxies like Traefik or nginx-proxy.

Tokens
41.2K
Snippets
100
Records
180
Agent score
81%

What's inside frappe_docker

  1. Built-in Features of Frappe Apps

    main

    Every Frappe app automatically inherits several core features without manual implementation:

    • REST API: Automatic CRUD endpoints derived from DocType definitions.
    • Permissions system: Row-level and field-level access control.
    • Audit trails: Automatic version tracking and change history.
    • Custom fields: Ability to add fields at runtime without code changes.
    • Workflows: Configurable approval and state management.
    • Reports: Built-in query builder and report designer.
    • Print formats: PDF generation using custom templates.
    • Email integration: Template-based email sending.
    • File attachments: Management of document attachments.
  2. Compare Frappe to Django concepts

    main

    For developers transitioning from Django, Frappe uses different terminology and architectural patterns. While Django is often used for consumer web apps, Frappe is optimized for business applications (ERP, CRM) with built-in multi-tenancy, background jobs, and real-time capabilities.

    Conceptual Mapping

    DjangoFrappeNotes
    ModelDocTypeIncludes UI, permissions, and API automatically
    ViewController methodRequires significantly less code
    AdminDeskMore powerful, auto-generated
    DRF SerializerBuilt-inAutomatic from DocType definition
    Celery taskBackground jobBuilt-in, no separate setup required
    signalshooks.pyMore structured
    Management commandbench commandMore discoverable

    Key Architectural Differences

    • Multi-tenancy: Django typically uses one app per database. Frappe allows one installation to host many sites, each with its own database.
    • Background Jobs: Django requires Celery, Redis, and worker setup. Frappe has a built-in queue system using enqueue().
    • Real-time: Django requires Channels, Redis, and ASGI. Frappe has Socket.IO built-in for automatic DocType updates.
    • API: Django requires manual DRF setup. Frappe provides automatic REST and RPC from DocType definitions.
  3. Understand the Frappe Docker multi-service architecture

    main

    Frappe Docker uses a multi-service architecture to handle web serving, background jobs, and real-time communication. The core services include:

    • configurator: An initialization service that configures database and Redis connections; it runs on startup and then exits.
    • backend: A Werkzeug development server for dynamic content processing.
    • frontend: An Nginx reverse proxy that serves static assets and routes requests.
    • websocket: A Node.js server running Socket.IO for real-time communications.
    • queue-short/long: Python workers using RQ (Redis Queue) for asynchronous background job processing.
    • scheduler: A Python service that runs scheduled tasks.

    Additional services like db (MariaDB or PostgreSQL) and redis-cache/queue are added via compose overrides.

  4. How services interact in Frappe Docker

    main

    The interaction flow between services follows this pattern:

    User Request Flow:

    1. frontend (Nginx): Serves static files directly or routes requests to the backend.
    2. backend (Werkzeug): Processes dynamic content and interacts with the database and cache.
    3. db (MariaDB/Postgres) & redis-cache: Provide data persistence and caching.

    Background Task Flow:

    1. scheduler triggers tasks.
    2. Tasks are placed in redis-queue.
    3. queue-short/long workers consume and execute the tasks.

    Real-time Flow:

    1. websocket (Socket.IO) communicates with the client and interacts with redis-cache.
    User Request
        ↓
    [frontend (Nginx)] → Static files served directly
        ↓
    [backend (Werkzeug)] → Dynamic content processing
        ↓                    ↓
    [db (MariaDB)]      [redis-cache]
    
    Background Tasks:
    [scheduler] → [redis-queue] → [queue-short/long workers]
    
    Real-time:
    [websocket (Socket.IO)] ←→ [redis-cache]
  5. Understand Bind Mounts vs Named Volumes vs Anonymous Volumes

    main

    When configuring Docker for Frappe, choose the volume type based on your use case:

    • Bind Mount: Maps a specific host path to a container path (./host/path:/container/path). Best for development (editing code) and overriding configuration files. Data lives on your host filesystem.
    • Named Volume: Uses a Docker-managed volume name (volume_name:/container/path). Best for production data and databases as it is managed by Docker and persists across container deletions.
    • Anonymous Volume: Maps only a container path (/container/path). Best for temporary or cache data that does not need to persist.
  6. Manage build cache invalidation with CACHE_BUST

    main

    When building custom images, Docker may reuse cached layers even if your apps.json secret has changed, because secret contents are not part of the standard Docker layer cache keys. To force a rebuild of the Frappe layer when your app definitions change, use the CACHE_BUST build argument.

    Depending on your requirements, you can pass different values to CACHE_BUST:

    • Timestamp: Forces a rebuild on every run (e.g., $(date +%s)).
    • Pipeline Run ID: Rebuilds once per CI run (e.g., $GITHUB_RUN_ID).
    • Commit SHA: Rebuilds once per commit (e.g., $GITHUB_SHA).
    • apps.json hash: Rebuilds only when the apps.json file content changes. This is the most efficient method but requires pinning specific commits or releases in apps.json to be truly effective.
  7. Understand Docker Bind Mounts and Volumes

    main

    Frappe Docker uses different volume types to manage data persistence and development workflows:

    1. Bind Mounts (./host/path:/container/path): Connects a host directory to a container directory. Best for development (editing code on host) and configuration (overriding files with :ro for read-only).
    2. Named Volumes (volume_name:/container/path): Managed by Docker. Best for production data (e.g., MariaDB/MySQL databases) to ensure persistence across container deletions.
    3. Anonymous Volumes (/container/path): Managed by Docker. Best for temporary/cache data.

    Performance Tip (macOS/Windows): Since Docker runs in a VM on these platforms, use mount flags to optimize speed:

    • :cached: Host writes are buffered. Recommended for most development.
    • :delegated: Container writes are buffered. Best for heavy container writes.
    • :consistent: Full synchronization. Slowest but safest.
    services:
      backend:
        volumes:
          # Development: Edit code on host
          - ./my_custom_app:/home/frappe/frappe-bench/apps/my_custom_app
          # Configuration: Read-only override
          - ./custom-config.json:/home/frappe/frappe-bench/sites/common_site_config.json:ro
          # Performance optimized for macOS/Windows
          - ./development:/home/frappe/frappe-bench:cached
    
      db:
        volumes:
          - db_data:/var/lib/mysql
    
    volumes:
      db_data:
  8. Custom App Directory Structure

    main

    A Frappe custom app follows a specific directory structure to organize business logic, data models, and assets. Key components include:

    • hooks.py: Configures the app and defines hooks into the Frappe lifecycle.
    • modules.txt: Lists the business modules contained within the app.
    • my_custom_app/config/desktop.py: Defines workspace icons and shortcuts.
    • my_custom_app/my_module/doctype/: Contains the data models (DocTypes), including Python controllers (.py), JSON schema definitions (.json), and frontend logic (.js).
    • my_custom_app/public/: Stores static assets like CSS, JS, and images.
    • my_custom_app/templates/: Contains Jinja2 templates for web pages.
    • my_custom_app/www/: Contains web pages accessible via specific routes.
    • requirements.txt: Lists Python package dependencies.
    my_custom_app/
    ├── hooks.py                          # App configuration and hooks into Frappe lifecycle
    ├── modules.txt                       # List of business modules in this app
    ├── my_custom_app/
    │   ├── __init__.py
    │   ├── config/
    │   │   └── desktop.py                # Desktop workspace icons and shortcuts
    │   ├── my_module/
    │   │   ├── doctype/
    │   │   │   ├── customer/
    │   │   │   │   ├── customer.py       # Python controller (business logic)
    │   │   │   │   ├── customer.json     # Model definition (schema, validation)
    │   │   │   │   └── customer.js       # Frontend logic (UI interactions)
    │   │   └── page/
    │   ├── public/
    │   ├── templates/
    │   └── www/
    └── requirements.txt                  # Python package dependencies
  9. Understand how assets are handled in Frappe Docker

    main

    In Frappe Docker, assets are managed using a symlink strategy to decouple build-time artifacts from persistent site data. This prevents stale assets from surviving image updates and ensures that assets always match the version of the container image being run.

    The Architecture

    During the image build, assets are moved from the sites/assets directory to a top-level assets/ directory. The sites/assets path is then replaced with a symlink pointing to the top-level directory.

    At runtime, the directory structure looks like this:

    /home/frappe/frappe-bench/
    ├── assets/          ← image layer (ephemeral, always matches the image)
    ├── sites/
    │   ├── assets -> /home/frappe/frappe-bench/assets    ← symlink
    │   ├── common_site_config.json                       ← persisted in volume
    │   └── <site>/                                       ← persisted in volume
    └── logs/            ← persisted in volume

    Volume Persistence Mapping

    PathPersistentSource
    sites/ (except assets)✅ YesNamed volume (sites)
    sites/assets (symlink)✅ Yes (symlink itself)Named volume (sites)
    assets/ (symlink target)❌ NoImage layer
    logs/✅ YesUnnamed volume

    Because the symlink is recreated in the container ENTRYPOINT, it automatically repairs older or pre-existing sites volumes that might not contain the symlink.

  10. Conceptual mapping between Django and Frappe

    main

    If you are coming from a Django background, use this mapping to understand Frappe's core abstractions:

    DjangoFrappeNotes
    ModelDocTypeIncludes UI, permissions, and API automatically
    ViewController methodRequires significantly less code
    AdminDeskMore powerful and auto-generated
    DRF SerializerBuilt-inAutomatic from DocType definition
    Celery taskBackground jobBuilt-in, no separate setup required
    signalshooks.pyMore structured approach
    Management commandbench commandMore discoverable

    Key Architectural Differences

    • Multi-tenancy: While Django typically maps one app to one database, a single Frappe installation supports many sites, each with its own database.
    • Background Jobs: Unlike Django which requires Celery, Redis, and worker setup, Frappe has a built-in queue system accessible via enqueue().
    • Real-time: Frappe includes Socket.IO built-in for automatic DocType updates, whereas Django requires Channels, Redis, and ASGI setup.
    • API: Frappe provides automatic REST and RPC endpoints derived directly from DocType definitions, avoiding the manual setup of serializers and views required in Django REST Framework (DRF).
  11. Understand Docker Immutability and Persistence in Frappe

    main

    In Frappe Docker deployments, containers are treated as immutable. You should not attempt to modify the internal state of a running container. Instead, configuration changes should be handled through environment variables, mounted volumes, or by rebuilding the Docker image.

    What is Persistent

    Only specific paths are designed to survive container recreation:

    • Site data (/sites)
    • Database storage

    This architecture allows you to safely recreate containers, run migrations, perform backups/restores, and create new sites without losing core data.