Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions 3.14-minimal/Dockerfile.fedora
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
FROM quay.io/fedora/fedora-minimal:43


EXPOSE 8080

ENV PYTHON_VERSION=3.14 \
PYTHONUNBUFFERED=1 \
PYTHONIOENCODING=UTF-8 \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8 \
CNB_STACK_ID=com.redhat.stacks.ubi-python-314 \
CNB_USER_ID=1001 \
CNB_GROUP_ID=0 \
PIP_NO_CACHE_DIR=off \
# The following variables are usually available from parent s2i images \
STI_SCRIPTS_PATH=/usr/libexec/s2i \
APP_ROOT=/opt/app-root \
HOME=/opt/app-root/src \
PLATFORM="el"

# /opt/app-root/bin - the main venv
# /opt/app-root/src/bin - app-specific binaries
# /opt/app-root/src/.local/bin - tools like pipenv
ENV PATH=$APP_ROOT/bin:$HOME/bin:$HOME/.local/bin:$PATH

# Ensure the virtual environment is active in interactive shells
ENV BASH_ENV=${APP_ROOT}/bin/activate \
ENV=${APP_ROOT}/bin/activate \
PROMPT_COMMAND=". ${APP_ROOT}/bin/activate"

ENV SUMMARY="Minimal platform for building and running Python $PYTHON_VERSION applications" \
DESCRIPTION="Python $PYTHON_VERSION available as container is a base platform for \
building and running various Python $PYTHON_VERSION applications and frameworks. \
Python is an easy to learn, powerful programming language. It has efficient high-level \
data structures and a simple but effective approach to object-oriented programming. \
Python's elegant syntax and dynamic typing, together with its interpreted nature, \
make it an ideal language for scripting and rapid application development in many areas \
on most platforms."

LABEL summary="$SUMMARY" \
description="$DESCRIPTION" \
io.k8s.description="$DESCRIPTION" \
io.k8s.display-name="Python 3.14" \
io.openshift.expose-services="8080:http" \
io.openshift.tags="builder,python,python314,python-314,rh-python314" \
com.redhat.component="python-314-container" \
name="fedora/python-314-minimal" \
usage="s2i build https://github.com/sclorg/s2i-python-container.git --context-dir=3.14-minimal/test/setup-test-app/ ubi/python-314-minimal python-sample-app" \
com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI" \
io.buildpacks.stack.id="com.redhat.stacks.ubi-python-314-minimal" \
maintainer="SoftwareCollections.org <sclorg@redhat.com>"

# Very minimal set of packages
# Python is obvious in the Python container :)
# glibc-langpack-en is needed to set locale to en_US and disable warning about it
# findutils - find command is needed for fix-permissions script
# nss_wrapper - used in generate_container_user script
RUN INSTALL_PKGS="python3.14 glibc-langpack-en findutils nss_wrapper-libs" && \
microdnf -y --setopt=tsflags=nodocs --setopt=install_weak_deps=0 install $INSTALL_PKGS && \
microdnf -y clean all --enablerepo='*'

# Copy the S2I scripts from the specific language image to $STI_SCRIPTS_PATH.
COPY 3.14-minimal/s2i/bin/ $STI_SCRIPTS_PATH

# Copy extra files to the image.
COPY 3.14-minimal/root/ /

# Python 3.7+ only
# Yes, the directory below is already copied by the previous command.
# The problem here is that the wheels directory is copied as a symlink.
# Only if you specify symlink directly as a source, COPY copies all the
# files from the symlink destination.
COPY 3.14-minimal/root/opt/wheels /opt/wheels

# This command sets (and also creates if necessary)
# the home directory - it has to be done here so the latter
# fix-permissions fixes this directory as well.
WORKDIR ${HOME}

# - Create a Python virtual environment for use by any application to avoid
# potential conflicts with Python packages preinstalled in the main Python
# installation.
# - In order to drop the root user, we have to make some directories world
# writable as OpenShift default security model is to run the container
# under random UID.
RUN \
python3.14 -m venv ${APP_ROOT} && \
# We have to upgrade pip to a newer version because \
# pip < 19.3 does not support manylinux2014 wheels. Only manylinux2014 (and later) wheels \
# support platforms like ppc64le, aarch64 or armv7 \
# We are newly using wheel from one of the latest stable Fedora releases (from RPM python-pip-wheel) \
# because it's tested better then whatever version from PyPI and contains useful patches. \
# We have to do it here so the permissions are correctly fixed and pip is able \
# to reinstall itself in the next build phases in the assemble script if user wants the latest version \
${APP_ROOT}/bin/pip install /opt/wheels/pip-* && \
rm -r /opt/wheels && \
chown -R 1001:0 ${APP_ROOT} && \
fix-permissions ${APP_ROOT} -P && \
rpm-file-permissions

USER 1001

# Set the default CMD to print the usage of the language image.
CMD $STI_SCRIPTS_PATH/usage
123 changes: 123 additions & 0 deletions 3.14-minimal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
Python 3.14 container image - minimal version
============================================

