mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-26 09:05:10 +00:00
refactor: build only one frappe/erpnext image
This commit is contained in:
parent
5a38d8da29
commit
2b9d3e9337
31 changed files with 462 additions and 656 deletions
9
.github/scripts/update_pwd.py
vendored
9
.github/scripts/update_pwd.py
vendored
|
|
@ -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)
|
||||
|
|
|
|||
28
compose.yaml
28
compose.yaml
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()))")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
...
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
142
images/custom/Containerfile
Normal 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" \
|
||||
]
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
137
images/production/Containerfile
Normal file
137
images/production/Containerfile
Normal 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" \
|
||||
]
|
||||
|
|
@ -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" ]
|
||||
|
|
@ -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
|
||||
|
|
@ -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())
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
import gevent.monkey
|
||||
|
||||
gevent.monkey.patch_all()
|
||||
|
|
@ -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
|
||||
|
|
@ -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())
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# shellcheck disable=SC2068
|
||||
~/frappe-bench/env/bin/python /usr/local/bin/patched_bench_helper.py frappe $@
|
||||
|
|
@ -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
74
pwd.yml
|
|
@ -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
52
resources/nginx-entrypoint.sh
Executable 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;'
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 [
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Reference in a new issue