Journal Une image de base docker

Posté par .
37
7
août
2018

Si on connait tous à priori nos bonnes vielles distributions (GNU?/)Linux. Ces dernières années l'arrivée de Docker a donné lieu à l'apparition de distributions nouvelles moins connues (en tout cas pas par moi). En effet même si les distributions classiques sont tout à fait utilisables dans une image docker, le fait d'avoir une distribution pensée pour docker peut être un avantage. Par exemple réduire fortement la taille de l'image rend son utilisation bien plus agréable (plus rapide à télécharger depuis le registry, utilise moins de place disque, certaines consomment même moins de mémoire) et réduit de fait la surface d'attaque.

Alpine

C'est LA reine de docker, mais elle n'a pas été conçue pour docker. Je n'ai pas trouvé de trace avant 2010 et la sortie de la version 2.0.0. Elle est un fork de LEAF que je ne connais pas du tout. On en a déjà parlé ici, mais je ne la connaissais pas plus que ça : https://linuxfr.org/tags/alpinelinux/public

En terme de choix de distribution linux arrive avec PaX et Grsecurity (ce dont on se fout pour docker). Elle utilise musl comme bibliothèque C, libreSSL pour TLS et OpenRC comme init (ce dont on se fout pour docker). Les core tools viennent de BusyBox.

