Comment conteneuriser une application héritée
Agence web » Actualités du digital » Comment conteneuriser une application héritée

Comment conteneuriser une application héritée

La conteneurisation a transformé la façon dont les nouvelles applications sont développées et déployées. Cependant, de nombreuses organisations conservent un catalogue d’anciens systèmes qui nécessitent une approche différente. Cette déconnexion entre le nouveau et l’ancien ne doit pas être perpétuée : vous pouvez également regrouper les systèmes plus anciens sous forme de conteneurs, ce qui facilite leur évolution avec des méthodes de développement plus modernes.

Dans cet article, nous examinerons un processus que vous pouvez utiliser pour commencer à conteneuriser les logiciels « hérités ». Bien qu’il n’y ait pas deux produits identiques et que le terme « hérité » soit subjectif, nous nous concentrerons sur les étapes largement applicables pour l’emballage de systèmes étroitement couplés actuellement liés à des environnements individuels.

1. Identifier les systèmes candidats

Il vaut la peine de préparer d’abord un inventaire des systèmes qui vous permet d’identifier les bons candidats pour la conteneurisation. Dans certains cas, vous pourriez conclure qu’une application particulière ne peut tout simplement pas être conteneurisée. Cela se produit généralement lorsqu’il a des exigences matérielles profondément ancrées ou s’appuie sur des fonctionnalités de noyau et des langages de programmation obsolètes.

Les meilleurs candidats sont les systèmes fréquemment utilisés qui bénéficieront immédiatement d’un développement futur accéléré. Recherchez des applications qui sont déjà assez autonomes si vous êtes complètement nouveau dans la conteneurisation. La sélection d’un système bien utilisé mais non critique vous donnera une marge de manœuvre en cas de problème tout en vous permettant de reconnaître les avantages d’une migration réussie.

2. Composant le système

Tu pourrait conteneurisez votre système candidat en écrivant un Dockerfile, y compris toutes les dépendances de l’application, et en l’appelant un jour. Bien qu’il s’agisse d’un moyen valable d’intégrer rapidement un système dans un conteneur, cela ne devrait pas être l’objectif final de vos efforts. Un conteneur monolithique entraînera de longues versions, des tailles d’image énormes et une mauvaise évolutivité.

Au lieu de cela, vous devriez rechercher des opportunités pour diviser chacun de vos systèmes en composants individuels. Ces composants doivent se retrouver dans leurs propres conteneurs, évitant qu’une seule pièce ne devienne trop grande. Vous pourrez mettre à l’échelle les composants individuellement en créant des répliques supplémentaires de conteneurs à ressources limitées.

Cette étape est également importante pour établir la modularité globale et encourager l’adoption de nouveaux conteneurs. Au fur et à mesure que vous séparez plus de systèmes dans leurs composants, vous commencerez à trouver des chevauchements qui vous permettront de réutiliser les images de conteneur que vous avez déjà créées. Vous remarquerez qu’il devient progressivement plus facile de continuer la conteneurisation.

Décider où diviser les composants ne devrait pas sembler trop éprouvant. Commencez par identifier où le système s’appuie sur des services qui sont déjà externes à son code source. Les connexions aux bases de données, les files d’attente de messages, les serveurs de messagerie, les proxys et les passerelles doivent tous être indépendants du composant qu’ils augmentent. Vous les séparerez dans leurs propres conteneurs qui se trouvent à côté de l’instance exécutant votre code.

Il vaut également la peine de rechercher des opportunités de refactoriser ce qui reste. Votre service a-t-il trop de responsabilités qui pourraient être réparties en unités fonctionnelles distinctes ? Vous pouvez avoir une API de profil utilisateur qui accepte les téléchargements de photos ; le service qui redimensionne ces photos pourrait être un bon candidat pour fonctionner de manière autonome dans son propre conteneur.

3. Préparez vos composants

Après avoir séparé les composants, vous devez les préparer à fonctionner dans un environnement conteneurisé. Les conteneurs présentent plusieurs différences essentielles par rapport aux machines virtuelles traditionnelles. Le stockage persistant, la configuration et les liens entre les composants sont les trois éléments les plus importants à prendre en compte dès le départ.

Stockage persistant

Les conteneurs sont des environnements éphémères. Les modifications du système de fichiers sont perdues lorsque vos conteneurs s’arrêtent. Vous êtes responsable de la gestion des données persistantes de votre application à l’aide des mécanismes fournis par votre runtime de conteneur.

