refactor: build only one frappe/erpnext image

This commit is contained in:
Revant Nandgaonkar 2022-12-28 15:53:15 +05:30
parent 5a38d8da29
commit 2b9d3e9337
31 changed files with 462 additions and 656 deletions

View file

@ -13,12 +13,9 @@ def get_versions():
def update_pwd(frappe_version: str, erpnext_version: str):
with open("pwd.yml", "r+") as f:
content = f.read()
for image, version in (
("frappe/frappe-socketio", frappe_version),
("frappe/erpnext-worker", erpnext_version),
("frappe/erpnext-nginx", erpnext_version),
):
content = re.sub(rf"{image}:.*", f"{image}:{version}", content)
content = re.sub(
rf"frappe/erpnext:.*", f"frappe/erpnext:{erpnext_version}", content
)
f.seek(0)
f.truncate()
f.write(content)

View file

@ -5,15 +5,24 @@ x-depends-on-configurator: &depends_on_configurator
x-backend-defaults: &backend_defaults
<<: *depends_on_configurator
image: frappe/erpnext-worker:${ERPNEXT_VERSION:?No ERPNext version set}
image: frappe/erpnext:${ERPNEXT_VERSION:?No ERPNext version set}
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets:ro
services:
configurator:
<<: *backend_defaults
command: configure.py
entrypoint:
- bash
- -c
command:
- >
bench set-config -g db_host $$DB_HOST;
bench set-config -gp db_port $$DB_PORT;
bench set-config -g redis_cache "redis://$$REDIS_CACHE";
bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
bench set-config -g redis_socketio "redis://$$REDIS_SOCKETIO";
bench set-config -gp socketio_port $$SOCKETIO_PORT;
environment:
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
@ -27,7 +36,9 @@ services:
<<: *backend_defaults
frontend:
image: frappe/erpnext-nginx:${ERPNEXT_VERSION}
image: frappe/erpnext:${ERPNEXT_VERSION}
command:
- nginx-entrypoint.sh
environment:
BACKEND: backend:8000
SOCKETIO: websocket:9000
@ -38,15 +49,17 @@ services:
PROXY_READ_TIMOUT: ${PROXY_READ_TIMOUT:-120}
CLIENT_MAX_BODY_SIZE: ${CLIENT_MAX_BODY_SIZE:-50m}
volumes:
- sites:/usr/share/nginx/html/sites
- assets:/usr/share/nginx/html/assets
- sites:/home/frappe/frappe-bench/sites
depends_on:
- backend
- websocket
websocket:
<<: *depends_on_configurator
image: frappe/frappe-socketio:${FRAPPE_VERSION}
image: frappe/erpnext:${ERPNEXT_VERSION}
command:
- node
- /home/frappe/frappe-bench/apps/frappe/socketio.js
volumes:
- sites:/home/frappe/frappe-bench/sites
@ -69,4 +82,3 @@ services:
# ERPNext requires local assets access (Frappe does not)
volumes:
sites:
assets:

View file

