python:3.8-slim-buster
Leyendo el Dockerfile
▍Imagen básica
Comencemos con una imagen base:
FROM debian:buster-slim
Resulta que la imagen base
python:3.8-slim-buster
es Debian GNU / Linux 10, la versión estable actual de Debian, también conocida como Buster (las versiones de Debian llevan el nombre de personajes de Toy Story). Buster es, si alguien está interesado, el perro de Andy.
Entonces, en el corazón de la imagen que nos interesa está la distribución de Linux, que garantiza su funcionamiento estable. Las correcciones de errores se publican periódicamente para esta distribución. La variante tiene
slim
menos paquetes instalados que la variante regular. Allí, por ejemplo, no hay compiladores.
▍Variables de entorno
Ahora echemos un vistazo a las variables de entorno. El primero asegura que se agregue
/usr/local/bin
lo antes posible a $PATH
.
# python, ,
ENV PATH /usr/local/bin:$PATH
La imagen está diseñada para que Python esté instalado en
/usr/local
. Como resultado, esta construcción asegura que los ejecutables instalados se utilizarán de forma predeterminada.
A continuación, echemos un vistazo a la configuración de idioma:
# http://bugs.python.org/issue19846
# > "LANG=C" Linux * Python 3*, .
ENV LANG C.UTF-8
Hasta donde yo sé, el Python 3 moderno, de forma predeterminada y sin esta configuración, usa UTF-8. Así que no estoy seguro de si esta línea es necesaria en el Dockerfile en cuestión estos días.
También hay una variable de entorno que contiene información sobre la versión actual de Python:
ENV PYTHON_VERSION 3.8.5
También hay una variable de entorno con clave GPG en el Dockerfile, que se utiliza para verificar el código fuente de Python cargado.
▍Dependencias de tiempo de ejecución
Python necesita algunos paquetes adicionales para funcionar:
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
netbase \
&& rm -rf /var/lib/apt/lists/*
El primer paquete ,,
ca-certificates
contiene una lista de certificados CA estándar. El navegador utiliza algo similar para validar las URL . Esto permite que Python wget
y otras herramientas validen los certificados proporcionados por los servidores.
El segundo paquete,
netbase
que realiza la instalación en /etc
varios archivos, es necesario para configurar el mapeo de ciertos nombres a ciertos puertos y protocolos. Por ejemplo, /etc/services
es responsable de configurar la correspondencia de los nombres de los servicios, como https
, con los números de puerto. En este caso, lo es 443/tcp
.
▍Instalar Python
Ahora se está instalando el kit de herramientas de compilación. Es decir, la fuente de Python se descarga y compila, y luego se desinstalan los paquetes Debian innecesarios:
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
Están sucediendo muchas cosas aquí, pero lo más importante es esto:
- Python está instalado en
/usr/local
. - Se eliminan todos los archivos .pyc.
- Los paquetes, en particular,
gcc
y otros del tipo que se necesitaban para compilar Python, se eliminan cuando ya no son necesarios.
Debido a que todo esto sucede en un solo comando
RUN
, como resultado, el compilador no se almacena en ninguna de las capas, lo que ayuda a mantener un tamaño de imagen compacto.
Aquí puede notar que Python necesita una biblioteca para compilar
libbluetooth-dev
. Esto me pareció inusual, así que decidí resolverlo. Resulta que Python puede crear sockets Bluetooth, pero solo si se compila con esta biblioteca.
▍Configuración de enlace simbólico
El siguiente paso
/usr/local/bin/python3
es asignar un enlace simbólico /usr/local/bin/python
, que permite invocar a Python de diferentes formas:
# ,
RUN cd /usr/local/bin \
&& ln -s idle3 idle \
&& ln -s pydoc3 pydoc \
&& ln -s python3 python \
&& ln -s python3-config python-config
▍Instalar pip
El administrador de paquetes
pip
tiene su propio programa de lanzamiento que difiere del programa de lanzamiento de Python. Por ejemplo, este Dockerfile instala Python 3.8.5, lanzado en julio de 2020. Y pip 20.2.2 se lanzó en agosto, después del lanzamiento de Python, pero el Dockerfile está diseñado para tener una nueva versión instalada 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
Después de completar estas operaciones, como antes, se eliminan todos los archivos .pyc.
▍Punto de entrada de la imagen
Como resultado, el punto de entrada a la imagen se especifica en el Dockerfile:
CMD ["python3"]
Usando en su
CMD
lugar, ENTRYPOINT
nosotros, al lanzar la imagen, obtenemos acceso a Python por defecto:
$ 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.
>>>
Pero, si es necesario, puede especificar otros archivos ejecutables al iniciar la imagen:
$ docker run -it python:3.8-slim-buster bash
root@280c9b73e8f9:/#
Salir
Esto es lo que aprendimos al analizar el Dockerfile de la imagen oficial de Python
slim-buster
.
▍La imagen incluye Python
Si bien esto puede parecer obvio, vale la pena prestar atención a cómo se incluye exactamente Python en la imagen. Es decir, esto se hace instalándolo en
/usr/local
.
Los programadores que usan esta imagen a veces cometen el mismo error, que es reinstalar la versión Debian de Python:
FROM python:3.8-slim-buster
# :
RUN apt-get update && apt-get install python3-dev
Cuando ejecute este comando,
RUN
Python se instalará nuevamente, pero /usr
no en /usr/local
. Y esta no suele ser la versión de Python que está instalada en /usr/local
. Y el programador que usó el archivo Docker anterior probablemente no necesite dos versiones diferentes de Python en la misma imagen. Esta es principalmente la razón de la confusión.
Y si alguien realmente necesita una versión Debian de Python, entonces sería mejor usarla como imagen base
debian:buster-slim
.
▍ La imagen incluye la última versión de pip
Por ejemplo, la versión más reciente de Python 3.5 fue en noviembre de 2019, pero la imagen de Docker
python:3.5-slim-buster
incluye la pip
que salió en agosto de 2020. Esto (generalmente) es bueno, ya que significa que tenemos las últimas correcciones de errores y mejoras de rendimiento. Esto también significa que podemos beneficiarnos de la compatibilidad con opciones de ruedas más nuevas.
▍ Todos los archivos .pyc se eliminan de la imagen
Si desea acelerar un poco el arranque del sistema, puede compilar de forma independiente el código fuente de la biblioteca estándar en formato .pyc. Esto se hace usando el módulo compileall .
▍Image no instala actualizaciones de seguridad de Debian
Aunque las imágenes de base
debian:buster-slim
, y python
se actualiza con frecuencia, hay una cierta diferencia entre el lanzamiento de las actualizaciones de seguridad y convertirlos en imágenes. Por lo tanto, debe instalar actualizaciones de seguridad de forma independiente para la distribución básica de Linux.
¿Qué imágenes de Docker usas para ejecutar código Python?