Optimiser la taille des images python
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 builderENV PYROOT=/venvENV PYTHONUSERBASE=$PYROOTCOPY 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 python3COPY --from=builder /venv /venv
# Make sure we use the virtualenv:ENV PATH="/venv/bin:$PATH"ENV PYTHONPATH="/venv/lib/python3.9/site-packages/"
WORKDIR /srcENTRYPOINT ["ansible-lint", "-p", "-v"]CMD ["--version"]
Le contenu du Pipfile:
[[source]]url = "https://pypi.org/simple"verify_ssl = truename = "pypi"
[packages]ansible-lint = "==5.2.0"yaml-lint = "*"ansible = "==2.9.26"
[dev-packages]
[requires]python_version = "3.9"
Je lance le build :
docker build -t ansible-lint-opt:5.2.0 .
Je lance le container pour la première fois:
docker run ansible-lint-opt:5.2.0ansible-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 :
docker run -v $PWD:/src ansible-lint-opt:5.2.0 provision-playbook.ymlINFO Running ansible-galaxy role install --force --roles-path /root/.cache/ansible-lint/56c9e1/roles -vr requirements.ymlINFO Running ansible-galaxy collection install --force -p /root/.cache/ansible-lint/56c9e1/collections -vr requirements.ymlINFO Added ANSIBLE_COLLECTIONS_PATHS=/root/.cache/ansible-lint/56c9e1/collectionsINFO Added ANSIBLE_ROLES_PATH=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:rolesINFO Running ansible-galaxy role install --force --roles-path /root/.cache/ansible-lint/56c9e1/roles -vr requirements.ymlINFO Running ansible-galaxy collection install --force -p /root/.cache/ansible-lint/56c9e1/collections -vr requirements.ymlINFO Added ANSIBLE_COLLECTIONS_PATHS=/root/.cache/ansible-lint/56c9e1/collections:/root/.cache/ansible-lint/56c9e1/collectionsINFO Added ANSIBLE_ROLES_PATH=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:roles:rolesINFO Executing syntax check on provision-playbook.yml (5.48s)
Ca marche !!!!
La taille de l’image est de :
docker images |grep ansible-lint
ansible-lint-opt 5.2.0 c5c2efc297ad 14 seconds ago 146MBregistry.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.