This container image is a special version of the [full Python 3.14 container image](https://github.com/sclorg/s2i-python-container/tree/master/3.14)
provided as a [S2I](https://github.com/openshift/source-to-image) base image for your Python 3.14 applications.

Because the minimal and full images work similarly, we document here only the differences and limitations
of the minimal container image. For the documentation of common features see the [full container image docs](https://github.com/sclorg/s2i-python-container/tree/master/3.14).

The Python 3.14 minimal container image is currently considered a tech-preview and only available on quay.io.
The image is built on top of the [official CentOS Stream base containers](quay.io/centos/centos).

To pull the Python 3.14 minimal container image to build on, run

```
podman pull quay.io/fedora/python-314-minimal
```

Description
-----------

The full container image is a universal base image to build your containerized applications on top of. However, its universal nature
means that the resulting containers it produces consume a lot of disk space. This is caused mainly by the fact that the image contains
npm, compilers, header files and some other packages one might need to install and deploy their applications.

Because size does matter for us and our customers, we have prepared this minimal container image with very limited subset
of installed packages. There are no compilers, no header files, no npm etc and the yum package manager is replaced with a minimalistic
reimplementation called microdnf, making the resulting container images much smaller. This creates some limitations
but we provide ways to workaround them.

Limitations
-----------

1. There is only a very limited subset of packages installed. They are choosen carefully to satisfy most of the Python apps but your app might have some special needs.
1. There is no npm and nodejs.
1. There are no compilers and header files. Installation from Python wheels should still work but compilation from a source code is not supported out of the box.

In the next chapter, we provide three possible workarounds for the mentioned limitations of the minimal container image.

Possible solutions for the limitations
--------------------------------------

### Use the full container image

It's easy at that. If you don't want to write your own Dockerfile and disk space is not a problem, use
the full universal container image and you should be fine.

### Build your own container image on top of the minimal container image

Let's say that your application depends on uwsgi. uwsgi cannot be installed from Python wheel and has to be
compiled from source which requires some additional packages to be installed - namely gcc for the compilation
itself and python3.14-devel containing Python header files.

To solve that problem, you can use all the pieces provided by the minimal container image and just add one more
step to install the missing dependencies:

```
FROM python-314-minimal

# Add application sources to a directory that the assemble script expects them
# and set permissions so that the container runs without root access
USER 0
ADD app-src /tmp/src
RUN /usr/bin/fix-permissions /tmp/src

# Install packages necessary for compiling uwsgi from source
RUN microdnf install -y gcc python3.14-devel
USER 1001

# Install the dependencies
RUN /usr/libexec/s2i/assemble

# Set the default command for the resulting image
CMD /usr/libexec/s2i/run
```

If you do it this way, your problem with the missing packages is solved. But there is also one disadvantage: the resulting
runtime image contains unnecessary compiler and Python header files. How to solve this? Uninstalling them at the end
of the Dockerfile is not really a solution but we have one. Keep reading.

### Build on full image, run on minimal image

Did you know that you can copy files from one image to another one during a build? That's the feature we are gonna use now.
We use the full container image with all compilers and other usefull packages installed to build our app and its dependencies
and we then move the result including the whole virtual environemnt to the minimal container image.

This app needs mod_wsgi and to install (compile it from source) it, we'll need: httpd-devel for header files, gcc and redhat-rpm-config
as a compiler and configuratuion and finally python3.14-devel containing Python header files. There is no need to install those packages
manually because the full container image already contains them. However, the application needs httpd as a runtime dependency
so we need to install it to the minimal container image as well.

```
# Part 1 - build

FROM python-314 as builder

# Add application sources to a directory that the assemble script expects them
# and set permissions so that the container runs without root access
USER 0
ADD app-src /tmp/src
RUN /usr/bin/fix-permissions /tmp/src
USER 1001

# Install the application's dependencies from PyPI
RUN /usr/libexec/s2i/assemble

# Part 2 - deploy

FROM python-314-minimal

# Copy app sources together with the whole virtual environment from the builder image
COPY --from=builder $APP_ROOT $APP_ROOT

# Install httpd package - runtime dependency of our application
USER 0
RUN microdnf install -y httpd
USER 1001

# Set the default command for the resulting image
CMD /usr/libexec/s2i/run
```

This way, the resulting container image does contain only necessary dependencies and it's much lighter.
19 changes: 19 additions & 0 deletions 3.14-minimal/root/opt/app-root/etc/generate_container_user
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Set current user in nss_wrapper
USER_ID=$(id -u)
GROUP_ID=$(id -g)

if [ x"$USER_ID" != x"0" -a x"$USER_ID" != x"1001" ]; then

NSS_WRAPPER_PASSWD=/opt/app-root/etc/passwd
NSS_WRAPPER_GROUP=/etc/group

cat /etc/passwd | sed -e 's/^default:/builder:/' > $NSS_WRAPPER_PASSWD

echo "default:x:${USER_ID}:${GROUP_ID}:Default Application User:${HOME}:/bin/bash" >> $NSS_WRAPPER_PASSWD

export NSS_WRAPPER_PASSWD
export NSS_WRAPPER_GROUP

LD_PRELOAD=libnss_wrapper.so
export LD_PRELOAD
fi
1 change: 1 addition & 0 deletions 3.14-minimal/root/opt/wheels
Loading