Alpine compila i build Docker per Python 50 volte più lentamente e le immagini sono 2 volte più pesanti.

Alpine compila i build Docker per Python 50 volte più lentamente e le immagini sono 2 volte più pesanti.

Alpine Linux — spesso raccomandato come immagine di base per Docker. Ti dicono che l'uso di Alpine renderà i tuoi build più leggeri e il processo di build più veloce.

Ma se usi Alpine Linux per applicazioni Python, allora:

  • Rende i tuoi build molto più lenti
  • Rende le tue immagini più grandi
  • Ti fa perdere tempo
  • E alla fine può causare errori a runtime


Analizziamo perché Alpine è raccomandato, ma perché non dovresti comunque usarlo con Python.

Perché la gente raccomanda Alpine?

Supponiamo di aver bisogno di gcc come parte della nostra immagine e vogliamo confrontare Alpine Linux con Ubuntu 18.04, in termini di velocità di build e dimensione finale dell'immagine.

Per iniziare, 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 questo articolo

Misuriamo la velocità di build:

$ 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 tutto per Alpine (Dockerfile):

FROM alpine
RUN apk add --update gcc

Costruiamo, guardiamo il tempo e la dimensione della build:

$ 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 si costruiscono più rapidamente e sono più piccole: 15 secondi invece di 30 e la dimensione dell'immagine è 105MB contro 150MB. È piuttosto buono!

Ma se ci spostiamo alla build di un'applicazione Python, le cose non sono così rose.

Immagine Python

Le applicazioni Python usano spesso pandas e matplotlib. Quindi, una delle opzioni è prendere l'immagine ufficiale basata su Debian, utilizzando un Dockerfile così:

FROM python:3.8-slim
RUN pip install --no-cache-dir matplotlib pandas

Costruiamola:

$ docker build -f Dockerfile.slim -t python-matpan.
Invio del contesto di build al demone Docker  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
Raccolta di matplotlib
  Scaricamento matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl (13.1 MB)
Raccolta di pandas
  Scaricamento pandas-0.25.3-cp38-cp38-manylinux1_x86_64.whl (10.4 MB)
...
Costruito con successo b98b5dc06690
Taggato con successo python-matpan:latest

real    0m30.297s
user    0m0.043s
sys     0m0.020s

Otteniamo un'immagine di dimensioni 363MB.
Funzionerà 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 .                                 
Invio del contesto di build al demone Docker  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                                                                 
Raccolta di matplotlib                                                                         
  Scaricamento matplotlib-3.1.2.tar.gz (40.9 MB)                                               
    ERRORE: Comando terminato con codice di uscita 1:                                            
     comando: /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                              

...
ERRORE: Comando terminato con codice di uscita 1: python setup.py egg_info Controlla i log per l'output completo del comando.
Il comando '/bin/sh -c pip install matplotlib pandas' ha restituito un codice non zero: 1

Cosa sta succedendo?

Alpine non supporta i wheels

Se guardi la build basata su Debian, vedrai che scarica matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl.

Questo è un binario per wheel. Alpine invece scarica i sorgenti `matplotlib-3.1.2.tar.gz`, poiché non supporta il standard wheels.

Perché? La maggior parte delle distribuzioni Linux utilizza la versione GNU (glibc) della libreria standard C, che è effettivamente necessaria per ogni programma scritto in C, incluso Python. Ma Alpine utilizza `musl`, e poiché quei binari sono destinati a `glibc`, non sono semplicemente un'opzione.

Quindi, se utilizzi Alpine, devi compilare tutto il codice scritto in C in ogni pacchetto Python.

Ah, sì, dovrai cercare tu stesso l'elenco di tutte quelle dipendenze che devono essere compilate.
In questo caso otteniamo quanto segue:

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 build è...

… 25 minuti e 57 secondi! E la dimensione dell'immagine è di 851MB.

Le immagini basate su Alpine richiedono molto più tempo per essere create, sono di dimensioni maggiori e devi anche cercare tutte le dipendenze. Certo, puoi ridurre la dimensione della build usando multi-stage builds ma questo significa che dovrai fare ancora più lavoro.

Ma non è tutto!

Alpine può causare bug inaspettati a runtime

Probabilmente questi errori sono già stati corretti, ma chissà quanti altri ce ne sono.

Non utilizzare immagini Alpine per Python

Se non vuoi affrontare build grandi e lunghe, ricerca di dipendenze e potenziali errori — non utilizzare Alpine Linux come immagine di base. Scegliere una buona immagine di base.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster