Container Builds

Read Container Basics before you begin.

Let’s build a simple frappe py server that returns 404 Not Found

Create a Dockerfile in current working directory.

FROM python:3-alpine

# Install required os packages to install frappe
RUN apk add -U git build-base linux-headers && \
  # Create directory for apps and sites
  mkdir -p /opt/simple-server/apps /opt/simple-server/sites && \
  # Create python env
  python3 -m venv /opt/simple-server/env && \
  # install frappe version-14
  /opt/simple-server/env/bin/pip install \
    --no-cache-dir \
    --upgrade \
    git+https://github.com/frappe/frappe.git@version-14

# Set working directory
WORKDIR /opt/simple-server

# Set container default command
CMD [ \
  "/opt/simple-server/env/bin/gunicorn", \
  "--chdir=/opt/simple-server/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" \
]

Build the image called simple with tag latest using following command:

buildah build -t simple:latest .
# or
docker build -t simple:latest .

Check the image size:

docker images
REPOSITORY      TAG               IMAGE ID       CREATED          SIZE
simple          latest            247f2247b270   3 minutes ago   806MB

Now let’s try to rebuild using layers to reduce size and only ship production related files

Change the dockerfile to following:

FROM python:3-alpine

# Install required os packages to install frappe
RUN apk add -U git build-base linux-headers && \
  # Create directory for apps and sites
  mkdir -p /opt/simple-server/apps /opt/simple-server/sites && \
  # Create python env
  python3 -m venv /opt/simple-server/env && \
  # install frappe version-14
  /opt/simple-server/env/bin/pip install \
    --no-cache-dir \
    --upgrade \
    git+https://github.com/frappe/frappe.git@version-14

# Start new mimimal layer
FROM python:3-alpine

# Copy from previous layer
COPY --from=0 /opt/simple-server /opt/simple-server

# Set working directory
WORKDIR /opt/simple-server

# Set container default command
CMD [ \
  "/opt/simple-server/env/bin/gunicorn", \
  "--chdir=/opt/simple-server/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" \
]

Now check size again.

docker images
REPOSITORY      TAG               IMAGE ID       CREATED          SIZE
simple          latest            247f2247b270   2 minutes ago   535MB

In multi layered file we only ship the venv with frappe installed.

Now start the container with image and check browser for 404.

podman run --rm -p 8000:8000 simple:latest
# or
docker run --rm -p 8000:8000 simple:latest

open http://localhost:8000 and it will respond with site not found message from frappe.

Check production builds

To check how Frappe / ERPNext is built check this file: frappe_docker/Containerfile at main · frappe/frappe_docker · GitHub

To check how Custom apps are built check this file: frappe_docker/Containerfile at main · frappe/frappe_docker · GitHub

To build custom apps or optionally base custom apps on forked Frappe or ERPNext check this doc: frappe_docker/custom-apps.md at main · frappe/frappe_docker · GitHub

8 Likes

Ways to automate frappe framework apps image build

CI and manual trigger

  • You need a git repo, ci runner and container registry, github and gitlab provide everything
  • Setup a repo with the job workflows from documentation.
  • Track apps.json for app changes.
  • Bump version.txt to generate image version tag from the file.
  • Gitlab or Github provides UI as well as ReST API to input variables to workflows and trigger them.
  • Override with input variables like base64encode(apps.json), version, creds, image name etc and trigger custom build.

More: custom_frappe_docker/runner-api.md at main · castlecraft/custom_frappe_docker · GitHub

4 Likes