Dans le cas de Docker, les volumes sont utilisés pour conserver les données en dehors de vos instances de conteneur. Les volumes sont montés sur des chemins spécifiques dans les conteneurs. Pour éviter d’avoir à monter des dizaines de volumes, il est préférable de concentrer les données de votre application dans quelques répertoires de niveau supérieur. Le montage de volumes à ces emplacements garantira la persistance des fichiers stockés par votre application.

Il est important d’auditer les interactions du système de fichiers de votre application pour comprendre les volumes dont vous avez besoin et les problèmes que vous rencontrerez. Ne pas prêter attention à cette étape peut s’avérer coûteux si les données que vous supposez persistantes sont perdues à chaque redémarrage d’un conteneur.

Gestion de la configuration

De nombreuses applications héritées sont configurées à l’aide de fichiers de configuration statiques. Ceux-ci peuvent être dans un format dédié, tel que XML, JSON ou INI, ou codés à l’aide du langage de programmation du système.

Les conteneurs sont normalement configurés par des variables d’environnement externes. Les variables sont définies lors de la création des conteneurs, à l’aide de mécanismes tels que Docker’s -e drapeau avec docker run. Ils sont injectés dans l’environnement du conteneur en cours d’exécution.

L’utilisation de ce système garantit que vous pouvez compter sur votre chaîne d’outils de conteneur pour définir et modifier les paramètres de configuration. Vous devrez peut-être d’abord refactoriser votre application pour prendre en charge la lecture des paramètres à partir des variables d’environnement. Une façon courante de faciliter la transition consiste à placer un petit script à l’intérieur du point d’entrée du conteneur. Cela peut énumérer les variables d’environnement lors de la création du conteneur et les écrire dans un fichier de configuration pour votre application.

La conteneurisation fait également penser à la mise en réseau interservices. Les services ne sont généralement pas exposés les uns aux autres, sauf par configuration explicite. Vous pouvez configurer une liaison automatique dans Docker en joignant plusieurs conteneurs au même réseau Docker. Cela offre une fonction de découverte de service qui permet aux conteneurs de se contacter par leur nom.

D’autres technologies de conteneurisation utilisent différentes approches de mise en réseau et de découverte de services. Après avoir séparé vos systèmes en composants individuels, vous devez les relier à l’aide des fonctionnalités offertes par votre environnement d’exécution. La nature des déploiements conteneurisés signifie qu’il y a souvent plus de complexité que la mise en réseau entre des machines virtuelles ou des hôtes physiques. Le trafic doit être acheminé et la charge équilibrée entre toutes vos répliques de conteneurs et leurs dépendances. Vous devez donc reconnaître ces exigences dès le début.

4. Écrivez vos fichiers Docker

Une fois que vous avez planifié votre architecture, vous pouvez commencer le travail physique associé à la conteneurisation. La première étape consiste à écrire des Dockerfiles pour les composants de votre application. Ceux-ci définissent la séquence de commandes et d’actions qui créent un système de fichiers contenant tout ce dont le composant a besoin pour s’exécuter.

Les Dockerfiles commencent par une image de base appropriée référencée par un FROM déclaration. Il s’agit généralement d’un système d’exploitation (ubuntu:20.04, alpine:3) ou un environnement de langage de programmation prédéfini (php:8, node:16). Vous pouvez choisir l’image qui correspond le mieux à l’environnement existant de votre application. Démarrer à partir d’un système de fichiers vide est possible mais généralement pas nécessaire, sauf si vous avez besoin d’un contrôle extrêmement granulaire.

Le contenu supplémentaire est superposé à l’image de base par des instructions telles que COPY et RUN. Ceux-ci vous permettent de copier des fichiers depuis votre hôte et d’exécuter des commandes sur le système de fichiers temporaire de la construction. Une fois que vous avez écrit votre Dockerfile, vous pouvez le construire avec le docker build -t my-image:latest . commande.

5. Configurer l’orchestration

En supposant que vous ayez divisé votre système en composants, vous vous retrouverez avec une image de conteneur pour chaque élément. Vous avez maintenant besoin d’un moyen d’afficher tous les conteneurs simultanément afin de pouvoir démarrer facilement une instance d’application fonctionnelle.

Les grandes installations de production utilisent couramment Kubernetes à cette fin. Il s’agit d’un système d’orchestration dédié qui ajoute ses propres concepts de niveau supérieur pour créer des déploiements conteneurisés répliqués. Les petits systèmes et environnements de développement sont souvent bien servis par Docker Compose, un outil qui s’appuie sur des fichiers YAML plus simples pour démarrer une « pile » de plusieurs conteneurs :

version: "3"

app:
  image: my-web-app:latest
  ports:
    - 80:80