Elle utilise un gestionnaire de paquet apk-tools (ne vous méprenez pas ça n'a rien à voir avec android). On peut rechercher les paquets disponibles via leur outil en ligne : https://pkgs.alpinelinux.org.

La version actuelle (sortie fin juin) est la 3.8. Les versions de la distributions sont généralement supportées 2 ans et sortent environ tous les 6 ou 7 mois (seulement pour des mises à jour de sécurité). Il y a une version edge qui est en rolling release. C'est la version en développement. La distribution me semble communautaire.

Site officiel : https://alpinelinux.org/
Documentation : https://wiki.alpinelinux.org (une aide pour s'y retrouver par rapport aux autres distributions)

Note : J'ai vu pas mal d'images utiliser edge comme base et ce n'est évidement pas une bonne idée

Distroless par Google

Google met énormément de billes dans docker (coucou kubernetes). J'ai découvert récemment qu'ils ont des images « distroless » (c'est forcément une distribution logicielle par définition). Leur objectif est de créer des images par langage aussi minimalistes que possibles. Ils incluent 3 bibliothèques glibc, libssl et openssl, c'est tout dans l'image de base, ensuite ça dépend des langages. Dans les langages supportés on trouve python (2.7 et 3), java, cc (je présume que c'est pour c et c++) et… surprise .Net !

Site officiel : https://github.com/GoogleContainerTools/distroless

Note : C'est très intéressant comme approche. Pour construire vraiment des images les plus petites possibles. Il n'y a pas de shells installés, aucun runtime en plus de ce dont vous avez besoin,… Pour aller plus loin il faudrait faire certains choix pour que les fichiers soient en lecture seule par exemple, mais bon c'est déjà pas mal je trouve.

Scratch

Pourquoi s'embêter ? Quand on compile statiquement son programme (coucou go ! ^^), il n'y a pas besoin de runtime. Docker n'est là que pour activer de manière simple le sandboxing de linux (chroot, namespace & cgroup) et les kubernetes pour déployer ça sur un parc de machines. C'est fourni directement par Docker Inc, mais ça ne devrait plus être utilisé (depuis Docker 1.5 FROM scratch ne télécharge plus d'images permettant de ne même plus avoir de première layer vide).


Personnellement je vois encore beaucoup d'ubuntu. Cela permet d'avoir un shell dans le conteneur pour des raisons de debug. On peut faire ça en utilisant une image de debug qui sera lancée dans le même sandbox que le container que l'on veut utiliser. Un article pas mal pour ça. Rien de tout cela n'est vraiment neuf, je sais mais c'est une occasion pour moi de coucher cela quelque part et de partager :)

Tout ce document est sous licence CC0.

  • # distroless

    Posté par (page perso) . Évalué à 8 (+6/-0).

    Jusqu'à présent j'utilisais pas mal d'alpine, et maintenant dès que je peux du distroless.
    Disons que distroless pour embarquer du static, c'est un peu comme du scratch mais en mieux.

    Alpine c'est sympa, mais ça finissait toujours par avoir besoin à un moment ou à un autre de la glibc (ou compat) donc l'intérêt se réduit franchement.

    Ce que j'aime dans scratch/distroless c'est aussi une histoire de principe. J'aime voir les containeurs comme étant juste mon app/service avec ses dépendances et rien d'autre. Juste une sandbox. La plus petite possible, le reste étant superflus, inutile, source problème, de failles, de maintenance, etc.
    Le contraire exact de "containers comme des VMs".

    Le seul problème que j'ai pour le moment avec distroless (outre le manque d'une image ruby) c'est pour faire tourner du python avec du pip install durant le build du container. Je crois qu'on peut faire des choses avec BAZEL mais j'ai pas encore vraiment tenté.
    Si quelqu'un sait embarquer au build des dépendances python sur distroless, ça m'intéresse grandement :-)

    Il y a pas mal de bonnes conférences sur pourquoi c'est bien d'avoir des images petites et comment faire (entre autre de Abby Fuller, par exemple https://www.youtube.com/watch?v=pPsREQbf3PA de mémoire)


    Après tout dépend aussi du contexte, parfois ça peut se faire d'avoir des images plus lourdes avec un layer commun, partagé entre toutes les images et qui sera dispo sur toutes les machines. Dans certains contextes ça peut le faire, avec l'avantage de mutualiser certains problèmes de sécu, d'outils dispo, de version, etc.
    L'avantage si tout est dans une image de base c'est qu'un docker pull ne téléchargera que les layers manquant, donc lui sera relativement rapide.

    • [^] # Re: distroless

      Posté par (page perso) . Évalué à 6 (+4/-0).

      Alpine c'est sympa, mais ça finissait toujours par avoir besoin à un moment ou à un autre de la glibc (ou compat) donc l'intérêt se réduit franchement.

      Plus gros qu'Alpine sans être énorme il y a des Debian light comme
      minideb
      https://github.com/bitnami/minideb

      Multitasking — The art of doing twice as much as you should half as well as you could.

      • [^] # Re: distroless

        Posté par . Évalué à 3 (+1/-0).

        kiff-kiff avec debian:stretch-slim :

        marc@gigabyte:~$ docker images | grep stretch
        bitnami/minideb stretch 349ecf6037a0 24 hours ago 53.7MB
        debian stretch-slim 184356db7df7 3 weeks ago 55.3MB

    • [^] # Re: distroless

      Posté par . Évalué à 4 (+3/-0).

      Disons que distroless pour embarquer du static, c'est un peu comme du scratch mais en mieux.

      Tiens pourquoi tu privilégie distrless pour du statique ?

      Le seul problème que j'ai pour le moment avec distroless (outre le manque d'une image ruby) c'est pour faire tourner du python avec du pip install durant le build du container. Je crois qu'on peut faire des choses avec BAZEL mais j'ai pas encore vraiment tenté.

      Je ne connais vraiment pas bien le build python, mais ça peut pas être résolu par du multistage ? Tu fais ton build dans une image alpine/ubuntu/whatever, puis tu copie tes artefacts (ton code et ses dépendances) dans un distroless. C'est un peu minimaliste, mais leur exemple montre ce genre d'usage : https://github.com/GoogleContainerTools/distroless/blob/master/examples/python2.7/Dockerfile

      Ce que j'aime dans scratch/distroless c'est aussi une histoire de principe.

      Ça dépend de pleins de choses les containers ce n'est pas que des runners de prod, c'est aussi des runners en dev que tu va vouloir potentiellement plus verbeux, des builders que tu va utilliser en IC, voir des outils que tu va utiliser sur ta machine. Par exemple, je n'installe pas node sur ma machine, mais une image node, ce qui me permet de choisir facilement quelle version de node j'utilise par exemple. Mais ça devient vraiment intéressant quand tu utilise npm, qui demande un compilateur C et que tu veux un peu uniformiser le build dans une équipe. Au lieu de demander à chacun d'installer build-essential ou équivalent dans sa distribution en espérant que les versions de chaque paquet soient identiques et compilés avec les même options, tu peux partager une image qui fait déjà le job. Mais pour ça, alpine ou ubuntu ça marche bien :)

      • [^] # Re: distroless

        Posté par (page perso) . Évalué à 3 (+1/-0).

        Tiens pourquoi tu privilégie distrless pour du statique ?

        Parce que sans inclure grand chose ça contient tout de même quelques bricoles quasi tout le temps nécessaires :

        The image contains:

        • glibc
        • libssl
        • openssl
        • ca-certificates
        • A /etc/passwd entry for a root user
        • A /tmp directory

        Je ne connais vraiment pas bien le build python, mais ça peut pas être résolu par du multistage ?

        La dernière fois que j'avais essayé je n'avais pas réussi, mais je viens de rechercher de nouveau et il semblerait que ce soit possible. Pas comme dans leur exemple trop réduit, mais je vais retester de nouveau. Faut dire que je ne suis pas un grand spécialiste de python.

        Ce que j'aime dans scratch/distroless c'est aussi une histoire de principe.

        Ça dépend de pleins de choses les containers ce n'est pas que des runners de prod

        Anéfé. Sans préciser je parlais bien que de services à exécuter (en prod ou autre), et pas d'outils, dev, etc.

        • [^] # Re: distroless

          Posté par . Évalué à 2 (+1/-0).

          Parce que sans inclure grand chose ça contient tout de même quelques bricoles quasi tout le temps nécessaires

          Pour du statique les 3 premiers ne servent pas justement. Par contre en y réfléchissant plus attentivement, si tu veux avoir un HEALTHCHECK, il va au moins te falloir un second outils. Perso j'utilise beaucoup la JVM et je la bichonne un peu au lancement par exemple pour la faire crasher sur des OOM et créer un memory dump (mais pour pouvoir le retrouver et savoir sur quel container il était, j'utilise un petit script shell java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/some/path/${host}.hprof MyApp).

          Une solution pourrait être de faire tout un outillage en go par simplicité pour :

          • faire le healthcheck
          • lancer comme je veux la commande java

          C'est un peu ce qui est conseillé ici : https://blog.sixeyed.com/docker-healthchecks-why-not-to-use-curl-or-iwr/

      • [^] # Re: distroless

        Posté par . Évalué à 2 (+0/-0). Dernière modification le 07/08/18 à 23:09.

        Je ne connais vraiment pas bien le build python, mais ça peut pas être résolu par du multistage ? Tu fais ton build dans une image alpine/ubuntu/whatever, puis tu copie tes artefacts (ton code et ses dépendances) dans un distroless. C'est un peu minimaliste, mais leur exemple montre ce genre d'usage : https://github.com/GoogleContainerTools/distroless/blob/master/examples/python2.7/Dockerfile

        Il y a un exemple un peu plus explicite :
        https://galnevis.wixsite.com/website/single-post/2018/02/10/Python-and-Docker-multistage-build

  • # créer sa propre image

    Posté par . Évalué à 6 (+4/-0).

    Il est relativement facile de créer sa propre image de base. À vrai dire une fois qu'on n'y a mis tous les composants qu'on voulait, il suffit d'un docker import <fichier>.tar <nom de l'image>

    De même un docker save --output <fichier>.tar <le nom de l'image> permet "d'exporter" une image et d'en vérifier/analysermodifier le contenu.

    • [^] # Re: créer sa propre image

      Posté par . Évalué à 1 (+0/-0).

      Et debootstrap peut être très pratique pour ça. Il permet de construire des arborescences de Debian dans un dossier très simplement. Il suffit ensuite d'archiver ce dossier et on peut construire une nouvelle image Debian.

  • # Image from scratch + Go = 🎉

    Posté par . Évalué à 5 (+5/-1).

    Pour moi, le couple From scratch + Go est parfait. L'image fait quelques mo, l'empreinte mémoire est d'une vingtaine de mo. Et même si on attribue quelques millicores au pod, le serveur Web de Go se comporte très bien. Bref, je suis satisfait.

    • [^] # Re: Image from scratch + Go = 🎉

      Posté par . Évalué à 3 (+2/-1).

      Et docker sert à quoi là dedans ?

      Je veux dire, un programme go, c’est un exécutable statique sans dépendance. Pourquoi s’embêter à l’embarquer dans du docker au lieu de le lancer directement ?

      • [^] # Re: Image from scratch + Go = 🎉

        Posté par (page perso) . Évalué à 9 (+6/-0). Dernière modification le 08/08/18 à 09:07.

        À l'isoler.

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Image from scratch + Go = 🎉

          Posté par . Évalué à 2 (+1/-0). Dernière modification le 08/08/18 à 12:46.

          Et surtout c'est une très bonne couche d'abstraction. Pour le OPS, que tu (en tant que DEV) produises une image légère ou un peu plus grosse (ex: jvm + ton appli) pour l'OPS ç'est un peu près la même chose. Les OPS peuvent in fine facilement l'installé sur un cluster k8s.

      • [^] # Re: Image from scratch + Go = 🎉

        Posté par . Évalué à 6 (+3/-0).

        L'isolation avec le reste, l'outillage de gestion.

        "La première sécurité est la liberté"

      • [^] # Re: Image from scratch + Go = 🎉

        Posté par . Évalué à 4 (+3/-0).

        docker va le placer dans un environnement virtuel via des namespaces et tu va pouvoir utiliser des fonctionnalités de plus haut niveau avec mesos, swarm ou kubernetes comme le redémarrage en cas de plantage, la gestion d'un cluster de machine physique, etc

        C'est aussi très utile quand tu as plus que juste un binaire go. Tu peux avoir ton application dans une image minimaliste, mais avec docker-compose la lier à d'autres images.

  • # iron.io

    Posté par . Évalué à 3 (+1/-0). Dernière modification le 07/08/18 à 17:44.

    les container iron.io semblent bien indiqués pour créer des images de taille raisonnables :

        marc@gigabyte:~$ docker images | grep iron
        iron/ruby                              latest              37eb57d54f45        5 months ago        52.2MB
        iron/base                              latest              b438fe7f76e9        6 months ago        4.7MB
    

    lien : https://blog.iron.io/microcontainers-tiny-portable-containers/ ; edit basés sur alpine linux, du coup, ce n'est pas une alternative complète.

  • # OpenRC dans la version Docker de Alpine

    Posté par . Évalué à 1 (+0/-1).

    En terme de choix de distribution linux arrive avec PaX et Grsecurity (ce dont on se fout pour docker). Elle utilise musl comme bibliothèque C, libreSSL pour TLS et OpenRC comme init (ce dont on se fout pour docker). Les core tools viennent de BusyBox.

    Je ne suis pas sûr d'avoir compris : il y a OpenRC dans une image docker ?

  • # Faute et Alpine

    Posté par . Évalué à 4 (+2/-0).

    C'est LA reine de docker, mais elle n'a pas était conçue pour docker.

    Aouch, mes yeux saignent.

    J'utilise au maximum Alpine, super légère avec apk très rapide, mais elle ne supporte pas les locales et j'ai déjà été bloqué à cause de ça. Du coup j'utilise stretch-slim en backup.

    • [^] # Re: Faute et Alpine

      Posté par (page perso) . Évalué à 4 (+1/-0).

      Corrigé, merci.

    • [^] # Re: Faute et Alpine

      Posté par . Évalué à 3 (+2/-0).

      Les deux ont leurs avantages et inconvénients. Mais honnêtement, dans les deux cas la taille est tellement petite que ça n'a plus trop d'importance. Surtout une fois compressé pour déposer sur un repo. Et une fois décompressée, on s'en fiche vu que chaque image intermédiaire n'est stockée qu'une fois sur chaque serveur.
      A noter qu'Alpine est de base incompatible avec le JRE Oracle qui est compilé pour la glibc. Et inversement, avec stretch-slim, pour installer l'openjdk-jre il faut bidouiller (créer un dossier man manquant).

  • # stalinux

    Posté par (page perso) . Évalué à -1 (+2/-4).

    Rien de tel qu'un bon binaire statique, malheureusent les gars de la Glibc le font expres de rendre la compilation statique cassee depuis des annees. C'est en discutant sur l'irc de musl que les gens te disent que c'est pour une raison politique.

  • # Guix

    Posté par . Évalué à 10 (+12/-0). Dernière modification le 09/08/18 à 14:50.

    Vu qu'on parle de docker et que chacun y va de sa solution préférée, je voulais vous parler de Guix, qui propose une méthode pour exporter un conteneur docker. Si je veux un conteneur avec emacs, voilà ce que je tape :

    guix pack --format=docker emacs
    

    Le résultat de cette commande est le chemin vers un conteneur docker qui contient emacs et ses dépendances, et rien d'autre. On peut alors charger le conteneur : docker load --input /gnu/store/.... Cette méthode a aussi l'avantage d'être reproductible : en indiquant cette commande et la version de guix utilisée, il est possible pour n'importe qui de reproduire le conteneur au bit près, et de vérifier que je n'ai pas triché. Et se sera toujours possible même dans 10 ans (avec toutes les failles de sécurité, évidemment).

    En dehors des paquets disponibles dans la distribution, on peut aussi créer ses propres paquets. Pour reproduire dans ce cas, il faut aussi évidemment distribuer la recette avec le conteneur, la commande et la version de guix utilisée.

    Ainsi, on obtient facilement un conteneur dont le contenu est traçable, reproductible et pérenne. Les conteneurs à coup de base « debian stable » et de « apt-get update » ont déjà perdu. Alors qu'en modifiant peu de choses, quelques options de la ligne de commande ou la version de Guix, on obtient un nouveau conteneur qui diffère du premier de manière compréhensible. Par exemple, on met à jour emacs et ses dépendances, on ajoute un logiciel supplémentaire, on change une option à la compilation d'emacs ou on remplace emacs par vim.

    Certes, la plupart des conteneurs sont toujours exécutables après des années, mais si on perd la capacité de les recréer (les recompiler) et de les modifier, je pourrais troller et poser la question : est-ce vraiment de logiciel libre dont on parle ?

    • [^] # Re: Guix

      Posté par (page perso) . Évalué à 1 (+0/-0). Dernière modification le 13/08/18 à 22:43.

      "Certes, la plupart des conteneurs sont toujours exécutables après des années, mais si on perd la capacité de les recréer (les recompiler) et de les modifier, je pourrais troller et poser la question : est-ce vraiment de logiciel libre dont on parle ?"

      Tu fais un "apt-get update" 10 ans après, et plus rien de marche. A quand IPFS ou un systeme permettant de maintenir X copies en permanence, et des repos qui bougent pas sans humains au milieu pour enlever le serveur, changer l'url et j'en passe?

      • [^] # Re: Guix

        Posté par (page perso) . Évalué à 4 (+1/-0). Dernière modification le 14/08/18 à 09:34.

        Dix ans d'apt-get sans rien faire et qui marche encore, ça voudrait aussi dire (pur exercice) :

        • maintenir des algorithmes de chiffrement cassés (il faudrait probablement du SSL encore)
        • il faudrait des certificats valables dix ans
        • des clés gpg valables plus de 10 ans pour signer les paquets
        • une équipe pérenne de mainteneurs motivés
        • qui jongle avec diverses libstdc++ et autres ABI incompatibles, des mélanges de versions majeures de composants majeurs (GNOME, KDE, Python, Perl, PHP, etc.)
        • maintenir du 32 bits (plus tard le non UEFI ou les vieilles architectures mourantes voire mortes aussi)
        • arrêter de déplacer vers archive.debian.org, tout garder dans l'obèse dépôt unique, le tout servi par un serveur web à configuration dangereuse (voir plus haut)
        • gérer des 'ordinosaures' n'ayant pas 32 zetaoctets de mémoire, 42 THz de CPU sur 513 coeurs et 69 Etaoctets de stockage, donc y aller mollo sur la consommation de ressources
        • les composants critiques niveau ressources devront être compilés / exister pour chacune des variantes CPU possibles sur plus de 10 ans (par exemple les composants multimédia qui sont souvent disponibles avec des optimisations par chaque jeu d'instructions CPU ou GPU)
        • même Debian sort plusieurs versions stables en 10 ans, donc au bout de cette période tu peux enchaîner les mises à jour de distribution (voire fournir la migration directe à la N+2 ou N+3)
        • vraisemblablement tout cela devrait en fait ralentir pas mal le développement de Debian et la sortie des versions finalement
        • sur le principe, ça changerait de la course à l'équipement et à la fonctionnalité
        • il faut un projet de distribution qui dure plus de 10 ans, et sans changer de nom/URL (c'est le cas pour Debian, mais pas de toutes les distrib)
        • sacré boulot

        (Évidemment c'est plus facile si on considère qu'il y a eu des apt-get upgrade intermédiaires pendant ces 10 ans)

Envoyer un commentaire

Suivre le flux des commentaires

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