Skip to content

NGRsoftlab/Astra-python-image

Repository files navigation

NGRSOFTLAB logo

Python

Dive efficiency Made with love Powered by Docker NGR Team

Python image

Ascii svg art by aasvg.

Description

Python container image - это реализация легковесной сборки ЯП Python на базе Astra Linux

Присоединяйтесь к нашим социальным сетям:

NGR Social Telegram       NGR Social Media

Contents

  • Docker >= 28.1.1 (возможно работает в предыдущих версиях, но мы не можем это гарантировать)
OS Python Status
Astra 1.7 Python 3.7 ✅ Fully supported
Astra 1.8 Python 3.11 ✅ Fully supported
Таблица 1. Поддерживаемые ОС-ы.

 

Этот образ предоставляет среду выполнения Python внутри контейнера. Он предназначен для запуска приложений на Python в изолированной среде. Образ содержит только стандартную библиотеку Python и минимальный набор зависимостей. Образ построен на основе отечественной ОС Astra Linux

Для начала работы необходимо установить pre-commit и хуки

$ pip install pre-commit
$ pre-commit --version

pre-commit 4.2.0

$ pre-commit install

pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/commit-msg
pre-commit installed at .git/hooks/pre-push

Warning

Чтобы проверить свои изменения, воспользуйтесь командой pre-commit run --all-files. Чтобы проверить конкретную задачу, воспользуетесь командой pre-commit run <target> --all-files. Если Вы понимаете что творите и хотите пропустить проверку pre-commit-ом воспользуйтесь --no-verify, пример git commit -m "Добавил изменения и не хочу проверки" --no-verify

Существует несколько способов как можно взаимодействовать со сборкой образа. Благодаря скрипту1 может существовать 3 способа передачи аргумента в Dockerfile:

  1. Передача 'примерной' версии. В результате передачи данной строки, скрипт попытается найти точную версии, если таковой нет, то будет возвращена пустая строка

    ## Export Python version for 1.7.5
    $ export PYTHON_VERSION='3.7-astra1.7.5-slim'
    
    ## Python build utils image: 126MB
    docker build \
      --progress=plain \
      --build-arg python_identity=3.7 \
      --build-arg image_version=1.7.5-slim \
      -t python:"${PYTHON_VERSION}" \
      .
    
    .. build ...
  2. Передача точной версии

    ## Export Python version for 1.8.2
    $ export PYTHON_VERSION='3.11-astra1.8.2-slim'
    
    ## Python build utils image: 141MB
    docker build \
      --progress=plain \
      --build-arg python_identity=3.11.2-1+b3 \
      --build-arg image_version=1.8.2-slim \
      -t python:"${PYTHON_VERSION}" \
      .
    
    .. build ...
  3. Передача ссылки, на заранее собранный из исходников Python

    ## Export Python version for 1.8.2
    $ export PYTHON_VERSION='3.13-astra1.8.2-slim'
    
    ## Python build utils image: 198MB
    docker build \
      --progress=plain \
      --build-arg python_identity=https://example-registry.com/repository/python/python-v3.13.2-linux-amd64.tar.gz \
      --build-arg image_version=1.8.2-slim \
      -t python:"${PYTHON_VERSION}" \
      .
    
    .. build ...

Tip

Проверка доступных версий приложения - apt show python3-minimal, apt-cache policy python3-minimal, apt-cache show python3-minimal

