
Quand j'apprenais à conduire, lors de ma première leçon, l'instructeur a reculé sur un carrefour et a ensuite dit qu'il ne fallait jamais faire ça. J'ai retenu cette règle immédiatement et pour toute ma vie.
En lisant aux enfants « Conseils nuisibles » de Grigori Oster, on voit à quel point il est facile et naturel pour eux de comprendre qu'il ne faut pas faire cela.
Il y a des tonnes d'articles sur la façon d'écrire des Dockerfiles correctement. Mais je n'ai pas trouvé d'instructions sur comment écrire de mauvais Dockerfiles. Je comble cette lacune. Et peut-être qu'il y aura moins de ces Dockerfiles dans les projets que je reçois pour maintenance.
Tous les personnages, situations et Dockerfiles sont fictifs. Si vous vous reconnaissez, désolé.
Créons un Dockerfile, sinistre et horrible
Petr (Développeur senior java/ruby/php) : Collègue Vassili, as-tu déjà intégré le nouveau module dans Docker ?
Vassili (junior) : Non, je n'ai pas eu le temps, je ne comprends pas ce Docker. Il y a tellement d'articles là-dessus, mes yeux se croisent.
Petr : Notre deadline était il y a un an. Allez, je vais t'aider et on s'expliquera en cours de route. Dis-moi ce qui ne va pas.
Vassili : Je ne peux pas choisir une image de base, je veux une minimale, mais qui ait tout ce dont j'ai besoin.
Petr : Prends l'image ubuntu, il y a tout ce qu'il faut. Et s'il y a un peu de superflu, ça sera utile plus tard. Et n'oublie pas de mettre le tag latest pour toujours avoir la dernière version.
Et dans le Dockerfile, la première ligne apparaît :
FROM ubuntu:latestPetr : Qu'est-ce qu'on fait ensuite, sur quoi avons-nous écrit notre module ?
Vassili : C'est du ruby, il doit y avoir un serveur web et quelques démons de service à démarrer.
Petr : D'accord, ce qu'il nous faut : ruby, bundler, nodejs, imagemagick et tout le reste... Et en même temps, fais une mise à jour pour être sûr d'obtenir les derniers paquets.
Vassili : On ne va pas créer d'utilisateur, pour ne pas être sous root ?
Petr : Laisse tomber, on s'occupera des droits plus tard.
Vassili : J'ai besoin de temps, environ 15 minutes, pour tout rassembler en une seule commande, j'ai lu que...
(Petr interrompt brutalement le junior trop pointilleux et intelligent.)
Petr : Écris des commandes séparées, ce sera plus facile à lire.
Le Dockerfile s'étoffe :
FROM ubuntu:latest
RUN apt-get update
RUN apt-get upgrade
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full
RUN gem install bundler
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
RUN bundle install --without development test --path vendor/bundle
RUN rm -rf /usr/local/bundle/cache/*.gem
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*Ici, Igor Ivanovich, DevOps (mais plus Ops que Dev), fait irruption dans le bureau, en criant :
IA : Petya, tes développeurs ont encore cassé la base de données en production, quand cela va-t-il cesser…
Après une petite dispute, Igor Ivanovich se calme et commence à s'enquérir de ce que font ses collègues ici.
IA : Que sont-ils en train de faire ?
Vassili : Piotr m'aide à rédiger le Dockerfile pour le nouveau module.
IA : Laissez-moi voir… Qu'avez-vous écrit ici, vous nettoyez le dépôt avec une équipe distincte, c'est un niveau supplémentaire… Comment installez-vous les dépendances si vous n'avez pas copié le Gemfile ! Et en général, ça ne sert à rien.
Piotr : Allez, s'il vous plaît, occupez-vous de vos affaires, nous allons nous débrouiller ici.
Igor Ivanovich soupire tristement et s'en va enquêter sur qui a bien pu casser la base de données.
Piotr : Oui, mais il a raison au sujet du code, il faut l'inclure dans l'image. Et mettons directement ssh et supervisor, sinon comment allons-nous lancer les démons.
Vassili : Je vais d'abord copier le Gemfile et le Gemfile.lock, ensuite je vais tout installer, et enfin je vais copier tout le projet. Si le Gemfile ne change pas, le niveau sera pris dans le cache.
Piotr : Qu'est-ce que vous avez tous avec ces niveaux ? Copiez tout d'un coup. Copiez tout d'un coup. Dès la première ligne.
Dockerfile ressemble maintenant à ceci :
FROM ubuntu:latest
COPY .\/ \/app
WORKDIR \/app
RUN apt-get update
RUN apt-get upgrade
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
RUN gem install bundler
RUN curl -sL https:\/\/deb.nodesource.com\/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
RUN bundle install --without development test --path vendor\/bundle
RUN rm -rf \/usr\/local\/bundle\/cache\/*.gem
RUN apt-get clean
RUN rm -rf \/var\/lib\/apt\/lists\/* \/tmp\/* \/var\/tmp\/* Piotr : Alors, quelle est la suite. As-tu des configs pour supervisor ?
Vassili : Non, je n'en ai pas. Mais je vais le faire rapidement.
Piotr : Tu le feras plus tard. Commençons par rédiger un script init qui lancera tout. Donc, tu vas lancer ssh, avec nohup, pour que nous puissions nous connecter au conteneur et voir ce qui n'a pas fonctionné. Puis, lance également supervisor. Et ensuite, tu lanceras simplement passenger.
V : Mais j'ai lu qu'il devait y avoir un seul processus, ainsi Docker saura que quelque chose ne va pas et pourra redémarrer le conteneur.
P : Ne te tracasse pas avec des bêtises. Et de toute façon, comment ? Comment vas-tu tout lancer en un seul processus ? Qu'Igor Ivanovich se préoccupe de la stabilité, ce n'est pas pour rien qu'il reçoit un salaire. Notre travail, c'est d'écrire du code. Et en fait, qu'il nous remercie d'avoir écrit le Dockerfile pour lui.
Après 10 minutes et deux vidéos de chats.
V : J'ai tout fait. J'ai aussi ajouté quelques commentaires.
P : Montre !
Nouvelle version du Dockerfile :
FROM ubuntu:latest
# Copie du code source
COPY .\/ \/app
WORKDIR \/app
# Met à jour la liste des paquets
RUN apt-get update
# Met à jour les paquets
RUN apt-get upgrade
# Installe les paquets nécessaires
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
# Installe bundler
RUN gem install bundler
# Installe nodejs utilisé pour la construction des fichiers statiques
RUN curl -sL https:\/\/deb.nodesource.com\/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
# Installe les dépendances
RUN bundle install --without development test --path vendor\/bundle
# Nettoie les caches
RUN rm -rf \/usr\/local\/bundle\/cache\/*.gem
RUN apt-get clean
RUN rm -rf \/var\/lib\/apt\/lists\/* \/tmp\/* \/var\/tmp\/*
# Lance le script au démarrage du conteneur, qui exécutera tout le reste.
CMD ["\/app\/init.sh"]P: Excellent, j'aime ça. Et les commentaires en russe, c'est pratique et lisible, tout le monde devrait travailler ainsi. Je t'ai tout appris, dorénavant tu pourras te débrouiller seul. Allons prendre un café...
Eh bien, nous avons obtenu un Dockerfile parfaitement horrible, dont la vue fera que Igor Ivanovich voudra démissionner et il aura encore les yeux douloureux pendant une semaine. Le Dockerfile aurait pu être encore pire, il n'y a pas de limite à la perfection. Mais pour commencer, ça ira.
Je terminerais par une citation de Grigori Osters:
Si vous n'avez pas encore fermement
Choisi votre chemin dans la vie,
Et ne savez pas par où
Commencer votre parcours de travail,
Faites éclater des ampoules dans les halls —
Les gens vous diront "Merci".
Vous aiderez le peuple
À économiser de l'électricité.
Source : habr.com
