[DOCKER] Installez le module dépendant du langage C de python au format roue avec une construction en plusieurs étapes

Contexte

L'installation Pip du module dépendant du langage C avec alpine est une histoire lourde

procédure

  1. Construisez les modules requis sur l'image alpine
  2. Rassemblez les produits (limes de roue) en un seul endroit pour une réutilisation facile
  3. Poussez vers Docker Hub en tant qu'image intégrée
  4. Obtenez et installez uniquement le répertoire wheel avec une construction multi-étapes en alpin pour l'environnement d'exécution
  5. Confirmation d'exécution et nettoyage

la mise en oeuvre

Tout d'abord, obtenez les comtés de modules requis Cette fois, je présenterai les modules suivants

requirements.txt


cycler==0.10.0
Cython==0.29.17
h5py==2.10.0
joblib==0.14.1
kiwisolver==1.2.0
matplotlib==3.2.1
numpy==1.18.4
pandas==1.0.3
Pillow==7.1.2
pyparsing==2.4.7
python-dateutil==2.8.1
pytz==2020.1
scikit-learn==0.22.2.post1
scipy==1.3.3
six==1.14.0

Collectez les modules requis en un seul endroit

Dans le cas de l'alpin, le format de compression tel que tar et zip est supprimé pour les modules dépendant du langage c. Il est nécessaire de les convertir au format whl.

Préparation

Il devrait y avoir une bibliothèque requise pour la conversion dans whl, alors installez-la via apk

apk update \
  && apk add --virtual .build --no-cache openblas-dev lapack-dev freetype-dev 
...
  && apk add --virtual .community_build --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/community hdf5-dev

Préparez le fichier whl nécessaire

Vous pouvez également télécharger le module avec pip download, Utilisez la commande pip wheel car elle téléchargera et extraira automatiquement le fichier tar / zip et le construira. Puisque pip wheel peut également utiliser l'option -r, spécifiez le fichier de contrôle de version avec pip freeze> requirements.txt.

pip wheel --no-cache --wheel-dir=./whl -r requirements.txt

Supplément lors de l'utilisation de la roue à pip

Malheureusement, dans ce cas ** il échoue en cours de route ** J'utilise requirements.txt construit dans un autre environnement alpin et pip gelé. scikit-learn tombe pendant la construction car numpy et scipy ne sont pas disponibles.

Avec pip install -r requirements.txt, le côté pip l'installera bien, mais [^ 1] [^ 1]: Puisque l'ordre d'installation de pip est exécuté en une seule fois sans tenir compte des bibliothèques et priorités dépendantes, le même phénomène se produit avec pip install. Au lieu de cela, les modules qui échouent au milieu en raison d'une «dépendance circulaire» sont évités en réexécutant la construction dès que tous les autres modules ont été installés. Seulement cette fois, il n'y a pas d'autre choix que de mettre le module dépendant en premier. [^ 2]

[^ 2]: Si scipy ~ = 1.4 dans l'environnement concerné, une erreur se produira et il échouera, alors spécifiez la série 1.3 qui est entrée docilement

pip install cython numpy==1.18.4 scipy==1.3.3
pip wheel --no-cache --wheel-dir=./whl -r requirements.txt

J'essayais de créer une image séparée pour éviter de construire numpy et scipy J'ai l'impression de faire quelque chose qui n'a pas de sens ...?

Poussez sur docker hub une fois la construction terminée

Étiqueter correctement et pousser

docker tag 123456789a hoge/builder-image:latest
docker push hoge/builder-image:latest

Apportez le produit pour l'environnement d'exécution

À partir de là, nous travaillerons sur le fichier dockerfile pour l'environnement d'exécution.

Installer la roue dans le répertoire local

Pour spécifier plusieurs modules avec pip install, écrivez solidement ou spécifiez un fichier texte avec --requirement. Il n'y a aucune spécification qui vous permet de collecter whl dans un répertoire approprié et de l'installer entièrement.

Cette fois, dans une construction en plusieurs étapes, COPY le répertoire contenant la roue et exécutez la commande suivante pour l'installer à partir de la roue locale.

pip install --no-index --no-deps --no-cache-dir -f ./whl -r requirement.txt

Module correspondant avec --upgrade

