From 728fbd10606573c11b7ce826a6357dc5a935c8c2 Mon Sep 17 00:00:00 2001 From: "Alex Ellis (OpenFaaS Ltd)" Date: Fri, 24 Jul 2026 16:07:56 +0100 Subject: [PATCH] Install function dependencies independently of HOME pip install --user resolves to $HOME/.local, which only works while the container runs as the user the image declares. OpenFaaS can be installed with functions.setNonRootUser=true, which pins runAsUser to 12000 and overrides that USER. A uid with no passwd entry gets HOME=/, so the packages are no longer on the import path and the function crash-loops: ModuleNotFoundError: No module named 'requests' It fails in the cluster only. local-run and docker run both honour the image's own USER, so the image passes every local test and CI, and the first sign of trouble is a CrashLoopBackOff. A Profile setting runAsUser, and OpenShift's per-namespace uid ranges, break it the same way. Install to /home/app/python instead, which no uid can move, and add it to the path. This is what the classic python3 template has always done. Dependency shadowing is unchanged: the directory still precedes site-packages, so a function may pin its own version of something the template also installs. index.py registers the directory with site.addsitedir rather than relying on PYTHONPATH alone, because .pth files are only processed for site directories. Without it, a dependency shipping a .pth would stop working for every build, not just the ones this change fixes. Signed-off-by: Alex Ellis (OpenFaaS Ltd) --- template/python27-flask/Dockerfile | 5 +++-- template/python27-flask/index.py | 9 +++++++++ template/python3-flask-debian/Dockerfile | 5 +++-- template/python3-flask-debian/index.py | 9 +++++++++ template/python3-flask/Dockerfile | 5 +++-- template/python3-flask/index.py | 9 +++++++++ template/python3-http-debian/Dockerfile | 5 +++-- template/python3-http-debian/index.py | 9 +++++++++ template/python3-http/Dockerfile | 5 +++-- template/python3-http/index.py | 9 +++++++++ 10 files changed, 60 insertions(+), 10 deletions(-) diff --git a/template/python27-flask/Dockerfile b/template/python27-flask/Dockerfile index 0c48134..2ecd335 100644 --- a/template/python27-flask/Dockerfile +++ b/template/python27-flask/Dockerfile @@ -14,7 +14,8 @@ RUN chown app /home/app USER app -ENV PATH=$PATH:/home/app/.local/bin +ENV PATH=$PATH:/home/app/python/bin +ENV PYTHONPATH=/home/app/python WORKDIR /home/app/ @@ -28,7 +29,7 @@ RUN mkdir -p function RUN touch ./function/__init__.py WORKDIR /home/app/function/ COPY --chown=app:app function/requirements.txt . -RUN pip install --no-cache-dir --user -r requirements.txt +RUN pip install --no-cache-dir --target=/home/app/python -r requirements.txt WORKDIR /home/app/ diff --git a/template/python27-flask/index.py b/template/python27-flask/index.py index 983ef34..24b11a4 100644 --- a/template/python27-flask/index.py +++ b/template/python27-flask/index.py @@ -1,3 +1,12 @@ +import site + +# The function's own dependencies are installed to a fixed path rather than +# a $HOME-derived one, so that they are still found when the platform runs +# the container as an arbitrary uid. Register it as a site directory rather +# than relying on PYTHONPATH alone, so that any .pth files shipped by those +# dependencies are processed as they would be in site-packages. +site.addsitedir("/home/app/python") + # Copyright (c) Alex Ellis 2017. All rights reserved. # Licensed under the MIT license. See LICENSE file in the project root for full license information. diff --git a/template/python3-flask-debian/Dockerfile b/template/python3-flask-debian/Dockerfile index 690723f..25e5538 100644 --- a/template/python3-flask-debian/Dockerfile +++ b/template/python3-flask-debian/Dockerfile @@ -23,7 +23,8 @@ RUN addgroup --system app \ USER app -ENV PATH=$PATH:/home/app/.local/bin +ENV PATH=$PATH:/home/app/python/bin +ENV PYTHONPATH=/home/app/python WORKDIR /home/app/ @@ -40,7 +41,7 @@ RUN mkdir -p function RUN touch ./function/__init__.py WORKDIR /home/app/function/ COPY --chown=app:app function/requirements.txt . -RUN pip install --no-cache-dir --user -r requirements.txt +RUN pip install --no-cache-dir --target=/home/app/python -r requirements.txt #install function code USER root diff --git a/template/python3-flask-debian/index.py b/template/python3-flask-debian/index.py index 48554ff..eadfdbd 100644 --- a/template/python3-flask-debian/index.py +++ b/template/python3-flask-debian/index.py @@ -1,3 +1,12 @@ +import site + +# The function's own dependencies are installed to a fixed path rather than +# a $HOME-derived one, so that they are still found when the platform runs +# the container as an arbitrary uid. Register it as a site directory rather +# than relying on PYTHONPATH alone, so that any .pth files shipped by those +# dependencies are processed as they would be in site-packages. +site.addsitedir("/home/app/python") + # Copyright (c) Alex Ellis 2017. All rights reserved. # Licensed under the MIT license. See LICENSE file in the project root for full license information. diff --git a/template/python3-flask/Dockerfile b/template/python3-flask/Dockerfile index 61d690d..34ad16d 100644 --- a/template/python3-flask/Dockerfile +++ b/template/python3-flask/Dockerfile @@ -20,7 +20,8 @@ RUN chown app /home/app USER app -ENV PATH=$PATH:/home/app/.local/bin +ENV PATH=$PATH:/home/app/python/bin +ENV PYTHONPATH=/home/app/python WORKDIR /home/app/ @@ -37,7 +38,7 @@ RUN mkdir -p function RUN touch ./function/__init__.py WORKDIR /home/app/function/ COPY --chown=app:app function/requirements.txt . -RUN pip install --no-cache-dir --user -r requirements.txt +RUN pip install --no-cache-dir --target=/home/app/python -r requirements.txt #install function code USER root diff --git a/template/python3-flask/index.py b/template/python3-flask/index.py index 48554ff..eadfdbd 100644 --- a/template/python3-flask/index.py +++ b/template/python3-flask/index.py @@ -1,3 +1,12 @@ +import site + +# The function's own dependencies are installed to a fixed path rather than +# a $HOME-derived one, so that they are still found when the platform runs +# the container as an arbitrary uid. Register it as a site directory rather +# than relying on PYTHONPATH alone, so that any .pth files shipped by those +# dependencies are processed as they would be in site-packages. +site.addsitedir("/home/app/python") + # Copyright (c) Alex Ellis 2017. All rights reserved. # Licensed under the MIT license. See LICENSE file in the project root for full license information. diff --git a/template/python3-http-debian/Dockerfile b/template/python3-http-debian/Dockerfile index 13c3eb7..8c11689 100644 --- a/template/python3-http-debian/Dockerfile +++ b/template/python3-http-debian/Dockerfile @@ -23,7 +23,8 @@ RUN addgroup --system app \ USER app -ENV PATH=$PATH:/home/app/.local/bin +ENV PATH=$PATH:/home/app/python/bin +ENV PYTHONPATH=/home/app/python WORKDIR /home/app/ @@ -37,7 +38,7 @@ RUN mkdir -p function RUN touch ./function/__init__.py WORKDIR /home/app/function/ COPY --chown=app:app function/requirements.txt . -RUN pip install --no-cache-dir --user -r requirements.txt +RUN pip install --no-cache-dir --target=/home/app/python -r requirements.txt USER root COPY --chown=app:app function/ . diff --git a/template/python3-http-debian/index.py b/template/python3-http-debian/index.py index b241d9b..d08b3eb 100644 --- a/template/python3-http-debian/index.py +++ b/template/python3-http-debian/index.py @@ -1,4 +1,13 @@ #!/usr/bin/env python +import site + +# The function's own dependencies are installed to a fixed path rather than +# a $HOME-derived one, so that they are still found when the platform runs +# the container as an arbitrary uid. Register it as a site directory rather +# than relying on PYTHONPATH alone, so that any .pth files shipped by those +# dependencies are processed as they would be in site-packages. +site.addsitedir("/home/app/python") + from flask import Flask, request, jsonify from waitress import serve import os diff --git a/template/python3-http/Dockerfile b/template/python3-http/Dockerfile index beb7bb0..eaccb12 100644 --- a/template/python3-http/Dockerfile +++ b/template/python3-http/Dockerfile @@ -19,7 +19,8 @@ RUN chown app /home/app USER app -ENV PATH=$PATH:/home/app/.local/bin +ENV PATH=$PATH:/home/app/python/bin +ENV PYTHONPATH=/home/app/python WORKDIR /home/app/ @@ -35,7 +36,7 @@ RUN mkdir -p function RUN touch ./function/__init__.py WORKDIR /home/app/function/ COPY --chown=app:app function/requirements.txt . -RUN pip install --no-cache-dir --user -r requirements.txt +RUN pip install --no-cache-dir --target=/home/app/python -r requirements.txt # install function code USER root diff --git a/template/python3-http/index.py b/template/python3-http/index.py index ac82b90..6ae9a2b 100644 --- a/template/python3-http/index.py +++ b/template/python3-http/index.py @@ -1,4 +1,13 @@ #!/usr/bin/env python +import site + +# The function's own dependencies are installed to a fixed path rather than +# a $HOME-derived one, so that they are still found when the platform runs +# the container as an arbitrary uid. Register it as a site directory rather +# than relying on PYTHONPATH alone, so that any .pth files shipped by those +# dependencies are processed as they would be in site-packages. +site.addsitedir("/home/app/python") + from flask import Flask, request, jsonify from waitress import serve import os