ProHoster > blog > amministrazione > Alpine compila le build Docker per Python 50 volte più lentamente e le immagini sono 2 volte più pesanti
Alpine compila le build Docker per Python 50 volte più lentamente e le immagini sono 2 volte più pesanti
Alpine Linux è spesso consigliato come immagine di base per Docker. Ti è stato detto che l'utilizzo di Alpine renderà le tue costruzioni più piccole e il processo di costruzione più veloce.
Ma se usi Alpine Linux per applicazioni Python, allora:
Rende le tue build molto più lente
Rende le tue immagini più grandi
Sprecare il tuo tempo
E alla fine può causare errori in fase di esecuzione
Diamo un'occhiata al motivo per cui Alpine è consigliato, ma perché non dovresti comunque usarlo con Python.
Perché le persone consigliano Alpine?
Supponiamo di aver bisogno di gcc come parte della nostra immagine e di voler confrontare Alpine Linux e Ubuntu 18.04 in termini di velocità di creazione e dimensione dell'immagine finale.
Per prima cosa scarichiamo due immagini e confrontiamo le loro dimensioni:
$ docker pull --quiet ubuntu:18.04
docker.io/library/ubuntu:18.04
$ docker pull --quiet alpine
docker.io/library/alpine:latest
$ docker image ls ubuntu:18.04
REPOSITORY TAG IMAGE ID SIZE
ubuntu 18.04 ccc6e87d482b 64.2MB
$ docker image ls alpine
REPOSITORY TAG IMAGE ID SIZE
alpine latest e7d92cdc71fe 5.59MB
Come puoi vedere, l'immagine di base per Alpine è molto più piccola. Proviamo ora a installare gcc e iniziamo con Ubuntu:
FROM ubuntu:18.04
RUN apt-get update &&
apt-get install --no-install-recommends -y gcc &&
apt-get clean && rm -rf /var/lib/apt/lists/*
Scrivere il Dockerfile perfetto va oltre lo scopo di questo articolo.
Misuriamo la velocità di assemblaggio:
$ time docker build -t ubuntu-gcc -f Dockerfile.ubuntu --quiet .
sha256:b6a3ee33acb83148cd273b0098f4c7eed01a82f47eeb8f5bec775c26d4fe4aae
real 0m29.251s
user 0m0.032s
sys 0m0.026s
$ docker image ls ubuntu-gcc
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-gcc latest b6a3ee33acb8 9 seconds ago 150MB
Ripetiamo lo stesso per Alpine (Dockerfile):
FROM alpine
RUN apk add --update gcc
Montiamo, guardiamo il tempo e le dimensioni dell'assemblea:
$ time docker build -t alpine-gcc -f Dockerfile.alpine --quiet .
sha256:efd626923c1478ccde67db28911ef90799710e5b8125cf4ebb2b2ca200ae1ac3
real 0m15.461s
user 0m0.026s
sys 0m0.024s
$ docker image ls alpine-gcc
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine-gcc latest efd626923c14 7 seconds ago 105MB
Come promesso, le immagini basate su Alpine vengono raccolte più velocemente e sono più piccole: 15 secondi invece di 30 e la dimensione dell'immagine è 105 MB contro 150 MB. È abbastanza buono!
Ma se passiamo alla creazione di un'applicazione Python, allora non tutto è così roseo.
Immagine pitone
Le applicazioni Python utilizzano spesso panda e matplotlib. Pertanto, un'opzione è prendere l'immagine ufficiale basata su Debian utilizzando questo Dockerfile:
FROM python:3.8-slim
RUN pip install --no-cache-dir matplotlib pandas
Raccogliamolo:
$ docker build -f Dockerfile.slim -t python-matpan.
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM python:3.8-slim
---> 036ea1506a85
Step 2/2 : RUN pip install --no-cache-dir matplotlib pandas
---> Running in 13739b2a0917
Collecting matplotlib
Downloading matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl (13.1 MB)
Collecting pandas
Downloading pandas-0.25.3-cp38-cp38-manylinux1_x86_64.whl (10.4 MB)
...
Successfully built b98b5dc06690
Successfully tagged python-matpan:latest
real 0m30.297s
user 0m0.043s
sys 0m0.020s
Otteniamo un'immagine di 363 MB di dimensione.
Faremo meglio con Alpine? Proviamo:
FROM python:3.8-alpine
RUN pip install --no-cache-dir matplotlib pandas
$ docker build -t python-matpan-alpine -f Dockerfile.alpine .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM python:3.8-alpine
---> a0ee0c90a0db
Step 2/2 : RUN pip install --no-cache-dir matplotlib pandas
---> Running in 6740adad3729
Collecting matplotlib
Downloading matplotlib-3.1.2.tar.gz (40.9 MB)
ERROR: Command errored out with exit status 1:
command: /usr/local/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/
tmp/pip-install-a3olrixa/matplotlib/setup.py'"'"'; __file__='"'"'/tmp/pip-install-a3olrixa/matplotlib/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'rn'"'"', '"'"'n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-a3olrixa/matplotlib/pip-egg-info
...
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
The command '/bin/sh -c pip install matplotlib pandas' returned a non-zero code: 1
Cosa sta succedendo?
Alpine non supporta le ruote
Se guardi la build, che è basata su Debian, vedrai che scarica matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.quando.
Questo è un binario per ruota. Alpine scarica i sorgenti `matplotlib-3.1.2.tar.gz` poiché non supporta lo standard ruote.
Perché? La maggior parte delle distribuzioni Linux utilizza la versione GNU (glibc) della libreria standard C, che è infatti richiesta da ogni programma scritto in C, compreso Python. Ma Alpine usa "musl" e poiché questi file binari sono progettati per "glibc", semplicemente non sono un'opzione.
Pertanto, se usi Alpine, devi compilare tutto il codice scritto in C in ogni pacchetto Python.
Oh, sì, dovrai cercare l'elenco di tutte queste dipendenze che devono essere compilate tu stesso.
In questo caso otteniamo questo:
FROM python:3.8-alpine
RUN apk --update add gcc build-base freetype-dev libpng-dev openblas-dev
RUN pip install --no-cache-dir matplotlib pandas
E il tempo di costruzione richiede...
... 25 minuti e 57 secondi! E la dimensione dell'immagine è 851 MB.
Le immagini basate su Alpine richiedono molto più tempo per essere create, sono di dimensioni maggiori ed è ancora necessario cercare tutte le dipendenze. Ovviamente è possibile ridurre le dimensioni dell'assieme utilizzando costruzioni a più stadi ma ciò significa che occorre fare ancora più lavoro.
Non è tutto!
Alpine può causare bug imprevisti in fase di runtime
In teoria, musl è compatibile con glibc, ma in pratica le differenze possono causare molti problemi. E se lo sono, probabilmente saranno spiacevoli. Ecco alcuni problemi che potrebbero verificarsi:
Alpine ha una dimensione dello stack di thread più piccola per impostazione predefinita, il che può portare a errori in Python
Sicuramente questi errori sono già stati corretti, ma chissà quanti altri ce ne saranno.
Non utilizzare immagini Alpine per Python
Se non vuoi preoccuparti di build grandi e lunghe, alla ricerca di dipendenze e potenziali errori, non utilizzare Alpine Linux come immagine di base. Scegliere una buona immagine di base.