web-dev-qa-db-fra.com

Dois-je inclure des tests dans l'image Docker?

En ce qui concerne les tests, je peux penser à deux options:

  1. Mettez le test et l'application dans une seule image.
  2. N'incluez que le code d'application dans l'image. Créez un conteneur spécifique au test qui se construit après l'image principale et y ajoute des couches (code de test, dépendances, etc.).

Avec la première option, je peux tester le conteneur et l'expédier exactement comme testé. Un inconvénient évident est que du code inutile (et potentiellement des données de test) sera inclus dans l'image.

Avec la deuxième option, l'image qui est expédiée n'est pas tout à fait la même que celle qui est testée.

Les deux ressemblent à de mauvaises stratégies. Existe-t-il une troisième meilleure stratégie?

23
lfk

Pour exécuter des tests au moment de la construction, la meilleure façon serait d'utiliser un build à plusieurs étapes . Les Dockerfiles à plusieurs étapes vous permettent d'avoir une étape plus grande avec toutes les dépendances pour la construction et les tests, puis copiez les artefacts exacts que vous avez testés dans une autre étape pour une image d'exécution plus petite.

Vous souhaitez également des tests au niveau système de plusieurs conteneurs, en utilisant leurs interfaces externes au lieu de s'exécuter dans le conteneur. Étant donné que ces tests impliquent une coordination entre les services, nécessitent des dépendances différentes telles que l'accès à votre orchestration, ne sont pas aussi approfondis que les tests au moment de la construction et sont souvent écrits dans des langues complètement différentes de toute façon, ce n'est pas un problème de les exécuter à partir d'un Docker distinct conteneur dédié uniquement aux tests système.

11
Karl Bielefeldt

Il y a une troisième voie, comme vous l'avez dit vous-même. Je pense que vous mélangez le développement, les tests et le déploiement. Je propose que l'ensemble du SDLC soit considéré dans son ensemble, d'abord, pour comprendre ce que vous essayez d'atteindre. C'est un gros sujet, mais je ferai de mon mieux pour résumer.

TL; DR;

En bref, vous devez séparer:

  • votre code, de
  • la configuration de l'application, de
  • la configuration de l'environnement système.

Chacun doit être indépendant les uns des autres et convenablement:

  • version contrôlée
  • testé
  • déployable

Version plus longue

Tout d'abord, vous avez une application composée de code et (ensembles séparés de) configuration. Cela doit être testé, à la fois pour la construction et la fonction intentionnelle - c'est ce qu'on appelle l'intégration continue (CI). Il existe de nombreux fournisseurs de ce service en ligne et localement - par exemple CircleCI pour un fournisseur de cloud qui se connecte à votre référentiel et construit et teste chaque fois que vous vous engagez. Si votre référentiel est sur site et ne peut pas utiliser de fournisseur de cloud, quelque chose comme Jenkins serait un équivalent. Si votre application est assez standard, il existe probablement une image Docker existante que le service CI peut utiliser. Si ce n'est pas le cas, vous devrez en créer un, ou un cluster, pour que votre code d'application et votre configuration puissent être déployés. Correctement configuré, vous disposerez d'une multitude de statistiques sur la qualité de votre code d'application.

Ensuite, une fois que vous êtes satisfait de la fonctionnalité et de l'exactitude de votre application, la base de code doit être correctement étiquetée pour une version spécifique. Cette version doit ensuite être déployée dans un environnement de test. Notez que le code sera le même que celui testé dans votre CI (peut-être, si vous l'avez fait correctement), mais votre configuration peut différer. Encore une fois, certains fournisseurs de CI peuvent proposer cette étape afin que vous puissiez tester votre déploiement d'une application packagée et d'une configuration discrète. Cette étape comprend généralement des tests fonctionnels de l'utilisateur (pour les nouvelles fonctionnalités), ainsi que des tests automatisés (pour les fonctionnalités connues). Si la version réussit cette étape, vous disposez d'une version candidate pour les tests d'intégration. Vous pouvez exécuter les tests d'automatisation à partir d'un autre conteneur Docker, selon votre application, ils peuvent être aussi volumineux et élaborés que votre application elle-même - en effet, il y a certaines mesures indiquant que l'effort de test est de 1: 1 à l'effort de codage = (même si je n'en suis pas sûr moi-même).

Avant toute chose, l'étape suivante consiste à créer votre environnement (système) comme s'il s'agissait de production. Si vous utilisez Docker en production, c'est là que vous penserez au renforcement de la sécurité, à l'optimisation du réseau et du serveur, etc. Vos images Docker peuvent être basées sur celles que vous avez utilisées dans le développement (idéalement), mais il peut y avoir des changements pour la mise à l'échelle et la sécurité , comme j'ai dit. A présent, les tests fonctionnels de l'application devraient être terminés, vous êtes plus préoccupé par la sécurité et les performances. Selon les tests fonctionnels, vos tests ici peuvent être développés, déployés et exécutés à partir d'autres images Docker. Auparavant, cette étape était horriblement coûteuse et rarement effectuée, vous aviez donc besoin d'un matériel dédié reproduisant la production. Aujourd'hui, cela est complètement viable car vous pouvez vous lever et détruire tout l'environnement de presque n'importe quelle échelle à la demande.

Enfin, vous disposez d'une version qui devrait être prête pour la production avec seulement un petit ensemble de deltas de configuration par rapport à vos tests d'intégration (adresses IP, URI de base de données, mots de passe, etc.) Votre base de code a été testée au moins dans trois environnements différents à ce stade. point et la majorité de la configuration du système au moins une fois.

9
avastmick

Je pense que vous mélangez différents types de tests. Fondamentalement, vous devez vous demander: quelle est l'unité testée ici?

Le scénario le plus courant lorsque vous travaillez en tant que développeur consiste à écrire des tests unitaires/d'intégration pour un morceau de code sur lequel vous travaillez, où ce morceau de code est l'unité testée. Vous exécutez ces tests localement et/ou dans CI.

Lorsque vous avez construit une nouvelle image docker, elle devient une nouvelle unité que vous pouvez tester. Quels types de choses aimeriez-vous tester pour cette image? Quelle est l'API qu'elle fournit? Comment testez-vous cela?

S'il s'agit d'une application Web, vous pouvez démarrer un conteneur basé sur l'image et effectuer certaines requêtes HTTP et vérifier que les réponses correspondent à vos attentes. Je pense que le problème que vous rencontrez est que vous êtes très habitué au cadre de test couplé au code de l'application. C'est bien pendant le développement, mais maintenant vous voulez tester une image docker et vous avez donc besoin d'un nouveau type de framework de test qui peut le faire et n'est pas lié au code de l'application.

Je pense donc que la 3ème option que vous recherchez est:

  • Exécutez vos tests unitaires/d'intégration avant de créer une image Docker.
  • Créez une image Docker contenant uniquement l'application que vous souhaitez distribuer.
  • Au lieu d'ajouter des couches supplémentaires au-dessus de cette image d'application, vous la testez telle quelle en l'exécutant avec certains paramètres donnés et confirmez vos résultats attendus.

Ainsi, les étapes CI/CD seraient:

Configuration de l'environnement de développement -> Exécuter des tests sur le code -> Créer l'image finale -> Exécuter des tests sur l'image -> Déployer l'image.

0
Lars Nyström