Skip to content

Rework and centralize app image build and publish workflows for registries #1828

@Rocket-Quack

Description

@Rocket-Quack

Hello everyone 🦆,

I am currently working on simplifying the operation of Docker for newbies or people who don't have much Docker experience with a script in the style of easy-install from Frappe using TUI (gum).
What I noticed during development and for some time now is that the workflows for building a Docker image differ depending on the repo and apparently also use different approaches.

I would like to tackle this and build the whole thing in a more systematic way.

I have already given it some thought, but so far I haven't come up with a solution that I think is great and should be used.

As a basis, I'm just going to take the four “big” Frappe apps (Erpnext, crm, helpdesk, and lms) and warn you that this could be a long text, but I think it's especially valuable for the future of Frappe apps and Docker.

First, I'd like to discuss the current situation.

Current Situation

The current setup appears to be historically split:
ERPNext triggers image builds centrally in frappe_docker, while CRM, Helpdesk and LMS still build in their own repositories (using frappe_docker layered build context) and publish mainly to GHCR.

This mixed model likely grew over time and is now harder to maintain consistently and is also difficult to understand from a technical perspective for Docker operation (except, of course, for people who build their own Docker image).

Proposed future

I propose a hybrid model for (now the big four/in the future all) the Frappe Apps.
Whats a Hybrid Model?
ERPNext, CRM, HRMS and LMS should only define when an image build is triggered and which app ref should be built, while frappe_docker should own the reusable workflow for how images are built, tested, tagged, and published. (ERPNext is doeing something like that already)

Practice example

In practice an app repo calls the reusable workflow in frappe_docker via workflow_call, passing inputs like app_repo, app_ref, and frappe_branch. The central workflow then builds the image using shared Dockerfiles from frappe_docker (typically images/layered/Containerfile), and pushes the resulting image to both registries (Docker Hub and GHCR app namespace, e.g. ghcr.io/frappe/crm).

flowchart TD
  A[frappe/crm release or dispatch] --> B[crm caller workflow]
  C[frappe/erpnext release or dispatch] --> D[erpnext caller workflow]
  B --> E[Checkout frappe_docker build context]
  D --> E
  E --> F[Build image]
  F --> H[(Docker Hub)]
  F --> I[(GHCR)]
Loading

Alternatives (maybe some bad ones and good ones)

I have also considered possible alternatives, but I am curious to hear your opinion

  1. Keep the current setup
    Each app repository keeps its own build/publish workflow and only applies small fixes.
    Pros: no effort
    Cons: duplicated logic, inconsistent building/tagging/publishing, higher long-term maintenance

  2. Fully centralized model
    Only frappe_docker triggers and builds all app images directly
    Pros: maximum central control and standardization
    Cons: stronger coupling, more operational bottleneck risk, less app-repo autonomy, repo developer lost authority over building

Additional topic: decouple ERPNext from default image building

images/production/Containerfile is also tightly coupled to ERPNext today (bench get-app erpnext is hardcoded), so the current default build path is not fully app free. (Maybe someone knows why and where this comes from i thin also historical 🤔 )
Because of this i suggest treating ERPNext decoupling as a dedicated follow-up step after workflow standardization.

This will likely require multiple PRs and should be done incrementally but in my opinion this is becoming increasingly necessary as the number of Frappe apps grows otherwise the current mixed setup will continue to increase overhead and complexity.

I think the more we pursue the approach of keeping everything related to Docker in Frappe Docker within reasonable limits, the better. Please feel free to share your thoughts or other approaches that I havent thought of yet.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions