2
0
mirror of https://github.com/frappe/frappe_docker.git synced 2024-12-24 11:05:29 +00:00

Merge pull request #149 from frappe/develop

chore: tag versions for erpnext-nginx and frappe-nginx
This commit is contained in:
Revant Nandgaonkar 2020-03-16 21:58:09 +05:30 committed by GitHub
commit 65b8e797b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1348 additions and 580 deletions

View File

@ -0,0 +1,12 @@
{
"name": "Frappe Bench",
"appPort": [8000, 9000, 6787],
"remoteUser": "frappe",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"dockerComposeFile": "./docker-compose.yml",
"service": "frappe",
"workspaceFolder": "/workspace/development",
"shutdownAction": "stopCompose"
}

View File

@ -0,0 +1,31 @@
version: "3.7"
services:
mariadb:
image: mariadb:10.3
environment:
- MYSQL_ROOT_PASSWORD=123
- MYSQL_USER=root
volumes:
- ../installation/frappe-mariadb.cnf:/etc/mysql/conf.d/frappe.cnf
- mariadb-vol:/var/lib/mysql
redis-cache:
image: redis:alpine
redis-queue:
image: redis:alpine
redis-socketio:
image: redis:alpine
frappe:
image: frappe/bench:latest
command: sleep infinity
volumes:
- ..:/workspace:cached
ports:
- "8000:8000"
- "9000:9000"
volumes:
mariadb-vol:

3
.gitignore vendored
View File

@ -5,3 +5,6 @@
# mounted volume # mounted volume
sites sites
development
!development/README.md

View File

@ -1,6 +1,6 @@
sudo: required sudo: required
dist: xenial dist: bionic
services: services:
- docker - docker
@ -13,189 +13,100 @@ before_install:
- if [[ $BUILD == "development" ]];then - if [[ $BUILD == "development" ]];then
sudo apt-get update && sudo apt-get -y install docker-compose; sudo apt-get update && sudo apt-get -y install docker-compose;
fi fi
- chmod u+x ./travis.py
after_success: after_success:
- docker --version - docker --version
matrix: jobs:
include: include:
- name: "Build Frappe python environment (edge)" - stage: "Build Frappe bench development environment (latest)"
if: branch = develop AND type != pull_request if: branch = develop AND type != pull_request
script: script:
- docker build -t frappe-worker -f build/frappe-worker/Dockerfile . - docker build -t frappe/bench:latest -f build/bench/Dockerfile .
- docker tag frappe-worker frappe/frappe-worker:edge - docker push frappe/bench:latest
- docker tag frappe-worker frappe/frappe-worker:develop - stage: "Frappe (edge)"
- docker push frappe/frappe-worker:edge
- docker push frappe/frappe-worker:develop
- name: "Build Frappe nginx + static assets (edge)"
if: branch = develop AND type != pull_request if: branch = develop AND type != pull_request
script: script:
- docker build -t frappe-assets -f build/frappe-assets/Dockerfile . - ./travis.py frappe --worker --tag edge
- docker tag frappe-assets frappe/frappe-assets:edge - ./travis.py frappe --worker --tag develop --tag-only
- docker tag frappe-assets frappe/frappe-assets:develop - stage: "Frappe (edge)"
- docker push frappe/frappe-assets:edge
- docker push frappe/frappe-assets:develop
- name: "Build ERPNext python environment (edge)"
if: branch = develop AND type != pull_request if: branch = develop AND type != pull_request
script: script:
- docker build -t erpnext-worker -f build/erpnext-worker/Dockerfile . - ./travis.py frappe --nginx --tag edge
- docker tag erpnext-worker frappe/erpnext-worker:edge - ./travis.py frappe --nginx --tag develop --tag-only
- docker tag erpnext-worker frappe/erpnext-worker:develop - stage: "Frappe (edge)"
- docker push frappe/erpnext-worker:edge
- docker push frappe/erpnext-worker:develop
- name: "Build ERPNext nginx + static assets (edge)"
if: branch = develop AND type != pull_request if: branch = develop AND type != pull_request
script: script:
- docker build -t erpnext-assets -f build/erpnext-assets/Dockerfile . - ./travis.py frappe --socketio --tag edge
- docker tag erpnext-assets frappe/erpnext-assets:edge - ./travis.py frappe --socketio --tag develop --tag-only
- docker tag erpnext-assets frappe/erpnext-assets:develop - stage: "ERPNext (edge)"
- docker push frappe/erpnext-assets:edge
- docker push frappe/erpnext-assets:develop
- name: "Build Frappe socketio service (edge)"
if: branch = develop AND type != pull_request if: branch = develop AND type != pull_request
script: script:
- docker build -t frappe-socketio -f build/frappe-socketio/Dockerfile . - ./travis.py erpnext --worker --tag edge
- docker tag frappe-socketio frappe/frappe-socketio:edge - ./travis.py erpnext --worker --tag develop --tag-only
- docker tag frappe-socketio frappe/frappe-socketio:develop - stage: "ERPNext (edge)"
- docker push frappe/frappe-socketio:edge if: branch = develop AND type != pull_request
- docker push frappe/frappe-socketio:develop script:
- name: "Build Frappe python environment (v12)" - ./travis.py erpnext --nginx --tag edge
- ./travis.py erpnext --nginx --tag develop --tag-only
- stage: "Frappe (v12)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/frappe --branch version-12 - ./travis.py frappe --worker --git-branch 12
- cd frappe - ./travis.py frappe --worker --tag v12 --tag-only
- git fetch --tags - ./travis.py frappe --worker --tag version-12 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v12*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "Frappe (v12)"
- cd ..
- docker build -t frappe/frappe-worker:$VERSION -f build/frappe-worker/v12.Dockerfile .
- docker tag frappe/frappe-worker:$VERSION frappe/frappe-worker:version-12
- docker tag frappe/frappe-worker:$VERSION frappe/frappe-worker:v12
- docker push frappe/frappe-worker:$VERSION
- docker push frappe/frappe-worker:version-12
- docker push frappe/frappe-worker:v12
- name: "Build Frappe nginx + static assets (v12)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/frappe --branch version-12 - ./travis.py frappe --nginx --git-branch 12
- cd frappe - ./travis.py frappe --nginx --tag v12 --tag-only
- git fetch --tags - ./travis.py frappe --nginx --tag version-12 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v12*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "Frappe (v12)"
- cd ..
- docker build -t frappe/frappe-assets:$VERSION -f build/frappe-assets/v12.Dockerfile .
- docker tag frappe/frappe-assets:$VERSION frappe/frappe-assets:version-12
- docker tag frappe/frappe-assets:$VERSION frappe/frappe-assets:v12
- docker push frappe/frappe-assets:$VERSION
- docker push frappe/frappe-assets:version-12
- docker push frappe/frappe-assets:v12
- name: "Build ERPNext python environment (v12)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/erpnext --branch version-12 - ./travis.py frappe --socketio --git-branch 12
- cd erpnext - ./travis.py frappe --socketio --tag v12 --tag-only
- git fetch --tags - ./travis.py frappe --socketio --tag version-12 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v12*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "ERPNext (v12)"
- cd ..
- docker build -t frappe/erpnext-worker:$VERSION -f build/erpnext-worker/v12.Dockerfile .
- docker tag frappe/erpnext-worker:$VERSION frappe/erpnext-worker:version-12
- docker tag frappe/erpnext-worker:$VERSION frappe/erpnext-worker:v12
- docker push frappe/erpnext-worker:$VERSION
- docker push frappe/erpnext-worker:version-12
- docker push frappe/erpnext-worker:v12
- name: "Build ERPNext nginx + static assets (v12)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/erpnext --branch version-12 - ./travis.py erpnext --worker --git-branch 12
- cd erpnext - ./travis.py erpnext --worker --tag v12 --tag-only
- git fetch --tags - ./travis.py erpnext --worker --tag version-12 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v12*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "ERPNext (v12)"
- cd ..
- docker build -t frappe/erpnext-assets:$VERSION -f build/erpnext-assets/v12.Dockerfile .
- docker tag frappe/erpnext-assets:$VERSION frappe/erpnext-assets:version-12
- docker tag frappe/erpnext-assets:$VERSION frappe/erpnext-assets:v12
- docker push frappe/erpnext-assets:$VERSION
- docker push frappe/erpnext-assets:version-12
- docker push frappe/erpnext-assets:v12
- name: "Build Frappe socketio service (v12)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/frappe --branch version-12 - ./travis.py erpnext --nginx --git-branch 12
- cd frappe - ./travis.py erpnext --nginx --tag v12 --tag-only
- git fetch --tags - ./travis.py erpnext --nginx --tag version-12 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v12*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "Frappe (v11)"
- cd ..
- docker build -t frappe/frappe-socketio:$VERSION -f build/frappe-socketio/v12.Dockerfile .
- docker tag frappe/frappe-socketio:$VERSION frappe/frappe-socketio:version-12
- docker tag frappe/frappe-socketio:$VERSION frappe/frappe-socketio:v12
- docker push frappe/frappe-socketio:$VERSION
- docker push frappe/frappe-socketio:version-12
- docker push frappe/frappe-socketio:v12
- name: "Build Frappe python environment (v11)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/frappe --branch version-11 - ./travis.py frappe --worker --git-branch 11
- cd frappe - ./travis.py frappe --worker --tag v11 --tag-only
- git fetch --tags - ./travis.py frappe --worker --tag version-11 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v11*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "Frappe (v11)"
- cd ..
- docker build -t frappe/frappe-worker:$VERSION -f build/frappe-worker/v11.Dockerfile .
- docker tag frappe/frappe-worker:$VERSION frappe/frappe-worker:version-11
- docker tag frappe/frappe-worker:$VERSION frappe/frappe-worker:v11
- docker push frappe/frappe-worker:$VERSION
- docker push frappe/frappe-worker:version-11
- docker push frappe/frappe-worker:v11
- name: "Build Frappe nginx + static assets (v11)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/frappe --branch version-11 - ./travis.py erpnext frappe --nginx --git-branch 11
- cd frappe - ./travis.py erpnext frappe --nginx --tag v11 --tag-only
- git fetch --tags - ./travis.py erpnext frappe --nginx --tag version-11 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v11*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "Frappe (v11)"
- cd ..
- docker build -t frappe/frappe-assets:$VERSION -f build/frappe-assets/v11.Dockerfile .
- docker tag frappe/frappe-assets:$VERSION frappe/frappe-assets:version-11
- docker tag frappe/frappe-assets:$VERSION frappe/frappe-assets:v11
- docker push frappe/frappe-assets:$VERSION
- docker push frappe/frappe-assets:version-11
- docker push frappe/frappe-assets:v11
- name: "Build ERPNext python environment (v11)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/erpnext --branch version-11 - ./travis.py frappe --socketio --git-branch 11
- cd erpnext - ./travis.py frappe --socketio --tag v11 --tag-only
- git fetch --tags - ./travis.py frappe --socketio --tag version-11 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v11*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "ERPNext (v11)"
- cd ..
- docker build -t frappe/erpnext-worker:$VERSION -f build/erpnext-worker/v11.Dockerfile .
- docker tag frappe/erpnext-worker:$VERSION frappe/erpnext-worker:version-11
- docker tag frappe/erpnext-worker:$VERSION frappe/erpnext-worker:v11
- docker push frappe/erpnext-worker:$VERSION
- docker push frappe/erpnext-worker:version-11
- docker push frappe/erpnext-worker:v11
- name: "Build ERPNext nginx + static assets (v11)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/erpnext --branch version-11 - ./travis.py erpnext --worker --git-branch 11
- cd erpnext - ./travis.py erpnext --worker --tag v11 --tag-only
- git fetch --tags - ./travis.py erpnext --worker --tag version-11 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v11*" | sed -n 1p | sed -e 's#.*@\(\)#\1#') - stage: "ERPNext (v11)"
- cd ..
- docker build -t frappe/erpnext-assets:$VERSION -f build/erpnext-assets/v11.Dockerfile .
- docker tag frappe/erpnext-assets:$VERSION frappe/erpnext-assets:version-11
- docker tag frappe/erpnext-assets:$VERSION frappe/erpnext-assets:v11
- docker push frappe/erpnext-assets:$VERSION
- docker push frappe/erpnext-assets:version-11
- docker push frappe/erpnext-assets:v11
- name: "Build Frappe socketio service (v11)"
if: branch = master AND type != pull_request if: branch = master AND type != pull_request
script: script:
- git clone https://github.com/frappe/frappe --branch version-11 - ./travis.py erpnext --nginx --git-branch 11
- cd frappe - ./travis.py erpnext --nginx --tag v11 --tag-only
- git fetch --tags - ./travis.py erpnext --nginx --tag version-11 --tag-only
- export VERSION=$(git tag --list --sort=-version:refname "v11*" | sed -n 1p | sed -e 's#.*@\(\)#\1#')
- cd ..
- docker build -t frappe/frappe-socketio:$VERSION -f build/frappe-socketio/v11.Dockerfile .
- docker tag frappe/frappe-socketio:$VERSION frappe/frappe-socketio:version-11
- docker tag frappe/frappe-socketio:$VERSION frappe/frappe-socketio:v11
- docker push frappe/frappe-socketio:$VERSION
- docker push frappe/frappe-socketio:version-11
- docker push frappe/frappe-socketio:v11

14
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-vscode-remote.remote-containers",
"ms-python.python"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
]
}

263
README.md
View File

@ -1,4 +1,4 @@
### Getting Started ## Getting Started
The templates in this repository will help deploy Frappe/ERPNext docker in a production environment. The templates in this repository will help deploy Frappe/ERPNext docker in a production environment.
@ -8,31 +8,15 @@ This docker installation takes care of the following:
* Setting up all the system requirements: eg. MariaDB, Node, Redis. * Setting up all the system requirements: eg. MariaDB, Node, Redis.
* [OPTIONAL] Configuring networking for remote access and setting up LetsEncrypt * [OPTIONAL] Configuring networking for remote access and setting up LetsEncrypt
### Installation Process For docker based development refer to this [README](development/README.md)
#### Setting up Pre-requisites ## Deployment
### Setting up Pre-requisites
This repository requires Docker and Git to be setup on the instance to be used. This repository requires Docker and Git to be setup on the instance to be used.
#### Setup Letsencrypt Nginx Proxy Companion ### Cloning the repository and preliminary steps
This is an optional first step. This step is only required if you want to have SSL setup on your docker instance.
This step also assumes that the DNS is preconfigured since it automatically handles setup and renewal of SSL certificates.
For more details, see: https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion
To setup the proxy companion, run the following steps:
```sh
cd $HOME
git clone https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion.git
cd docker-compose-letsencrypt-nginx-proxy-companion
cp .env.sample .env
./start.sh
```
#### Setting up Frappe/ERPNext Docker
Clone this repository somewhere in your system: Clone this repository somewhere in your system:
@ -43,7 +27,7 @@ cd frappe_docker
Copy the example docker environment file to `.env`: Copy the example docker environment file to `.env`:
``` ```sh
cp installation/env-example installation/.env cp installation/env-example installation/.env
``` ```
@ -53,28 +37,98 @@ Make a directory for sites:
mkdir installation/sites mkdir installation/sites
``` ```
#### Setup Environment Variables ### Setup Environment Variables
Docker allows passing an environment file to aide in setting up containers, which is used by this repository to pass secret and variable data.
To get started, copy the existing `env-example` file to `.env` inside the `installation` directory. By default, the file will contain the following variables: To get started, copy the existing `env-example` file to `.env` inside the `installation` directory. By default, the file will contain the following variables:
- `VERSION=edge` - `VERSION=edge`
- In this case, `edge` corresponds to `develop`. To setup any other version, you may use the branch name or version specific tags. (eg. version-12, v11.1.15, v11) - In this case, `edge` corresponds to `develop`. To setup any other version, you may use the branch name or version specific tags. (eg. version-12, v11.1.15, v11)
- `MYSQL_ROOT_PASSWORD=admin` - `MYSQL_ROOT_PASSWORD=admin`
- Bootstraps a MariaDB container with this value set as the root password. If a managed MariaDB instance is to be used, there is no need to set the password here. - Bootstraps a MariaDB container with this value set as the root password. If a managed MariaDB instance is used, there is no need to set the password here.
- `MARIADB_HOST=mariadb` - `MARIADB_HOST=mariadb`
- Sets the hostname to `mariadb`. This is required if the database is managed with the containerized MariaDB instance. - Sets the hostname to `mariadb`. This is required if the database is managed by the containerized MariaDB instance.
- In case of a separately managed database setup, set the value to the database's hostname/IP/domain. - In case of a separately managed database setups, set the value to the database's hostname/IP/domain.
- `SITES=site1.domain.com,site2.domain.com` - `SITES=site1.domain.com,site2.domain.com`
- List of sites that are part of the deployment "bench". Each site is separated by a comma(,). - List of sites that are part of the deployment "bench" Each site is separated by a comma(,).
- If LetsEncrypt is being setup, make sure that the DNS for all the site domains are pointing to the current instance. - If LetsEncrypt is being setup, make sure that the DNS for all the site's domains correctly point to the current instance.
- `LETSENCRYPT_EMAIL=your.email@your.domain.com` - `LETSENCRYPT_EMAIL=your.email@your.domain.com`
- Email for LetsEncrypt expiry notification. This is only required if you are setting up the nginx proxy companion. - Email for LetsEncrypt expiry notification. This is only required if you are setting up LetsEncrypt.
### Local deployment for testing
For trying out locally or to develop apps using ERPNext REST API port 80 must be published.
The first command will start the containers; the second command will publish the port of the *-nginx container.
For Erpnext:
```sh
# Start services
docker-compose \
--project-name <project-name> \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-erpnext.yml \
--project-directory installation up -d
# Publish port
docker-compose \
--project-name <project-name> \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-erpnext.yml \
--project-directory installation run --publish 80:80 -d erpnext-nginx
```
For Frappe:
```sh
# Start services
docker-compose \
--project-name <project-name> \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-frappe.yml \
--project-directory installation up -d
# Publish port
docker-compose \
--project-name <project-name> \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-frappe.yml \
--project-directory installation run --publish 80:80 -d frappe-nginx
```
Make sure to replace `<project-name>` with the desired name you wish to set for the project.
Notes:
- The local deployment is for testing and REST API development purpose only
- A complete development environment is available [here](Development/README.md)
- The site names are limited to patterns matching \*.localhost by default
- Additional site name patterns can be added by editing /etc/hosts of your host machine
### Deployment for production
#### Setup Letsencrypt Nginx Proxy Companion
Letsencrypt Nginx Proxy Companion can optionally be setup to provide SSL. This is recommended for instances accessed over the internet.
Your DNS will need to be configured correctly for Letsencrypt to verify your domain.
To setup the proxy companion, run the following commands:
```sh
cd $HOME
git clone https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion.git
cd docker-compose-letsencrypt-nginx-proxy-companion
cp .env.sample .env
./start.sh
```
For more details, see the [Letsencrypt Nginx Proxy Companion github repo](https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion). Letsencrypt Nginx Proxy Companion github repo works by automatically proxying to containers with the `VIRTUAL_HOST` environmental variable.
#### Start Frappe/ERPNext Services #### Start Frappe/ERPNext Services
To start the Frappe/ERPNext services, run the following command: To start the Frappe/ERPNext services for production, run the following command:
```sh ```sh
docker-compose \ docker-compose \
@ -86,15 +140,51 @@ docker-compose \
``` ```
Make sure to replace `<project-name>` with any desired name you wish to set for the project. Make sure to replace `<project-name>` with any desired name you wish to set for the project.
Note: use `docker-compose-frappe.yml` in case you need only Frappe without ERPNext.
Note: use `docker-compose-frappe.yml` in case you need bench with just frappe installed. ### Docker containers
This repository contains the following docker-compose files, each one containing the described images:
* docker-compose-common.yml
* redis-cache
* volume: redis-cache-vol
* redis-queue
* volume: redis-queue-vol
* redis-socketio
* volume: redis-socketio-vol
* mariadb: main database
* volume: mariadb-vol
* docker-compose-erpnext.yml
* erpnext-nginx: serves static assets and proxies web request to the appropriate container, allowing to offer all services on the same port.
* volume: assets
* erpnext-python: main application code
* frappe-socketio: enables realtime communication to the user interface through websockets
* frappe-worker-default: background runner
* frappe-worker-short: background runner for short-running jobs
* frappe-worker-long: background runner for long-running jobs
* frappe-schedule
* docker-compose-frappe.yml
* frappe-nginx: serves static assets and proxies web request to the appropriate container, allowing to offer all services on the same port.
* volume: assets
* erpnext-python: main application code
* frappe-socketio: enables realtime communication to the user interface through websockets
* frappe-worker-default: background runner
* frappe-worker-short: background runner for short-running jobs
* frappe-worker-long: background runner for long-running jobs
* frappe-schedule
* docker-compose-networks.yml: this yaml define the network to communicate with *Letsencrypt Nginx Proxy Companion*.
### Site operations
#### Setup New Sites #### Setup New Sites
Note: Note:
- Wait for the mariadb service to start before trying to create a new site. - Wait for the MariaDB service to start before trying to create a new site.
- If new site creation fails, retry after the mariadb container is up and running. - If new site creation fails, retry after the MariaDB container is up and running.
- If you're using a managed database instance, make sure that the database is running before setting up a new site. - If you're using a managed database instance, make sure that the database is running before setting up a new site.
- Use `.env` file or environment variables instead of passing secrets as command arguments. - Use `.env` file or environment variables instead of passing secrets as command arguments.
@ -105,25 +195,25 @@ docker exec -it \
-e "DB_ROOT_USER=$DB_ROOT_USER" \ -e "DB_ROOT_USER=$DB_ROOT_USER" \
-e "MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD" \ -e "MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD" \
-e "ADMIN_PASSWORD=$ADMIN_PASSWORD" \ -e "ADMIN_PASSWORD=$ADMIN_PASSWORD" \
-e "INSTALL_ERPNEXT=1" \ -e "INSTALL_APPS=erpnext" \
<project-name>_erpnext-python_1 docker-entrypoint.sh new <project-name>_erpnext-python_1 docker-entrypoint.sh new
``` ```
Environment Variables needed: Environment Variables needed:
- `SITE_NAME`: name of the new site to create. - `SITE_NAME`: name of the new site to create.
- `DB_ROOT_USER`: MariaDB Root user. The user that can create databases. - `DB_ROOT_USER`: MariaDB Root user.
- `MYSQL_ROOT_PASSWORD`: In case of mariadb docker container use the one set in `MYSQL_ROOT_PASSWORD` in previous steps. In case of managed database use appropriate password. - `MYSQL_ROOT_PASSWORD`: In case of the MariaDB docker container use the one set in `MYSQL_ROOT_PASSWORD` in previous steps. In case of a managed database use the appropriate password.
- `ADMIN_PASSWORD`: set the administrator password for new site. - `ADMIN_PASSWORD`: set the administrator password for the new site.
- `INSTALL_ERPNEXT=1`: available only in erpnext-worker and erpnext containers. Installs ERPNext on this new site. - `INSTALL_APPS=erpnext`: available only in erpnext-worker and erpnext containers (or other containers with custom apps). Installs ERPNext (and/or the specified apps, comma-delinieated) on this new site.
- `FORCE=1`: is optional variable which force installs the same site. - `FORCE=1`: optional variable which force installation of the same site.
#### Backup Sites #### Backup Sites
Environment Variables Environment Variables
- `SITES` is list of sites separated by (:) colon to migrate. e.g. `SITES=site1.domain.com` or `SITES=site1.domain.com:site2.domain.com` By default all sites in bench will be backed up. - `SITES` is list of sites separated by `:` colon to migrate. e.g. `SITES=site1.domain.com` or `SITES=site1.domain.com:site2.domain.com` By default all sites in bench will be backed up.
- `WITH_FILES` if set to 1, it will backup user uploaded files for the sites. - `WITH_FILES` if set to 1, it will backup user-uploaded files.
```sh ```sh
docker exec -it \ docker exec -it \
@ -132,7 +222,7 @@ docker exec -it \
<project-name>_erpnext-python_1 docker-entrypoint.sh backup <project-name>_erpnext-python_1 docker-entrypoint.sh backup
``` ```
Backup will be available in the `sites` mounted volume. The backup will be available in the `sites` mounted volume.
#### Updating and Migrating Sites #### Updating and Migrating Sites
@ -161,13 +251,71 @@ docker exec -it \
<project-name>_erpnext-python_1 docker-entrypoint.sh migrate <project-name>_erpnext-python_1 docker-entrypoint.sh migrate
``` ```
### Troubleshoot ### Custom apps
1. Remove containers and volumes, and clear redis cache: To add your own Frappe/ERPNext apps to the image, we'll need to create a custom image with the help of a unique wrapper script
This can be used when existing images are upgraded and migration fails. > For the sake of simplicity, in this example, we'll be using a place holder called `[custom]`, and we'll be building off the edge image.
Create two directories called `[custom]-worker` and `[custom]-nginx` in the `build` directory.
```shell
cd frappe_docker
mkdir ./build/[custom]-worker ./build/[custom]-nginx
``` ```
Create a `Dockerfile` in `./build/[custom]-worker` with the following content:
```Dockerfile
FROM frappe/erpnext-worker:edge
RUN install_app [custom] https://github.com/[username]/[custom] [branch]
# Only add the branch if you are using a specific tag or branch.
```
Create a `Dockerfile` in `./build/[custom]-nginx` with the following content:
```Dockerfile
FROM bitnami/node:12-prod
COPY build/[custom]-nginx/install_app.sh /install_app
RUN /install_app [custom] https://github.com/[username]/[custom]
FROM frappe/erpnext-nginx:edge
COPY --from=0 /home/frappe/frappe-bench/sites/ /var/www/html/
COPY --from=0 /rsync /rsync
RUN echo -n "\n[custom]" >> /var/www/html/apps.txt
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
```
Copy over the `install_app.sh` file from `./build/erpnext-nginx`
```shell
cp ./build/erpnext-nginx/install.sh ./build/[custom]-nginx
```
Open up `./installation/docker-compose-custom.yml` and replace all instances of `[app]` with the name of your app.
```shell
sed -i "s#\[app\]#[custom]#" ./installation/docker-compose-custom.yml
```
Install like usual, except that when you set the `INSTALL_APPS` variable to `erpnext,[custom]`.
## Troubleshoot
### Failed migration after image upgrade
Issue: After upgrade of the containers, the automatic migration fails.
Solution: Remove containers and volumes, and clear redis cache:
```shell
# change to repo root # change to repo root
cd $HOME/frappe_docker cd $HOME/frappe_docker
@ -202,9 +350,10 @@ docker-compose \
--project-directory installation up -d --project-directory installation up -d
``` ```
2. Clear redis cache using `docker exec` command: ### ValueError: There exists an active worker named XXX already
Issue: You have the following error during container restart
In case of following error during container restarts:
``` ```
frappe-worker-short_1 | Traceback (most recent call last): frappe-worker-short_1 | Traceback (most recent call last):
@ -219,7 +368,7 @@ frappe-worker-short_1 | raise ValueError(msg.format(self.name))
frappe-worker-short_1 | ValueError: There exists an active worker named '8dfe5c234085.10.short' already frappe-worker-short_1 | ValueError: There exists an active worker named '8dfe5c234085.10.short' already
``` ```
Use commands : Solution: Clear redis cache using `docker exec` command (take care of replacing `<project-name>` accordingly):
```sh ```sh
# Clear the cache which is causing problem. # Clear the cache which is causing problem.
@ -229,4 +378,14 @@ docker exec -it <project-name>_redis-queue_1 redis-cli FLUSHALL
docker exec -it <project-name>_redis-socketio_1 redis-cli FLUSHALL docker exec -it <project-name>_redis-socketio_1 redis-cli FLUSHALL
``` ```
Note: Environment variables from `.env` file located at current working directory will be used. Note: Environment variables from `.env` file located at the current working directory will be used.
## Development
This repository includes a complete setup to develop with Frappe/ERPNext and Bench, Including the following features:
- VSCode containers integration
- VSCode Python debugger
- Pre-configured Docker containers for an easy start
A complete Readme is available in [development/README.md](development/README.md)

113
build/bench/Dockerfile Normal file
View File

@ -0,0 +1,113 @@
# Frappe Bench Dockerfile
FROM bitnami/minideb:latest
LABEL author=frappé
RUN install_packages \
git \
wkhtmltopdf \
mariadb-client \
gettext-base \
wget \
# for PDF
libssl-dev \
fonts-cantarell \
xfonts-75dpi \
xfonts-base \
# to work inside the container
locales \
build-essential \
cron \
curl \
vim \
sudo \
iputils-ping \
watch \
tree \
nano \
software-properties-common \
bash-completion \
# For psycopg2
libpq-dev \
# Other
libffi-dev \
liblcms2-dev \
libldap2-dev \
libmariadbclient-dev \
libsasl2-dev \
libtiff5-dev \
libwebp-dev \
redis-tools \
rlwrap \
tk8.6-dev \
# VSCode container requirements
net-tools \
# PYTHON
python3-dev \
python3-pip \
python3-setuptools \
python3-tk \
python-virtualenv
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \
&& dpkg-reconfigure --frontend=noninteractive locales
# Install wkhtmltox correctly
RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN dpkg -i wkhtmltox_0.12.5-1.stretch_amd64.deb && rm wkhtmltox_0.12.5-1.stretch_amd64.deb
# Create new user with home directory, improve docker compatibility with UID/GID 1000, add user to sudo group, allow passwordless sudo, switch to that user and change directory to user home directory
RUN groupadd -g 1000 frappe
RUN useradd --no-log-init -r -m -u 1000 -g 1000 -G sudo frappe
RUN echo "frappe ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
USER frappe
WORKDIR /home/frappe
# Install bench in the local user home directory
RUN pip3 install --user git+https://github.com/frappe/bench.git#egg=bench --no-cache
# Export python executables for Dockerfile
ENV PATH=/home/frappe/.local/bin:$PATH
# Export python executables for interactive shell
RUN echo "export PATH=/home/frappe/.local/bin:\$PATH" >> /home/frappe/.bashrc
# Print version and verify bashrc is properly sourced so that everything works in the Dockerfile
RUN bench --version
# Print version and verify bashrc is properly sourced so that everything works in the interactive shell
RUN bash -c "bench --version"
# !!! UPDATE NODEJS PERIODICALLY WITH LATEST VERSIONS !!!
# https://nodejs.org/en/about/releases/
# https://nodejs.org/download/release/latest-v10.x/
# https://nodejs.org/download/release/latest-v12.x/
# https://nodejs.org/download/release/latest-v13.x/
ENV NODE_VERSION=12.16.1
ENV NODE_VERSION_FRAPPEV11=10.19.0
# Install nvm with node
RUN wget https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh
RUN chmod +x install.sh
RUN ./install.sh
ENV NVM_DIR=/home/frappe/.nvm
# Install node for Frappe V11, install yarn
RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION_FRAPPEV11}
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION_FRAPPEV11} && npm install -g yarn
# Install node for latest frappe, set as default, install node
RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION}
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION} && npm install -g yarn
RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION}
ENV PATH="/home/frappe/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
# Install yarn
RUN npm install -g yarn
# Print version and verify bashrc is properly sourced so that everything works in the Dockerfile
RUN node --version \
&& npm --version \
&& yarn --version
# Print version and verify bashrc is properly sourced so that everything works in the interactive shell
RUN bash -c "node --version" \
&& bash -c "npm --version" \
&& bash -c "yarn --version"
EXPOSE 8000 9000 6787

View File

@ -1,6 +1,13 @@
import socket, os, json, time import socket, os, json, time
from six.moves.urllib.parse import urlparse from six.moves.urllib.parse import urlparse
COMMON_SITE_CONFIG_FILE = 'common_site_config.json'
REDIS_QUEUE_KEY = 'redis_queue'
REDIS_CACHE_KEY = 'redis_cache'
REDIS_SOCKETIO_KEY = 'redis_socketio'
DB_HOST_KEY = 'db_host'
DB_PORT = 3306
def is_open(ip, port, timeout=30): def is_open(ip, port, timeout=30):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout) s.settimeout(timeout)
@ -13,9 +20,10 @@ def is_open(ip, port, timeout=30):
finally: finally:
s.close() s.close()
def check_host(ip, port, retry=10, delay=3): def check_host(ip, port, retry=10, delay=3, print_attempt=True):
ipup = False ipup = False
for i in range(retry): for i in range(retry):
if print_attempt:
print("Attempt {i} to connect to {ip}:{port}".format(ip=ip,port=port,i=i+1)) print("Attempt {i} to connect to {ip}:{port}".format(ip=ip,port=port,i=i+1))
if is_open(ip, port): if is_open(ip, port):
ipup = True ipup = True
@ -25,43 +33,87 @@ def check_host(ip, port, retry=10, delay=3):
return ipup return ipup
# Check connection to servers # Check connection to servers
def get_config():
config = None config = None
try: try:
with open('common_site_config.json') as config_file: with open(COMMON_SITE_CONFIG_FILE) as config_file:
config = json.load(config_file) config = json.load(config_file)
except FileNotFoundError: except FileNotFoundError as exception:
raise FileNotFoundError("common_site_config.json missing") print(exception)
exit(1)
except: except:
raise ValueError("common_site_config.json is not valid") print(COMMON_SITE_CONFIG_FILE+" is not valid")
exit(1)
return config
# Check mariadb # Check mariadb
def check_mariadb(retry=10, delay=3, print_attempt=True):
config = get_config()
check_mariadb = False check_mariadb = False
check_mariadb = check_host(config.get('db_host', 'mariadb'), 3306) check_mariadb = check_host(
config.get(DB_HOST_KEY, 'mariadb'),
DB_PORT,
retry,
delay,
print_attempt)
if not check_mariadb: if not check_mariadb:
raise ConnectionError("Connection to mariadb timed out") print("Connection to MariaDB timed out")
exit(1)
# Check redis queue # Check redis queue
def check_redis_queue(retry=10, delay=3, print_attempt=True):
check_redis_queue = False check_redis_queue = False
redis_queue_url = urlparse(config.get("redis_queue","redis://redis:6379")).netloc config = get_config()
redis_queue_url = urlparse(config.get(REDIS_QUEUE_KEY,"redis://redis-queue:6379")).netloc
redis_queue, redis_queue_port = redis_queue_url.split(":") redis_queue, redis_queue_port = redis_queue_url.split(":")
check_redis_queue = check_host(redis_queue, redis_queue_port) check_redis_queue = check_host(
redis_queue,
redis_queue_port,
retry,
delay,
print_attempt)
if not check_redis_queue: if not check_redis_queue:
raise ConnectionError("Connection to redis queue timed out") print("Connection to redis queue timed out")
exit(1)
# Check redis cache # Check redis cache
def check_redis_cache(retry=10, delay=3, print_attempt=True):
check_redis_cache = False check_redis_cache = False
redis_cache_url = urlparse(config.get("redis_cache","redis://redis:6379")).netloc config = get_config()
redis_cache_url = urlparse(config.get(REDIS_CACHE_KEY,"redis://redis-cache:6379")).netloc
redis_cache, redis_cache_port = redis_cache_url.split(":") redis_cache, redis_cache_port = redis_cache_url.split(":")
check_redis_cache = check_host(redis_cache, redis_cache_port) check_redis_cache = check_host(
redis_cache,
redis_cache_port,
retry,
delay,
print_attempt)
if not check_redis_cache: if not check_redis_cache:
raise ConnectionError("Connection to redis cache timed out") print("Connection to redis cache timed out")
exit(1)
# Check redis socketio # Check redis socketio
def check_redis_socketio(retry=10, delay=3, print_attempt=True):
check_redis_socketio = False check_redis_socketio = False
redis_socketio_url = urlparse(config.get("redis_socketio","redis://redis:6379")).netloc config = get_config()
redis_socketio_url = urlparse(config.get(REDIS_SOCKETIO_KEY,"redis://redis-socketio:6379")).netloc
redis_socketio, redis_socketio_port = redis_socketio_url.split(":") redis_socketio, redis_socketio_port = redis_socketio_url.split(":")
check_redis_socketio = check_host(redis_socketio, redis_socketio_port) check_redis_socketio = check_host(
redis_socketio,
redis_socketio_port,
retry,
delay,
print_attempt)
if not check_redis_socketio: if not check_redis_socketio:
raise ConnectionError("Connection to redis socketio timed out") print("Connection to redis socketio timed out")
exit(1)
def main():
check_mariadb()
check_redis_queue()
check_redis_cache()
check_redis_socketio()
print('Connections OK') print('Connections OK')
if __name__ == "__main__":
main()

View File

@ -1,4 +1,26 @@
import frappe import frappe
from frappe.utils.doctor import doctor import json
import redis
from rq import Worker
from check_connection import (
check_mariadb,
check_redis_cache,
check_redis_queue,
check_redis_socketio,
)
doctor() def main():
check_mariadb(retry=1, delay=0, print_attempt=False)
print("MariaDB Connected")
check_redis_cache(retry=1, delay=0, print_attempt=False)
print("Redis Cache Connected")
check_redis_queue(retry=1, delay=0, print_attempt=False)
print("Redis Queue Connected")
check_redis_socketio(retry=1, delay=0, print_attempt=False)
print("Redis SocketIO Connected")
print("Health check successful")
exit(0)
if __name__ == "__main__":
main()

View File

@ -6,7 +6,8 @@ site_name = os.environ.get("SITE_NAME", 'site1.localhost')
mariadb_root_username = os.environ.get("DB_ROOT_USER", 'root') mariadb_root_username = os.environ.get("DB_ROOT_USER", 'root')
mariadb_root_password = os.environ.get("MYSQL_ROOT_PASSWORD", 'admin') mariadb_root_password = os.environ.get("MYSQL_ROOT_PASSWORD", 'admin')
force = True if os.environ.get("FORCE", None) else False force = True if os.environ.get("FORCE", None) else False
install_apps = ['erpnext'] if os.environ.get("INSTALL_ERPNEXT", None) else False install_apps = os.environ.get("INSTALL_APPS", None)
install_apps = install_apps.split(',') if install_apps else []
frappe.init(site_name, new_site=True) frappe.init(site_name, new_site=True)
_new_site( _new_site(

View File

@ -11,6 +11,11 @@ server {
server_name $http_host; server_name $http_host;
root /var/www/html; root /var/www/html;
add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location /assets { location /assets {
try_files $uri =404; try_files $uri =404;
} }
@ -32,6 +37,15 @@ server {
} }
location / { location / {
rewrite ^(.+)/$ $1 permanent;
rewrite ^(.+)/index\.html$ $1 permanent;
rewrite ^(.+)\.html$ $1 permanent;
location ~ ^/files/.*.(htm|html|svg|xml) {
add_header Content-disposition "attachment";
try_files /sites/$http_host/public/$uri @webserver;
}
try_files /sites/$http_host/public/$uri @webserver; try_files /sites/$http_host/public/$uri @webserver;
} }

View File

@ -0,0 +1,16 @@
#!/bin/bash
APP_NAME=${1}
APP_REPO=${2}
APP_BRANCH=${3}
cd /home/frappe/frappe-bench/
. env/bin/activate
cd ./apps
[ "${APP_BRANCH}" ] && BRANCH="-b ${APP_BRANCH}"
git clone --depth 1 -o upstream ${APP_REPO} ${BRANCH}
pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/${APP_NAME}

View File

@ -1,40 +0,0 @@
FROM bitnami/node:12-prod
WORKDIR /home/frappe/frappe-bench
RUN mkdir -p /home/frappe/frappe-bench/sites \
&& echo "frappe\nerpnext" > /home/frappe/frappe-bench/sites/apps.txt
RUN install_packages git python2
RUN mkdir -p apps sites/assets \
&& cd apps \
&& git clone --depth 1 https://github.com/frappe/frappe \
&& git clone --depth 1 https://github.com/frappe/erpnext
RUN cd /home/frappe/frappe-bench/apps/frappe \
&& yarn \
&& yarn run production \
&& rm -fr node_modules \
&& yarn install --production=true
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
&& mkdir -p /var/www/error_pages \
&& cp -r /tmp/bench/bench/config/templates/502.html /var/www/error_pages
RUN cp -R /home/frappe/frappe-bench/apps/frappe/frappe/public/* /home/frappe/frappe-bench/sites/assets/frappe \
&& cp -R /home/frappe/frappe-bench/apps/frappe/node_modules /home/frappe/frappe-bench/sites/assets/frappe/ \
&& mkdir -p /home/frappe/frappe-bench/sites/assets/erpnext \
&& cp -R /home/frappe/frappe-bench/apps/erpnext/erpnext/public/* /home/frappe/frappe-bench/sites/assets/erpnext
FROM nginx:latest
COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/
COPY --from=0 /var/www/error_pages /var/www/
COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
COPY build/erpnext-assets/docker-entrypoint.sh /
RUN apt-get update && apt-get install -y rsync && apt-get clean
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -1,40 +0,0 @@
FROM bitnami/node:10-prod
WORKDIR /home/frappe/frappe-bench
RUN mkdir -p /home/frappe/frappe-bench/sites \
&& echo "frappe\nerpnext" > /home/frappe/frappe-bench/sites/apps.txt
RUN install_packages git python2
RUN mkdir -p apps sites/assets \
&& cd apps \
&& git clone --depth 1 https://github.com/frappe/frappe --branch version-11 \
&& git clone --depth 1 https://github.com/frappe/erpnext --branch version-11
RUN cd /home/frappe/frappe-bench/apps/frappe \
&& yarn \
&& yarn run production \
&& rm -fr node_modules \
&& yarn install --production=true
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
&& mkdir -p /var/www/error_pages \
&& cp -r /tmp/bench/bench/config/templates/502.html /var/www/error_pages
RUN cp -R /home/frappe/frappe-bench/apps/frappe/frappe/public/* /home/frappe/frappe-bench/sites/assets/frappe \
&& cp -R /home/frappe/frappe-bench/apps/frappe/node_modules /home/frappe/frappe-bench/sites/assets/frappe/ \
&& mkdir -p /home/frappe/frappe-bench/sites/assets/erpnext \
&& cp -R /home/frappe/frappe-bench/apps/erpnext/erpnext/public/* /home/frappe/frappe-bench/sites/assets/erpnext
FROM nginx:latest
COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/
COPY --from=0 /var/www/error_pages /var/www/
COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
COPY build/erpnext-assets/docker-entrypoint.sh /
RUN apt-get update && apt-get install -y rsync && apt-get clean
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -1,40 +0,0 @@
FROM bitnami/node:12-prod
WORKDIR /home/frappe/frappe-bench
RUN mkdir -p /home/frappe/frappe-bench/sites \
&& echo "frappe\nerpnext" > /home/frappe/frappe-bench/sites/apps.txt
RUN install_packages git python2
RUN mkdir -p apps sites/assets \
&& cd apps \
&& git clone --depth 1 https://github.com/frappe/frappe --branch version-12 \
&& git clone --depth 1 https://github.com/frappe/erpnext --branch version-12
RUN cd /home/frappe/frappe-bench/apps/frappe \
&& yarn \
&& yarn run production \
&& rm -fr node_modules \
&& yarn install --production=true
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
&& mkdir -p /var/www/error_pages \
&& cp -r /tmp/bench/bench/config/templates/502.html /var/www/error_pages
RUN cp -R /home/frappe/frappe-bench/apps/frappe/frappe/public/* /home/frappe/frappe-bench/sites/assets/frappe \
&& cp -R /home/frappe/frappe-bench/apps/frappe/node_modules /home/frappe/frappe-bench/sites/assets/frappe/ \
&& mkdir -p /home/frappe/frappe-bench/sites/assets/erpnext \
&& cp -R /home/frappe/frappe-bench/apps/erpnext/erpnext/public/* /home/frappe/frappe-bench/sites/assets/erpnext
FROM nginx:latest
COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/
COPY --from=0 /var/www/error_pages /var/www/
COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
COPY build/erpnext-assets/docker-entrypoint.sh /
RUN apt-get update && apt-get install -y rsync && apt-get clean
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -0,0 +1,16 @@
FROM bitnami/node:12-prod
COPY build/erpnext-nginx/install_app.sh /install_app
RUN /install_app erpnext https://github.com/frappe/erpnext
FROM frappe/frappe-nginx:develop
COPY --from=0 /home/frappe/frappe-bench/sites/ /var/www/html/
COPY --from=0 /rsync /rsync
RUN echo -n "\nerpnext" >> /var/www/html/apps.txt
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -9,7 +9,7 @@ set -e
rsync -a --delete /var/www/html/assets/js /assets rsync -a --delete /var/www/html/assets/js /assets
rsync -a --delete /var/www/html/assets/css /assets rsync -a --delete /var/www/html/assets/css /assets
rsync -a --delete /var/www/html/assets/frappe /assets rsync -a --delete /var/www/html/assets/frappe /assets
rsync -a --delete /var/www/html/assets/erpnext /assets . /rsync
chmod -R 755 /assets chmod -R 755 /assets
@ -37,4 +37,11 @@ envsubst '${API_HOST}
${SOCKETIO_PORT}' \ ${SOCKETIO_PORT}' \
< /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
echo "Waiting for frappe-python to be available on $FRAPPE_PY port $FRAPPE_PY_PORT"
timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' $FRAPPE_PY $FRAPPE_PY_PORT
echo "Frappe-python available on $FRAPPE_PY port $FRAPPE_PY_PORT"
echo "Waiting for frappe-socketio to be available on $FRAPPE_PY port $FRAPPE_PY_PORT"
timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' $FRAPPE_SOCKETIO $SOCKETIO_PORT
echo "Frappe-socketio available on $FRAPPE_PY port $FRAPPE_PY_PORT"
exec "$@" exec "$@"

View File

@ -0,0 +1,31 @@
#!/bin/bash
APP_NAME=${1}
APP_REPO=${2}
APP_BRANCH=${3}
[ "${APP_BRANCH}" ] && BRANCH="-b ${APP_BRANCH}"
mkdir -p /home/frappe/frappe-bench/sites/assets
cd /home/frappe/frappe-bench
echo -e "frappe\n${APP_NAME}" > /home/frappe/frappe-bench/sites/apps.txt
install_packages git python2
mkdir -p apps
cd apps
git clone --depth 1 https://github.com/frappe/frappe ${BRANCH}
git clone --depth 1 ${APP_REPO} ${BRANCH}
cd /home/frappe/frappe-bench/apps/frappe
yarn
yarn production
rm -fr node_modules
yarn install --production=true
mkdir -p /home/frappe/frappe-bench/sites/assets/${APP_NAME}
cp -R /home/frappe/frappe-bench/apps/${APP_NAME}/${APP_NAME}/public/* /home/frappe/frappe-bench/sites/assets/${APP_NAME}
echo "rsync -a --delete /var/www/html/assets/${APP_NAME} /assets" > /rsync
rm /home/frappe/frappe-bench/sites/apps.txt

View File

@ -0,0 +1,16 @@
FROM bitnami/node:10-prod
COPY build/erpnext-nginx/install_app.sh /install_app
RUN /install_app erpnext https://github.com/frappe/erpnext version-11
FROM frappe/frappe-nginx:v11
COPY --from=0 /home/frappe/frappe-bench/sites/ /var/www/html/
COPY --from=0 /rsync /rsync
RUN echo -n "\nerpnext" >> /home/frappe/frappe-bench/sites/apps.txt
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -0,0 +1,16 @@
FROM bitnami/node:12-prod
COPY build/erpnext-nginx/install_app.sh /install_app
RUN /install_app erpnext https://github.com/frappe/erpnext version-12
FROM frappe/frappe-nginx:v12
COPY --from=0 /home/frappe/frappe-bench/sites/ /var/www/html/
COPY --from=0 /rsync /rsync
RUN echo -n "\nerpnext" >> /home/frappe/frappe-bench/sites/apps.txt
VOLUME [ "/assets" ]
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

View File

@ -1,44 +1,3 @@
FROM bitnami/python:latest-prod FROM frappe/frappe-worker:develop
RUN useradd -ms /bin/bash frappe RUN install_app erpnext https://github.com/frappe/erpnext
WORKDIR /home/frappe/frappe-bench
RUN install_packages \
git \
wkhtmltopdf \
mariadb-client \
gettext-base \
wget \
# for PDF
libssl-dev \
fonts-cantarell \
xfonts-75dpi \
xfonts-base \
# For psycopg2
libpq-dev \
build-essential
# Install wkhtmltox correctly
RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN dpkg -i wkhtmltox_0.12.5-1.stretch_amd64.deb && rm wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN mkdir -p apps logs commands
RUN virtualenv env \
&& . env/bin/activate \
&& cd apps \
&& git clone --depth 1 -o upstream https://github.com/frappe/frappe \
&& git clone --depth 1 -o upstream https://github.com/frappe/erpnext \
&& pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/frappe \
&& pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/erpnext
COPY build/common/commands/* /home/frappe/frappe-bench/commands/
COPY build/common/common_site_config.json.template /opt/frappe/common_site_config.json.template
# Setup docker-entrypoint
COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
WORKDIR /home/frappe/frappe-bench/sites
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["start"]

View File

@ -1,41 +1,3 @@
FROM bitnami/python:latest-prod FROM frappe/frappe-worker:v11
RUN useradd -ms /bin/bash frappe RUN install_app erpnext https://github.com/frappe/erpnext version-11
WORKDIR /home/frappe/frappe-bench
RUN install_packages \
git \
wkhtmltopdf \
mariadb-client \
gettext-base \
wget \
# for PDF
libssl-dev \
fonts-cantarell \
xfonts-75dpi \
xfonts-base
# Install wkhtmltox correctly
RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN dpkg -i wkhtmltox_0.12.5-1.stretch_amd64.deb && rm wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN mkdir -p apps logs commands
RUN virtualenv env \
&& . env/bin/activate \
&& cd apps \
&& git clone --depth 1 -o upstream https://github.com/frappe/frappe --branch version-11 \
&& git clone --depth 1 -o upstream https://github.com/frappe/erpnext --branch version-11 \
&& pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/frappe \
&& pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/erpnext
COPY build/common/commands/* /home/frappe/frappe-bench/commands/
COPY build/common/common_site_config.json.template /opt/frappe/common_site_config.json.template
# Setup docker-entrypoint
COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
WORKDIR /home/frappe/frappe-bench/sites
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["start"]

View File

@ -1,44 +1,3 @@
FROM bitnami/python:latest-prod FROM frappe/frappe-worker:v12
RUN useradd -ms /bin/bash frappe RUN install_app erpnext https://github.com/frappe/erpnext version-12
WORKDIR /home/frappe/frappe-bench
RUN install_packages \
git \
wkhtmltopdf \
mariadb-client \
gettext-base \
wget \
# for PDF
libssl-dev \
fonts-cantarell \
xfonts-75dpi \
xfonts-base \
# For psycopg2
libpq-dev \
build-essential
# Install wkhtmltox correctly
RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN dpkg -i wkhtmltox_0.12.5-1.stretch_amd64.deb && rm wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN mkdir -p apps logs commands
RUN virtualenv env \
&& . env/bin/activate \
&& cd apps \
&& git clone --depth 1 -o upstream https://github.com/frappe/frappe --branch version-12 \
&& git clone --depth 1 -o upstream https://github.com/frappe/erpnext --branch version-12 \
&& pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/frappe \
&& pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/erpnext
COPY build/common/commands/* /home/frappe/frappe-bench/commands/
COPY build/common/common_site_config.json.template /opt/frappe/common_site_config.json.template
# Setup docker-entrypoint
COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
WORKDIR /home/frappe/frappe-bench/sites
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["start"]

View File

@ -14,7 +14,10 @@ RUN cd /home/frappe/frappe-bench/apps/frappe \
&& yarn \ && yarn \
&& yarn run production \ && yarn run production \
&& rm -fr node_modules \ && rm -fr node_modules \
&& yarn install --production=true && yarn install --production=true \
&& node --version \
&& npm --version \
&& yarn --version
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \ RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
&& mkdir -p /var/www/error_pages \ && mkdir -p /var/www/error_pages \
@ -27,7 +30,7 @@ FROM nginx:latest
COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/ COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/
COPY --from=0 /var/www/error_pages /var/www/ COPY --from=0 /var/www/error_pages /var/www/
COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
COPY build/frappe-assets/docker-entrypoint.sh / COPY build/frappe-nginx/docker-entrypoint.sh /
RUN apt-get update && apt-get install -y rsync && apt-get clean RUN apt-get update && apt-get install -y rsync && apt-get clean

View File

@ -9,6 +9,7 @@ set -e
rsync -a --delete /var/www/html/assets/js /assets rsync -a --delete /var/www/html/assets/js /assets
rsync -a --delete /var/www/html/assets/css /assets rsync -a --delete /var/www/html/assets/css /assets
rsync -a --delete /var/www/html/assets/frappe /assets rsync -a --delete /var/www/html/assets/frappe /assets
. /rsync
chmod -R 755 /assets chmod -R 755 /assets
@ -36,4 +37,11 @@ envsubst '${API_HOST}
${SOCKETIO_PORT}' \ ${SOCKETIO_PORT}' \
< /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
echo "Waiting for frappe-python to be available on $FRAPPE_PY port $FRAPPE_PY_PORT"
timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' $FRAPPE_PY $FRAPPE_PY_PORT
echo "Frappe-python available on $FRAPPE_PY port $FRAPPE_PY_PORT"
echo "Waiting for frappe-socketio to be available on $FRAPPE_PY port $FRAPPE_PY_PORT"
timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' $FRAPPE_SOCKETIO $SOCKETIO_PORT
echo "Frappe-socketio available on $FRAPPE_PY port $FRAPPE_PY_PORT"
exec "$@" exec "$@"

View File

@ -14,7 +14,10 @@ RUN cd /home/frappe/frappe-bench/apps/frappe \
&& yarn \ && yarn \
&& yarn run production \ && yarn run production \
&& rm -fr node_modules \ && rm -fr node_modules \
&& yarn install --production=true && yarn install --production=true \
&& node --version \
&& npm --version \
&& yarn --version
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \ RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
&& mkdir -p /var/www/error_pages \ && mkdir -p /var/www/error_pages \
@ -27,7 +30,7 @@ FROM nginx:latest
COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/ COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/
COPY --from=0 /var/www/error_pages /var/www/ COPY --from=0 /var/www/error_pages /var/www/
COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
COPY build/frappe-assets/docker-entrypoint.sh / COPY build/frappe-nginx/docker-entrypoint.sh /
RUN apt-get update && apt-get install -y rsync && apt-get clean RUN apt-get update && apt-get install -y rsync && apt-get clean

View File

@ -14,7 +14,10 @@ RUN cd /home/frappe/frappe-bench/apps/frappe \
&& yarn \ && yarn \
&& yarn run production \ && yarn run production \
&& rm -fr node_modules \ && rm -fr node_modules \
&& yarn install --production=true && yarn install --production=true \
&& node --version \
&& npm --version \
&& yarn --version
RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \ RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \
&& mkdir -p /var/www/error_pages \ && mkdir -p /var/www/error_pages \
@ -27,7 +30,7 @@ FROM nginx:latest
COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/ COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/
COPY --from=0 /var/www/error_pages /var/www/ COPY --from=0 /var/www/error_pages /var/www/
COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template
COPY build/frappe-assets/docker-entrypoint.sh / COPY build/frappe-nginx/docker-entrypoint.sh /
RUN apt-get update && apt-get install -y rsync && apt-get clean RUN apt-get update && apt-get install -y rsync && apt-get clean

View File

@ -19,7 +19,9 @@ RUN cd /home/frappe/frappe-bench/apps/frappe \
--output /home/frappe/frappe-bench/apps/frappe/node_utils.js --output /home/frappe/frappe-bench/apps/frappe/node_utils.js
RUN cd /home/frappe/frappe-bench/apps/frappe \ RUN cd /home/frappe/frappe-bench/apps/frappe \
&& npm install --only=production && npm install --only=production \
&& node --version \
&& npm --version
COPY build/frappe-socketio/health.js /home/frappe/frappe-bench/apps/frappe/health.js COPY build/frappe-socketio/health.js /home/frappe/frappe-bench/apps/frappe/health.js
RUN chown -R frappe:frappe /home/frappe RUN chown -R frappe:frappe /home/frappe

View File

@ -19,7 +19,9 @@ RUN cd /home/frappe/frappe-bench/apps/frappe \
--output /home/frappe/frappe-bench/apps/frappe/node_utils.js --output /home/frappe/frappe-bench/apps/frappe/node_utils.js
RUN cd /home/frappe/frappe-bench/apps/frappe \ RUN cd /home/frappe/frappe-bench/apps/frappe \
&& npm install --only=production && npm install --only=production \
&& node --version \
&& npm --version
COPY build/frappe-socketio/health.js /home/frappe/frappe-bench/apps/frappe/health.js COPY build/frappe-socketio/health.js /home/frappe/frappe-bench/apps/frappe/health.js
RUN chown -R frappe:frappe /home/frappe RUN chown -R frappe:frappe /home/frappe

View File

@ -19,7 +19,9 @@ RUN cd /home/frappe/frappe-bench/apps/frappe \
--output /home/frappe/frappe-bench/apps/frappe/node_utils.js --output /home/frappe/frappe-bench/apps/frappe/node_utils.js
RUN cd /home/frappe/frappe-bench/apps/frappe \ RUN cd /home/frappe/frappe-bench/apps/frappe \
&& npm install --only=production && npm install --only=production \
&& node --version \
&& npm --version
COPY build/frappe-socketio/health.js /home/frappe/frappe-bench/apps/frappe/health.js COPY build/frappe-socketio/health.js /home/frappe/frappe-bench/apps/frappe/health.js
RUN chown -R frappe:frappe /home/frappe RUN chown -R frappe:frappe /home/frappe

View File

@ -36,6 +36,8 @@ COPY build/common/common_site_config.json.template /opt/frappe/common_site_confi
COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
COPY build/common/worker/install_app.sh /usr/local/bin/install_app
WORKDIR /home/frappe/frappe-bench/sites WORKDIR /home/frappe/frappe-bench/sites
ENTRYPOINT ["docker-entrypoint.sh"] ENTRYPOINT ["docker-entrypoint.sh"]

View File

@ -33,6 +33,8 @@ COPY build/common/common_site_config.json.template /opt/frappe/common_site_confi
COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
COPY build/common/worker/install_app.sh /usr/local/bin/install_app
WORKDIR /home/frappe/frappe-bench/sites WORKDIR /home/frappe/frappe-bench/sites
ENTRYPOINT ["docker-entrypoint.sh"] ENTRYPOINT ["docker-entrypoint.sh"]

View File

@ -36,6 +36,8 @@ COPY build/common/common_site_config.json.template /opt/frappe/common_site_confi
COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
COPY build/common/worker/install_app.sh /usr/local/bin/install_app
WORKDIR /home/frappe/frappe-bench/sites WORKDIR /home/frappe/frappe-bench/sites
ENTRYPOINT ["docker-entrypoint.sh"] ENTRYPOINT ["docker-entrypoint.sh"]

22
development/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Bench",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py",
"args": [
"frappe", "serve", "--port", "8000", "--noreload", "--nothreading"
],
"pythonPath": "${workspaceFolder}/frappe-bench/env/bin/python",
"cwd": "${workspaceFolder}/frappe-bench/sites",
"env": {
"DEV_SERVER": "1"
}
}
]
}

4
development/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"python.pythonPath": "frappe-bench/env/bin/python",
"debug.node.autoAttach": "on"
}

173
development/README.md Normal file
View File

@ -0,0 +1,173 @@
# Getting Started
## Prerequisites
- Docker
- docker-compose
- user added to docker group
## Bootstrap Containers for development
Clone and change directory to frappe_docker directory
```shell
git clone https://github.com/frappe/frappe_docker.git
cd frappe_docker
```
## Use VSCode Remote Containers extension
For most people getting started with Frappe development, the best solution is to use [ VSCode Remote - Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
VSCode should automatically inquiry you to install the required extensions, that can also be installed manually as follows:
- Install Remote - Containers for VSCode
- through command line `code --install-extension ms-vscode-remote.remote-containers`
- clicking on the button at the following link: [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
- searching for extension `ms-vscode-remote.remote-containers`
- Install Python for VSCode
- through command line `code --install-extension ms-python.python`
- clicking on the button at the following link: [install](https://marketplace.visualstudio.com/items?itemName=ms-python.python)
- searching for extension `ms-python.python`
After the extensions are installed, you can:
- Open frappe_docker folder in VS Code.
- `code .`
- Launch the command, from Command Palette (Ctrl + Shift + P) `Execute Remote Containers : Reopen in Container`. You can also click in the bottom left corner to access the remote container menu.
Notes:
- The `development` directory is ignored by git. It is mounted and available inside the container. Create all your benches (installations of bench, the tool that manages frappe) inside this directory.
- nvm with node v12 and v10 is installed. Check with `nvm ls`. Node v12 is used by default.
### Setup first bench
Run the following commands in the terminal inside the container. You might need to create a new terminal in VSCode.
```shell
bench init --skip-redis-config-generation --frappe-branch version-12 frappe-bench
cd frappe-bench
```
### Setup hosts
We need to tell bench to use the right containers instead of localhost. Run the following commands inside the container:
```shell
bench set-mariadb-host mariadb
bench set-redis-cache-host redis-cache:6379
bench set-redis-queue-host redis-queue:6379
bench set-redis-socketio-host redis-socketio:6379
```
### Edit Honcho's Procfile
Honcho is the tool used by Bench to manage all the processes Frappe requires. Usually, these all run in localhost, but in this case, we have external containers for Redis. For this reason, we have to stop Honcho from trying to start Redis processes.
Open the Procfile file and remove the three lines containing the configuration from Redis, either by editing manually the file:
```shell
code Procfile
```
Or running the following command:
```shell
sed -i '/redis/d' ./Procfile
```
### Create a new site with bench
You can create a new site with the following command:
```shell
bench new-site sitename
```
for example:
```shell
bench new-site localhost
```
The command will ask the MariaDB root password. The default root password is `123`.
This will create a new site and a `localhost` directory under `frappe-bench/sites`.
Your website will now be accessible on [localhost on port 8000](http://locahost:8000)
### Set bench developer mode on the new site
To develop a new app, the last step will be setting the site into developer mode. Documentation is available at [this link](https://frappe.io/docs/user/en/guides/app-development/how-enable-developer-mode-in-frappe).
```shell
bench set-config developer_mode 1
bench clear-cache
```
### Fixing MariaDB issues after rebuilding the container
The `bench new-site` command creates a user in MariaDB with container IP as host, for this reason after rebuilding the container there is a chance that you will not be able to access MariaDB correctly with the previous configuration
The parameter `'db_name'@'%'` needs to be set in MariaDB and permission to the site database suitably assigned to the user.
This step has to be repeated for all sites available under the current bench.
Example shows the queries to be executed for site `localhost`
Open sites/localhost/site_config.json:
```shell
code sites/localhost/site_config.json
```
and take note of the parameters `db_name` and `db_password`.
Enter MariaDB Interactive shell:
```shell
mysql -uroot -p123 -hmariadb
```
Execute following queries replacing `db_name` and `db_password` with the values found in site_config.json.
```sql
UPDATE mysql.user SET Host = '%' where User = 'db_name'; FLUSH PRIVILEGES;
SET PASSWORD FOR 'db_name'@'%' = PASSWORD('db_password'); FLUSH PRIVILEGES;
GRANT ALL PRIVILEGES ON `db_name`.* TO 'db_name'@'%'; FLUSH PRIVILEGES;
EXIT;
```
## Manually start containers
In case you don't use VSCode, you may start the containers manually with the following command:
```shell
docker-compose -f .devcontainer/docker-compose.yml up -d
```
And enter the interactive shell for the development container with the following command:
```shell
docker exec -e "TERM=xterm-256color" -w /workspace/development -it devcontainer_frappe_1 bash
```
### Visual Studio Code Python Debugging
To enable Python debugging inside Visual Studio Code, you must first install the `ms-python.python` extension inside the container.
- Click on the extension icon inside VSCode
- Search `ms-python.python`
- Click on `Install on Dev Container: Frappe Bench`
- Click on 'Reload'
We need to start bench separately through the VSCode debugger. For this reason, **instead** of running `bench start` you should run the following command inside the frappe-bench directory:
```shell
honcho start \
socketio \
watch \
schedule \
worker_short \
worker_long \
worker_default
```
This command starts all processes with the exception of Redis (which is already running in separate container) and the `web` process. The latter can can finally be started from the debugger tab of VSCode.

View File

@ -1,80 +0,0 @@
version: '3.7'
services:
mariadb:
image: mariadb
environment:
- MYSQL_ROOT_PASSWORD=123
- MYSQL_USER=root
volumes:
- ./conf/mariadb-conf.d:/etc/mysql/conf.d
- /var/lib/mysql
ports:
- "3307:3306" # MariaDB Port
container_name: mariadb
redis-cache:
image: redis:alpine
volumes:
- ./conf/redis-conf.d:/etc/conf.d
command: ["redis-server","/etc/conf.d/redis_cache.conf"]
container_name: redis-cache
redis-queue:
image: redis:alpine
volumes:
- ./conf/redis-conf.d:/etc/conf.d
command: ["redis-server","/etc/conf.d/redis_queue.conf"]
container_name: redis-queue
redis-socketio:
image: redis:alpine
volumes:
- ./conf/redis-conf.d:/etc/conf.d
command: ["redis-server","/etc/conf.d/redis_socketio.conf"]
container_name: redis-socketio
frappe:
build: .
volumes:
- ./frappe-bench:/home/frappe/frappe-bench
- ./conf/redis-conf.d/redis_cache.conf:/home/frappe/frappe-bench/config/redis_cache.conf
- ./conf/redis-conf.d/redis_queue.conf:/home/frappe/frappe-bench/config/redis_queue.conf
- ./conf/redis-conf.d/redis_socketio.conf:/home/frappe/frappe-bench/config/redis_socketio.conf
ports:
- "8000:8000" # Webserver Port
- "9000:9000" # Socketio Port
- "6787:6787" # File Watcher Port
stdin_open: true
tty: true
links:
- redis-cache
- redis-queue
- redis-socketio
- mariadb
depends_on:
- mariadb
- redis-cache
- redis-queue
- redis-socketio
container_name: frappe

250
frappe-installer Executable file
View File

@ -0,0 +1,250 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
[ -z "$DEBUG" ] & [ "${DEBUG}" == 1 ] && set -o xtrace
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$__dir"
env_url="https://raw.githubusercontent.com/frappe/frappe_docker/master/installation/env-example"
docker_nginx_url="https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion"
frappe_docker_url="https://github.com/frappe/frappe_docker"
env_file="$__dir/.env"
check_root() {
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root. Login as root or use sudo." 1>&2
exit 1
fi
}
check_git() {
if [ ! -x "$(command -v git)" ]; then
echo "Git is not installed. Please install git before continuing."
exit 1
fi
}
check_docker() {
if [ ! -x "$(command -v docker)" ]; then
read -rp "No docker installation found. Press Enter to install docker or ctrl+c to exit."
curl -fsSL https://get.docker.com | sh
fi
if [ ! -x "$(command -v docker)" ]; then
echo "Docker installation failed. Exiting."
exit 1
fi
}
check_env() {
if [ ! -f "$env_file" ]; then
echo "No environment file found. This file is required for setting up Frappe/ERPNext Docker."
echo "Would you like to fetch the default environment file?"
echo "(NOTE: You will be prompted to set it up later)"
read -rp "Press Enter to fetch the configuration file, or create a .env file and re-run the script."
curl -fsSL "$env_url" -o "$env_file"
fi
}
clone_repository() {
echo "Cloning Repository: $1"
git clone "$2"
}
get_config() {
if [ -n "$2" ]; then
config_file="$2"
else
config_file="$env_file"
fi
line=$(grep -E "^$=" "$config_file")
line_result=$(echo "$line" | awk -F"=" '{print $2}')
}
get_install_version() {
echo "Choose a version you would like to setup [current: $1]:"
echo "1. develop (edge)"
echo "2. version-12"
echo "3. version-11"
echo "Please enter your choice [1-3]: "
select choice in "1" "2" "3"; do
case $choice in
1 ) version="edge" ;;
2 ) version="version-12" ;;
3 ) version="version-11" ;;
esac
done
}
prompt_config() {
# inspired by discourse_docker
get_config "VERSION"
local install_version=$line_result
get_config "MYSQL_ROOT_PASSWORD"
local mysql_password=$line_result
get_config "SITES"
local sites=$line_result
get_config "LETSENCRYPT_EMAIL"
local letsencrypt_email=$line_result
echo "Would you like to setup networking for docker? [y/n]"
echo "This is required if you wish to access the instance from other machines."
select choice in "y" "n"; do
case $choice in
y ) setup_networking=1 ;;
n ) setup_networking=0
setup_letsencrypt=0 ;;
esac
done
if [ -n "$letsencrypt_email" ] & [ "$setup_networking" -ne "0" ]; then
echo "Would you like to setup LetsEncrypt? [y/n]"
select choice in "y" "n"; do
case $choice in
y ) setup_letsencrypt=1
echo "Please ensure that all the required domains point to this IP address."
read -rp "Enter an Email Address to setup LetsEncrypt with: " letsencrypt_email ;;
n ) setup_letsencrypt=0
echo "Skipping LetsEncrypt Setup." ;;
esac
done
fi
local new_value=""
local config_state="n"
echo
get_install_version "$install_version"
install_version="$version"
while [ "$config_state" = "n" ]; do
if [ -n "$mysql_password" ]; then
read -srp "Enter MySQL Password [$mysql_password]: " new_value
if [ -n "$new_value" ]; then
mysql_password="$new_value"
fi
fi
if [ -n "$sites" ]; then
read -rp "Enter sitename to setup [$sites]: " new_value
if [ -n "$new_value" ]; then
sites="$new_value"
fi
fi
if [ "$setup_letsencrypt" -ne "0" ]; then
read -rp "Enter email address for LetsEncrypt [$letsencrypt_email]: " new_value
if [ -n "$new_value" ]; then
letsencrypt_email=$new_value
fi
fi
echo "Current Configuration:"
echo "Version: $([ "$install_version" = "edge" ] && echo "develop" || echo "$install_version")"
echo "MySQL Root Password: $mysql_password"
echo "Sites: $sites"
if [ "$setup_letsencrypt" -ne "0" ]; then
echo "LetsEncrypt Email Address: $letsencrypt_email"
fi
echo
echo "Does this configuration look okay?"
read -rp "Press Enter to continue, 'n' to try again, or ctrl+c to exit: " config_state
done
echo "Saving the current configuration file to $env_file"
cat << EOF > "$env_file"
VERSION=$install_version
MYSQL_ROOT_PASSWORD=$mysql_password
SITES=$sites
$([ "$setup_letsencrypt" -ne "0" ] && echo "LETSENCRYPT_EMAIL=$letsencrypt_email")
EOF
setup_configuration=$(<"$env_file")
}
setup_user() {
echo "The rest of the setup requires a user account."
echo "You may use an existing account, or set up a new one right away."
read -rp "Enter username: " username
if grep -E "^$username" /etc/passwd > /dev/null; then
echo "User $username already exists."
else
read -rsp "Enter password: " password
password="$(perl -e 'print crypt($ARGV[0], "password")' "$password")"
if useradd -m -p "$password" "$username" -s "$(command -v bash)"; then
echo "User $username has been added to the system."
else
echo "Failed to add user to the system."
echo "Please add a user manually and re-run the script."
exit 1
fi
fi
if ! getent group docker > /dev/null 2>&1 ; then
echo "Creating group: docker"
groupadd docker
fi
echo "Adding user $username to group: docker"
usermod -aG docker "$username"
newgrp docker
}
install() {
if [ "$setup_letsencrypt" -ne "0" ] & [ "$setup_networking" -ne "0" ]; then
echo "Setting up NGINX Proxy for LetsEncrypt"
clone_repository "Docker Compose LetsEncrypt NGINX Proxy Companion" "$docker_nginx_url"
cd "$(basename "$docker_nginx_url")"
if [ -f .env.sample ]; then
cp .env.sample env
fi
./start.sh > /dev/null 2>&1
cd "$(eval echo ~"$username")"
fi
echo "Setting up Frappe/ERPNext"
clone_repository "Frappe/ERPNext Docker" "$frappe_docker_url"
cd "$(basename "$frappe_docker_url")"
echo "$setup_configuration" > .env
echo "Enter a name for the project."
read -rp "This project name will be used to setup the docker instance: [erpnext_docker]" project_name
if [ -z "$project_name" ]; then
echo "Setting the project name to erpnext_docker"
project_name="erpnext_docker"
fi
docker-compose \
--project-name "$project_name" \
--project-directory . up -d \
-f installation/docker-compose-frappe.yml \
-f installation/docker-compose-erpnext.yml \
-f installation/docker-compose-common.yml \
"$( (( setup_networking == 1 )) && printf %s '-f installation/docker-compose-networks.yml' )"
get_config "SITES" "$(pwd)/.env"
local sites=$line_result
docker exec \
-e "SITE_NAME=$sites" \
-e "INSTALL_ERPNEXT=1" \
-it "$project_name"_erpnext-python_1 docker-entrypoint.sh new
echo "Installation Complete!"
}
check_root
check_git
check_docker
check_env
prompt_config
setup_user
su - "$username" << EOF
install
EOF

View File

@ -0,0 +1,117 @@
version: '3'
services:
[app]-assets:
image: [app]-assets
build:
context: .
dockerfile: ./build/[app]-assets/Dockerfile
restart: on-failure
environment:
- FRAPPE_PY=erpnext-python
- FRAPPE_PY_PORT=8000
- FRAPPE_SOCKETIO=frappe-socketio
- SOCKETIO_PORT=9000
- LETSENCRYPT_HOST=${SITES}
- VIRTUAL_HOST=${SITES}
- LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
depends_on:
- [app]-python
- frappe-socketio
- frappe-worker-default
- frappe-worker-long
- frappe-worker-short
links:
- [app]-python
- frappe-socketio
- frappe-worker-default
- frappe-worker-long
- frappe-worker-short
volumes:
- ./sites:/var/www/html/sites:rw
- assets-vol:/assets:rw
[app]-python:
image: [app]-worker
build:
context: .
dockerfile: ./build/[app]-worker/Dockerfile
restart: on-failure
environment:
- MARIADB_HOST=${MARIADB_HOST}
- REDIS_CACHE=redis-cache:6379
- REDIS_QUEUE=redis-queue:6379
- REDIS_SOCKETIO=redis-socketio:6379
- SOCKETIO_PORT=9000
volumes:
- ./sites:/home/frappe/frappe-bench/sites:rw
- assets-vol:/home/frappe/frappe-bench/sites/assets:rw
frappe-socketio:
image: frappe/frappe-socketio:${VERSION}
restart: on-failure
depends_on:
- redis-socketio
links:
- redis-socketio
volumes:
- ./sites:/home/frappe/frappe-bench/sites:rw
frappe-worker-default:
image: [app]-worker
restart: on-failure
command: worker
depends_on:
- redis-queue
- redis-cache
links:
- redis-queue
- redis-cache
volumes:
- ./sites:/home/frappe/frappe-bench/sites:rw
frappe-worker-short:
image: [app]-worker
restart: on-failure
command: worker
environment:
- WORKER_TYPE=short
depends_on:
- redis-queue
- redis-cache
links:
- redis-queue
- redis-cache
volumes:
- ./sites:/home/frappe/frappe-bench/sites:rw
frappe-worker-long:
image: [app]-worker
restart: on-failure
command: worker
environment:
- WORKER_TYPE=long
depends_on:
- redis-queue
- redis-cache
links:
- redis-queue
- redis-cache
volumes:
- ./sites:/home/frappe/frappe-bench/sites:rw
frappe-schedule:
image: [app]-worker
restart: on-failure
command: schedule
depends_on:
- redis-queue
- redis-cache
links:
- redis-queue
- redis-cache
volumes:
- ./sites:/home/frappe/frappe-bench/sites:rw
volumes:
assets-vol:

View File

@ -1,8 +1,8 @@
version: '3' version: '3'
services: services:
erpnext-assets: erpnext-nginx:
image: frappe/erpnext-assets:${VERSION} image: frappe/erpnext-nginx:${VERSION}
restart: on-failure restart: on-failure
environment: environment:
- FRAPPE_PY=erpnext-python - FRAPPE_PY=erpnext-python

View File

@ -1,8 +1,8 @@
version: '3' version: '3'
services: services:
frappe-assets: frappe-nginx:
image: frappe/frappe-assets:${VERSION} image: frappe/frappe-nginx:${VERSION}
restart: on-failure restart: on-failure
environment: environment:
- FRAPPE_PY=frappe-python - FRAPPE_PY=frappe-python

59
travis.py Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
import argparse
import subprocess
import os
parser = argparse.ArgumentParser(description='frappe_docker common CI elements', add_help=True)
parser.add_argument('service', action='store', type=str, help='Name of the service to build: "erpnext" or "frappe"')
parser.add_argument('-o', '--tag-only', required=False, action='store_true', dest='tag_only', help='Only tag an image and push it.')
image_type = parser.add_mutually_exclusive_group(required=True)
image_type.add_argument('-a', '--nginx', action='store_const', dest='image_type', const='nginx', help='Build the nginx + static assets image')
image_type.add_argument('-s', '--socketio', action='store_const', dest='image_type', const='socketio', help='Build the frappe-socketio image')
image_type.add_argument('-w', '--worker', action='store_const', dest='image_type', const='worker', help='Build the python environment image')
tag_type = parser.add_mutually_exclusive_group(required=True)
tag_type.add_argument('-g', '--git-version', action='store', type=int, dest='version', help='The version number of --service (i.e. "11", "12", etc.)')
tag_type.add_argument('-t', '--tag', action='store', type=str, dest='tag', help='The image tag (i.e. erpnext-worker:$TAG )')
args = parser.parse_args()
def git_version(service, version):
print(f'Pulling {service} v{version}')
subprocess.run(f'git clone https://github.com/frappe/{service} --branch version-{version}', shell=True)
cd = os.getcwd()
os.chdir(os.getcwd() + f'/{service}')
subprocess.run('git fetch --tags', shell=True)
version_tag = subprocess.check_output(f'git tag --list --sort=-version:refname "v{version}*" | sed -n 1p | sed -e \'s#.*@\(\)#\\1#\'', shell=True).strip().decode('ascii')
os.chdir(cd)
return version_tag
def build(service, tag, image, dockerfile):
print(f'Building {service} {image} image using {dockerfile}')
subprocess.run(f'docker build -t {service}-{image} -f build/{service}-{image}/{dockerfile} .', shell=True)
tag_and_push(f'{service}-{image}', tag)
def tag_and_push(image_name, tag):
print(f'Tagging {image_name} as "{tag}" and pushing')
subprocess.run(f'docker tag {image_name} frappe/{image_name}:{tag}', shell=True)
subprocess.run(f'docker push frappe/{image_name}:{tag}', shell=True)
def main():
global tag
global dockerfile
if args.version:
tag = git_version(args.service, args.version)
dockerfile = f'v{args.version}.Dockerfile'
else:
tag = args.tag
dockerfile = 'Dockerfile'
if args.tag_only:
tag_and_push(f'{args.service}-{args.image_type}', tag)
else:
build(args.service, tag, args.image_type, dockerfile)
main()