Journal Un ramasse-miette pour docker

Posté par (page perso) . Licence CC by-sa
Tags :
26
10
nov.
2015

Lorsqu'on utilise docker pour déployer une application, la routine de maintenance des machines hébergeant les containers doit inclure un ramasse-miette dont la tâche est de se débarrasser des images obsolètes devenues inutiles. Si cet aspect de la maintenance est ignoré, en fonction de la fréquence des déploiements, de la taille des images et de l'espace disque disponible, le disque peut se remplir en quelques semaines voire en quelques heures.

Pour résoudre ce problème une bonne fois pour toutes, j'ai écrit un ramasse-miette très flexible pour docker. La procédure suit deux étapes. Dans la première, les containers qui ne sont pas marqués running sont effacés ; dans la seconde une règle de nettoyage est appliquée pour déterminer quelles images présentes dans la bibliothèque locale sont obsolètes et doivent être effacées. Les règles de nettoyage associent des prédicats sur les images à des actions, et peuvent être librement fixées. Il est facile d'inscrire le ramasse-miette dans le crontab(5) ou bien de le lancer avant les procédures préparant les nouvelles images.

Règles de nettoyage

Voici un exemple de règles de nettoyage, à inscrire dans le fichier ~/.docker/docker_gc.conf:

Dandling                            : Delete
Not(Age(3))                         : PreserveAll
Repository("organisation/repo")     : PreserveRecent(3)
True                                : Delete

elles demandent:

  • L'effacement toutes les images feuilles qui ne sont pas associées à un repository.
  • La préservation de toutes les images crées il y a moins de trois jours.
  • La préservation d'au plus 3 images dans le repository organisation/repo — les images préservées par la règle précédente participent au comptage.
  • L'effacement de toutes les autres images.

Les prédicats (membres de gauche dans le fichier de configuration ci-dessus) peuvent-être combinés arbitrairement à l'aide des connecteurs Or et And.

Utilisation dans le crontab

J'utilise ce programme en production sur des clusters dédiés au déploiement avec docker, en déclenchant le ramasse-miette toutes les heures:

CAML_LD_LIBRARY_PATH=/opt/opam/system/lib/stublibs:/usr/lib64/ocaml/stublibs
12 * * * * docker-user env HOME=/home/docker-user /opt/local/bin/docker_gc -v >> /opt/local/var/log/docker_gc.log 2>&1

(La ligne CAML_LD_LIBRARY_PATH doit diriger vers le dossier approprié de votre installation opam.)

Utilisation dans la production des images

Le ramasse-miette n'interagit pas bien avec la production d'images. Sur les serveurs dédiés à la préparation des images, il est facile et préférable d'intégrer le ramasse-miette comme préliminaire à la procédure de production des images.

Installation

Pour installer, le plus simple est d'utiliser opam. Comme quelques PRs sont en retard, il faut installer les paquets lemonade, rashell, gasoline, à partir du repository, la petite boucle shell suivante automatise tout cela:

for repo in lemonade rashell gasoline dockertk; do
  git clone "https://github.com/michipili/${repo}" "${repo}"
  (cd "${repo}" && autoconf)
  opam pin add "${repo}" "${repo}"
done
  • # Plus on est de fous ;-)

    Posté par . Évalué à 5.

    Pour résoudre ce problème une bonne fous pour toutes

    fous => fois

  • # Alternative de chez Spotify

    Posté par (page perso) . Évalué à 4.

    Pas essayé, et apparemment moins flexible que ta solution: https://github.com/spotify/docker-gc

    • [^] # Re: Alternative de chez Spotify

      Posté par (page perso) . Évalué à 6.

      Oui, j'aurais dû mentionner leur travail, qui est à ma connaissance le seul programme remplissant cette tâche. C'est un script shell, qui a donc l'avantage de la portabilité et de la facilité de déploiement, mais rend la généralisation de la tâche particulièrement ardue. J'ai donc écrit un autre ramasse miette, qui est un chouette petit projet de ouiquende! :)

  • # Mesos comme ramasse-miette

    Posté par . Évalué à 3.

    J'utilise Mesos pour gérer mon déploiement de containeurs docker, il s'occupe alors lui même de supprimer les containers qui ne sont plus utilisés (voir l'option --docker_remove_delay).

  • # race condition?

    Posté par (page perso) . Évalué à 4.

    Le passage suivant me perplexifie:

    Le ramasse-miette n'interagit pas bien avec la production d'images. Sur les serveurs dédiés à la préparation des images, il est facile et préférable d'intégrer le ramasse-miette comme préliminaire à la procédure de production des images.

    Qu'est-ce que ça veut dire au juste? Si ça se réfère au fait que la production d'images entraîne la création temporaire d'objets "Dangling" (ce qui est vraiment un bug particulièrement énervant de Docker), je vois mal pourquoi rendre le processus synchrone ou asynchrone changerait quoi que ce soit au problème, sauf à imposer une seule image en cours de création à un instant T, ou à stopper complètement le processus de création le temps d'un "gc". Dans les 2 cas, ça ne me semble pas particulièrement réaliste comme contrainte, pour un serveur dédié à cette activité.

    Est-ce qu'il ne vaudrait pas mieux suggérer une configuration fiable pour ces cas? (quitte à prendre une hypothèse sur le temps maximal de construction d'une image par exemple)

    Et si je suis complètement à côté de la plaque, une explication (voire un ajout au README) serait bienvenue ! :)

    Projet sympa sinon. Si je peux me permettre une suggestion, des instructions pour construire une image statique de ton programme lui donnerait de la visibilité: la plupart des systèmes pour lesquels il serait vraiment utiles n'ont pas OCaml, et souvent aucun moyen (simple) de l'installer (immutable infrastructure et tout ça).
    Ou encore mieux… fournir une image docker de ton programme (dans le style docker-in-docker)

    • [^] # Re: race condition?

      Posté par (page perso) . Évalué à 4.

      …sauf à imposer une seule image en cours de création à un instant T…

      C'est effectivement l'hypothèse implicite que je fais dans cette phrase, mais comme tu le soulignes, ce n'est pas particulièrement réaliste en production.

      Et si je suis complètement à côté de la plaque,

      non, non tu es au bon endroit! :)

      Ou encore mieux… fournir une image docker de ton programme (dans le style docker-in-docker)

      Cela fait partie des mes projets, ce sera effectivement plus facile à utiliser pour ceux qui ne sont pas encore familiers avec OCaml et son écosystème.

    • [^] # Re: race condition?

      Posté par (page perso) . Évalué à 2.

      Ou encore mieux… fournir une image docker de ton programme (dans le style docker-in-docker)

      Ça y est, j'ai décrit la procédure de préparation des images dans le README du projet et un petit script a été ajouté pour utiliser facilement cette image.

  • # Volumes?

    Posté par (page perso) . Évalué à 1.

    Vu que j'ai découvert cette blague hier …

    Une option sympathique à ajouter pourrait être le ramasse-miettage des anciens volumes également (qui ne sont pas effacés par défaut, et qui peuvent donc prendre pas mal de place au bout d'un moment)

    cf http://stackoverflow.com/questions/27812807/orphaned-docker-mounted-host-volumes

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.