Работа с прокси репозиториями. Логика работы тоже является 'плавающей' т.е. позволяет передавать разный набор параметров для Вашего удобства:

  1. Если Вам необходим полный контроль над расположением репозиториев и/или индекс отличается от индекса местоположения прокси репозитория - разрешается использовать полный набор определения прокси

    ## Export Python version for 1.8.2
    $ export PYTHON_VERSION='3.11-astra1.8.2-slim'
    
    docker build \
      --progress=plain \
      --build-arg image_registry=example-container.registry.com/ \
      --build-arg pip_registry_index=https://example-registry.com/repository/python-cache-repostory/pypi \
      --build-arg pip_registry_url=https://example-registry.com/repository/python-cache-repostory/simple \
      --build-arg pip_trusted_host=example-registry.com \
      --build-arg python_identity=3.11 \
      --build-arg image_version=1.8.2-slim \
      -t python:"${PYTHON_VERSION}" \
      .
    
    .. build ...
  2. Если index и index-url имеют один 'источник', то возможна логика обобщения через переменные

    ## Export Python version for 1.8.2
    $ export PYTHON_VERSION='3.11-astra1.8.2-slim'
    
    docker build \
      --progress=plain \
      --build-arg image_registry=example-container.registry.com/ \
      --build-arg package_registry_proxy=https://example-registry.com/repository/python-cache-repostory \
      --build-arg package_registry_trust_host=example-registry.com \
      --build-arg python_identity=3.11 \
      --build-arg image_version=1.8.2-slim \
      -t python:"${PYTHON_VERSION}" \
      .
    
    .. build ...
Имя Значение по умолчанию Тип Описание
image_name astra string Имя образа.
image_registry '' string Адрес до реестра образа2.
image_version 1.8.2-slim string Версия образа.
pip_registry_index '' string Имя индекса, который pip будет использовать из списка заранее заданных в конфиге3.
pip_registry_url '' string Переопределение основного источника пакетов, откуда pip будет скачивать по умолчанию3.
pip_trusted_host '' string Добавляет хост в список доверенных, чтобы pip не проверял SSL-сертификаты при подключении к нему3.
python_identity 3.11 string Ожидаемая версия Python1.
Таблица 2. Переопределяемые аргументы для сборки образа.

 

Вовремя работы сборки, pip использует env-wrapper который помогает ускорить установку компонентов. Ниже приведена таблица с краткой информацией о переменных, которые МОГУТ использоваться во время сборки И также глобально объявляться в конечном(целевом) образе. Вы можете использовать те или иные переменные для управления собственными сборками, если понимаете что творите

Название переменной Значение Необходимость при сборке контейнера Необходимость в scratch-образе Краткое объяснение переменной
PIP_BREAK_SYSTEM_PACKAGES=1 Включено Позволяет обновлять системные пакеты через pip Обычно не нужна Позволяет pip изменять пакеты, установленные системным пакетным менеджером (например, apt, apk)
PIP_DISABLE_PIP_VERSION_CHECK=1 Включено Отключает проверку обновлений pip — ускоряет установку и избегает сетевых запросов Полезно, если образ не имеет интернета или нужно избежать предупреждений Отключает уведомления о том, что есть новая версия pip
PIP_NO_CACHE_DIR=1 Включено Ускоряет сборку и экономит место — отключает кэширование пакетов Может сэкономить место Отключает создание кэша pip (по умолчанию ~/.cache/pip)
PIP_NO_COMPILE=1 Включено Ускоряет сборку — не генерирует .pyc файлы Уменьшает производительность импорта модулей Отключает компиляцию .py в .pyc, экономя время и место на этапе сборки
PIP_ROOT_USER_ACTION=ignore ignore Позволяет запускать pip от root без предупреждений Используется, если образ работает от root Отключает предупреждения при запуске pip от имени root
PYTHONDONTWRITEBYTECODE=1 Включено Экономит место — не создаёт .pyc файлов Ухудшает производительность Python не будет записывать скомпилированные байт-коды (__pycache__, .pyc), экономя место и время
PYTHONWARNINGS="ignore:Unverified HTTPS request" "ignore:Unverified HTTPS request" Полезно при использовании небезопасных источников или внутренних репозиториев Может понадобиться, если используется pip или python с HTTP(S) Подавляет предупреждения о непроверенных HTTPS-запросах (часто связано с самоподписанными SSL-сертификатами)
Таблица 3. Дополнительные переменные окружения PIP для работы с образами и их влияние на сборку/работу в контейнере.

 

Альтернативный способ очистки кеша, чтобы уменьшить размер образа:

FROM python:3.11-astra1.8.2-slim

WORKDIR /app