@ -1,46 +0,0 @@
This is basic configuration for building images and testing custom apps that use Frappe.
You can see that there's four files in this folder:
- `backend.Dockerfile`,
- `frontend.Dockerfile`,
- `docker-bake.hcl`,
- `compose.override.yaml`.
Python code will be built in `backend.Dockerfile`. JS and CSS (and other fancy frontend stuff) files will be built in `frontend.Dockerfile`.
`docker-bake.hcl` is reference file for [Buildx Bake](https://github.com/docker/buildx/blob/master/docs/reference/buildx_bake.md). It helps to build images without having to remember all build arguments.
`compose.override.yaml` is [Compose](https://docs.docker.com/compose/compose-file/) override that replaces images from [main compose file](https://github.com/frappe/frappe_docker/blob/main/compose.yaml) so it would use your own images.
To get started, install Docker and [Buildx](https://github.com/docker/buildx#installing). Then copy all content of this folder (except this README) to your app's root directory. Also copy `compose.yaml` in the root of this repository.
Before the next step—to build images—replace "custom_app" with your app's name in `docker-bake.hcl`. After that, let's try to build:
```bash
FRAPPE_VERSION=... ERPNEXT_VERSION=... docker buildx bake
```
> 💡 We assume that majority of our users use ERPNext, that's why images in this tutorial are based on ERPNext images. If don't want ERPNext, change base image in Dockerfile and remove ERPNEXT_VERSION from bake file. To know more about steps used to build frontend image read comments in `frontend.Dockerfile`.
If something goes wrong feel free to leave an issue.
To test if site works, setup `.env` file (check [example](<(https://github.com/frappe/frappe_docker/blob/main/example.env)>)) and run:
```bash
docker-compose -f compose.yaml -f overrides/compose.noproxy.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml -f custom_app/compose.override.yaml up -d
docker-compose exec backend \
bench new-site 127.0.0.1 \
--mariadb-root-password 123 \
--admin-password admin \
--install-app <Name of your app>
docker-compose restart backend
```
Cool! You just containerized your app!
## Installing multiple apps
Backend builds contain `install-app` script that places app where it should be. Each call to script installs given app. Usage: `install-app [APP_NAME]`.
If you want to install an app from git, clone it locally, COPY in Dockerfile.

View file

@ -1,14 +0,0 @@
# syntax=docker/dockerfile:1.3
ARG ERPNEXT_VERSION
FROM frappe/erpnext-worker:${ERPNEXT_VERSION}
USER root
ARG APP_NAME
COPY . ../apps/${APP_NAME}
RUN --mount=type=cache,target=/root/.cache/pip \
install-app ${APP_NAME}
USER frappe

View file

@ -1,21 +0,0 @@
services:
configurator:
image: custom_app/worker:${VERSION}
backend:
image: custom_app/worker:${VERSION}
frontend:
image: custom_app/nginx:${VERSION}
queue-short:
image: custom_app/worker:${VERSION}
queue-default:
image: custom_app/worker:${VERSION}
queue-long:
image: custom_app/worker:${VERSION}
scheduler:
image: custom_app/worker:${VERSION}

View file

@ -1,27 +0,0 @@
APP_NAME="custom_app"
variable "FRAPPE_VERSION" {}
variable "ERPNEXT_VERSION" {}
group "default" {
targets = ["backend", "frontend"]
}
target "backend" {
dockerfile = "backend.Dockerfile"
tags = ["custom_app/worker:latest"]
args = {
"ERPNEXT_VERSION" = ERPNEXT_VERSION
"APP_NAME" = APP_NAME
}
}
target "frontend" {
dockerfile = "frontend.Dockerfile"
tags = ["custom_app/nginx:latest"]
args = {
"FRAPPE_VERSION" = FRAPPE_VERSION
"ERPNEXT_VERSION" = ERPNEXT_VERSION
"APP_NAME" = APP_NAME
}
}

View file

@ -1,37 +0,0 @@
ARG FRAPPE_VERSION=version-14
# Prepare builder image
FROM frappe/bench:latest as assets
ARG FRAPPE_VERSION=version-14
ARG ERPNEXT_VERSION=version-14
ARG APP_NAME
# Setup frappe-bench using FRAPPE_VERSION
RUN bench init --version=${FRAPPE_VERSION} --skip-redis-config-generation --verbose --skip-assets /home/frappe/frappe-bench
WORKDIR /home/frappe/frappe-bench
# Comment following if ERPNext is not required
RUN bench get-app --branch=${ERPNEXT_VERSION} --skip-assets --resolve-deps erpnext
# Copy custom app(s)
COPY --chown=frappe:frappe . apps/${APP_NAME}
# Setup dependencies
RUN bench setup requirements
# Build static assets, copy files instead of symlink
RUN bench build --production --verbose --hard-link
# Use frappe-nginx image with nginx template and env vars
FROM frappe/frappe-nginx:${FRAPPE_VERSION}
# Remove existing assets
USER root
RUN rm -fr /usr/share/nginx/html/assets
# Copy built assets
COPY --from=assets /home/frappe/frappe-bench/sites/assets /usr/share/nginx/html/assets
# Use non-root user
USER 1000

View file

@ -44,10 +44,6 @@ target "bench-test" {
# Main images
# Base for all other targets
group "erpnext" {
targets = ["erpnext-worker", "erpnext-nginx", "frappe-socketio"]
}
group "default" {
targets = ["erpnext"]
}
@ -64,46 +60,20 @@ function "tag" {
target "default-args" {
args = {
FRAPPE_REPO = "${FRAPPE_REPO}"
ERPNEXT_REPO = "${ERPNEXT_REPO}"
FRAPPE_PATH = "${FRAPPE_REPO}"
ERPNEXT_PATH = "${ERPNEXT_REPO}"
BENCH_REPO = "${BENCH_REPO}"
FRAPPE_VERSION = "${FRAPPE_VERSION}"
ERPNEXT_VERSION = "${ERPNEXT_VERSION}"
FRAPPE_BRANCH = "${FRAPPE_VERSION}"
ERPNEXT_BRANCH = "${ERPNEXT_VERSION}"
PYTHON_VERSION = can(regex("v13", "${ERPNEXT_VERSION}")) ? "3.9.9" : "3.10.5"
NODE_VERSION = can(regex("v13", "${FRAPPE_VERSION}")) ? "14.19.3" : "16.18.0"
}
}
target "frappe-worker" {
target "erpnext" {
inherits = ["default-args"]
context = "images/worker"
target = "frappe"
tags = tag("frappe-worker", "${FRAPPE_VERSION}")
}
target "erpnext-worker" {
inherits = ["default-args"]
context = "images/worker"
context = "."
dockerfile = "images/production/Containerfile"
target = "erpnext"
tags = tag("erpnext-worker", "${ERPNEXT_VERSION}")
}
target "frappe-nginx" {
inherits = ["default-args"]
context = "images/nginx"
target = "frappe"
tags = tag("frappe-nginx", "${FRAPPE_VERSION}")
}
target "erpnext-nginx" {
inherits = ["default-args"]
context = "images/nginx"
target = "erpnext"
tags = tag("erpnext-nginx", "${ERPNEXT_VERSION}")
}
target "frappe-socketio" {
inherits = ["default-args"]
context = "images/socketio"
tags = tag("frappe-socketio", "${FRAPPE_VERSION}")
tags = tag("erpnext", "${ERPNEXT_VERSION}")
}

View file

@ -5,7 +5,7 @@ Create backup service or stack.
version: "3.7"
services:
backup:
image: frappe/erpnext-worker:v14
image: frappe/erpnext:v14
entrypoint: ["bash", "-c"]
command: |
for SITE in $(/home/frappe/frappe-bench/env/bin/python -c "import frappe;print(' '.join(frappe.utils.get_sites()))")

View file

@ -3,7 +3,7 @@ Example: https://discuss.erpnext.com/t/sms-two-factor-authentication-otp-msg-cha
Above example needs following Dockerfile based patch
```Dockerfile
FROM frappe/erpnext-worker:v12.17.0
FROM frappe/erpnext:v14
...
USER root
@ -12,23 +12,3 @@ USER frappe
...
```
Example for `nginx` image,
```Dockerfile
FROM frappe/erpnext-nginx:v13.27.0
# Hack to use Frappe/ERPNext offline.
RUN sed -i 's/navigator.onLine/navigator.onLine||true/' \
/usr/share/nginx/html/assets/js/desk.min.js \
/usr/share/nginx/html/assets/js/dialog.min.js \
/usr/share/nginx/html/assets/js/frappe-web.min.js
```
Alternatively copy the modified source code file directly over `/home/frappe/frappe-bench/apps/frappe/frappe/twofactor.py`
```Dockerfile
...
COPY twofactor.py /home/frappe/frappe-bench/apps/frappe/frappe/twofactor.py
...
```

View file

@ -176,7 +176,7 @@ Create sites `one.example.com` and `two.example.com`:
```shell
# one.example.com
docker compose --project-name erpnext-one exec backend \
bench new-site one.example.com --mariadb-root-password changeit --install-app erpnext --admin-password changeit
bench new-site one.example.com --no-mariadb-socket --mariadb-root-password changeit --install-app erpnext --admin-password changeit
```
You can stop here and have a single bench single site setup complete. Continue to add one more site to the current bench.
@ -184,7 +184,7 @@ You can stop here and have a single bench single site setup complete. Continue t
```shell
# two.example.com
docker compose --project-name erpnext-one exec backend \
bench new-site two.example.com --mariadb-root-password changeit --install-app erpnext --admin-password changeit
bench new-site two.example.com --no-mariadb-socket --mariadb-root-password changeit --install-app erpnext --admin-password changeit
```
#### Create second bench
@ -236,10 +236,10 @@ Create sites `three.example.com` and `four.example.com`:
```shell
# three.example.com
docker compose --project-name erpnext-two exec backend \
bench new-site three.example.com --mariadb-root-password changeit --install-app erpnext --admin-password changeit
bench new-site three.example.com --no-mariadb-socket --mariadb-root-password changeit --install-app erpnext --admin-password changeit
# four.example.com
docker compose --project-name erpnext-two exec backend \
bench new-site four.example.com --mariadb-root-password changeit --install-app erpnext --admin-password changeit
bench new-site four.example.com --no-mariadb-socket --mariadb-root-password changeit --install-app erpnext --admin-password changeit
```
#### Create custom domain to existing site

View file

@ -9,7 +9,7 @@ Note:
- Wait for the `db` service to start and `configurator` to exit before trying to create a new site. Usually this takes up to 10 seconds.
```sh
docker-compose exec backend bench new-site <site-name> --mariadb-root-password <db-password> --admin-password <admin-password>
docker-compose exec backend bench new-site <site-name> --no-mariadb-socket --mariadb-root-password <db-password> --admin-password <admin-password>
```
If you need to install some app, specify `--install-app`. To see all options, just run `bench new-site --help`.
@ -24,7 +24,7 @@ docker-compose exec backend bench set-config -g root_password <root-password>
Also command is slightly different:
```sh
docker-compose exec backend bench new-site <site-name> --db-type postgres --admin-password <admin-password>
docker-compose exec backend bench new-site <site-name> --no-mariadb-socket --db-type postgres --admin-password <admin-password>
```
## Push backup to S3 storage

142
images/custom/Containerfile Normal file
View file

@ -0,0 +1,142 @@
ARG PYTHON_VERSION=3.10.5
FROM python:${PYTHON_VERSION}-slim-bullseye AS base
ARG WKHTMLTOPDF_VERSION=0.12.6-1
ARG NODE_VERSION=16.18.0
ENV NVM_DIR=/home/frappe/.nvm
ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
RUN useradd -ms /bin/bash frappe \
&& apt-get update \
&& apt-get install --no-install-recommends -y \
curl \
git \
vim \
nginx \
gettext-base \
# MariaDB
mariadb-client \
# Postgres
libpq-dev \
postgresql-client \
# For healthcheck
wait-for-it \
jq \
# NodeJS
&& mkdir -p ${NVM_DIR} \
&& curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash \
&& . ${NVM_DIR}/nvm.sh \
&& nvm install ${NODE_VERSION} \
&& nvm use v${NODE_VERSION} \
&& npm install -g yarn \
&& nvm alias default v${NODE_VERSION} \
&& rm -rf ${NVM_DIR}/.cache \
&& echo 'export NVM_DIR="/home/frappe/.nvm"' >>/home/frappe/.bashrc \
&& echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm' >>/home/frappe/.bashrc \
&& echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion' >>/home/frappe/.bashrc \
# Install wkhtmltopdf with patched qt
&& if [ "$(uname -m)" = "aarch64" ]; then export ARCH=arm64; fi \
&& if [ "$(uname -m)" = "x86_64" ]; then export ARCH=amd64; fi \
&& downloaded_file=wkhtmltox_$WKHTMLTOPDF_VERSION.buster_${ARCH}.deb \
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
&& apt-get install -y ./$downloaded_file \
&& rm $downloaded_file \
# Clean up
&& rm -rf /var/lib/apt/lists/* \
&& rm -fr /etc/nginx/sites-enabled/default \
&& pip3 install frappe-bench
FROM base AS builder
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
# For frappe framework
wget \
# For psycopg2
libpq-dev \
# Other
libffi-dev \
liblcms2-dev \
libldap2-dev \
libmariadb-dev \
libsasl2-dev \
libtiff5-dev \
libwebp-dev \
redis-tools \
rlwrap \
tk8.6-dev \
cron \
# For pandas
gcc \
build-essential \
libbz2-dev \
&& rm -rf /var/lib/apt/lists/*
# apps.json includes
ARG APPS_JSON=[]
RUN mkdir /opt/frappe && echo "${APPS_JSON}" | jq . > /opt/frappe/apps.json
USER frappe
ARG FRAPPE_BRANCH=version-14
ARG FRAPPE_PATH=https://github.com/frappe/frappe
RUN bench init \
--frappe-branch=${FRAPPE_BRANCH} \
--frappe-path=${FRAPPE_PATH} \
--no-procfile \
--no-backups \
--skip-redis-config-generation \
--verbose \
--skip-assets \
--apps_path=/opt/frappe/apps.json \
/home/frappe/frappe-bench && \
cd /home/frappe/frappe-bench && \
bench setup requirements && \
find /home/frappe/frappe-bench/apps -mindepth 1 -path "*/.git" | xargs rm -fr
WORKDIR /home/frappe/frappe-bench
RUN export BUILD_OPTS="--production --hard-link" && \
if [ -z "${FRAPPE_BRANCH##*v12*}" ] || [ -z "${FRAPPE_BRANCH##*v13*}" ] \
|| [ "$FRAPPE_BRANCH" = "version-12" ] || [ "$FRAPPE_BRANCH" = "version-13" ]; then \
export BUILD_OPTS="--make-copy"; \
fi && \
FRAPPE_ENV=production bench build --verbose ${BUILD_OPTS}
FROM base as backend
# Fixes for non-root nginx and logs to stdout
RUN sed -i '/user www-data/d' /etc/nginx/nginx.conf && \
ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log && \
touch /run/nginx.pid && \
chown -R frappe:frappe /etc/nginx/conf.d && \
chown -R frappe:frappe /etc/nginx/nginx.conf && \
chown -R frappe:frappe /var/log/nginx && \
chown -R frappe:frappe /var/lib/nginx && \
chown -R frappe:frappe /run/nginx.pid
COPY resources/nginx-template.conf /templates/nginx/frappe.conf.template
COPY resources/nginx-entrypoint.sh /usr/local/bin/nginx-entrypoint.sh
COPY resources/push_backup.py /usr/local/bin/push-backup
USER frappe
COPY --from=builder --chown=frappe:frappe /home/frappe/frappe-bench /home/frappe/frappe-bench
WORKDIR /home/frappe/frappe-bench
VOLUME [ \
"/home/frappe/frappe-bench/sites", \
"/home/frappe/frappe-bench/sites/assets", \
"/home/frappe/frappe-bench/logs" \
]
CMD [ \
"/home/frappe/frappe-bench/env/bin/gunicorn", \
"--chdir=/home/frappe/frappe-bench/sites", \
"--bind=0.0.0.0:8000", \
"--threads=4", \
"--workers=2", \
"--worker-class=gthread", \
"--worker-tmp-dir=/dev/shm", \
"--timeout=120", \
"--preload", \
"frappe.app:application" \
]

View file

@ -1,62 +0,0 @@
FROM frappe/bench:latest as assets_builder
ARG FRAPPE_VERSION
ARG FRAPPE_REPO=https://github.com/frappe/frappe
ARG PYTHON_VERSION
ARG NODE_VERSION
ENV NVM_DIR=/home/frappe/.nvm
ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
RUN PYENV_VERSION=${PYTHON_VERSION} bench init --version=${FRAPPE_VERSION} --frappe-path=${FRAPPE_REPO} --skip-redis-config-generation --verbose --skip-assets /home/frappe/frappe-bench
WORKDIR /home/frappe/frappe-bench
FROM assets_builder as frappe_assets
RUN bench setup requirements \
&& if [ -z "${FRAPPE_VERSION##*v14*}" ] || [ "$FRAPPE_VERSION" = "develop" ]; then \
export BUILD_OPTS="--production";\
fi \
&& FRAPPE_ENV=production bench build --verbose --hard-link ${BUILD_OPTS}
FROM assets_builder as erpnext_assets
ARG ERPNEXT_VERSION
ARG ERPNEXT_REPO=https://github.com/frappe/erpnext
RUN bench get-app --branch=${ERPNEXT_VERSION} --skip-assets --resolve-deps erpnext ${ERPNEXT_REPO}\
&& if [ -z "${ERPNEXT_VERSION##*v14*}" ] || [ "$ERPNEXT_VERSION" = "develop" ]; then \
export BUILD_OPTS="--production"; \
fi \
&& FRAPPE_ENV=production bench build --verbose --hard-link ${BUILD_OPTS}
FROM alpine/git as bench
# Error pages
ARG BENCH_REPO=https://github.com/frappe/bench
RUN git clone --depth 1 ${BENCH_REPO} /tmp/bench \
&& mkdir /out \
&& mv /tmp/bench/bench/config/templates/502.html /out \
&& touch /out/.build
FROM nginxinc/nginx-unprivileged:1.23.3-alpine as frappe
# Set default ENV variables for backwards compatibility
ENV PROXY_READ_TIMOUT=120
ENV CLIENT_MAX_BODY_SIZE=50m
# https://github.com/nginxinc/docker-nginx-unprivileged/blob/main/stable/alpine/20-envsubst-on-templates.sh
COPY nginx-template.conf /etc/nginx/templates/default.conf.template
# https://github.com/nginxinc/docker-nginx-unprivileged/blob/main/stable/alpine/docker-entrypoint.sh
COPY entrypoint.sh /docker-entrypoint.d/frappe-entrypoint.sh
COPY --from=bench /out /usr/share/nginx/html/
COPY --from=frappe_assets /home/frappe/frappe-bench/sites/assets /usr/share/nginx/html/assets
USER 1000
FROM frappe as erpnext
COPY --from=erpnext_assets /home/frappe/frappe-bench/sites/assets /usr/share/nginx/html/assets

View file

@ -1,9 +0,0 @@
#!/bin/sh
set -e
# Update timestamp for ".build" file to enable caching assets:
# https://github.com/frappe/frappe/blob/52d8e6d952130eea64a9990b9fd5b1f6877be1b7/frappe/utils/__init__.py#L799-L805
if [ -d /usr/share/nginx/html/sites ]; then
touch /usr/share/nginx/html/sites/.build -r /usr/share/nginx/html/.build
fi

View file

@ -0,0 +1,137 @@
ARG PYTHON_VERSION=3.10.5
FROM python:${PYTHON_VERSION}-slim-bullseye AS base
ARG WKHTMLTOPDF_VERSION=0.12.6-1
ARG NODE_VERSION=16.18.0
ENV NVM_DIR=/home/frappe/.nvm
ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
RUN useradd -ms /bin/bash frappe \
&& apt-get update \
&& apt-get install --no-install-recommends -y \
curl \
git \
vim \
nginx \
gettext-base \
# MariaDB
mariadb-client \
# Postgres
libpq-dev \
postgresql-client \
# For healthcheck
wait-for-it \
jq \
# NodeJS
&& mkdir -p ${NVM_DIR} \
&& curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash \
&& . ${NVM_DIR}/nvm.sh \
&& nvm install ${NODE_VERSION} \
&& nvm use v${NODE_VERSION} \
&& npm install -g yarn \
&& nvm alias default v${NODE_VERSION} \
&& rm -rf ${NVM_DIR}/.cache \
&& echo 'export NVM_DIR="/home/frappe/.nvm"' >>/home/frappe/.bashrc \
&& echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm' >>/home/frappe/.bashrc \
&& echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion' >>/home/frappe/.bashrc \
# Install wkhtmltopdf with patched qt
&& if [ "$(uname -m)" = "aarch64" ]; then export ARCH=arm64; fi \
&& if [ "$(uname -m)" = "x86_64" ]; then export ARCH=amd64; fi \
&& downloaded_file=wkhtmltox_$WKHTMLTOPDF_VERSION.buster_${ARCH}.deb \
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
&& apt-get install -y ./$downloaded_file \
&& rm $downloaded_file \
# Clean up
&& rm -rf /var/lib/apt/lists/* \
&& rm -fr /etc/nginx/sites-enabled/default \
&& pip3 install frappe-bench
FROM base AS builder
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
# For frappe framework
wget \
# For psycopg2
libpq-dev \
# Other
libffi-dev \
liblcms2-dev \
libldap2-dev \
libmariadb-dev \
libsasl2-dev \
libtiff5-dev \
libwebp-dev \
redis-tools \
rlwrap \
tk8.6-dev \
cron \
# For pandas
gcc \
build-essential \
libbz2-dev \
&& rm -rf /var/lib/apt/lists/*
USER frappe
ARG FRAPPE_BRANCH=version-14
ARG FRAPPE_PATH=https://github.com/frappe/frappe
ARG ERPNEXT_REPO=https://github.com/frappe/erpnext
ARG ERPNEXT_BRANCH=version-14
RUN bench init \
--frappe-branch=${FRAPPE_BRANCH} \
--frappe-path=${FRAPPE_PATH} \
--no-procfile \
--no-backups \
--skip-redis-config-generation \
--verbose \
--skip-assets \
/home/frappe/frappe-bench
WORKDIR /home/frappe/frappe-bench
RUN bench get-app --branch=${ERPNEXT_BRANCH} --skip-assets --resolve-deps erpnext ${ERPNEXT_REPO} && \
export BUILD_OPTS="--production --hard-link" && \
if [ -z "${FRAPPE_BRANCH##*v12*}" ] || [ -z "${FRAPPE_BRANCH##*v13*}" ] \
|| [ "$FRAPPE_BRANCH" = "version-12" ] || [ "$FRAPPE_BRANCH" = "version-13" ]; then \
export BUILD_OPTS="--make-copy"; \
fi && \
FRAPPE_ENV=production bench build --verbose ${BUILD_OPTS}
FROM base as erpnext
# Fixes for non-root nginx and logs to stdout
RUN sed -i '/user www-data/d' /etc/nginx/nginx.conf && \
ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log && \
touch /run/nginx.pid && \
chown -R frappe:frappe /etc/nginx/conf.d && \
chown -R frappe:frappe /etc/nginx/nginx.conf && \
chown -R frappe:frappe /var/log/nginx && \
chown -R frappe:frappe /var/lib/nginx && \
chown -R frappe:frappe /run/nginx.pid
COPY resources/nginx-template.conf /templates/nginx/frappe.conf.template
COPY resources/nginx-entrypoint.sh /usr/local/bin/nginx-entrypoint.sh
COPY resources/push_backup.py /usr/local/bin/push-backup
USER frappe
COPY --from=builder --chown=frappe:frappe /home/frappe/frappe-bench /home/frappe/frappe-bench
WORKDIR /home/frappe/frappe-bench
VOLUME [ \
"/home/frappe/frappe-bench/sites", \
"/home/frappe/frappe-bench/sites/assets", \
"/home/frappe/frappe-bench/logs" \
]
CMD [ \
"/home/frappe/frappe-bench/env/bin/gunicorn", \
"--chdir=/home/frappe/frappe-bench/sites", \
"--bind=0.0.0.0:8000", \
"--threads=4", \
"--workers=2", \
"--worker-class=gthread", \
"--worker-tmp-dir=/dev/shm", \
"--timeout=120", \
"--preload", \
"frappe.app:application" \
]

View file

@ -1,34 +0,0 @@
FROM alpine/git as builder
ARG FRAPPE_VERSION
ARG FRAPPE_REPO=https://github.com/frappe/frappe
RUN apk add -U jq
RUN git clone --depth 1 -b ${FRAPPE_VERSION} ${FRAPPE_REPO} /opt/frappe
RUN jq --argjson dependencies "$(jq '.dependencies | INDEX( "express", "redis", "socket.io", "superagent" ) as $keep | \
del( \
. | objects | \
.[ \
keys_unsorted[] | \
select( $keep[ . ] | not ) \
] \
)' /opt/frappe/package.json)" '.dependencies = $dependencies | del(.scripts.prepare)' /opt/frappe/package.json > /opt/frappe/dependencies.json && \
mv /opt/frappe/dependencies.json /opt/frappe/package.json
# NodeJS LTS
FROM node:18-alpine
RUN addgroup -S frappe \
&& adduser -S frappe -G frappe
USER frappe
WORKDIR /home/frappe/frappe-bench
RUN mkdir -p sites apps/frappe
COPY --chown=frappe:frappe --from=builder /opt/frappe/package.json /opt/frappe/socketio.js /opt/frappe/node_utils.js apps/frappe/
RUN cd apps/frappe \
&& npm install --omit=dev
WORKDIR /home/frappe/frappe-bench/sites
CMD [ "node", "/home/frappe/frappe-bench/apps/frappe/socketio.js" ]

View file

@ -1,146 +0,0 @@
# syntax=docker/dockerfile:1.3
ARG PYTHON_VERSION
FROM python:${PYTHON_VERSION}-slim-bullseye as base
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
# Postgres
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -ms /bin/bash frappe
USER frappe
RUN mkdir -p /home/frappe/frappe-bench/apps /home/frappe/frappe-bench/logs /home/frappe/frappe-bench/sites /home/frappe/frappe-bench/config
WORKDIR /home/frappe/frappe-bench
USER root
RUN pip install --no-cache-dir -U pip wheel \
&& python -m venv env \
&& env/bin/pip install --no-cache-dir -U pip wheel
COPY install-app.sh /usr/local/bin/install-app
FROM base as build_deps
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
# Install git here because it is not required in production
git \
# gcc and g++ are required for building different packages across different versions
# of Frappe and ERPNext and also on different platforms (for example, linux/arm64).
# It is safe to install build deps even if they are not required
# because they won't be included in final images.
gcc \
g++ \
# Make is required to build wheels of ERPNext deps in develop branch for linux/arm64
make \
&& rm -rf /var/lib/apt/lists/*
FROM build_deps as frappe_builder
ARG FRAPPE_VERSION
ARG FRAPPE_REPO=https://github.com/frappe/frappe
RUN --mount=type=cache,target=/root/.cache/pip \
git clone --depth 1 -b ${FRAPPE_VERSION} ${FRAPPE_REPO} apps/frappe \
&& install-app frappe \
&& env/bin/pip install -U gevent \
# Link Frappe's node_modules/ to make Website Theme work
&& mkdir -p /home/frappe/frappe-bench/sites/assets/frappe/node_modules \
&& ln -s /home/frappe/frappe-bench/sites/assets/frappe/node_modules /home/frappe/frappe-bench/apps/frappe/node_modules
FROM frappe_builder as erpnext_builder
ARG PAYMENTS_VERSION=develop
ARG PAYMENTS_REPO=https://github.com/frappe/payments
ARG ERPNEXT_VERSION
ARG ERPNEXT_REPO=https://github.com/frappe/erpnext
RUN --mount=type=cache,target=/root/.cache/pip \
if [ -z "${ERPNEXT_VERSION##*v14*}" ] || [ "$ERPNEXT_VERSION" = "develop" ]; then \
git clone --depth 1 -b ${PAYMENTS_VERSION} ${PAYMENTS_REPO} apps/payments && install-app payments; \
fi \
&& git clone --depth 1 -b ${ERPNEXT_VERSION} ${ERPNEXT_REPO} apps/erpnext \
&& install-app erpnext
FROM base as configured_base
ARG WKHTMLTOPDF_VERSION=0.12.6-1
ARG NODE_VERSION
ENV NVM_DIR=/home/frappe/.nvm
ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH}
RUN apt-get update \
# Setup Node lists
&& apt-get install --no-install-recommends -y curl git \
# NodeJS with NVM
&& mkdir -p ${NVM_DIR} \
&& curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \
&& . ${NVM_DIR}/nvm.sh \
&& nvm install ${NODE_VERSION} \
&& nvm use v${NODE_VERSION} \
&& npm install -g yarn \
&& nvm alias default v${NODE_VERSION} \
&& rm -rf ${NVM_DIR}/.cache \
&& echo 'export NVM_DIR="/home/frappe/.nvm"' >>~/.bashrc \
&& echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.bashrc \
&& echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion' >> ~/.bashrc \
# Install wkhtmltopdf with patched qt
&& if [ "$(uname -m)" = "aarch64" ]; then export ARCH=arm64; fi \
&& if [ "$(uname -m)" = "x86_64" ]; then export ARCH=amd64; fi \
&& downloaded_file=wkhtmltox_$WKHTMLTOPDF_VERSION.buster_${ARCH}.deb \
&& curl -sLO https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \
&& apt-get install -y ./$downloaded_file \
&& rm $downloaded_file \
# Cleanup
&& apt-get purge -y --auto-remove curl \
&& apt-get update \
&& apt-get install --no-install-recommends -y \
# MariaDB
mariadb-client \
# Postgres
postgresql-client \
# For healthcheck
wait-for-it \
jq \
# Clean up
&& rm -rf /var/lib/apt/lists/*
COPY pretend-bench.sh /usr/local/bin/bench
COPY push_backup.py /usr/local/bin/push-backup
COPY configure.py patched_bench_helper.py /usr/local/bin/
COPY gevent_patch.py /opt/patches/
WORKDIR /home/frappe/frappe-bench/sites
CMD [ "/home/frappe/frappe-bench/env/bin/gunicorn", \
"--bind=0.0.0.0:8000", \
"--threads=4", \
"--workers=2", \
"--worker-class=gthread", \
"--worker-tmp-dir=/dev/shm", \
"--timeout=120", \
"--preload", \
"frappe.app:application" \
]
FROM configured_base as frappe
COPY --from=frappe_builder /home/frappe/frappe-bench/apps/frappe /home/frappe/frappe-bench/apps/frappe
COPY --from=frappe_builder /home/frappe/frappe-bench/env /home/frappe/frappe-bench/env
COPY --from=frappe_builder /home/frappe/frappe-bench/sites/apps.txt /home/frappe/frappe-bench/sites/
USER frappe
# Split frappe and erpnext to reduce image size (because of frappe-bench/env/ directory)
FROM configured_base as erpnext
COPY --from=erpnext_builder --chown=frappe:frappe /home/frappe/frappe-bench/apps /home/frappe/frappe-bench/apps
COPY --from=erpnext_builder --chown=frappe:frappe /home/frappe/frappe-bench/env /home/frappe/frappe-bench/env
COPY --from=erpnext_builder --chown=frappe:frappe /home/frappe/frappe-bench/sites/apps.txt /home/frappe/frappe-bench/sites/
USER frappe

View file

@ -1,56 +0,0 @@
#!/usr/local/bin/python
from __future__ import annotations
import json
import os
from typing import Any, TypeVar
def update_config(**values: Any):
fname = "common_site_config.json"
if not os.path.exists(fname):
with open(fname, "a") as f:
json.dump({}, f)
with open(fname, "r+") as f:
config: dict[str, Any] = json.load(f)
config.update(values)
f.seek(0)
f.truncate()
json.dump(config, f)
_T = TypeVar("_T")
def env(name: str, type_: type[_T] = str) -> _T:
value = os.getenv(name)
if not value:
raise RuntimeError(f'Required environment variable "{name}" not set')
try:
value = type_(value)
except Exception:
raise RuntimeError(
f'Cannot convert environment variable "{name}" to type "{type_}"'
)
return value
def generate_redis_url(url: str):
return f"redis://{url}"
def main() -> int:
update_config(
db_host=env("DB_HOST"),
db_port=env("DB_PORT", int),
redis_cache=generate_redis_url(env("REDIS_CACHE")),
redis_queue=generate_redis_url(env("REDIS_QUEUE")),
redis_socketio=generate_redis_url(env("REDIS_SOCKETIO")),
socketio_port=env("SOCKETIO_PORT", int),
)
return 0
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -1,3 +0,0 @@
import gevent.monkey
gevent.monkey.patch_all()

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -e
set -x
APP=$1
cd /home/frappe/frappe-bench
env/bin/pip install -e "apps/$APP"
echo "$APP" >>sites/apps.txt

View file

@ -1,48 +0,0 @@
from __future__ import annotations
import click
import click.exceptions
import frappe.app
import frappe.database.db_manager
import frappe.utils.bench_helper
def patch_database_creator():
"""
We need to interrupt Frappe site database creation to monkeypatch
functions that resolve host for user that owns site database.
In frappe_docker this was implemented in "new" command:
https://github.com/frappe/frappe_docker/blob/c808ad1767feaf793a2d14541ac0f4d9cbab45b3/build/frappe-worker/commands/new.py#L87
"""
frappe.database.db_manager.DbManager.get_current_host = lambda self: "%"
def patch_click_usage_error():
bits: tuple[str, ...] = (
click.style(
"Only Frappe framework bench commands are available in container setup.",
fg="yellow",
bold=True,
),
"https://frappeframework.com/docs/v13/user/en/bench/frappe-commands",
)
notice = "\n".join(bits)
def format_message(self: click.exceptions.UsageError):
if "No such command" in self.message:
return f"{notice}\n\n{self.message}"
return self.message
click.exceptions.UsageError.format_message = format_message
def main() -> int:
patch_database_creator()
patch_click_usage_error()
frappe.utils.bench_helper.main()
return 0
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -1,5 +0,0 @@
#!/bin/bash
set -e
# shellcheck disable=SC2068
~/frappe-bench/env/bin/python /usr/local/bin/patched_bench_helper.py frappe $@

View file

@ -1,16 +1,30 @@
services:
configurator:
environment:
REDIS_CACHE: redis:6379/0
REDIS_QUEUE: redis:6379/1
REDIS_SOCKETIO: redis:6379/2
REDIS_CACHE: redis-cache:6379
REDIS_QUEUE: redis-queue:6379
REDIS_SOCKETIO: redis-socketio:6379
depends_on:
- redis
- redis-cache
- redis-queue
- redis-socketio
redis:
redis-cache:
image: redis:6.2-alpine
volumes:
- redis-data:/data
- redis-cache-data:/data
redis-queue:
image: redis:6.2-alpine
volumes:
- redis-queue-data:/data
redis-socketio:
image: redis:6.2-alpine
volumes:
- redis-socketio-data:/data
volumes:
redis-data:
redis-cache-data:
redis-queue-data:
redis-socketio-data:

74
pwd.yml
View file

@ -2,18 +2,30 @@ version: "3"
services:
backend:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
configurator:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: none
entrypoint:
- bash
- -c
command:
- configure.py
- >
bench set-config -g db_host $$DB_HOST;
bench set-config -gp db_port $$DB_PORT;
bench set-config -g redis_cache "redis://$$REDIS_CACHE";
bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
bench set-config -g redis_socketio "redis://$$REDIS_SOCKETIO";
bench set-config -gp socketio_port $$SOCKETIO_PORT;
environment:
DB_HOST: db
DB_PORT: "3306"
@ -23,15 +35,16 @@ services:
SOCKETIO_PORT: "9000"
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs
create-site:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
condition: none
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
entrypoint:
- bash
- -c
@ -42,19 +55,19 @@ services:
wait-for-it -t 120 redis-queue:6379;
wait-for-it -t 120 redis-socketio:6379;
export start=`date +%s`;
until [[ -n `grep -hs ^ common_site_config.json | jq -r ".db_host // empty"` ]] && \
[[ -n `grep -hs ^ common_site_config.json | jq -r ".redis_cache // empty"` ]] && \
[[ -n `grep -hs ^ common_site_config.json | jq -r ".redis_queue // empty"` ]];
until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]];
do
echo "Waiting for common_site_config.json to be created";
echo "Waiting for sites/common_site_config.json to be created";
sleep 5;
if (( `date +%s`-start > 120 )); then
echo "could not find common_site_config.json with required keys";
echo "could not find sites/common_site_config.json with required keys";
exit 1
fi
done;
echo "common_site_config.json found";
bench new-site frontend --admin-password=admin --db-root-password=admin --install-app payments --install-app erpnext --set-default;
echo "sites/common_site_config.json found";
bench new-site frontend --no-mariadb-socket --admin-password=admin --db-root-password=admin --install-app payments --install-app erpnext --set-default;
db:
image: mariadb:10.6
@ -76,10 +89,12 @@ services:
- db-data:/var/lib/mysql
frontend:
image: frappe/erpnext-nginx:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
command:
- nginx-entrypoint.sh
environment:
BACKEND: backend:8000
FRAPPE_SITE_NAME_HEADER: frontend
@ -90,13 +105,13 @@ services:
PROXY_READ_TIMOUT: 120
CLIENT_MAX_BODY_SIZE: 50m
volumes:
- sites:/usr/share/nginx/html/sites
- assets:/usr/share/nginx/html/assets
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs
ports:
- "8080:8080"
queue-default:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
@ -107,10 +122,10 @@ services:
- default
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
queue-long:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
@ -121,10 +136,10 @@ services:
- long
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
queue-short:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
@ -135,7 +150,7 @@ services:
- short
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
redis-queue:
image: redis:6.2-alpine
@ -162,7 +177,7 @@ services:
- redis-socketio-data:/data
scheduler:
image: frappe/erpnext-worker:v14.12.1
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
@ -171,21 +186,24 @@ services:
- schedule
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
websocket:
image: frappe/frappe-socketio:v14.22.0
image: frappe/erpnext:v14.12.1
deploy:
restart_policy:
condition: on-failure
command:
- node
- /home/frappe/frappe-bench/apps/frappe/socketio.js
volumes:
- sites:/home/frappe/frappe-bench/sites
- assets:/home/frappe/frappe-bench/sites/assets
- logs:/home/frappe/frappe-bench/logs
volumes:
assets:
db-data:
redis-queue-data:
redis-cache-data:
redis-socketio-data:
sites:
logs:

52
resources/nginx-entrypoint.sh Executable file
View file

@ -0,0 +1,52 @@
#!/bin/bash
# Set variables that do not exist
if [[ -z "$BACKEND" ]]; then
echo "BACKEND defaulting to 0.0.0.0:8000"
export BACKEND=0.0.0.0:8000
fi
if [[ -z "$SOCKETIO" ]]; then
echo "SOCKETIO defaulting to 0.0.0.0:9000"
export SOCKETIO=0.0.0.0:9000
fi
if [[ -z "$UPSTREAM_REAL_IP_ADDRESS" ]]; then
echo "UPSTREAM_REAL_IP_ADDRESS defaulting to 127.0.0.1"
export UPSTREAM_REAL_IP_ADDRESS=127.0.0.1
fi
if [[ -z "$UPSTREAM_REAL_IP_HEADER" ]]; then
echo "UPSTREAM_REAL_IP_HEADER defaulting to X-Forwarded-For"
export UPSTREAM_REAL_IP_HEADER=X-Forwarded-For
fi
if [[ -z "$UPSTREAM_REAL_IP_RECURSIVE" ]]; then
echo "UPSTREAM_REAL_IP_RECURSIVE defaulting to off"
export UPSTREAM_REAL_IP_RECURSIVE=off
fi
if [[ -z "$FRAPPE_SITE_NAME_HEADER" ]]; then
# shellcheck disable=SC2016
echo 'FRAPPE_SITE_NAME_HEADER defaulting to $host'
# shellcheck disable=SC2016
export FRAPPE_SITE_NAME_HEADER='$host'
fi
if [[ -z "$PROXY_READ_TIMEOUT" ]]; then
echo "PROXY_READ_TIMEOUT defaulting to 120"
export PROXY_READ_TIMEOUT=120
fi
if [[ -z "$CLIENT_MAX_BODY_SIZE" ]]; then
echo "CLIENT_MAX_BODY_SIZE defaulting to 50m"
export CLIENT_MAX_BODY_SIZE=50m
fi
# shellcheck disable=SC2016
envsubst '${BACKEND}
${SOCKETIO}
${UPSTREAM_REAL_IP_ADDRESS}
${UPSTREAM_REAL_IP_HEADER}
${UPSTREAM_REAL_IP_RECURSIVE}
${FRAPPE_SITE_NAME_HEADER}
${PROXY_READ_TIMEOUT}
${CLIENT_MAX_BODY_SIZE}' \
</templates/nginx/frappe.conf.template >/etc/nginx/conf.d/frappe.conf
nginx -g 'daemon off;'

View file

@ -15,7 +15,7 @@ map $http_x_forwarded_proto $proxy_x_forwarded_proto {
server {
listen 8080;
server_name $http_host;
root /usr/share/nginx/html;
root /home/frappe/frappe-bench/sites;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
@ -37,7 +37,7 @@ server {
location ~ ^/protected/(.*) {
internal;
try_files /sites/$http_host/$1 =404;
try_files /$http_host/$1 =404;
}
location /socket.io {
@ -60,10 +60,10 @@ server {
location ~ ^/files/.*.(htm|html|svg|xml) {
add_header Content-disposition "attachment";
try_files /sites/${FRAPPE_SITE_NAME_HEADER}/public/$uri @webserver;
try_files /${FRAPPE_SITE_NAME_HEADER}/public/$uri @webserver;
}
try_files /sites/${FRAPPE_SITE_NAME_HEADER}/public/$uri @webserver;
try_files /${FRAPPE_SITE_NAME_HEADER}/public/$uri @webserver;
}
location @webserver {
@ -72,18 +72,12 @@ server {
proxy_set_header X-Frappe-Site-Name ${FRAPPE_SITE_NAME_HEADER};
proxy_set_header Host $host;
proxy_set_header X-Use-X-Accel-Redirect True;
proxy_read_timeout ${PROXY_READ_TIMOUT};
proxy_read_timeout ${PROXY_READ_TIMEOUT};
proxy_redirect off;
proxy_pass http://backend-server;
}
# error pages
error_page 502 /502.html;
location /502.html {
internal;
}
# optimizations
sendfile on;
keepalive_timeout 15;

View file

@ -109,6 +109,7 @@ def parse_args(args: list[str]) -> Arguments:
def main(args: list[str]) -> int:
os.chdir("sites")
push_backup(parse_args(args))
return 0

View file

@ -1,24 +1,24 @@
services:
configurator:
image: localhost:5000/frappe/erpnext-worker:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
backend:
image: localhost:5000/frappe/erpnext-worker:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
frontend:
image: localhost:5000/frappe/erpnext-nginx:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
websocket:
image: localhost:5000/frappe/frappe-socketio:${FRAPPE_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
queue-short:
image: localhost:5000/frappe/erpnext-worker:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
queue-default:
image: localhost:5000/frappe/erpnext-worker:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
queue-long:
image: localhost:5000/frappe/erpnext-worker:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}
scheduler:
image: localhost:5000/frappe/erpnext-worker:${ERPNEXT_VERSION}
image: localhost:5000/frappe/erpnext:${ERPNEXT_VERSION}

View file

@ -55,11 +55,12 @@ def frappe_site(compose: Compose):
site_name = "tests"
compose.bench(
"new-site",
site_name,
"--no-mariadb-socket",
"--mariadb-root-password",
"123",
"--admin-password",
"admin",
site_name,
)
compose("restart", "backend")
yield site_name
@ -79,13 +80,14 @@ def erpnext_site(compose: Compose):
site_name = "test_erpnext_site"
args = [
"new-site",
site_name,
"--no-mariadb-socket",
"--mariadb-root-password",
"123",
"--admin-password",
"admin",
"--install-app",
"erpnext",
site_name,
]
erpnext_version = os.environ.get("ERPNEXT_VERSION")
if erpnext_version in [

View file

@ -89,7 +89,13 @@ def test_frappe_connections_in_backends(
):
filename = "_ping_frappe_connections.py"
compose("cp", f"tests/{filename}", f"{service}:/tmp/")
compose.exec(service, python_path, f"/tmp/{filename}")
compose.exec(
"-w",
"/home/frappe/frappe-bench/sites",
service,
python_path,
f"/tmp/{filename}",
)
def test_push_backup(