How to Install Frappe/Erpnext Development Environment using Docker for Windows

Frappe Application Development Tutorial: https://frappe.io/docs/user/en/tutorial

frappe_docker GitHub repository: https://github.com/frappe/frappe_docker

git clone https://github.com/frappe/frappe_docker.git
cd frappe_docker

From now we will use “dbench” for many things. You may be wondering what this “dbench” is, I was wondering the same too. It is a thin wrapper & short script that basically runs the “bench” script but inside your Docker container, hence the “d” prefix. However, there are some special commands that are handled by dbench itself:

./dbench -h
            Shows this help message
./dbench
            Launches you into an interactive shell in the container as user frappe
./dbench <command to send to bench>
            Runs the bench command <command>, i.e. ./dbench new-site "site1.local" = bench new-site "site1.local"
./dbench setup docker [ stop | down ]
            Builds and starts the docker containers using "docker-compose up -d"
./dbench setup hosts
            Adds all site names to the containers hosts file
./dbench -c frappe | root <command to run>
            Runs a command in the container, as the selected user

Other commands are passed directly to bench inside the Docker container.

Docker for Windows only: You can run dbench in Windows e.g. using Git Bash for Windows. However, due to this issue you will get this error: the input device is not a TTY. If you are using mintty, try prefixing the command with ‘winpty’. As a workaround, you will need to prefix winpty to every docker command. Use this before calling any docker command:

alias docker='winpty docker'

Edit in dbench: (currently as PR #86)

    winpty docker exec -itu "${user}" frappe bash -c "$@"

Because of frontmatter bug, you need to edit the following in dbench:

    run frappe "cd .. && bench init frappe-bench --frappe-branch version-12 --ignore-exist --skip-redis-config-generation && cd frappe-bench"

Now you can run:

# This will create Docker containers using: docker-compose up -d
./dbench setup docker
# This will run: bench init frappe-bench
./dbench init

./dbench init in particular will take a long time, because it will download a lot of packages:

ceefour@amanahspectre MINGW64 /d/project_amanah/SatuJuara/frappe_docker (master)
$ ./dbench setup docker
Creating network "frappe_docker_default" with the default driver
Creating redis-cache    ... done
Creating redis-queue    ... done
Creating redis-socketio ... done
Creating mariadb        ... done
Creating frappe         ... done

ceefour@amanahspectre MINGW64 /d/project_amanah/SatuJuara/frappe_docker (master)
$ ./dbench init
WARN: Command not being executed in bench directory
INFO:bench.utils:virtualenv -q env -p /usr/bin/python3
INFO:bench.utils:env/bin/pip -q install -U pip wheel six
INFO:bench.utils:env/bin/pip -q install -e git+https://github.com/frappe/python-
pdfkit.git#egg=pdfkit
INFO:bench.app:getting app frappe
INFO:bench.utils:git clone -q https://github.com/frappe/frappe.git --branch vers
ion-12 --depth 1 --origin upstream
installing frappe
INFO:bench.app:installing frappe
INFO:bench.utils:frappe-bench/env/bin/pip install -q -U -e frappe-bench/apps/fra
ppe
Updating node packages...
INFO:bench.utils:yarn install
yarn install v1.22.0
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning " > bootstrap@4.3.1" has unmet peer dependency "jquery@1.9.1 - 3".
warning " > bootstrap@4.3.1" has unmet peer dependency "popper.js@^1.14.7".
[4/4] Building fresh packages...
Done in 613.80s.
INFO:bench.utils:bench build
yarn run v1.22.0
$ FRAPPE_ENV=production node rollup/build.js
Production mode
✔ Built js/moment-bundle.min.js
✔ Built js/libs.min.js

Building frappe assets...

✔ Built js/checkout.min.js
✔ Built js/dialog.min.js
✔ Built js/modules.min.js
✔ Built js/social.min.js
✔ Built js/web_form.min.js
✔ Built css/frappe-rtl.css
✔ Built css/printview.css
✔ Built js/list.min.js
✔ Built js/chat.js
✔ Built css/form.min.css
✔ Built css/module.min.css
✔ Built css/report.min.css
✔ Built css/list.min.css
✔ Built frappe/css/email.css
✔ Built css/frappe-chat-web.css
✔ Built css/web_form.css
✔ Built css/desk.min.css
✔ Built js/desk.min.js
✔ Built js/barcode_scanner.min.js
✔ Built js/frappe-web.min.js
✔ Built js/bootstrap-4-web.min.js
✔ Built css/frappe-web-b4.css
✔ Built js/data_import_tools.min.js
✔ Built js/frappe-recorder.min.js
✔ Built js/report.min.js
✔ Built js/control.min.js
✔ Built js/form.min.js
✨  Done in 86.689s
Done in 96.37s.
INFO:bench.utils:setting up backups
no crontab for frappe
INFO:bench.utils:setting up auto update
SUCCESS: Bench frappe-bench initialized

Add a new site and start Frappe:

./dbench new-site site1.local
./dbench setup hosts
./dbench start
ceefour@amanahspectre MINGW64 /d/project_amanah/SatuJuara/frappe_docker (master)
$ ./dbench new-site site1.local

Installing frappe...
Updating DocTypes for frappe        : [========================================]
Updating country info               : [========================================]
*** Scheduler is disabled ***

ceefour@amanahspectre MINGW64 /d/project_amanah/SatuJuara/frappe_docker (master)
$ ./dbench setup hosts
stdout is not a tty
127.0.0.1

Troubleshooting: If “./dbench start” fails, and you get output similar to the following:

$ ./dbench start
 17:41:53 system           | redis_socketio.1 started (pid=687)
 17:41:53 redis_socketio.1 | /bin/sh: 1: redis-server: not found
 17:41:53 system           | redis_socketio.1 stopped (rc=127)
 17:41:53 system           | worker_long.1 started (pid=701)
 17:41:53 system           | worker_short.1 started (pid=700)
 17:41:53 system           | schedule.1 started (pid=697)
 17:41:53 system           | watch.1 started (pid=692)
 17:41:53 system           | web.1 started (pid=696)
 17:41:53 system           | redis_queue.1 started (pid=695)
 17:41:53 redis_queue.1    | /bin/sh: 1: redis-server: not found
 17:41:53 system           | redis_queue.1 stopped (rc=127)
 17:41:53 system           | worker_default.1 started (pid=698)
 17:41:53 system           | redis_cache.1 started (pid=699)
 17:41:53 redis_cache.1    | /bin/sh: 1: redis-server: not found
 17:41:53 system           | redis_cache.1 stopped (rc=127)
 17:41:53 system           | socketio.1 started (pid=702)
 17:41:53 system           | sending SIGTERM to worker_long.1 (pid 701)
 17:41:53 system           | sending SIGTERM to watch.1 (pid 692)
 17:41:53 system           | sending SIGTERM to web.1 (pid 696)
 17:41:53 system           | sending SIGTERM to schedule.1 (pid 697)
 17:41:53 system           | sending SIGTERM to worker_default.1 (pid 698)
 17:41:53 system           | sending SIGTERM to socketio.1 (pid 702)
 17:41:53 system           | sending SIGTERM to worker_short.1 (pid 700)
 17:41:53 system           | watch.1 stopped (rc=-15)
 17:41:53 system           | schedule.1 stopped (rc=-15)
 17:41:53 system           | web.1 stopped (rc=-15)
 17:41:53 system           | worker_default.1 stopped (rc=-15)
 17:41:53 system           | worker_long.1 stopped (rc=-15)
 17:41:53 system           | worker_short.1 stopped (rc=-15)
 17:41:53 system           | socketio.1 stopped (rc=-15)

then your problem might be issue #1.

Solution: Make sure that inside Docker container:

  • ~/frappe-bench/Procfile contains exactly like Procfile_docker in frappe_docker repo, and
  • ~/frappe-bench/sites/common_site_config.json contains exactly like sites/common_site_config_docker.json in frappe_docker folder.

Troubleshooting: You may get “bench” errors when running “./dbench start”, and every time you run “./dbench start” you get different set of errors (almost like random or race condition-like):

  • watch.1 | Error: No such command “watch”.
  • watch.1 | Fatal Python error: initfsencoding: Unable to get the locale encoding
  • web.1 | Error: No such command “serve”.
  • web.1 | ImportError: No module named ‘werkzeug.contrib’
  • worker_default.1 | Error: No such command “worker”.
  • schedule.1 | Error: No such command “schedule”.
  • worker_default.1 | Fatal Python error: init_sys_streams: can’t initialize sys standard streams
  • worker_default.1 | ModuleNotFoundError: No module named ‘encodings.latin_1’
  • worker_short.1 | Fatal Python error: initfsencoding: Unable to get the locale encoding
  • worker_short.1 | LookupError: unknown encoding: UTF-8
  • web.1 | OSError: [Errno 16] Device or resource busy: ‘/home/frappe/frappe-bench/env/lib/python3.7/encodings’
$ ./dbench start
 17:51:14 system           | socketio.1 started (pid=758)
 17:51:14 system           | schedule.1 started (pid=755)
 17:51:14 system           | worker_short.1 started (pid=757)
 17:51:14 system           | worker_long.1 started (pid=750)
 17:51:14 system           | web.1 started (pid=753)
 17:51:14 system           | watch.1 started (pid=754)
 17:51:14 system           | worker_default.1 started (pid=756)
 17:51:17 socketio.1       | listening on *: 9000
 17:51:18 web.1            | Usage: bench [OPTIONS] COMMAND [ARGS]…
 17:51:18 web.1            | Try "bench --help" for help.
 17:51:18 web.1            |
 17:51:18 web.1            | Error: No such command "serve".
 17:51:18 worker_short.1   | Usage: bench [OPTIONS] COMMAND [ARGS]…
 17:51:18 worker_short.1   | Try "bench --help" for help.
 17:51:18 worker_short.1   |
 17:51:18 worker_short.1   | Error: No such command "worker".
 17:51:18 system           | web.1 stopped (rc=2)
 17:51:18 system           | sending SIGTERM to worker_long.1 (pid 750)
 17:51:18 system           | sending SIGTERM to watch.1 (pid 754)
 17:51:18 system           | sending SIGTERM to schedule.1 (pid 755)
 17:51:18 system           | sending SIGTERM to worker_default.1 (pid 756)
 17:51:18 system           | sending SIGTERM to socketio.1 (pid 758)
 17:51:18 system           | sending SIGTERM to worker_short.1 (pid 757)
 17:51:18 system           | watch.1 stopped (rc=-15)
 17:51:18 system           | worker_long.1 stopped (rc=-15)
 17:51:18 system           | schedule.1 stopped (rc=-15)
 17:51:18 system           | worker_default.1 stopped (rc=-15)
 17:51:18 system           | worker_short.1 stopped (rc=-15)
 17:51:18 system           | socketio.1 stopped (rc=-15)

Current Workaround: My hypothesis is this is caused by “Device or resource busy” errors when honcho/Python/bench tries to load the same libraries at the same time, and for some reason Docker for Windows is unable to do service these requests. It turns out, by starting the processes at different times (using “sleep” to delay each process), bench will work properly. In order to do that, I use this Procfile:

web: bench serve --port 8000

socketio: /usr/bin/node apps/frappe/socketio.js
watch: sleep 3 && bench watch
schedule: sleep 6 && bench schedule
worker_short: sleep 9 && bench worker --queue short
worker_long: sleep 12 && bench worker --queue long
worker_default: sleep 15 && bench worker --queue default

Tried and Failed: Based on advice here and bench error no such command “worker” issue, file permissions issue:

# Go into Docker container's bash shell
./dbench
# Inside Docker container
sudo chown -R frappe:frappe /src/bench
sudo chown -R frappe:frappe ~
bench update --reset

However, I’ve tried running without honcho (the Python-based Procfile process manager used by bench), and also tried using foreman (the Ruby process manager). I think there is an issue between bench framework and honcho/foreman/process managers, because the commands inside Procfile work fine when run directly/individually, and only throw errors when run by honcho or foreman. Weirdly, I can run with foreman successfully if specifically running a single process. It might also be caused by my Docker environment, on Windows 10.

Try: Editing the Dockerfile and using debian:buster-slim. Also upgrading to Node 12 (although I’d say this has no effect).

Try: Run the commands individually, for example using ConEmu:

docker exec -it frappe bench serve --port 8000
docker exec -it frappe /usr/bin/node apps/frappe/socketio.js
docker exec -it frappe bench watch
docker exec -it frappe bench schedule
docker exec -it frappe bench worker --queue short
docker exec -it frappe bench worker --queue long
docker exec -it frappe bench worker --queue default

Troubleshooting: If you get error below, the solution is downgrade werkzeug.

frappe@565aecade7db:~/frappe-bench$ bench start
20:39:10 system           | worker_long.1 started (pid=1233)
20:39:10 system           | schedule.1 started (pid=1238)
20:39:10 system           | worker_short.1 started (pid=1241)
20:39:10 system           | socketio.1 started (pid=1237)
20:39:10 system           | watch.1 started (pid=1240)
20:39:11 system           | worker_default.1 started (pid=1236)
20:39:11 system           | web.1 started (pid=1239)
20:39:12 socketio.1       | listening on *: 9000
20:39:31 worker_long.1    | 20:39:31 RQ worker 'rq:worker:565aecade7db.1243.long' started, version 0.12.0
20:39:31 worker_long.1    | 20:39:31 *** Listening on long...
20:39:31 worker_long.1    | 20:39:31 Cleaning registries for queue: long
20:39:32 worker_default.1 | 20:39:32 RQ worker 'rq:worker:565aecade7db.1260.default' started, version 0.12.0
20:39:32 worker_default.1 | 20:39:32 *** Listening on default...
20:39:32 worker_default.1 | 20:39:32 Cleaning registries for queue: default
20:39:32 web.1            | Traceback (most recent call last):
20:39:32 web.1            |   File "/usr/lib/python3.5/runpy.py", line 193, in _run_module_as_main
20:39:32 web.1            |     "__main__", mod_spec)
20:39:32 web.1            |   File "/usr/lib/python3.5/runpy.py", line 85, in _run_code
20:39:32 web.1            |     exec(code, run_globals)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 97, in 
20:39:32 web.1            |     main()
20:39:32 web.1            |   File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 18, in main
20:39:32 web.1            |     click.Group(commands=commands)(prog_name='bench')
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/core.py", line 764, in __call__
20:39:32 web.1            |     return self.main(*args, **kwargs)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/core.py", line 717, in main
20:39:32 web.1            |     rv = self.invoke(ctx)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/core.py", line 1137, in invoke
20:39:32 web.1            |     return _process_result(sub_ctx.command.invoke(sub_ctx))
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/core.py", line 1137, in invoke
20:39:32 web.1            |     return _process_result(sub_ctx.command.invoke(sub_ctx))
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/core.py", line 956, in invoke
20:39:32 web.1            |     return ctx.invoke(self.callback, **ctx.params)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/core.py", line 555, in invoke
20:39:32 web.1            |     return callback(*args, **kwargs)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/env/lib/python3.5/site-packages/click/decorators.py", line 17, in new_func
20:39:32 web.1            |     return f(get_current_context(), *args, **kwargs)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 25, in _func
20:39:32 web.1            |     ret = f(frappe._dict(ctx.obj), *args, **kwargs)
20:39:32 web.1            |   File "/home/frappe/frappe-bench/apps/frappe/frappe/commands/utils.py", line 547, in serve
20:39:32 web.1            |     import frappe.app
20:39:32 web.1            |   File "/home/frappe/frappe-bench/apps/frappe/frappe/app.py", line 13, in 
20:39:32 web.1            |     from werkzeug.contrib.profiler import ProfilerMiddleware
20:39:32 web.1            | ImportError: No module named 'werkzeug.contrib'
20:39:32 worker_short.1   | 20:39:32 RQ worker 'rq:worker:565aecade7db.1247.short' started, version 0.12.0
20:39:32 worker_short.1   | 20:39:32 *** Listening on short...
20:39:32 worker_short.1   | 20:39:32 Cleaning registries for queue: short
20:39:33 system           | web.1 stopped (rc=1)
20:39:33 system           | sending SIGTERM to worker_long.1 (pid 1233)
20:39:33 system           | sending SIGTERM to watch.1 (pid 1240)
20:39:33 system           | sending SIGTERM to schedule.1 (pid 1238)
20:39:33 system           | sending SIGTERM to worker_default.1 (pid 1236)
20:39:33 system           | sending SIGTERM to socketio.1 (pid 1237)
20:39:33 system           | sending SIGTERM to worker_short.1 (pid 1241)
20:39:33 worker_long.1    | 20:39:33 Warm shut down requested
20:39:33 worker_default.1 | 20:39:33 Warm shut down requested
20:39:33 worker_short.1   | 20:39:33 Warm shut down requested
20:39:33 system           | socketio.1 stopped (rc=-15)
20:39:33 system           | watch.1 stopped (rc=-15)
20:39:33 system           | schedule.1 stopped (rc=-15)
20:39:33 system           | worker_short.1 stopped (rc=-15)
20:39:33 system           | worker_default.1 stopped (rc=-15)
20:39:33 system           | worker_long.1 stopped (rc=-15)

Troubleshooting:

bench.utils.CommandFailedError: /home/frappe/frappe-bench/env/bin/frappe --use site1.local

Tried: (but still doesn’t restore frappe command)

# Go into Docker container's bash shell
./dbench
# Inside Docker container
sudo chown -R frappe:frappe /src/bench
sudo chown -R frappe:frappe ~
bench update --reset

Troubleshooting: If you get error:

pymysql.err.OperationalError: (1045, “Access denied for user ‘frappe’@’frappe.frappe_docker_default’ (using password: NO)”)

It means your frappe-bench/sites/site1.local/site_config.json file contains wrong DB configuration (should contain correct db_name, db_password, and db_type).

pymysql.err.OperationalError: (1045, “Access denied for user ‘frappe’@’frappe.frappe_docker_default’ (using password: NO)”)

Use Frappe: Open your browser to localhost:8000/login. Then log in using the username Administrator and the password admin.

You will be prompted to create an administrator user, configure the default country, time zone, and currency. Then Frappe will refresh and you will be shown the Desk web-based UI.

Frappe’s Desk web-based UI

At this point, you can use Frappe, and you can also create new apps.

FAQ

Can I install Frappe/Erpnext Development Environment using Ubuntu in Windows 10 Store (aka WSL)?

Unfortunately, I’ve tried using Ubuntu in Windows 10 Store, doesn’t work because MariaDB won’t run.

Although frappe-bench itself will work, I think a better and more consistent/cross-platform approach is the Docker way.

References

0

Leave a Comment

Your email address will not be published. Required fields are marked *