COPY . .

RUN pip install --no-cache-dir -r requirements.txt

CMD ["python", "app.py"]

В результате сборки базового образа идёт наполнение файла /etc/environment. В нём отражены общие переменные, которые могут использоваться в сборочных образах приложений

  1. Пример переменных для образа 3.13 установленного из удаленного и скомпилированного Python

    $ cat /etc/environment
    
    PYTHON_REVISION=Installed-from-URL
    BEGIN_BUILD_IN_EPOCH=1746194532
    PYTHON_LIB_PATH=/usr/local/lib/python3.13
    PYTHON_SITE_PACKAGES=/usr/local/lib/python3.13/site-packages
    PYTHON_MAJOR_MINOR_PATCH_VERSION=3.13.2
    PYTHON_MAJOR_MINOR_VERSION=3.13
  2. Пример переменных для образа 3.11 из репозиториев Astra Linux

    $ cat /etc/environment
    
    PYTHON_REVISION=3.11.2-1+b3
    BEGIN_BUILD_IN_EPOCH=1746191721
    PYTHON_LIB_PATH=/usr/lib/python3.11
    PYTHON_SITE_PACKAGES=/usr/local/lib/python3.11/dist-packages
    PYTHON_MAJOR_MINOR_PATCH_VERSION=3.11.2
    PYTHON_MAJOR_MINOR_VERSION=3.11
  3. Пример переменных для образа 3.7 из репозиториев Astra Linux

    $ cat /etc/environment
    
    PYTHON_REVISION=3.7.3-1
    BEGIN_BUILD_IN_EPOCH=1746278986
    PYTHON_LIB_PATH=/usr/lib/python3.7
    PYTHON_SITE_PACKAGES=/usr/local/lib/python3.7/dist-packages
    PYTHON_MAJOR_MINOR_PATCH_VERSION=3.7.3
    PYTHON_MAJOR_MINOR_VERSION=3.7

Для того чтобы начать использовать данный образ, создайте Dockerfile с простыми настройками

FROM python:3.11-astra1.8.2-slim

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "python", "./your-daemon-or-script.py" ]

Затем соберите и запустите полученный образ

$ docker build -t my-python-app .
$ docker run -it --rm --name my-running-app my-python-app

...run logic...

Для того, чтобы запустить одиночный файл Python-а, Вы можете использовать следующую команду

$ docker run -it --rm --name my-running-script -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3.11-astra1.8.2-slim python your-daemon-or-script.py

...run logic...

Простой тест:

docker run --rm python:3.11-astra1.8.2-slim python -c "print('Hello from Python')"

Данный раздел будет обеспечивать краткие вводные для того, чтобы Вы в дальнейшем могла проектировать свои Scratch сборки, на примере сложносоставного проекта. Все, что демонстрируется, также подкреплено и всеми задействованными скриптами сборочными или специализированными для сборки через scratch. Все манипуляции поделены на определенное количество 'шагов' для которых будут даны краткие комментарии:

  1. Первым этапом идёт подготовка окружения, установка зависимостей как системных, так и pip

    ## Install base project deps
    # hadolint ignore=DL3042
    RUN \
        --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
        --mount=type=bind,source=./requirements.txt,target=/requirements.txt,readonly \
        apt-install.sh \
            libldap2-dev \
            libpq-dev \
            libsasl2-dev \
            libssl-dev \
            iputils-ping \
            python3-dev \
            build-essential \
            ldap-utils \
            libfreetype6-dev \
            libpq-dev \
            libidn2-dev \
    ## Set corporative proxy
        && python-set-proxy.sh \
    ## Install project components
        && pip-env.sh pip install -r /requirements.txt \
        && python-rm-cache.sh "${PYTHON_VENV_SITE_PACKAGES}" \
    ## Clean cache
        && apt-clean.sh
  2. Второй этап включает в себя компиляцию интерпретатора Python, без компиляции установленных пакетов. Пояснение: компилирование пакетов, может грозить тем, что проект будет не пригоден, т.к. помимо .py могут находится и .c расширения и при компилировании такой 'солянки' приложение попросту перестанет работать, т.к. не сможет найти ассоциации с другими расширениями. Пример таких расширений которые могут 'сломать' сборку: numpy, pandas, cryptography и т.д.

    ## Change path to work dir
    WORKDIR /opt
    
    ## Compile and cleanup cpython
    ## We not compile VENV because this packages include C and multiple another extension
    # hadolint ignore=DL3003,SC1091
    RUN \
        --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
    ## Get build info from env file
        source /etc/environment \
    ## Change path to main python
        && cd "${PYTHON_LIB_PATH}" \
    ## Compile root python
        && python-compile.sh \
    ## Reduce package directory size
        && PYTHON_VENV_SITE_PACKAGES="$(python3 -c 'import site;print(site.getsitepackages()[0])')" \
        && python-remove-unwanted.sh "${PYTHON_VENV_SITE_PACKAGES}" \
        && find "${PYTHON_VENV_PATH}" -iname '*.exe' -ls -delete
  3. Третьим этапом формируем базовую структуру, которая будет перенесена в Scratch

    ## Install build components
    RUN \
    ## Directory structure and permissions
        mkdir -p \
            /base/bin \
            /base/tmp \
            /base/var/tmp \
            /base/etc/ssl \
            /base/sbin \
            /base/root \
            /base/usr/lib/ \
            "/base${PYTHON_VENV_PATH%/*}" \
            /base/usr/src/app \
        && chmod 700 /base/root \
        && chown root:root /base/root \
        && chmod 1777 /base/tmp /base/var/tmp \
    ## UID and GID
        && echo 'root:x:0:' > /base/etc/group \
        && echo 'root:x:0:0:root:/root:/sbin/nologin' > /base/etc/passwd \
    ## Nologin binary
        && echo 'int main() { return 1; }' > nologin.c \
        && gcc -Os -no-pie -static -std=gnu99 -s -Wall -Werror -o /base/sbin/nologin nologin.c
  4. Четвертым этапом происходит перенос основной файловой структуры, для оптимальной и минимальной работы приложения

    ## Copy depended binary
    # hadolint ignore=SC1091
    RUN \
        --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
    ## Get python version
        source /etc/environment \
    ## Execute transfer ldd /bin
        && copy-bin.sh \
            --prefix "/base" \
            --ldd "/bin/dumb-init" \
            --links "/bin:/sbin:/usr/bin:/usr/sbin" \
    ## Execute transfer ldd /usr/bin
        && copy-bin.sh \
            --prefix "/base" \
            --ldd "/usr/bin/python${PYTHON_MAJOR_MINOR_VERSION}" \
            --links "/bin:/sbin:/usr/bin:/usr/sbin" \
    ## Copy compiled python venv
        && cp -R "${PYTHON_VENV_PATH}" "/base${PYTHON_VENV_PATH%/*}" \
    ## Copy compiled python
        && cp -R "${PYTHON_LIB_PATH}" "/base/usr/lib/" \
    ## Copy shared objects
        && copy-lib.sh /base/lib/x86_64-linux-gnu/ \
    ## Can read host files for FQDN
            /usr/lib/x86_64-linux-gnu/libnss_files \
    ## PYTHON critical shared objects
            /usr/lib/libgost \
            /usr/lib/x86_64-linux-gnu/libquadmath \
            ... list of libs ...
    ## Cleanup from deduplicates transfer directory
        && dedup-clean.sh /base/usr/
  5. Пятый - это побочный этап, здесь можно раздать необходимые права на рабочий путь и перенести необходимые рабочие файлы

    ## Transfer base project component
    COPY lib/ /base/usr/src/app/lib/
    
    ## Remove extra write permissions
    RUN \
        find /base/usr/src/app -type f -print0 | xargs -0 chmod 644 \
        && find /base/usr/src/app -type d -print0 | xargs -0 chmod 755
  6. Шестой этап - это слой отладки. Необходимая мера, для того чтобы в случае неполадок или ошибок, мы могли собрать образ с docker build --target debug-stage и вывести отладочную информацию о вызовах при помощи, например, wrapper-lib.sh

    FROM base-stage AS debug-stage
    
    RUN \
        --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
    ## Install debug tools
        apt-install.sh \
            strace \
            ltrace \
            gdb \
            tcpdump \
            procps \
            net-tools \
            jq \
            xmlstarlet \
    ## Clean cache
        && apt-clean.sh
    
    ## Set work directory
    WORKDIR /usr/src/app
    
    ## Transfer base project component
    COPY lib/ lib/
  7. Седьмой этап - интеграция со Scratch образом. Т.к. там нет ничего, то необходимо позаботиться о том, чтобы существовали необходимые пути, переменные. Также, т.к. установка пакетов была без .pyc расширения, то на наши плечи ложится такая операция как прогрев кеша. Пользуясь небольшой хитростью, мы временно монтируем bash как sh, чтобы обойти ограничение, при котором Docker ссылается, без явного указания на оболочку через SHELL, на /bin/sh и выполняем желаемый список команд

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    #                        Final image                          #
    #              Third stage, compact optimize layer            #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    FROM scratch
    
    COPY --from=base-stage /base/ /
    
    ENV PYTHON_VENV_PATH='/usr/local/lib/python-venv'
    
    ## Add venv into path
    ENV \
        PATH="${PYTHON_VENV_PATH}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
        LANG=C.UTF-8
    
    ## Set work directory
    WORKDIR /usr/src/app
    
    ## Little trick, we just mounting shell to provide cache warmup
    RUN \
        --mount=type=bind,from=base-stage,source=/usr/bin/bash,target=/bin/sh,readonly \
        --mount=type=bind,from=base-stage,source=/usr/lib/x86_64-linux-gnu/libtinfo.so.6,target=/usr/lib/x86_64-linux-gnu/libtinfo.so.6,readonly \
        gunicorn --help \
        && netaddr --help \
        && normalizer --help \
        && f2py -h \
        && flask --help \
        && fonttools --help \
        && numpy-config --help
    
    ENTRYPOINT [ "dumb-init", "--" ]
    CMD [ "python3" ]