database:
  image: mysql:8.0
  ports:
    - 3306:3306

UN docker-compose.yml fichier vous permet de démarrer tous ses services en utilisant le docker-compose binaire:

docker-compose up -d

La mise en place d’une certaine forme d’orchestration rend votre flotte de conteneurs plus gérable et facilite la mise à l’échelle via la réplication. Kubernetes et Docker Compose sont capables de démarrer plusieurs instances de vos services, une capacité qui ne peut pas être obtenue avec des applications héritées formées de composants étroitement couplés.

6. Après le déménagement : surveiller et développer votre flotte de conteneurs

La conteneurisation ne s’arrête pas au démarrage d’une instance de votre application. Pour tirer le meilleur parti de la technologie, vous devez surveiller correctement vos conteneurs pour rester informé des erreurs et de l’utilisation des ressources.

Les grands systèmes sont mieux servis par une plate-forme d’observabilité dédiée qui peut regrouper les journaux et les métriques de l’ensemble de votre flotte. Vous utilisez peut-être déjà une solution similaire avec vos déploiements d’applications héritées, mais c’est encore plus important pour les conteneurs. Une bonne observabilité vous permettra de retracer les problèmes jusqu’à l’instance de conteneur dont ils sont issus, en faisant apparaître les informations importantes lorsque vous avez des centaines ou des milliers de répliques.

Pour continuer à développer votre flotte, doublez la documentation et la standardisation. Nous avons déjà vu comment la division des systèmes en composants facilite la réutilisation future. Cependant, cela ne fonctionne efficacement que si vous avez documenté ce que vous avez et comment chaque pièce s’emboîte. Prendre le temps d’écrire sur votre système et le processus que vous avez suivi simplifiera les travaux futurs. Cela aidera également les nouveaux membres de l’équipe à comprendre les décisions que vous avez prises.

Est-ce que ça vaut le coup?

La conteneurisation est utile lorsque vous sentez que le développement d’un système est freiné par ses processus actuels. Pouvoir le déployer en tant qu’ensemble de conteneurs simplifie l’expérience de développement et vous offre plus de polyvalence dans le déploiement. Vous pouvez désormais lancer le service partout où un environnement d’exécution de conteneur est disponible, qu’il s’agisse d’une instance sur votre ordinateur portable ou de 1 000 sur un fournisseur de cloud public.

L’utilisation complète des conteneurs facilite l’exploitation de la puissance du cloud, la consolidation de vos déploiements et la réduction des coûts d’infrastructure sur site. Cependant, ces gains apparents peuvent être contrebalancés par la nécessité de recycler les ingénieurs, d’embaucher de nouveaux talents spécialisés et d’entretenir vos conteneurs au fil du temps.

La décision de conteneuriser un système hérité doit tenir compte de la valeur de ce système pour votre entreprise, du temps actuellement consacré à sa maintenance et de la réduction probable résultant de l’utilisation de conteneurs. Il se peut qu’il soit préférable de ne pas toucher aux services de faible priorité si les processus qui leur sont associés ne causent pas de problèmes immédiats.

Il convient de reconnaître que toutes les applications héritées n’auront pas besoin ou ne seront pas capables d’utiliser tous les avantages vantés de la conteneurisation. L’adoption est un spectre, allant de l’exécution du système dans un seul conteneur monolithique à la pleine composante, à l’orchestration et à l’intégration avec des suites d’observabilité. Ce dernier modèle est la cible idéale pour les applications critiques que les ingénieurs font évoluer chaque jour ; à l’inverse, le premier peut être adéquat pour les services rarement touchés où le principal obstacle est le temps passé à provisionner de nouveaux environnements de développement basés sur des machines virtuelles.

Conclusion

La migration d’applications héritées vers des flux de travail conteneurisés peut sembler difficile à première vue. Diviser le processus en étapes distinctes aide généralement à définir où vous en êtes et où vous voulez être. Dans cet article, nous avons examiné six étapes granulaires que vous pouvez utiliser pour aborder la conteneurisation des systèmes existants. Nous avons également discuté de certaines des considérations que vous devez prendre en compte lorsque vous décidez de continuer ou non.

D’un point de vue conceptuel, la conteneurisation d’une application héritée est peu différente de l’utilisation d’une nouvelle. Vous appliquez les mêmes principes de constitution de composants, de services liés et de configuration injectés depuis l’environnement extérieur. La plupart des systèmes sont relativement simples à conteneuriser vus sous cet angle. Se concentrer sur ces aspects vous aidera à découpler vos applications, à créer des composants évolutifs et à concevoir une méthodologie de conteneurisation efficace.

★★★★★