setup eu_einvoice app in frappe_docker environment

hey there,

i’m kind of stuck with an issue.

I setup my erpnext with docker-compose and now i wanted to add the eu_einvoice app from github inside the backend container.

i did connect to the container with “docker exec -it erpnext-backend bash” and ran the following commands:

“bench get-app https://github.com/alyf-de/eu_einvoice.git”

“bench —site example.some.domain install-app eu_einvoice”

“bench —site example.some.domain migrate”

and I restarted the container(s) afterwards.

The frontend and the eu_einvoice app was available but when looking into the logs of docker queue-long, queue-short and scheduler all log the same errors.

maybe one of you has the time to look through and maybe help me with my issue.

thanks in advance!

here are the logs from docker and the pwd.yml file (passwords changed)

erpnext-scheduler | Traceback (most recent call last):
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 75, in get_app_commands
erpnext-scheduler | app_command_module = importlib.import_module(f"{app}.commands")
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/usr/local/lib/python3.11/importlib/init.py”, line 126, in import_module
erpnext-scheduler | return _bootstrap._gcd_import(name[level:], package, level)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “”, line 1204, in _gcd_import
erpnext-scheduler | File “”, line 1176, in _find_and_load
erpnext-scheduler | File “”, line 1126, in _find_and_load_unlocked
erpnext-scheduler | File “”, line 241, in _call_with_frames_removed
erpnext-scheduler | File “”, line 1204, in _gcd_import
erpnext-scheduler | File “”, line 1176, in _find_and_load
erpnext-scheduler | File “”, line 1140, in _find_and_load_unlocked
erpnext-scheduler | ModuleNotFoundError: No module named ‘eu_einvoice’
erpnext-scheduler | Traceback (most recent call last):
erpnext-scheduler | File “”, line 198, in _run_module_as_main
erpnext-scheduler | File “”, line 88, in _run_code
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 114, in
erpnext-scheduler | main()
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 20, in main
erpnext-scheduler | click.Group(commands=commands)(prog_name=“bench”)
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/core.py”, line 1442, in call
erpnext-scheduler | return self.main(*args, **kwargs)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/core.py”, line 1363, in main
erpnext-scheduler | rv = self.invoke(ctx)
erpnext-scheduler | ^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/core.py”, line 1830, in invoke
erpnext-scheduler | return _process_result(sub_ctx.command.invoke(sub_ctx))
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/core.py”, line 1827, in invoke
erpnext-scheduler | super().invoke(ctx)
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/core.py”, line 1226, in invoke
erpnext-scheduler | return ctx.invoke(self.callback, **ctx.params)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/core.py”, line 794, in invoke
erpnext-scheduler | return callback(*args, **kwargs)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/env/lib/python3.11/site-packages/click/decorators.py”, line 34, in new_func
erpnext-scheduler | return f(get_current_context(), args, *kwargs)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 44, in app_group
erpnext-scheduler | ctx.obj = {“sites”: get_sites(site), “force”: force, “verbose”: verbose, “profile”: profile}
erpnext-scheduler | ^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py”, line 56, in get_sites
erpnext-scheduler | elif default_site := frappe.get_conf().default_site:
erpnext-scheduler | ^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 406, in get_conf
erpnext-scheduler | with init_site(site):
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 416, in enter
erpnext-scheduler | init(self.site)
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 258, in init
erpnext-scheduler | setup_module_map(include_all_apps=not (frappe.request or frappe.job or frappe.flags.in_migrate))
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 1670, in setup_module_map
erpnext-scheduler | for module in get_module_list(app):
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 1518, in get_module_list
erpnext-scheduler | return get_file_items(get_app_path(app_name, “modules.txt”))
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 1483, in get_app_path
erpnext-scheduler | return get_pymodule_path(app_name, *joins)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 1513, in get_pymodule_path
erpnext-scheduler | return abspath(join(dirname(get_module(scrub(modulename)).file or “”), *joins))
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 1454, in get_module
erpnext-scheduler | return importlib.import_module(modulename)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “/usr/local/lib/python3.11/importlib/init.py”, line 126, in import_module
erpnext-scheduler | return _bootstrap._gcd_import(name[level:], package, level)
erpnext-scheduler | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
erpnext-scheduler | File “”, line 1204, in _gcd_import
erpnext-scheduler | File “”, line 1176, in _find_and_load
erpnext-scheduler | File “”, line 1140, in _find_and_load_unlocked
erpnext-scheduler | ModuleNotFoundError: No module named ‘eu_einvoice’
erpnext-scheduler exited with code 1

and my pwd.yml file looks like this:
services:

backend:

image: frappe/erpnext:v15.83.0

container_name: erpnext-backend

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

environment:

  DB_HOST: db

  DB_PORT: "3306"

  MYSQL_ROOT_PASSWORD: 123456

  MARIADB_ROOT_PASSWORD: 123456

configurator:

image: frappe/erpnext:v15.83.0

container_name: erpnext-configurator

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: none

entrypoint:

  - bash

  - -c

command:

  - >

    ls -1 apps > sites/apps.txt;

    bench set-config -g db_host $$DB_HOST;

    bench set-config -gp db_port $$DB_PORT;

    bench set-config -g redis_cache "redis://$$REDIS_CACHE";

    bench set-config -g redis_queue "redis://$$REDIS_QUEUE";

    bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";

    bench set-config -gp socketio_port $$SOCKETIO_PORT;

environment:

  DB_HOST: db

  DB_PORT: "3306"

  REDIS_CACHE: redis-cache:6379

  REDIS_QUEUE: redis-queue:6379

  SOCKETIO_PORT: "9000"

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

create-site:

image: frappe/erpnext:v15.83.0

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: none

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

entrypoint:

  - bash

  - -c

command:

  - >

    wait-for-it -t 120 db:3306;

    wait-for-it -t 120 redis-cache:6379;

    wait-for-it -t 120 redis-queue:6379;

    export start=\`date +%s\`;

    until \[\[ -n \`grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"\` \]\] && \\

      \[\[ -n \`grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"\` \]\] && \\

      \[\[ -n \`grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"\` \]\];

    do

      echo "Waiting for sites/common_site_config.json to be created";

      sleep 5;

      if (( \`date +%s\`-start > 120 )); then

        echo "could not find sites/common_site_config.json with required keys";

        exit 1

      fi

    done;

    echo "sites/common_site_config.json found";

    bench new-site --mariadb-user-host-login-scope='%' --admin-password=admin --db-root-username=root --db-root-password=123456 --install-app erpnext --set-default example.some.domain;

db:

image: mariadb:10.6

container_name: erpnext-mariadb

networks:

  - frappe_network

healthcheck:

  test: mysqladmin ping -h localhost --password=123456

  interval: 1s

  retries: 20

deploy:

  restart_policy:

    condition: on-failure

command:

  - --character-set-server=utf8mb4

  - --collation-server=utf8mb4_unicode_ci

  - --skip-character-set-client-handshake

  - --skip-innodb-read-only-compressed # Temporary fix for MariaDB 10.6

environment:

  MYSQL_ROOT_PASSWORD: 123456

  MARIADB_ROOT_PASSWORD: 123456

volumes:

  - db-data:/var/lib/mysql

frontend:

image: frappe/erpnext:v15.83.0

container_name: erpnext-frontend

networks:

  - proxy

  - frappe_network

depends_on:

  - websocket

deploy:

  restart_policy:

    condition: on-failure

command:

  - nginx-entrypoint.sh

environment:

  BACKEND: backend:8000

  FRAPPE_SITE_NAME_HEADER: example.some.domain

  SOCKETIO: websocket:9000

  UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1

  UPSTREAM_REAL_IP_HEADER: X-Forwarded-For

  UPSTREAM_REAL_IP_RECURSIVE: "off"

  PROXY_READ_TIMEOUT: 120

  CLIENT_MAX_BODY_SIZE: 50m

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

expose:

  - 8080

queue-long:

image: frappe/erpnext:v15.83.0

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

command:

  - bench

  - worker

  - --queue

  - long,default,short

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

environment:

  FRAPPE_REDIS_CACHE: redis://redis-cache:6379

  FRAPPE_REDIS_QUEUE: redis://redis-queue:6379

queue-short:

image: frappe/erpnext:v15.83.0

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

command:

  - bench

  - worker

  - --queue

  - short,default

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

environment:

  FRAPPE_REDIS_CACHE: redis://redis-cache:6379

  FRAPPE_REDIS_QUEUE: redis://redis-queue:6379

redis-queue:

image: redis:6.2-alpine

container_name: erpnext-redis-queue

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

volumes:

  - redis-queue-data:/data

redis-cache:

image: redis:6.2-alpine

container_name: erpnext-redis-cache

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

scheduler:

image: frappe/erpnext:v15.83.0

container_name: erpnext-scheduler

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

command:

  - bench

  - schedule

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

websocket:

image: frappe/erpnext:v15.83.0

container_name: erpnext-websocket

networks:

  - frappe_network

deploy:

  restart_policy:

    condition: on-failure

command:

  - node

  - /home/frappe/frappe-bench/apps/frappe/socketio.js

environment:

  FRAPPE_REDIS_CACHE: redis://redis-cache:6379

  FRAPPE_REDIS_QUEUE: redis://redis-queue:6379

volumes:

  - sites:/home/frappe/frappe-bench/sites

  - logs:/home/frappe/frappe-bench/logs

  - apps:/home/frappe/frappe-bench/apps

volumes:

db-data:

redis-queue-data:

sites:

logs:

apps:

networks:

frappe_network:

driver: bridge

proxy:

external: true

To add apps in docker do not use bench get-app. Instead to create docker multi-site and multi-app please use easy-install.py: -

  1. wget https://raw.githubusercontent.com/frappe/bench/develop/easy-install.py

  2. git clone GitHub - frappe/frappe_docker: Docker images for production and development setups of the Frappe framework and ERPNext

  3. In “frappe_docker/development/apps-example.json” edit your apps with their branch: -
    [
    { “url”: “https://github.com/frappe/erpnext”, “branch”: “version-15” },
    { “url”: “https://github.com/frappe/hrms”, “branch”: “version-15” },
    { “url”: “https://github.com/frappe/education”, “branch”: “version-15” },
    { “url”: “https://github.com/frappe/crm”, “branch”: “main” },
    { “url”: “https://github.com/frappe/wiki”, “branch”: “master”},
    { “url”: “https://github.com/Aakvatech-Limited/CSF_TZ”, “branch”: “master”}
    ]

  4. python3 easy-install.py build

  5. python3 easy-install.py deploy --image=custom-apps --version=latest --sitename=bench3site1.duckdns.org --sitename=bench3site2.duckdns.org --sitename=bench3site3.duckdns.org --app=erpnext --app=hrms --app=education --app=crm --app=wiki --app=csf_tz

For step 4 and 5 if you want more options rather than default values please check out GitHub - frappe/bench: CLI to manage Multi-tenant deployments for Frappe apps

Don’t forget to add the sites to your host file

Thanks for your reply! I appreciate it, and I will try it.

But to complete my understanding of your solution, i create the site before i start my docker containers?

and do i have to create multiple sites (like bench3site1, bench3site2, etc.) or was that just showing that it is possible to create multiple sites?

where do I find the host file?

most welcome

no need to create sites just put them (even if its one) in step 5 and you should be okay
it was to show that you can create multiple sites so fit your needs

in windows its C:\Windows\System32\drivers\etc but in linux/mac you can ask ChaGPT

best of luck