
Alpine Linux — frequentemente recomendado como uma imagem base para Docker. Dizem que usar Alpine torna suas construções menores e o processo de construção mais rápido.
Mas se você usar Alpine Linux para aplicativos Python, ele:
- Torna suas construções muito mais lentas
- Torna suas imagens maiores
- Consome seu tempo
- E no final pode resultar em erros em tempo de execução
Vamos analisar por que o Alpine é recomendado, mas por que você ainda não deve usá-lo com Python.
Por que as pessoas recomendam Alpine?
Vamos supor que precisamos do gcc como parte da nossa imagem e queremos comparar Alpine Linux vs Ubuntu 18.04, em termos de velocidade de construção e tamanho final da imagem.
Para começar, vamos baixar duas imagens e comparar seu tamanho:
$ 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
Como você pode ver, a imagem base para Alpine é significativamente menor. Vamos agora tentar instalar o gcc e começar com o 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/*
A redação do Dockerfile perfeito está além do escopo deste artigo
Vamos medir a velocidade de construção:
$ 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
Repetimos o mesmo para Alpine (Dockerfile):
FROM alpine
RUN apk add --update gcc
Construímos, observamos o tempo e o tamanho da construção:
$ 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
Como prometido, as imagens baseadas em Alpine são construídas mais rapidamente e são menores: 15 segundos em vez de 30 e um tamanho de imagem de 105MB contra 150MB. Isso é bastante bom!
Mas se mudarmos para a construção de um aplicativo Python, as coisas não são tão boas.
Imagem Python
Aplicativos Python frequentemente usam pandas e matplotlib. Portanto, uma opção é usar a imagem oficial baseada em Debian com o seguinte Dockerfile:
FROM python:3.8-slim
RUN pip install --no-cache-dir matplotlib pandas
Construímos isso:
$ docker build -f Dockerfile.slim -t python-matpan.
Enviando contexto de construção para o daemon Docker 3.072kB
Etapa 1/2 : FROM python:3.8-slim
---> 036ea1506a85
Etapa 2/2 : RUN pip install --no-cache-dir matplotlib pandas
---> Executando em 13739b2a0917
Coletando matplotlib
Baixando matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl (13.1 MB)
Coletando pandas
Baixando pandas-0.25.3-cp38-cp38-manylinux1_x86_64.whl (10.4 MB)
...
Construído com sucesso b98b5dc06690
Marcado com sucesso python-matpan:latest
real 0m30.297s
usuario 0m0.043s
sistema 0m0.020s
Estamos obtendo uma imagem de 363MB.
Sairá melhor para nós com Alpine? Vamos tentar:
FROM python:3.8-alpine
RUN pip install --no-cache-dir matplotlib pandas
$ docker build -t python-matpan-alpine -f Dockerfile.alpine .
Enviando contexto de construção para o daemon Docker 3.072kB
Etapa 1/2 : FROM python:3.8-alpine
---> a0ee0c90a0db
Etapa 2/2 : RUN pip install --no-cache-dir matplotlib pandas
---> Executando em 6740adad3729
Coletando matplotlib
Baixando matplotlib-3.1.2.tar.gz (40.9 MB)
ERRO: Comando falhou com status de saída 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
...
ERRO: Comando falhou com status de saída 1: python setup.py egg_info Verifique os logs para ver a saída completa do comando.
O comando '/bin/sh -c pip install matplotlib pandas' retornou um código diferente de zero: 1
O que está acontecendo?
Alpine não suporta wheels
Se você olhar para a build que é baseada em Debian, verá que ele baixa matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl.
Este é um binário para wheel. O Alpine, por outro lado, baixa o código-fonte `matplotlib-3.1.2.tar.gz`, pois ele não suporta o padrão .
Por quê? A maioria das distribuições Linux usa a versão GNU (glibc) da biblioteca padrão C, que é de fato necessária para cada programa escrito em C, incluindo Python. Mas Alpine usa `musl`, e como aqueles binários são destinados ao `glibc`, eles simplesmente não são uma opção.
Portanto, se você estiver usando Alpine, precisa compilar todo o código escrito em C em cada pacote Python.
Ah, sim, a lista de todas essas dependências que precisam ser compiladas terá que ser procurada por conta própria.
Neste caso, obtemos o seguinte:
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 o tempo de build leva…
… 25 minutos e 57 segundos! E o tamanho da imagem é 851MB.
Imagens baseadas em Alpine são construídas muito mais lentamente, têm um tamanho maior por si mesmas e você ainda precisa buscar todas as dependências. É possível, é claro, reduzir o tamanho da construção usando mas isso significa que você terá que fazer ainda mais trabalho.
E isso não é tudo!
Alpine pode ser a causa de bugs inesperados em tempo de execução
- Na teoria, musl é compatível com glibc, mas na prática, as diferenças podem causar muitos problemas. E se houver, certamente serão desagradáveis. Aqui estão alguns problemas que podem surgir:
- Alpine tem um tamanho de pilha de thread menor por padrão, o que pode levar a
- Alguns usuários descobriram que devido à forma como o musl aloca memória (diferente do glibc).
- Um dos usuários
Certamente esses erros já foram corrigidos, mas quem sabe quantos ainda existem.
Não use imagens Alpine para Python
Se você não quer se preocupar com construções longas e volumosas, busca de dependências e potenciais erros — não use Alpine Linux como imagem base. .
Fonte: habr.com
