inventree / InvenTree

Open Source Inventory Management System
https://docs.inventree.org
MIT License
4.34k stars 786 forks source link

Docker venv #8502

Closed SchrodingersGat closed 5 days ago

SchrodingersGat commented 6 days ago

This PR changes behavior under docker, using the python virtual environment even in "production" mode.

The purpose for this is to ensure that any extra python packages that get installed (i.e. plugins) persist between container runs, and across the webserver and worker containers.

The Problem

Ref: https://github.com/inventree/InvenTree/issues/7709

The webserver and background worker processes run on separate container instances - meaning that they have different python package installation environments.

Thus, if a plugin is installed via the webserver (in the admin interface), it gets installed into the webserver container instance, but the background worker instance does not have a copy of the newly installed plugin code. When it tries to find it, it fails, and can result in some different subtle bugs (as well as the obvious "plugin does not work" issue).

As an added complication, if the background worker process is restarted, it may successfully result in the plugin being correctly installed inside that container, due to the auto-install behaviour of plugins.txt - however, this is kinda flaky and the static files don't get copied across reliably in this scenario.

The Solution

In the init.sh entrypoint script for both containers, active a python virtual environment which points to a subdirectory on the externally mounted volume. This means that:

A) Installed plugin packages persist on the host machine (via mounted volume) B) Installed plugin packages are shared between the webserver and background worker containers

Testing

You can test that this works on an existing docker installation by adding the following line to the .env file:

# Enable python virtual environment
INVENTREE_PY_ENV=/home/inventree/data/venv

Then, restart the docker containers.

Install a new plugin and verify that the plugin has been installed in the <data>/venv/ subdirectory in the mounted volume

Base Packages

Base python packages (that is, everything in requirements.txt needed for core InvenTree functionality) is installed inside the container image - when the container is built. Thus, only secondary packages (user installed plugins, etc) will persist in the external venv.

netlify[bot] commented 6 days ago

Deploy Preview for inventree-web-pui-preview canceled.

Name Link
Latest commit ffdca024f0467e79ecdfabdf7d8aaa7cf41647fb
Latest deploy log https://app.netlify.com/sites/inventree-web-pui-preview/deploys/673915f346e35c000894a75d
SchrodingersGat commented 5 days ago

It does not appear to by working correctly yet, as the server runs system python and invoke binnaries (/usr/local/bin/python) rather than the python in the "venv" directory (/home/inventree/data/venv/bin/python) - which means that the venv is bypassed anyway.

A fully functional solution might be a ltitle trickier here. What we want is for:

a) All base-level packages are installed into the docker image (to prevent changes to versions of pinned packages, and ensure the image is distributed with a known set of python packages b) All "plugin" (user installed) packages should be installed to a persistent directory in the mounted volume c) Ideally, the python executable is the system one, not located in the external volume

Perhaps instead of using a venv for docker, we want to expose the --user directory to the external volume?

SchrodingersGat commented 5 days ago

Closing this out in favour of https://github.com/inventree/InvenTree/pull/8503