docs: reorganize container setup information into new subfolder docs/container-setup (#1720)

This commit is contained in:
DanielRadlAMR
2025-10-14 14:01:25 +02:00
committed by GitHub
parent 5b8cbd3aee
commit ffd2aa47a6
10 changed files with 352 additions and 403 deletions

View File

@@ -53,9 +53,9 @@ If you ran in a Dev Docker environment, to view container logs: `docker compose
### [Production](#production)
- [List of containers](docs/list-of-containers.md)
- [List of containers](docs/container-setup/01-overview.md)
- [Single Compose Setup](docs/single-compose-setup.md)
- [Environment Variables](docs/environment-variables.md)
- [Environment Variables](docs/container-setup/env-variables.md)
- [Single Server Example](docs/single-server-example.md)
- [Setup Options](docs/setup-options.md)
- [Site Operations](docs/site-operations.md)
@@ -67,8 +67,7 @@ If you ran in a Dev Docker environment, to view container logs: `docker compose
### [Custom Images](#custom-images)
- [Custom Apps](docs/custom-apps.md)
- [Custom Apps with podman](docs/custom-apps-podman.md)
- [Custom Apps](docs/container-setup/02-build-setup.md)
- [Build Version 10 Images](docs/build-version-10-images.md)
### [Development](#development)

View File

@@ -0,0 +1,47 @@
The purpose of this document is to give you an overview of how the Frappe Docker containers are structured.
# 🐳 Images
There are **four predefined Dockerfiles** available in the `/images` directory.
| Dockerfile | Ingredients | Purpose & Use Case |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **bench** | Sets up only the Bench CLI. | Used for **development** or debugging. Provides the command-line tooling but does not include runtime services. |
| **custom** | Multi-purpose Python backend built from a plain Python image. Includes everything needed to run a Frappe instance via a Compose setup. Installs apps defined in `apps.json`. | Suitable for **production** and **testing**. Ideal when you need control over dependencies (e.g. trying new Python or Node versions). |
| **layered** | Final contents are the same as `custom`, but it is based on **prebuilt images from [Docker Hub](https://hub.docker.com/u/frappe)**. | Great for **production builds** when youre fine with the dependency versions managed by Frappe. Builds much faster since the base layers are already prepared. |
| **production** | Similar to `custom` (built from a Python base image), but installs **only Frappe and ERPNext**. Not customizable with `apps.json`. | Best for **quick starts** or exploration. For real deployments or CI/CD pipelines, `custom` or `layered` are preferred because they offer more flexibility. |
---
These images include everything needed to run all processes required by the Frappe framework
(see [Bench Procfile reference](https://frappeframework.com/docs/v14/user/en/bench/resources/bench-procfile)).
- The `bench` image only sets up the CLI tool.
- The other images (`custom`, `layered`, and `production`) go further — enabling a nearly **plug-and-play** setup for ERPNext and custom apps.
> We use [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) and [Docker Buildx](https://docs.docker.com/engine/reference/commandline/buildx/) to maximize layer reuse and make our builds more efficient.
# 🏗️ Compose
Once images are built, containers are orchestrated using a [compose file](https://docs.docker.com/compose/compose-file/). The main compose.yaml provides core services, networking, and volumes for any Frappe setup.
## 🛠️ Services
| Service | Role | Purpose |
| ---------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **configurator** | Setup | Updates `common_site_config.json` so Frappe knows how to access db and redis. It is executed on every `docker-compose up` (and exited immediately). Other services start after this container exits successfully |
| **backend** | Runtime | [Werkzeug server](https://werkzeug.palletsprojects.com/en/2.0.x/) |
| **frontend** | Proxy | [nginx](https://www.nginx.com) server that serves JS/CSS assets and routes incoming requests |
| **websocket** | Real-time | Node server that runs [Socket.IO](https://socket.io) |
| **queue-\_** | Background Jobs | Python servers that run job queues using [rq](https://python-rq.org) |
| **scheduler** | Task Automation | Python server that runs tasks on schedule using [schedule](https://schedule.readthedocs.io/en/stable/) |
## 🧩 Overrides
Additional functionality can be added using [overrides](https://docs.docker.com/compose/extends/). These files modify existing services or add new ones without changing the main `compose.yaml`.
Example: The main compose file has no database service, but `compose.mariadb.yaml` adds MariaDB. See [overrider.md](overrider.md) for the complete list of available overrides and how to use them.
---
**Next:** [Build Setup →](02-build-setup.md)

View File

@@ -0,0 +1,121 @@
This guide walks you through building Frappe images from the repository resources.
# Prerequisites
- git
- docker or podman
- docker compose v2 or podman compose
> Install containerization software according to the official maintainer documentation. Avoid package managers when not recommended, as they frequently cause compatibility issues.
# Clone this repo
```bash
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
```
# Define custom apps
If you dont want to install specific apps to the image skip this section.
To include custom apps in your image, create an `apps.json` file in the repository root:
```json
[
{
"url": "https://github.com/frappe/erpnext",
"branch": "version-15"
},
{
"url": "https://github.com/frappe/hrms",
"branch": "version-15"
},
{
"url": "https://github.com/frappe/helpdesk",
"branch": "main"
}
]
```
Then generate a base64-encoded string from this file:
```bash
export APPS_JSON_BASE64=$(base64 -w 0 apps.json)
```
# Build the image
Choose the appropriate build command based on your container runtime and desired image type. This example builds the `layered` image with the custom `apps.json` you created.
`Docker`:
```bash
docker build \
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
--build-arg=FRAPPE_BRANCH=version-15 \
--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \
--tag=custom:15 \
--file=images/layered/Containerfile .
```
`Podman`:
```bash
podman build \
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
--build-arg=FRAPPE_BRANCH=version-15 \
--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \
--tag=custom:15 \
--file=images/layered/Containerfile .
```
## Build args
| Arg | Purpose |
| -------------------- | --------------------------------------------------------------------------------------------- |
| **Frappe Framework** | |
| FRAPPE_PATH | Repository URL for Frappe framework source code. Defaults to https://github.com/frappe/frappe |
| FRAPPE_BRANCH | Branch to use for Frappe framework. Defaults to version-15 |
| **Custom Apps** | |
| APPS_JSON_BASE64 | Base64-encoded JSON string from apps.json defining apps to install |
| **Dependencies** | |
| PYTHON_VERSION | Python version for the base image |
| NODE_VERSION | Node.js version |
| WKHTMLTOPDF_VERSION | wkhtmltopdf version |
| **bench only** | |
| DEBIAN_BASE | Debian base version for the bench image, defaults to `bookworm` |
| WKHTMLTOPDF_DISTRO | use the specified distro for debian package. Default is `bookworm` |
# env file
The compose file requires several environment variables. You can either export them on your system or create a `.env` file.
```bash
cp example.env custom.env
```
Edit `custom.env` to customize variables for your setup. The template includes common variables, but you can add, modify, or remove any as needed. See [env-variables.md](env-variables.md) for detailed descriptions of all available variables.
# Creating the final compose file
Combine the base compose file with appropriate overrides for your use case. This example adds MariaDB, Redis, and exposes ports on `:8080`:
```bash
docker compose --env.file example.env \
-f compose.yaml \
-f overrides/compose.mariadb.yaml \
-f overrides/compose.redis.yaml \
-f overrides/compose.noproxy.yaml \
config > compose.custom.yaml
```
This generates `compose.custom.yaml`, which you'll use to start all containers. Customize the overrides and environment variables according to your requirements.
> **NOTE**: podman compose is just a wrapper, it uses docker-compose if it is available or podman-compose if not. podman-compose have an issue reading .env files ([Issue](https://github.com/containers/podman-compose/issues/475)) and might create an issue when running the containers.
---
**Next:** [Start Setup →](03-start-setup.md)
**Back:** [Container Overview ←](01-overview.md)

View File

@@ -0,0 +1,42 @@
# start Container
Once your compose file is ready, start all containers with a single command:
```bash
docker compose -p frappe -f compose.custom.yaml up -d
```
```bash
podman-compose --in-pod=1 --project-name frappe -f compose.custom.yaml up -d
```
The `-p` (or `--project-name`) flag names the project `frappe`, allowing you to easily reference and manage all containers together.
# Create a site and install apps
Frappe is now running, but it's not yet configured. You need to create a site and install your apps.
```bash
docker compose -p frappe exec backend bench new-site <sitename> --mariadb-user-host-login-scope='172.%.%.%'
docker compose -p frappe exec backend bench --site <sitename> install-app erpnext
```
```bash
podman exec -ti erpnext_backend_1 /bin/bash
bench new-site <sitename> --mariadb-user-host-login-scope='172.%.%.%'
bench --site <sitename> install-app erpnext
```
Replace `<sitename>` with your desired site name.
> ## Understanding the MariaDB User Scope
>
> The flag --mariadb-user-host-login-scope='172.%.%.%' allows database connections from any IP address within the 172.0.0.0/8 range. This includes all containers and virtual machines running on your machine.
>
> **Why is this necessary?** Docker and Podman assign dynamic IP addresses to containers. If you set a fixed IP address instead, database connections will fail when the container restarts and receives a new IP. The wildcard pattern ensures connections always work, regardless of IP changes.
>
> **Security note:** This scope is sufficient because only the backend container accesses the database. If you need external database access, adjust the scope accordingly, but be cautious with overly permissive settings.
---
**Back:** [Build Setup →](02-build-setup.md)

View File

@@ -0,0 +1,112 @@
# Environment Variables Reference
Environment variables configure your Frappe Docker setup. They can be set directly in the container or defined in a `.env` file referenced by Docker Compose.
**Getting Started:**
```bash
cp example.env .env
```
Then edit `.env` and set variables according to your needs.
---
## Required Variables
| Variable | Purpose | Example | Notes |
| ----------------- | ------------------------------------------------ | -------------------------------- | ---------------------------------------------------------------- |
| `FRAPPE_PATH` | Frappe framework path | https://github.com/frappe/frappe | |
| `FRAPPE_BRANCH` | Frappe Branch | `version-15` | See [Frappe releases](https://github.com/frappe/frappe/releases) |
| `ERPNEXT_VERSION` | ERPNext release version | `v15.67.0` | Required although its never used |
| `DB_PASSWORD` | Password for database root (MariaDB or Postgres) | `secure_password_123` | Not needed if using `DB_PASSWORD_SECRETS_FILE` |
---
## Database Configuration
| Variable | Purpose | Default | When to Set |
| -------------------------- | ----------------------------------------- | ------------------------------------ | ---------------------------------- |
| `DB_PASSWORD` | Database root user password | 123 | Always (unless using secrets file) |
| `DB_PASSWORD_SECRETS_FILE` | Path to file containing database password | — | Setup mariadb-secrets overrider |
| `DB_HOST` | Database hostname or IP | `db` (service name) | Only if using external database |
| `DB_PORT` | Database port | `3306` (MariaDB) / `5432` (Postgres) | Only if using external database |
---
## Redis Configuration
| Variable | Purpose | Default | When to Set |
| ------------- | --------------------------------------------------- | ---------------------------- | ------------------------------------- |
| `REDIS_CACHE` | Redis hostname for caching | `redis-cache` (service name) | Only if using external Redis instance |
| `REDIS_QUEUE` | Redis hostname for job queues and real-time updates | `redis-queue` (service name) | Only if using external Redis instance |
---
## HTTPS & SSL Configuration
| Variable | Purpose | Default | When to Set |
| ------------------- | ------------------------------------------------ | ------- | ---------------------------------------- |
| `LETSENCRYPT_EMAIL` | Email for Let's Encrypt certificate registration | — | Required if using HTTPS override |
| `SITES` | List of domains for SSL certificates | — | Required if using reverse proxy override |
**Format for `SITES`:**
```bash
# Single site
SITES=`mysite.example.com`
# Wildcard (any subdomain)
SITES=`{any:.+}`
```
---
## Site Configuration
| Variable | Purpose | Default | When to Set |
| ------------------------- | -------------------------------- | ---------------------------------------- | ----------------------------------------------- |
| `FRAPPE_SITE_NAME_HEADER` | Site name for multi-tenant setup | `$host` (resolved from request hostname) | When accessing by IP or need explicit site name |
**Examples:**
If your site is named `mysite` but you want to access it via `127.0.0.1`:
```bash
FRAPPE_SITE_NAME_HEADER=mysite
```
If your site is named `example.com` and you access it via that domain, no need to set this (defaults to hostname).
---
## Image Configuration
| Variable | Purpose | Default | Notes |
| ---------------- | ------------------------------ | --------------------- | ------------------------------------------------------- |
| `CUSTOM_IMAGE` | Custom Docker image repository | Frappe official image | Leave empty to use default |
| `CUSTOM_TAG` | Custom Docker image tag | Latest stable | Corresponds to `FRAPPE_VERSION` |
| `PULL_POLICY` | Image pull behavior | `always` | Options: `always`, `never`, `if-not-present` |
| `RESTART_POLICY` | Container restart behavior | `unless-stopped` | Options: `no`, `always`, `unless-stopped`, `on-failure` |
---
## Nginx Proxy Configuration
| Variable | Purpose | Default | Allowed Values |
| ---------------------- | ---------------------------------- | -------------- | -------------------------------------------- |
| `BACKEND` | Backend service address and port | `0.0.0.0:8000` | `{host}:{port}` |
| `SOCKETIO` | Socket.IO service address and port | `0.0.0.0:9000` | `{host}:{port}` |
| `HTTP_PUBLISH_PORT` | Published HTTP port | `8080` | Any available port |
| `PROXY_READ_TIMEOUT` | Upstream request timeout | `120s` | Any nginx timeout value (e.g., `300s`, `5m`) |
| `CLIENT_MAX_BODY_SIZE` | Maximum upload file size | `50m` | Any nginx size value (e.g., `100m`, `1g`) |
### Real IP Configuration (Behind Proxy)
Use these variables when running behind a reverse proxy or load balancer:
| Variable | Purpose | Default |
| ---------------------------- | ------------------------------------------------- | ----------------- |
| `UPSTREAM_REAL_IP_ADDRESS` | Trusted upstream IP address for real IP detection | `127.0.0.1` |
| `UPSTREAM_REAL_IP_HEADER` | Request header containing client IP | `X-Forwarded-For` |
| `UPSTREAM_REAL_IP_RECURSIVE` | Enable recursive IP search | `off` |

View File

@@ -0,0 +1,27 @@
Overrides extend the base compose.yaml with additional services or modify existing behavior. Include them in your compose command using multiple -f flags.
```bash
docker compose -f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml config > compose.custom.yaml
```
| Overrider | Purpose | Additional Info |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| **Database** | | |
| compose.mariadb.yaml | Adds MariaDB database service | set `DB_PASSWORD` or default Password will be used |
| compose.mariadb-secrets.yaml | Adds MariaDB with password from a secret file instead of environment variable | Set `DB_PASSWORD_SECRETS_FILE` to the path of your secret file |
| compose.mariadb-shared.yaml | Makes MariaDB available on a shared network (mariadb-network) for other services | set `DB_PASSWORD` |
| compose.postgres.yaml | Uses PostgreSQL instead of MariaDB as the database | set `DB_PASSWORD` |
| **Proxy** | | |
| compose.noproxy.yaml | Exposes the application directly on port `:8080` without a reverse proxy | |
| compose.proxy.yaml | Uses Traefik as HTTP reverse proxy on port `:80` | You can change the published port by setting `HTTP_PUBLISH_PORT` |
| compose.https.yaml | Uses Traefik as HTTPS reverse proxy on Port `:443` with automatic HTTP-to-HTTPS redirect | `SITES` and `LETSENCRYPT_EMAIL` must be set. `HTTP_PUBLISH_PORT` and `HTTPS_PUBLISH_PORT` can be set. |
| **Redis** | | |
| compose.redis.yaml | Adds Redis service for caching and background job queuing |
| **TBD** | **The following overrides are available but lack documentation. If you use them and understand their purpose, please consider contributing to this documentation.** |
| compose.backup-cron.yaml | | |
| compose.custom-domain-ssl.yaml | | |
| compose.custom-domain.yaml | | |
| compose.multi-bench-ssl.yaml | | |
| compose.multi-bench.yaml | | |
| compose.traefik-ssl.yaml | | |
| compose.traefik.yaml | | |

View File

@@ -1,125 +0,0 @@
## Prerequisites
- podman
- podman-compose
- docker-compose
Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers. It is available on the official repositories of many Linux distributions.
## Step 1
- Clone this repository and change the current directory to the downloaded folder
```cmd
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
```
## Step 2
- Create `apps.json` file with custom apps listed in it
```json
[
{
"url": "https://github.com/frappe/erpnext",
"branch": "version-15"
},
{
"url": "https://github.com/frappe/hrms",
"branch": "version-15"
},
{
"url": "https://github.com/frappe/helpdesk",
"branch": "main"
}
]
```
Check the syntax of the file using `jq empty apps.json`
### Generate base64 string from JSON file:
`cmd export APPS_JSON_BASE64=$(base64 -w 0 apps.json)`
## Step 3
- Building the custom image using podman
```ruby
podman build \
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
--build-arg=FRAPPE_BRANCH=version-15 \
--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \
--tag=custom:15 \
--file=images/layered/Containerfile .
```
### Note
- Make sure to use the same tag when you export a variable on the next step
## Step 4
- Using the image
- Export environment variables with image name, tag and pull_policy
```ruby
export CUSTOM_IMAGE=custom
export CUSTOM_TAG=15
export PULL_POLICY=never
```
- Configuration of parameters used when starting the containers
- create `.env` file copying from example.env (Read more on setting up environment variables [here](https://github.com/frappe/frappe_docker/blob/main/docs/environment-variables.md)
## Final step
- Creating a compose file
- ```ruby
podman compose -f compose.yaml \
-f overrides/compose.mariadb.yaml \
-f overrides/compose.redis.yaml \
-f overrides/compose.noproxy.yaml \
config > ./docker-compose.yml
```
### NOTE
- podman compose is just a wrapper, it uses docker-compose if it is available or podman-compose if not. podman-compose have an issue reading .env files ([Issue](https://github.com/containers/podman-compose/issues/475)) and might create an issue when running the containers.
- Creating pod and starting the containers
- `podman-compose --in-pod=1 --project-name erpnext -f ./docker-compose.yml up -d`
## Creating sites and installing apps
- You can create sites from the backend container
- `podman exec -ti erpnext_backend_1 /bin/bash`
- `bench new-site myerp.net --mariadb-root-password 123456 --admin-password 123123`
- `bench --site myerp.net install-app erpnext`
## Autostart pod
- Systemd is the best option on autostart pods when the system boots. Create a unit file in either `/etc/systemd/system` [for root user] or `~/.config/systemd/user` [for non-root user]
```ruby
[Unit]
Description=Podman system daemon service
After=network-online.target
[Service]
#User=
#Group=
Type=oneshot
ExecStart=podman pod start POD_NAME
[Install]
WantedBy=default.target
```
**Note:** Replace POD_NAME with a created pod name while creating a pod. This is a basic systemd unit file to autostart pod, but multiple options can be used, refer to the man page for [systemd](https://man7.org/linux/man-pages/man1/init.1.html). For better management of containers, [Quadlet](https://docs.podman.io/en/v4.4/markdown/podman-systemd.unit.5.html) is the best option for ease of updating and tracing issues on each container.
## Troubleshoot
- If there is a network issue while building the image, you need to remove caches and restart again
- `podman system reset`
- `sudo rm -rf ~/.local/share/containers/ /var/lib/container ~/.caches/containers`
- Database issue when restarting the container
- Execute the following commands from **backend** container
- `mysql -uroot -padmin -hdb` (Note: put your db password in place of _admin_).
- `SELECT User, Host FROM mysql.user;`
- Change the IP address to %, e.g. `RENAME USER '_5e5899d8398b5f7b'@'172.18.0.7' TO '_5e5899d8398b5f7b'@'%'`

View File

@@ -1,156 +0,0 @@
### Load custom apps through apps.json file
Base64 encoded string of `apps.json` file needs to be passed in as build arg environment variable.
Create the following `apps.json` file:
```json
[
{
"url": "https://github.com/frappe/erpnext",
"branch": "version-15"
},
{
"url": "https://github.com/frappe/payments",
"branch": "version-15"
},
{
"url": "https://{{ PAT }}@git.example.com/project/repository.git",
"branch": "main"
}
]
```
Note:
- The `url` needs to be http(s) git url with personal access tokens without username eg:- `http://{{PAT}}@github.com/project/repository.git` in case of private repo.
- Add dependencies manually in `apps.json` e.g. add `erpnext` if you are installing `hrms`.
- Use fork repo or branch for ERPNext in case you need to use your fork or test a PR.
Generate base64 string from json file:
```shell
export APPS_JSON_BASE64=$(base64 -w 0 /path/to/apps.json)
```
Test the Previous Step: Decode the Base64-encoded Environment Variable
To verify the previous step, decode the `APPS_JSON_BASE64` environment variable (which is Base64-encoded) into a JSON file. Follow the steps below:
1. Use the following command to decode and save the output into a JSON file named apps-test-output.json:
```shell
echo -n ${APPS_JSON_BASE64} | base64 -d > apps-test-output.json
```
2. Open the apps-test-output.json file to review the JSON output and ensure that the content is correct.
### Clone frappe_docker and switch directory
```shell
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
```
### Configure build
Common build args.
- `FRAPPE_PATH`, customize the source repo for frappe framework. Defaults to `https://github.com/frappe/frappe`
- `FRAPPE_BRANCH`, customize the source repo branch for frappe framework. Defaults to `version-15`.
- `APPS_JSON_BASE64`, correct base64 encoded JSON string generated from `apps.json` file.
Notes
- Use `buildah` or `docker` as per your setup.
- Make sure `APPS_JSON_BASE64` variable has correct base64 encoded JSON string. It is consumed as build arg, base64 encoding ensures it to be friendly with environment variables. Use `jq empty apps.json` to validate `apps.json` file.
- Make sure the `--tag` is valid image name that will be pushed to registry. See section [below](#use-images) for remarks about its use.
- `.git` directories for all apps are removed from the image.
### Quick build image
This method uses pre-built `frappe/base:${FRAPPE_BRANCH}` and `frappe/build:${FRAPPE_BRANCH}` image layers which come with required Python and NodeJS runtime. It speeds up the build time.
It uses `images/layered/Containerfile`.
```shell
docker build \
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
--build-arg=FRAPPE_BRANCH=version-15 \
--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \
--tag=ghcr.io/user/repo/custom:1.0.0 \
--file=images/layered/Containerfile .
```
### Custom build image
This method builds the base and build layer every time, it allows to customize Python and NodeJS runtime versions. It takes more time to build.
It uses `images/custom/Containerfile`.
```shell
docker build \
--build-arg=FRAPPE_PATH=https://github.com/frappe/frappe \
--build-arg=FRAPPE_BRANCH=version-15 \
--build-arg=PYTHON_VERSION=3.11.9 \
--build-arg=NODE_VERSION=20.19.2 \
--build-arg=APPS_JSON_BASE64=$APPS_JSON_BASE64 \
--tag=ghcr.io/user/repo/custom:1.0.0 \
--file=images/custom/Containerfile .
```
Custom build args,
- `PYTHON_VERSION`, use the specified python version for base image. Default is `3.11.6`.
- `NODE_VERSION`, use the specified nodejs version, Default `20.19.2`.
- `DEBIAN_BASE` use the base Debian version, defaults to `bookworm`.
- `WKHTMLTOPDF_VERSION`, use the specified qt patched `wkhtmltopdf` version. Default is `0.12.6.1-3`.
- `WKHTMLTOPDF_DISTRO`, use the specified distro for debian package. Default is `bookworm`.
### Push image to use in yaml files
Login to `docker` or `buildah`
```shell
docker login
```
Push image
```shell
docker push ghcr.io/user/repo/custom:1.0.0
```
### Use Images
In the [compose.yaml](../compose.yaml), you can set the image name and tag through environment variables, making it easier to customize.
```yaml
x-customizable-image: &customizable_image
image: ${CUSTOM_IMAGE:-frappe/erpnext}:${CUSTOM_TAG:-${ERPNEXT_VERSION:?No ERPNext version or tag set}}
pull_policy: ${PULL_POLICY:-always}
```
The environment variables can be set in the shell or in the .env file as [setup-options.md](setup-options.md) describes.
- `CUSTOM_IMAGE`: The name of your custom image. Defaults to `frappe/erpnext` if not set.
- `CUSTOM_TAG`: The tag for your custom image. Must be set if `CUSTOM_IMAGE` is used. Defaults to the value of `ERPNEXT_VERSION` if not set.
- `PULL_POLICY`: The Docker pull policy. Defaults to `always`. Recommended set to `never` for local images, so prevent `docker` from trying to download the image when it has been built locally.
- `HTTP_PUBLISH_PORT`: The port to publish through no SSL channel. Default depending on deployment, it may be `80` if SSL activated or `8080` if not.
- `HTTPS_PUBLISH_PORT`: The secure port to publish using SSL. Default is `443`.
Make sure the image name is correct before pushing to the registry. After the images are pushed, you can pull them to servers to be deployed. If the registry is private, additional auth is needed.
#### Example
If you built an image with the tag `ghcr.io/user/repo/custom:1.0.0`, you would set the environment variables as follows:
```bash
export CUSTOM_IMAGE='ghcr.io/user/repo/custom'
export CUSTOM_TAG='1.0.0'
docker compose -f compose.yaml \
-f overrides/compose.mariadb.yaml \
-f overrides/compose.redis.yaml \
-f overrides/compose.https.yaml \
config > ~/gitops/docker-compose.yaml
```

View File

@@ -1,60 +0,0 @@
## Environment Variables
All of the commands are directly passed to container as per type of service. Only environment variables used in image are for `nginx-entrypoint.sh` command. They are as follows:
- `BACKEND`: Set to `{host}:{port}`, defaults to `0.0.0.0:8000`
- `SOCKETIO`: Set to `{host}:{port}`, defaults to `0.0.0.0:9000`
- `UPSTREAM_REAL_IP_ADDRESS`: Set Nginx config for [ngx_http_realip_module#set_real_ip_from](http://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from), defaults to `127.0.0.1`
- `UPSTREAM_REAL_IP_HEADER`: Set Nginx config for [ngx_http_realip_module#real_ip_header](http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header), defaults to `X-Forwarded-For`
- `UPSTREAM_REAL_IP_RECURSIVE`: Set Nginx config for [ngx_http_realip_module#real_ip_recursive](http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive) Set defaults to `off`
- `FRAPPE_SITE_NAME_HEADER`: Set proxy header `X-Frappe-Site-Name` and serve site named in the header, defaults to `$host`, i.e. find site name from host header. More details [below](#frappe_site_name_header)
- `PROXY_READ_TIMEOUT`: Upstream gunicorn service timeout, defaults to `120`
- `CLIENT_MAX_BODY_SIZE`: Max body size for uploads, defaults to `50m`
To bypass `nginx-entrypoint.sh`, mount desired `/etc/nginx/conf.d/default.conf` and run `nginx -g 'daemon off;'` as container command.
## Configuration
We use environment variables to configure our setup. docker-compose uses variables from the `environment:` section of the services defined within and the`.env` file, if present. Variables defined in the `.env` file are referenced via `${VARIABLE_NAME}` within the docker-compose `.yml` file. `example.env` contains a non-exhaustive list of possible configuration variables. To get started, copy `example.env` to `.env`.
### `FRAPPE_VERSION`
Frappe framework release. You can find all releases [here](https://github.com/frappe/frappe/releases).
### `DB_PASSWORD`
Password for MariaDB (or Postgres) database.
### `DB_PASSWORD_SECRETS_FILE`
Path to the db_password.txt file. Set only if you use docker secrets for the database password (use `overrides/compose.mariadb-secrets.yaml`)
### `DB_HOST`
Hostname for MariaDB (or Postgres) database. Set only if external service for database is used or the container can not be reached by its service name (db) by other containers.
### `DB_PORT`
Port for MariaDB (3306) or Postgres (5432) database. Set only if external service for database is used.
### `REDIS_CACHE`
Hostname for redis server to store cache. Set only if external service for redis is used or the container can not be reached by its service name (redis-cache) by other containers.
### `REDIS_QUEUE`
Hostname for redis server to store queue data and socketio. Set only if external service for redis is used or the container can not be reached by its service name (redis-queue) by other containers.
### `ERPNEXT_VERSION`
ERPNext [release](https://github.com/frappe/erpnext/releases). This variable is required if you use ERPNext override.
### `LETSENCRYPT_EMAIL`
Email that used to register https certificate. This one is required only if you use HTTPS override.
### `FRAPPE_SITE_NAME_HEADER`
This environment variable is not required. Default value is `$$host` which resolves site by host. For example, if your host is `example.com`, site's name should be `example.com`, or if host is `127.0.0.1` (local debugging), it should be `127.0.0.1` This variable allows to override described behavior. Let's say you create site named `mysite` and do want to access it by `127.0.0.1` host. Than you would set this variable to `mysite`.
There is other variables not mentioned here. They're somewhat internal and you don't have to worry about them except you want to change main compose file.

View File

@@ -1,58 +0,0 @@
# Images
There are 3 images that you can find in `/images` directory:
- `bench`. It is used for development. [Learn more how to start development](development.md).
- `production`.
- Multi-purpose Python backend. Runs [Werkzeug server](https://werkzeug.palletsprojects.com/en/2.0.x/) with [gunicorn](https://gunicorn.org), queues (via `bench worker`), or schedule (via `bench schedule`).
- Contains JS and CSS assets and routes incoming requests using [nginx](https://www.nginx.com).
- Processes realtime websocket requests using [Socket.IO](https://socket.io).
- `custom`. It is used to build bench using `apps.json` file set with `--apps_path` during bench initialization. `apps.json` is a json array. e.g. `[{"url":"{{repo_url}}","branch":"{{repo_branch}}"}]`
Image has everything we need to be able to run all processes that Frappe framework requires (take a look at [Bench Procfile reference](https://frappeframework.com/docs/v14/user/en/bench/resources/bench-procfile)). We follow [Docker best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#decouple-applications) and split these processes to different containers.
> We use [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) and [Docker Buildx](https://docs.docker.com/engine/reference/commandline/buildx/) to reuse as much things as possible and make our builds more efficient.
# Compose files
After building the images we have to run the containers. The best and simplest way to do this is to use [compose files](https://docs.docker.com/compose/compose-file/).
We have one main compose file, `compose.yaml`. Services described, networking, volumes are also handled there.
## Services
All services are described in `compose.yaml`
- `configurator`. Updates `common_site_config.json` so Frappe knows how to access db and redis. It is executed on every `docker-compose up` (and exited immediately). Other services start after this container exits successfully.
- `backend`. [Werkzeug server](https://werkzeug.palletsprojects.com/en/2.0.x/).
- `db`. Optional service that runs [MariaDB](https://mariadb.com) if you also use `overrides/compose.mariadb.yaml` or [Postgres](https://www.postgresql.org) if you also use `overrides/compose.postgres.yaml`.
- `redis`. Optional service that runs [Redis](https://redis.io) server with cache, [Socket.IO](https://socket.io) and queues data.
- `frontend`. [nginx](https://www.nginx.com) server that serves JS/CSS assets and routes incoming requests.
- `proxy`. [Traefik](https://traefik.io/traefik/) proxy. It is here for complicated setups or HTTPS override (with `overrides/compose.https.yaml`).
- `websocket`. Node server that runs [Socket.IO](https://socket.io).
- `queue-short`, `queue-long`. Python servers that run job queues using [rq](https://python-rq.org).
- `scheduler`. Python server that runs tasks on schedule using [schedule](https://schedule.readthedocs.io/en/stable/).
## Overrides
We have several [overrides](https://docs.docker.com/compose/extends/):
- `overrides/compose.proxy.yaml`. Adds traefik proxy to setup.
- `overrides/compose.noproxy.yaml`. Publishes `frontend` ports directly without any proxy.
- `overrides/compose.https.yaml`. Automatically sets up Let's Encrypt certificate and redirects all requests to directed to http, to https.
- `overrides/compose.mariadb.yaml`. Adds `db` service and sets its image to MariaDB.
- `overrides/compose.postgres.yaml`. Adds `db` service and sets its image to Postgres. Note that ERPNext currently doesn't support Postgres.
- `overrides/compose.redis.yaml`. Adds `redis` service and sets its image to `redis`.
It is quite simple to run overrides. All we need to do is to specify compose files that should be used by docker-compose. For example, we want ERPNext:
```bash
# Point to main compose file (compose.yaml) and add one more.
docker-compose -f compose.yaml -f overrides/compose.redis.yaml config
```
⚠ Make sure to use docker-compose v2 (run `docker-compose -v` to check). If you want to use v1 make sure the correct `$`-signs as they get duplicated by the `config` command!
That's it! Of course, we also have to setup `.env` before all of that, but that's not the point.
Check [environment variables](environment-variables.md) for more.