7 anti-modèles Docker que vous devez éviter
Docker a transformé le développement de logiciels avec son modèle simple de conteneurisation qui vous permet de regrouper rapidement les charges de travail en unités reproductibles. Bien que Docker soit facile à maîtriser, son utilisation est plus nuancée qu’il n’y paraît toujours. Cela est particulièrement vrai lorsque vous cherchez à optimiser votre utilisation de Docker pour augmenter l’efficacité et les performances.
Voici sept des anti-modèles Docker les plus courants que vous devriez rechercher et éviter. Bien que vos conteneurs et images puissent répondre à vos besoins immédiats, la présence de l’une de ces pratiques suggère que vous vous écartez des principes de la conteneurisation d’une manière qui pourrait être préjudiciable plus tard.
Sommaire
1. Application des mises à jour dans les conteneurs
L’anti-modèle Docker le plus courant essaie sans doute de mettre à jour les conteneurs à l’aide de techniques héritées des machines virtuelles traditionnelles. Les systèmes de fichiers de conteneur sont éphémères, donc toutes les modifications sont perdues lorsque le conteneur s’arrête. Leur état doit être reproductible à partir du Dockerfile
utilisé pour construire l’image.
Cela signifie que vous ne devriez pas exécuter un apt upgrade
à l’intérieur de vos conteneurs. Ils seraient alors différents de l’image à partir de laquelle ils ont été construits. Les conteneurs sont destinés à être librement interchangeables ; séparer vos données de votre code et de vos dépendances vous permet de remplacer les instances de conteneur à tout moment.
Les correctifs doivent être appliqués en reconstruisant périodiquement votre image, en arrêtant les conteneurs existants et en en commençant de nouveaux en fonction de l’image révisée. Des projets de chaîne d’outils communautaires sont disponibles pour simplifier ce processus et vous informer des mises à jour en amont disponibles.
2. Exécution de plusieurs services dans un seul conteneur
Les conteneurs doivent être indépendants et concentrés sur une fonction particulière. Bien que vous ayez peut-être déjà exécuté vos serveurs Web et de base de données sur une seule machine physique, une approche entièrement découplée verrait les deux composants séparés dans des conteneurs individuels.
Cette méthodologie empêche les images de conteneur individuelles de devenir trop volumineuses. Vous pouvez inspecter les journaux de chaque service à l’aide des commandes Docker intégrées et les mettre à jour indépendamment les uns des autres.
Les conteneurs multiples vous offrent une évolutivité améliorée car vous pouvez facilement augmenter le nombre de répliques des parties individuelles de votre pile. La base de données fonctionne lentement ? Utilisez votre orchestrateur de conteneurs pour ajouter quelques instances de conteneur MySQL supplémentaires, sans allouer de ressources supplémentaires aux composants qui fonctionnent déjà correctement.
3. Créations d’images avec effets secondaires
Les builds d’image Docker doivent être des opérations idempotentes qui produisent toujours le même résultat. Fonctionnement docker build
ne devrait pas avoir d’impact sur votre environnement au sens large, car son seul objectif est de produire une image de conteneur.
Néanmoins, de nombreuses équipes créent des Dockerfiles qui manipulent des ressources externes. Un Dockerfile peut se transformer en une forme de script CI global qui publie des versions, crée des commits Git et écrit dans des API ou des bases de données externes.
Ces actions n’appartiennent pas à un Dockerfile. La création d’une image Docker est une opération indépendante qui devrait être sa propre étape de pipeline CI. La préparation de la libération se produit alors comme un séparé scène pour que vous puissiez toujours docker build
sans publier de façon inattendue une nouvelle balise.
4. Trop compliquer votre Dockerfile
Dans la même veine, il est possible que Dockerfiles en fasse trop. Limiter votre Dockerfile au strict minimum d’instructions dont vous avez besoin minimise la taille de votre image et améliore la lisibilité et la maintenabilité.
Des problèmes peuvent souvent survenir lors de l’utilisation de builds Docker en plusieurs étapes. Cette fonctionnalité facilite le développement de séquences de construction complexes référençant plusieurs images de base. De nombreuses étapes indépendantes peuvent indiquer que vous mélangez les préoccupations et que vous couplez trop étroitement les processus.
Recherchez des sections logiques dans votre Dockerfile qui servent à des fins spécifiques. Essayez de les diviser en fichiers Docker individuels, en créant des images utilitaires autonomes qui peuvent s’exécuter indépendamment pour remplir des parties de votre pipeline plus large.
Vous pouvez créer une image « constructeur » avec les dépendances nécessaires pour compiler votre source. Utilisez cette image comme une étape dans votre pipeline CI, puis transmettez sa sortie sous forme d’artefacts à l’étape suivante. Vous pouvez maintenant copier les binaires compilés dans une image Docker finale que vous utilisez en production.
5. Configuration codée en dur
Les images de conteneur qui incluent des informations d’identification, des secrets ou des clés de configuration codées en dur peuvent causer de sérieux problèmes ainsi que des risques de sécurité. L’intégration des paramètres dans votre image compromet l’attrait fondamental de Docker, la capacité de déployer la même chose dans plusieurs environnements.
Utilisez des variables d’environnement et des secrets Docker déclarés pour injecter la configuration au moment où vous démarrez un conteneur. Cela conserve les images en tant qu’actifs réutilisables et limite l’accès aux données sensibles à l’exécution uniquement.
Cette règle s’applique toujours aux images destinées à un usage interne uniquement. Les secrets de codage en dur impliquent qu’ils sont également liés à votre logiciel de contrôle de version, ce qui les rend potentiellement vulnérables au vol en cas de violation du serveur.
6. Séparer les images de développement et de déploiement
Vous ne devez créer qu’une seule image de conteneur pour chaque modification apportée à votre application. Le fait de conserver plusieurs images similaires pour des environnements individuels suggère que vous ne bénéficiez pas de la mentalité « fonctionne partout » de Docker.
Il est préférable de promouvoir une seule image dans vos environnements, de la mise en scène à la production. Cela vous donne l’assurance que vous exécutez exactement le même environnement logique dans chacun de vos déploiements, de sorte que ce qui a fonctionné lors de la mise en scène fonctionnera toujours en production.
Avoir une image de « production » dédiée suggère que vous souffrez peut-être de certains des autres anti-modèles indiqués ci-dessus. Vous avez probablement une séquence de construction complexe qui pourrait être décomposée, ou des informations d’identification spécifiques à la production codées en dur dans votre image. Les images doivent être séparées par étape du cycle de vie de développement, et non par environnement de déploiement. Gérez les différences entre les environnements en injectant la configuration à l’aide de variables.
7. Stockage des données dans des conteneurs
La nature éphémère des systèmes de fichiers conteneurs signifie que vous ne devriez pas y écrire de données. Les données persistantes créées par les utilisateurs de votre application, telles que les téléchargements et les bases de données, doivent être stockées dans des volumes Docker ou elles seront perdues au redémarrage de vos conteneurs.
D’autres types de données utiles devraient éviter d’écrire dans le système de fichiers dans la mesure du possible. Diffusez les journaux dans le flux de sortie de votre conteneur, où ils peuvent être consommés via le docker logs
commande, au lieu de les vider dans un répertoire qui serait perdu après une panne de conteneur.
Les écritures du système de fichiers du conteneur peuvent également entraîner une perte de performances significative lors de la modification de fichiers existants. L’utilisation par Docker de la stratégie de superposition « copie sur écriture » signifie que les fichiers qui existent dans les couches inférieures du système de fichiers sont lus à partir de cette couche, plutôt que de la couche finale de votre image. Si une modification est apportée au fichier, Docker doit d’abord la copier dans le calque supérieur, puis appliquer la modification. Ce processus peut prendre plusieurs secondes pour les fichiers plus volumineux.
Conclusion
En surveillant ces anti-modèles, vos images Docker seront plus réutilisables et plus faciles à entretenir. Ils font la différence entre simplement utiliser des conteneurs Docker et adopter un workflow conteneurisé. Vous pouvez facilement écrire un Dockerfile fonctionnel, mais un fichier mal planifié limitera votre capacité à capitaliser sur tous les avantages potentiels.
Les conteneurs doivent être des unités de fonctionnalités éphémères et autonomes créées à partir d’un processus de construction reproductible. Ils correspondent aux étapes de votre processus de développement, et non aux environnements de déploiement, mais ne facilitent pas directement ce processus eux-mêmes. Les images doivent être les artefacts produits par un pipeline CI, et non le mécanisme définissant ce pipeline.
Adopter des conteneurs nécessite un changement de mentalité. Il est préférable de commencer par les principes fondamentaux, d’être conscient des objectifs primordiaux, puis de voir comment vous pouvez les intégrer dans votre processus. Utiliser des conteneurs sans tenir compte de ces aspects peut finir par créer un casse-tête à long terme, loin de la flexibilité et de la fiabilité accrues vantées par les partisans de l’approche.