Les modules tels que pip et setuptools que vous souhaitez installer avec l'option --upgrade sont installés séparément dans le fichier texte de mise à niveau. Le fichier texte référencé par l'option -r peut être installé sans spécifier la version.

upgrade.txt


pip
setuptools
wheel

Mettez à niveau les modules regroupés dans un répertoire spécifique avec la commande suivante

pip install -U --no-index --no-deps --no-cache-dir -f ./upgrade  -r upgrade.txt

Cependant, étant donné que le nombre de fichiers à gérer augmentera, il est préférable d'écrire directement dans le fichier docker, sauf si vous êtes dans un environnement hors ligne.

Confirmation d'exécution

Vérifiez s'il peut être importé. Créez un fichier shell et appuyez directement sur la commande RUN.

import_test.sh


#!/bin/sh
python -c "import numpy"
python -c "import scipy"
python -c "import h5py"
python -c "import pandas"
python -c "import matplotlib"
python -c "import sklearn"

Nettoyer

Supprimez les fichiers supplémentaires pour réduire le poids de l'image du docker L'image utilisée pour construire n'a besoin que d'un produit, alors effacez tout le reste.

builder-image


apk del --purge .build .testing_build
pip freeze | xargs pip uninstall -y
pip cache purge

Vérifiez la luminosité de l'image construite en supprimant les fichiers supplémentaires. ** 360 Mo ** semble avoir réussi à perdre du poids

# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
naka345/wheel_build     latest              b6c9df898334        9 minutes ago       1.04GB 
naka345/wheel_build     latest              3236cf2f87de        2 days ago          639MB

Vient ensuite la disposition du côté de l'environnement d'exécution. Docker python officiel est très intelligent, donc je vais supprimer le fichier en fonction de cela. [^ 3]

[^ 3]: Dans l'environnement d'exécution installé avec -no-cache-dir spécifié, lorsque pip cache purge est exécuté, le fichier cache n'est pas trouvé et un code d'erreur est renvoyé. C'est sobre et difficile à utiliser.

execution-image


#Seuls les fichiers nécessaires au module sont regroupés sous la forme d'un nouveau package virtuel,
find /usr/local -type f -executable -not \( -name '*tkinter*' \) -exec scanelf --needed --nobanner --format '%n#p' '{}' ';' \
    | tr ',' '\n' \
    | sort -u \
    | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
    | xargs -rt apk add --no-cache --virtual .module-rundeps && \
  #Effacer tous les packages utilisés au moment de la construction
  apk del --purge .build .community_build
#Supprimer les fichiers supplémentaires et les déchets du côté python
find /usr/local -depth \
		\( \
			\( -type d -a \( -name test -o -name tests -o -name idle_test \) \) \
			-o \
			\( -type f -a \( -name '*.pyc' -o -name '*.pyo' \) \) \
		\) -exec rm -rf '{}' + 

#Nettoyage de la poussière pour cette gamme d'exécution
rm -rf /tmp/whl

Comparons-le avec le temps où il n'a pas été effacé du côté de l'environnement d'exécution.

# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
naka345/wheel_install   latest              f0df8a9887de        3 hours ago         1.29GB
↓
naka345/wheel_install   latest              27b4805053f2        3 hours ago         968MB

J'ai réussi à le maintenir en dessous de 1 Go.

Essayez d'en faire un fichier docker

Sur la base de ce qui précède, notez-le dans le fichier docker. Comme ce sera long, j'ai collé le lien github.

Résumé

Nous avons rendu possible la mise en place en toute sécurité et relativement rapidement de modules chronophages via pip. L'image du docker était également légèrement plus claire.

Cependant, la partie qui doit avoir plusieurs images est différée. Étant donné que la cohérence de requirements.txt est requise, Serait-ce plus facile s'il y avait un mécanisme pour pousser les deux images vers le docker hub lorsque celui-ci a été mis à jour?

Les références

Recommended Posts

Installez le module dépendant du langage C de python au format roue avec une construction en plusieurs étapes
Test de module multi-instance en langage C
Segfo avec 16 caractères en langage C
J'ai mesuré le temps pendant lequel j'ai installé le module dépendant du langage C avec alpin
Créer un environnement de développement de langage C avec un conteneur
Essayez de créer un module Python en langage C