Полный Dockerfile:

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                         Base image                          #
#               First stage, prepare environment              #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
FROM python:3.11-astra1.8.2 AS base-stage

SHELL [ "/bin/bash", "-exo", "pipefail", "-c" ]

## Redefined DEFAULT args
ARG package_registry_proxy
ARG package_registry_trust_host

## Install base project deps
# hadolint ignore=DL3042
RUN \
    --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
    --mount=type=bind,source=./requirements.txt,target=/requirements.txt,readonly \
    apt-install.sh \
        libldap2-dev \
        libpq-dev \
        libsasl2-dev \
        libssl-dev \
        iputils-ping \
        python3-dev \
        build-essential \
        ldap-utils \
        libfreetype6-dev \
        libpq-dev \
        libidn2-dev \
## Set corporative proxy
    && python-set-proxy.sh \
## Install project components
    && pip-env.sh pip install -r /requirements.txt \
    && python-rm-cache.sh "${PYTHON_VENV_SITE_PACKAGES}" \
## Clean cache
    && apt-clean.sh

## Change path to work dir
WORKDIR /opt

## Compile and cleanup cpython
## We not compile VENV because this packages include C and multiple another extension
# hadolint ignore=DL3003,SC1091
RUN \
    --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
## Get build info from env file
    source /etc/environment \
## Change path to main python
    && cd "${PYTHON_LIB_PATH}" \
## Compile root python
    && python-compile.sh \
## Reduce package directory size
    && PYTHON_VENV_SITE_PACKAGES="$(python3 -c 'import site;print(site.getsitepackages()[0])')" \
    && python-remove-unwanted.sh "${PYTHON_VENV_SITE_PACKAGES}" \
    && find "${PYTHON_VENV_PATH}" -iname '*.exe' -ls -delete

