Comprendre les fonctionnalités de l'image officielle Python Docker

L'image officielle de Python Docker est très populaire. À propos, j'ai moi-même recommandé l' une de ses variantes comme image de base. Mais de nombreux programmeurs ne comprennent pas exactement comment cela fonctionne. Cela peut conduire à la confusion et à divers problèmes. Dans cet article, je vais parler de la création de cette image, de son utilité, de son utilisation correcte et de ses limites. Plus précisément, je vais le décomposer ici (dans l'état représenté par le Dockerfile du 19 août 2020 ) et m'attarder sur les détails les plus importants en cours de route.







python:3.8-slim-buster



Lire le Dockerfile



▍Image de base



Commençons par une image de base:



FROM debian:buster-slim


Il s'avère que l'image de base python:3.8-slim-busterest Debian GNU / Linux 10 - la version stable actuelle de Debian, également connue sous le nom de Buster (les versions de Debian sont nommées d'après des personnages de Toy Story). Buster est, si quelqu'un est intéressé, le chien d'Andy.



Ainsi, au cœur de l'image qui nous intéresse se trouve la distribution Linux, qui garantit son fonctionnement stable. Des corrections de bogues sont régulièrement publiées pour cette distribution. La variante a slimmoins de packages installés que la variante régulière. Là, par exemple, il n'y a pas de compilateurs.



▍ Variables d'environnement



Jetons maintenant un œil aux variables d'environnement. Le premier garantit qu'il est ajouté le /usr/local/binplus tôt possible $PATH.



#     python,   ,    
ENV PATH /usr/local/bin:$PATH


L'image est conçue pour que Python soit installé dans /usr/local. En conséquence, cette construction garantit que les exécutables installés seront utilisés par défaut.



Ensuite, jetons un coup d'œil aux paramètres de langue:



# http://bugs.python.org/issue19846
# >     "LANG=C"  Linux *    Python 3*,   .
ENV LANG C.UTF-8


Pour autant que je sache, Python 3 moderne, par défaut, et sans ce paramètre, utilise UTF-8. Je ne suis donc pas sûr que cette ligne soit nécessaire dans le Dockerfile en question ces jours-ci.



Il existe également une variable d'environnement qui contient des informations sur la version actuelle de Python:



ENV PYTHON_VERSION 3.8.5


Il existe également une variable d'environnement à clé GPG dans le Dockerfile, qui est utilisée pour vérifier le code source Python chargé.



▍ Dépendances d'exécution



Python a besoin de quelques packages supplémentaires pour fonctionner:



RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    netbase \
  && rm -rf /var/lib/apt/lists/*


Le premier package ,, ca-certificatescontient une liste de certificats CA standard. Quelque chose de similaire est utilisé par le navigateur pour valider les adresses . Cela permet à Python wgetet à d'autres outils de valider les certificats fournis par les serveurs.



Le deuxième package, netbasequi effectue l'installation dans /etcplusieurs fichiers, est nécessaire pour configurer le mappage de certains noms vers certains ports et protocoles. Par exemple, il /etc/servicesest chargé de configurer la correspondance des noms de service, comme https, avec les numéros de port. Dans ce cas, c'est le cas 443/tcp.



▍Installez Python



La boîte à outils de compilation est en cours d'installation. À savoir, la source Python est téléchargée et compilée, puis les paquets Debian inutiles sont désinstallés:



RUN set -ex \
  \
  && savedAptMark="$(apt-mark showmanual)" \
  && apt-get update && apt-get install -y --no-install-recommends \
    dpkg-dev \
    gcc \
    libbluetooth-dev \
    libbz2-dev \
    libc6-dev \
    libexpat1-dev \
    libffi-dev \
    libgdbm-dev \
    liblzma-dev \
    libncursesw5-dev \
    libreadline-dev \
    libsqlite3-dev \
    libssl-dev \
    make \
    tk-dev \
    uuid-dev \
    wget \
    xz-utils \
    zlib1g-dev \
#   Stretch "gpg"       
    $(command -v gpg > /dev/null || echo 'gnupg dirmngr') \
  \
  && wget -O python.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz" \
  && wget -O python.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc" \
  && export GNUPGHOME="$(mktemp -d)" \
  && gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$GPG_KEY" \
  && gpg --batch --verify python.tar.xz.asc python.tar.xz \
  && { command -v gpgconf > /dev/null && gpgconf --kill all || :; } \
  && rm -rf "$GNUPGHOME" python.tar.xz.asc \
  && mkdir -p /usr/src/python \
  && tar -xJC /usr/src/python --strip-components=1 -f python.tar.xz \
  && rm python.tar.xz \
  \
  && cd /usr/src/python \
  && gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \
  && ./configure \
    --build="$gnuArch" \
    --enable-loadable-sqlite-extensions \
    --enable-optimizations \
    --enable-option-checking=fatal \
    --enable-shared \
    --with-system-expat \
    --with-system-ffi \
    --without-ensurepip \
  && make -j "$(nproc)" \
    LDFLAGS="-Wl,--strip-all" \
  && make install \
  && rm -rf /usr/src/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' -o -name '*.a' \) \) \
      -o \( -type f -a -name 'wininst-*.exe' \) \
    \) -exec rm -rf '{}' + \
  \
  && ldconfig \
  \
  && apt-mark auto '.*' > /dev/null \
  && apt-mark manual $savedAptMark \
  && find /usr/local -type f -executable -not \( -name '*tkinter*' \) -exec ldd '{}' ';' \
    | awk '/=>/ { print $(NF-1) }' \
    | sort -u \
    | xargs -r dpkg-query --search \
    | cut -d: -f1 \
    | sort -u \
    | xargs -r apt-mark manual \
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/* \
  \
  && python3 --version


Il se passe beaucoup de choses ici, mais le plus important est ceci:



  1. Python est installé dans /usr/local.
  2. Tous les fichiers .pyc sont supprimés.
  3. Les packages, en particulier - gccet d'autres du type qui étaient nécessaires pour compiler Python, sont supprimés une fois qu'ils ne sont plus nécessaires.


En raison du fait que tout cela se produit en une seule commande RUN, le compilateur n'est stocké dans aucune des couches, ce qui permet de maintenir une taille d'image compacte.



Ici, vous pouvez noter que Python a besoin d'une bibliothèque pour compiler libbluetooth-dev. Cela me semblait inhabituel, alors j'ai décidé de le découvrir. En fait, Python peut créer des sockets Bluetooth, mais uniquement s'il est compilé à l'aide de cette bibliothèque.



▍ Configuration du lien symbolique



L'étape suivante consiste /usr/local/bin/python3à attribuer un lien symbolique /usr/local/bin/python, ce qui permet à Python d'être invoqué de différentes manières:



#     ,     
RUN cd /usr/local/bin \
  && ln -s idle3 idle \
  && ln -s pydoc3 pydoc \
  && ln -s python3 python \
  && ln -s python3-config python-config


▍Installer pip



Le gestionnaire de packages pipa son propre calendrier de publication qui diffère du calendrier de publication de Python. Par exemple, ce Dockerfile installe Python 3.8.5, publié en juillet 2020. Et pip 20.2.2 est sorti en août, après la sortie de Python, mais le Dockerfile est conçu pour avoir une nouvelle version installée pip:



#     "PIP_VERSION",  pip  : "ValueError: invalid truth value '<VERSION>'"
ENV PYTHON_PIP_VERSION 20.2.2
# https://github.com/pypa/get-pip
ENV PYTHON_GET_PIP_URL https://github.com/pypa/get-pip/raw/5578af97f8b2b466f4cdbebe18a3ba2d48ad1434/get-pip.py
ENV PYTHON_GET_PIP_SHA256 d4d62a0850fe0c2e6325b2cc20d818c580563de5a2038f917e3cb0e25280b4d1

RUN set -ex; \
  \
  savedAptMark="$(apt-mark showmanual)"; \
  apt-get update; \
  apt-get install -y --no-install-recommends wget; \
  \
  wget -O get-pip.py "$PYTHON_GET_PIP_URL"; \
  echo "$PYTHON_GET_PIP_SHA256 *get-pip.py" | sha256sum --check --strict -; \
  \
  apt-mark auto '.*' > /dev/null; \
  [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
  apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
  rm -rf /var/lib/apt/lists/*; \
  \
  python get-pip.py \
    --disable-pip-version-check \
    --no-cache-dir \
    "pip==$PYTHON_PIP_VERSION" \
  ; \
  pip --version; \
  \
  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 '{}' +; \
  rm -f get-pip.py


Une fois ces opérations terminées, comme auparavant, tous les fichiers .pyc sont supprimés.



▍ Point d'entrée d'image



En conséquence, le point d'entrée de l'image est spécifié dans le Dockerfile:



CMD ["python3"]


En utilisant à la CMDplace, ENTRYPOINTnous lançons l'image, par défaut, nous avons accès à python:



$ docker run -it python:3.8-slim-buster
Python 3.8.5 (default, Aug  4 2020, 16:24:08)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>


Mais, si nécessaire, vous pouvez spécifier d'autres fichiers exécutables lors du démarrage de l'image:



$ docker run -it python:3.8-slim-buster bash
root@280c9b73e8f9:/#


Résultat



Voici ce que nous avons appris en analysant le fichier Dockerfile officiel de l'image Python slim-buster.



▍L'image comprend Python



Bien que cela puisse sembler évident, il convient de prêter attention à la manière exacte dont Python est inclus dans l'image. À savoir, cela se fait en l'installant dans /usr/local.



Les programmeurs utilisant cette image font parfois la même erreur, qui est de réinstaller la version Debian de Python:



FROM python:3.8-slim-buster

#    :
RUN apt-get update && apt-get install python3-dev


Lorsque vous exécutez cette commande, RUNPython sera de nouveau installé, mais dans /usr, pas dans /usr/local. Et ce ne sera généralement pas la version de Python installée dans /usr/local. Et le programmeur qui a utilisé le fichier Docker ci-dessus n'a probablement pas besoin de deux versions différentes de Python dans la même image. C'est principalement la raison de la confusion.



Et si quelqu'un a vraiment besoin d'une version Debian de Python, il serait préférable de l'utiliser comme image de base debian:buster-slim.



▍ L'image comprend la dernière version de pip



Par exemple, la dernière version de Python 3.5 datait de novembre 2019, mais l'image Docker python:3.5-slim-busterinclut pipcelle qui est sortie en août 2020. C'est (généralement) une bonne chose car cela signifie que nous avons à notre disposition les correctifs de bogues les plus récents et les améliorations de performances. Cela signifie également que nous pouvons bénéficier d'une assistance pour les nouvelles options de roues.



▍ Tous les fichiers .pyc sont supprimés de l'image



Si vous souhaitez accélérer un peu le démarrage du système, vous pouvez compiler indépendamment le code source de la bibliothèque standard au format .pyc. Ceci est fait en utilisant le module compileall .



▍Image n'installe pas les mises à jour de sécurité Debian



Bien que les images de base debian:buster-slim, et pythonsont fréquemment mis à jour, il y a un certain écart entre la sortie des mises à jour de sécurité de Debian et de les transformer en images. Par conséquent, vous devez installer indépendamment les mises à jour de sécurité pour la distribution Linux de base.



Quelles images Docker utilisez-vous pour exécuter du code Python?






All Articles