Aller au contenu

Optimiser la taille des images python

logo docker

Ce matin en parcourant la documentation de pipenv j’ai redécouvert qu’il était possible de packager l’application avec l’option —deploy. Et la le déclic et si cette méthode permettait de réduire la taille de mes containers utilisant python. En parcourant quelques sites j’ai vu que cela pouvait fonctionner. Cela vient compléter mon précédent billet d’optimisation des images docker.

Mise en pratique

J’ai repris l’image d’ansible-lint et j’ai modifié l’image de build pour qu’elle :

  • installe pipenv.
  • copie le fichier Pipfile
  • et installe les packages dans le répertoire venv
FROM alpine:latest as builder
ENV PYROOT=/venv
ENV PYTHONUSERBASE=$PYROOT
COPY Pipfile* ./
RUN apk update && apk add --no-cache bc cargo gcc libffi-dev musl-dev openssl-dev rust python3-dev py3-pip \
&& pip3 install --no-cache-dir --no-compile pipenv && pipenv lock && PIP_USER=1 pipenv sync --system
FROM alpine:latest as default
RUN apk add --no-cache git python3
COPY --from=builder /venv /venv
# Make sure we use the virtualenv:
ENV PATH="/venv/bin:$PATH"
ENV PYTHONPATH="/venv/lib/python3.9/site-packages/"
WORKDIR /src
ENTRYPOINT ["ansible-lint", "-p", "-v"]
CMD ["--version"]

Le contenu du Pipfile:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
ansible-lint = "==5.2.0"
yaml-lint = "*"
ansible = "==2.9.26"
[dev-packages]
[requires]
python_version = "3.9"

Je lance le build :

Terminal window
docker build -t ansible-lint-opt:5.2.0 .

Je lance le container pour la première fois:

Terminal window
docker run ansible-lint-opt:5.2.0
ansible-lint unknown using ansible 2.9.26

Oh il n’affiche pas la version. Un détail? Fonctionne t’il ?

On le teste sur un playbook :

Terminal window
docker run -v $PWD:/src ansible-lint-opt:5.2.0 provision-playbook.yml
INFO Running ansible-galaxy role install --force --roles-path /root/.cache/ansible-lint/56c9e1/roles -vr requirements.yml
INFO Running ansible-galaxy collection install --force -p /root/.cache/ansible-lint/56c9e1/collections -vr requirements.yml
INFO Added ANSIBLE_COLLECTIONS_PATHS=/root/.cache/ansible-lint/56c9e1/collections
INFO Added ANSIBLE_ROLES_PATH=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:roles
INFO Running ansible-galaxy role install --force --roles-path /root/.cache/ansible-lint/56c9e1/roles -vr requirements.yml
INFO Running ansible-galaxy collection install --force -p /root/.cache/ansible-lint/56c9e1/collections -vr requirements.yml
INFO Added ANSIBLE_COLLECTIONS_PATHS=/root/.cache/ansible-lint/56c9e1/collections:/root/.cache/ansible-lint/56c9e1/collections
INFO Added ANSIBLE_ROLES_PATH=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:roles:roles
INFO Executing syntax check on provision-playbook.yml (5.48s)

Ca marche !!!!

La taille de l’image est de :

Terminal window
docker images |grep ansible-lint
ansible-lint-opt 5.2.0 c5c2efc297ad 14 seconds ago 146MB
registry.gitlab.com/dockerfiles6/ansible-lint 5.2.0 369443c79b4a 2 days ago 451MB

Le choc on est passé de 1.9Gb à 451Mb avec venv et maintenant à 146Mb avec pipenv. Good job! A tester sur d’autres projets python.

Mais attention la taille ne fait pas tout. Utiliser une Alpine Linux peut parfois avoir des effets secondaires. En effet, par exemple sur les projets python contrairement à d’autres distributions Alpine ne met à disposition qu’un seul package wheel (binaire précompilé). Du coup il recompile tout à partir du code source et parfois ca peut être très très long … Un exemple les packages cryptography et lxml.

Donc faut trouver le bon compromis.

Source