## Install build components
RUN \
## Directory structure and permissions
    mkdir -p \
        /base/bin \
        /base/tmp \
        /base/var/tmp \
        /base/etc/ssl \
        /base/sbin \
        /base/root \
        /base/usr/lib/ \
        "/base${PYTHON_VENV_PATH%/*}" \
        /base/usr/src/app \
    && chmod 700 /base/root \
    && chown root:root /base/root \
    && chmod 1777 /base/tmp /base/var/tmp \
## UID and GID
    && echo 'root:x:0:' > /base/etc/group \
    && echo 'root:x:0:0:root:/root:/sbin/nologin' > /base/etc/passwd \
## Nologin binary
    && echo 'int main() { return 1; }' > nologin.c \
    && gcc -Os -no-pie -static -std=gnu99 -s -Wall -Werror -o /base/sbin/nologin nologin.c

## Copy depended binary
# hadolint ignore=SC1091
RUN \
    --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
## Get python version
    source /etc/environment \
## Execute transfer ldd /bin
    && copy-bin.sh \
        --prefix "/base" \
        --ldd "/bin/dumb-init" \
        --links "/bin:/sbin:/usr/bin:/usr/sbin" \
## Execute transfer ldd /usr/bin
    && copy-bin.sh \
        --prefix "/base" \
        --ldd "/usr/bin/python${PYTHON_MAJOR_MINOR_VERSION}" \
        --links "/bin:/sbin:/usr/bin:/usr/sbin" \
## Copy compiled python venv
    && cp -R "${PYTHON_VENV_PATH}" "/base${PYTHON_VENV_PATH%/*}" \
## Copy compiled python
    && cp -R "${PYTHON_LIB_PATH}" "/base/usr/lib/" \
## Copy shared objects
    && copy-lib.sh /base/lib/x86_64-linux-gnu/ \
## Can read host files for FQDN
        /usr/lib/x86_64-linux-gnu/libnss_files \
## PYTHON critical shared objects
        /usr/lib/libgost \
        /usr/lib/x86_64-linux-gnu/libquadmath \
        /usr/lib/x86_64-linux-gnu/libbfd-2.40-system \
        /usr/lib/x86_64-linux-gnu/libctf \
        /usr/lib/x86_64-linux-gnu/libgmp \
        /usr/lib/x86_64-linux-gnu/libjansson \
        /usr/lib/x86_64-linux-gnu/libliboqs \
        /usr/lib/x86_64-linux-gnu/liboqs \
        /usr/lib/x86_64-linux-gnu/libsframe \
        /usr/lib/x86_64-linux-gnu/libuuid \
        /usr/lib/x86_64-linux-gnu/libgcc_s \
        /usr/lib/x86_64-linux-gnu/libffi \
        /usr/lib/x86_64-linux-gnu/liblzma \
        /usr/lib/x86_64-linux-gnu/libexpat \
        /usr/lib/x86_64-linux-gnu/libbz2 \
        /usr/lib/x86_64-linux-gnu/libhogweed \
        /usr/lib/x86_64-linux-gnu/libnettle \
        /usr/lib/x86_64-linux-gnu/libtasn1 \
        /usr/lib/x86_64-linux-gnu/libunistring \
        /usr/lib/x86_64-linux-gnu/libidn2 \
        /usr/lib/x86_64-linux-gnu/libpq \
        /usr/lib/x86_64-linux-gnu/libp11-kit \
        /usr/lib/x86_64-linux-gnu/libresolv \
        /usr/lib/x86_64-linux-gnu/libkeyutils \
        /usr/lib/x86_64-linux-gnu/libgnutls \
        /usr/lib/x86_64-linux-gnu/liblber-2.5 \
        /usr/lib/x86_64-linux-gnu/libkrb5 \
        /usr/lib/x86_64-linux-gnu/libkrb5support \
        /usr/lib/x86_64-linux-gnu/libk5crypto \
        /usr/lib/x86_64-linux-gnu/libcom_err \
        /usr/lib/x86_64-linux-gnu/libzstd \
        /usr/lib/x86_64-linux-gnu/libgssapi_krb5 \
        /usr/lib/x86_64-linux-gnu/librt \
        /usr/lib/x86_64-linux-gnu/libssl \
        /usr/lib/x86_64-linux-gnu/libcrypto \
        /usr/lib/x86_64-linux-gnu/libcrypt \
        /usr/lib/x86_64-linux-gnu/libstdc++ \
        /usr/lib/x86_64-linux-gnu/libc \
        /usr/lib/x86_64-linux-gnu/libpthread \
        /usr/lib/x86_64-linux-gnu/libm \
        /usr/lib/x86_64-linux-gnu/libdl \
        /usr/lib/x86_64-linux-gnu/libz \
        /usr/lib/x86_64-linux-gnu/libldap-2.5 \
        /usr/lib/x86_64-linux-gnu/libsasl2 \
## Cleanup from deduplicates transfer directory
    && dedup-clean.sh /base/usr/

## Transfer base project component
COPY lib/ /base/usr/src/app/lib/

## Remove extra write permissions
RUN \
    find /base/usr/src/app -type f -print0 | xargs -0 chmod 644 \
    && find /base/usr/src/app -type d -print0 | xargs -0 chmod 755

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                         Debug image                         #
#               Second stage, install debug tools             #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
FROM base-stage AS debug-stage

RUN \
    --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
## Install debug tools
    apt-install.sh \
        strace \
        ltrace \
        gdb \
        tcpdump \
        procps \
        net-tools \
        jq \
        xmlstarlet \
## Clean cache
    && apt-clean.sh

## Set work directory
WORKDIR /usr/src/app

## Transfer base project component
COPY lib/ lib/

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                        Final image                          #
#              Third stage, compact optimize layer            #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
FROM scratch

COPY --from=base-stage /base/ /

## Set base label
LABEL \
    maintainer="Vladislav Avdeev" \
    organization="NGRSoftlab"

ENV PYTHON_VENV_PATH='/usr/local/lib/python-venv'

## Add venv into path
ENV \
    PATH="${PYTHON_VENV_PATH}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
    LANG=C.UTF-8

## Set work directory
WORKDIR /usr/src/app

## Little trick, we just mounting shell to provide cache warmup
RUN \
    --mount=type=bind,from=base-stage,source=/usr/bin/bash,target=/bin/sh,readonly \
    --mount=type=bind,from=base-stage,source=/usr/lib/x86_64-linux-gnu/libtinfo.so.6,target=/usr/lib/x86_64-linux-gnu/libtinfo.so.6,readonly \
    gunicorn --help \
    && netaddr --help \
    && normalizer --help \
    && f2py -h \
    && flask --help \
    && fonttools --help \
    && numpy-config --help

ENTRYPOINT [ "dumb-init", "--" ]
CMD [ "python3" ]

Добавочная ситуация, при которой в существующий Scratch необходимо добавить пакеты

  1. Первым этапом устанавливаем пакет в отдельную директорию, которая послужит дальнейшим 'донором' для дополнения подготовленного заранее scratch образа. Здесь показана связка установки пакета из репозитория Gitlab-a

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    #                         Base image                          #
    #               First stage, prepare environment              #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    FROM python:3.11-astra1.8.2-slim AS base-stage
    
    SHELL [ "/bin/bash", "-exo", "pipefail", "-c" ]
    
    # hadolint ignore=DL3013,DL3042
    RUN \
        --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
        apt-install.sh git \
        && pip-env.sh pip install setuptools \
        && pip-env.sh pip install \
            --prefix=/additional-package \
            "git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/python/package-lib.git"
  2. Вторым этапом, мы дополняем подготовленный scratch образ недостающим пакетов по пути нахождения предыдущих пакетов(в данном случае путь будет /usr/local/lib/python-venv/), наполняем недостающими файлами, необходимыми для работы приложения, и объявляем команду его запуска

    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    #                        Final image                          #
    #              Third stage, compact optimize layer            #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    FROM python-scratch-prepared-bundle:1.0.0
    
    COPY --from=base-stage /additional-package/ /usr/local/lib/python-venv/
    
    WORKDIR /usr/src/app
    
    COPY --chmod=644 ./app.py ./app.py
    COPY --chmod=755 lib/ lib/
    COPY --chmod=755 etc/ etc/
    
    EXPOSE 5052
    
    CMD ["gunicorn", "--certfile", "etc/service.crt", "--keyfile", "etc/service.key",  "-b", "0.0.0.0:5052", "--timeout", "180", "app:create_app()"]

Полный Dockerfile:

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                         Base image                          #
#               First stage, prepare environment              #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
FROM python:3.11-astra1.8.2-slim AS base-stage

SHELL [ "/bin/bash", "-exo", "pipefail", "-c" ]

# hadolint ignore=DL3013,DL3042
RUN \
    --mount=type=bind,source=./scripts,target=/usr/local/sbin,readonly \
    apt-install.sh git \
    && pip-env.sh pip install setuptools \
    && pip-env.sh pip install \
        --prefix=/additional-package \
        "git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/python/package-lib.git"

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#                        Final image                          #
#              Third stage, compact optimize layer            #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
FROM python-scratch-prepared-bundle:1.0.0

COPY --from=base-stage /additional-package/ /usr/local/lib/python-venv/

WORKDIR /usr/src/app

COPY --chmod=644 ./app.py ./app.py
COPY --chmod=755 lib/ lib/
COPY --chmod=755 etc/ etc/

EXPOSE 5052

CMD ["gunicorn", "--certfile", "etc/service.crt", "--keyfile", "etc/service.key",  "-b", "0.0.0.0:5052", "--timeout", "180", "app:create_app()"]

Возможно, можно обойтись иными способами, например компиляция приложения Python

  1. PyInstaller

    $ pip install pyinstaller
    $ pyinstaller --onefile --add-data 'venv/lib/python3.11/site-packages;pandas' app.py
    
    ...compiling binary...
  2. PEX(Python EXecutable)

    $ pex pandas -o app.pex -m app
    
    ...prepared app.pex file...

Дополнительно можно изучить источники вдохновения4

Лого для проекта создано при помощи aasvg проекта. Вы можете создать такое же и/или модифицировать имеющееся. Для этого воспользуйтесь сайтом или установите figlet. Если Вы используете способ с установкой figlet, то вдобавок необходимо сказать необходимый шрифт, например я использую Doom. Далее, необходимо воспользоваться aasvg и конвертировать ascii арт в svg. Обратите внимание - по умолчанию будет svg в красном цвете, чтобы изменить цвет, необходимо изменить его определение тут

$ curl 'http://www.figlet.org/fonts/doom.flf' -o /usr/share/figlet/doom.flf
$ curl 'http://www.figlet.org/fonts/larry3d.flf' -o /usr/share/figlet/larry3d.flf
$ figlet -f doom 'Python'

______      _   _
| ___ \    | | | |
| |_/ /   _| |_| |__   ___  _ __
|  __/ | | | __| '_ \ / _ \| '_ \
| |  | |_| | |_| | | | (_) | | | |
\_|   \__, |\__|_| |_|\___/|_| |_|
       __/ |
      |___/

$ aasvg --source --embed < ./docs/ascii.txt > docs/images/logo.svg
Python Chicken Chimera
Питоновый Петухон под авторством qwen.ai.

Footnotes

  1. 🛠️ За счёт скрипта python-install-approximately.sh нас может не волновать полная версия Python, мы можем передавать лишь приблизительно желаемую версию, а скрипт позаботится чтобы была выбрана последняя и актуальная из списка 2

  2. 🛠️ Например можно использовать свой приватный реестр образов: --build-arg image_registry=my-container-registry:1111/

  3. 🛠️ За счёт скрипта python-set-proxy.sh мы можем пользоваться и другим набором аргументов, таких как: package_registry_proxy и package_registry_trust_host 2 3

  4. 🛠️ Статическое Python приложение в образе контейнера на базе scratch

About

Минимальный базовый образ Python на Astra Linux

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published