Modèle Strangler Fig à grande échelle : modernisation des monolithes avec Azure Front Door et API Management

24 juin 2026

Modèle Strangler Fig à grande échelle : modernisation des monolithes avec Azure Front Door et API Management

La modernisation de systèmes monolithiques hérités présente l’un des plus grands risques financiers et opérationnels de l’ingénierie logicielle d’entreprise. Tenter de réécrire l’ensemble de la plateforme lors d’un seul événement de transition (réécriture Big Bang) échoue systématiquement en raison de la complexité cachée du domaine et de l’incapacité à geler le développement de nouvelles fonctionnalités pendant des années. La mise en œuvre du motif Strangler Fig élimine ce risque en permettant le remplacement progressif et méthodique des composants hérités. En positionnant une façade réseau intelligente à la bordure de l’infrastructure en utilisant le Azure Front Door et le Azure API Management, les architectes interceptent le trafic client et le redirigent vers les nouveaux microservices au fur et à mesure de leur développement. Le système hérité demeure en opération, se rétrécissant graduellement jusqu’à ce que toutes ses fonctionnalités soient modernisées et qu’il puisse être éteint en toute sécurité. Cette topologie garantit des livraisons continues de valeur, une tolérance aux pannes lors de la migration et zéro impact perceptible pour l’utilisateur final pendant la transition vers le cloud d’Azure.

Pré-requis

L’orchestration de ce maillage de routage transitoire exige une maîtrise des réseaux de distribution de contenu (CDN) et une manipulation avancée des en-têtes HTTP. L’infrastructure en tant que code doit être déclarée strictement via Terraform version 1.7.0 ou supérieure, en utilisant le fournisseur HashiCorp AzureRM version 3.90.0. La Couche Anti-Corruption (ACL) requiert Python 3.12, couplé aux bibliothèques azure-servicebus et moteur relationnel SQLAlchemy pour les interactions directes avec la base de données héritée. Des privilèges administratifs sur l’abonnement Azure sont nécessaires pour gérer les zones DNS publiques et enregistrer les certificats TLS/SSL dans Azure Key Vault.

Étapes

Façade de routage global et isolation DNS

Les fondations du motif Strangler démarrent par l’abstraction totale de l’adresse réseau du système hérité. Si les applications clientes (web ou mobile) communiquent directement avec les IPs ou domaines d’origine du monolithe, il devient impossible de rediriger des routes spécifiques sans modifier le code client. Nous provisionnons Azure Front Door Premium pour prendre en charge le nom de domaine d’entreprise officiel et agir comme le point d’entrée global unique. L’argumentaire architectural réside dans la dissociation du client vis‑à‑vis de la topologie du backend. Front Door reçoit les requêtes à la bordure globale de Microsoft, termine la connexion TLS proche de l’utilisateur afin de réduire la latence et réachemine le trafic vers l’origine héritée via le backbone privé. Initialement, Front Door est configuré avec un routage en mode pass-through total, où 100% du trafic atteint le système ancien inchangé. Cela établit le réseau de contrôle nécessaire sans modifier le comportement fonctionnel de l’application.

resource "azurerm_cdn_frontdoor_profile" "strangler_edge" {
  name                = "afd-enterprise-strangler"
  resource_group_name = var.resource_group_name
  sku_name            = "Premium_AzureFrontDoor"
}

resource "azurerm_cdn_frontdoor_endpoint" "global_ingress" {
  name                     = "api-enterprise-global"
  cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.strangler_edge.id
}
resource "azurerm_cdn_frontdoor_origin_group" "legacy_backend" {
  name                     = "legacy-monolith-group"
  cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.strangler_edge.id
  health_probe {
    interval_in_seconds = 60
    path                = "/healthcheck.aspx"
    protocol            = "Https"
    request_type        = "HEAD"
  }
  load_balancing {
    successful_samples_required = 1
  }
}
resource "azurerm_cdn_frontdoor_origin" "legacy_server" {
  name                           = "onpremise-monolith"
  cdn_frontdoor_origin_group_id  = azurerm_cdn_frontdoor_origin_group.legacy_backend.id
  enabled                        = true
  host_name                      = "legacy.internal.empresa.com"
  origin_host_header             = "api.empresa.com"
  certificate_name_check_enabled = false
}
resource "azurerm_cdn_frontdoor_route" "default_pass_through" {
  name                          = "catch-all-legacy"
  cdn_frontdoor_endpoint_id     = azurerm_cdn_frontdoor_endpoint.global_ingress.id
  cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.legacy_backend.id
  cdn_frontdoor_origin_ids      = [ azurerm_cdn_frontdoor_origin.legacy_server.id ]
  patterns_to_match             = "/*"
  supported_protocols           = ["Https"]
  https_redirect_enabled        = true
}

Comment interceptons-nous des chemins fonctionnels plus granulaires et profonds dans le payload de la requête pour les acheminer vers de nouveaux microservices sans surcharger le CDN global avec des règles métier volatiles ?

Interceptation L7 et étranglement via API Management

Nous déléguons l’inspection approfondie de la couche 7 et le routage contextuel en déployant Azure API Management (APIM) juste derrière le Front Door. Azure Front Door se concentre sur la sécurité périphérique (WAF) et l’accélération globale, tandis que l’APIM domine la transformation des requêtes. Le raisonnement technique pour empiler ces deux solutions est la capacité de l’APIM à exécuter des politiques (Policies) en XML qui peuvent réécrire les URL, extraire des jetons JWT et convertir des formats de charge utile (comme le XML hérité en JSON moderne) en temps réel. Nous modifions la route du Front Door pour pointer vers l’APIM. À l’intérieur de l’APIM, nous configurons une opération précise, comme /api/v1/billing, pour être routée (étranglée) vers le nouveau microservice hébergé sur Azure Container Apps. L’APIM capte cette URI, traduit l’appel et l’envoie vers le cloud nouvellement déployé. Toutes les autres requêtes non mappées tombent dans la politique de base de l’APIM et sont acheminées vers le monolithe. Du point de vue de l’application mobile du client, la transition entre le code vieux de 15 ans et le conteneur récemment déployé est invisible.

Press enter or click to view image in full size

Diagramme de séquence
resource "azurerm_api_management_api" "billing_facade" {
  name                = "billing-api"
  resource_group_name = var.resource_group_name
  api_management_name = azurerm_api_management.core.name
  revision            = "1"
  display_name        = "Faturamento Strangler API"
  path                = "api/v1/billing"
  protocols           = ["https"]
}

resource "azurerm_api_management_api_policy" "route_to_microservice" {
  api_name            = azurerm_api_management_api.billing_facade.name
  api_management_name = azurerm_api_management.core.name
  resource_group_name = var.resource_group_name
  # A política XML instrui o APIM a alterar o backend alvo exclusivamente para esta rota
  xml_content = <<XML
<policies>
    <inbound>
        <base />
        <set-backend-service base-url="https://app-billing-aca.internal.azurecontainerapps.io" />
        <rewrite-uri template="/billing" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
XML
}

Lorsque le nouveau microservice de facturation traite un paiement de manière isolée, comment notifie-t-il et met-il à jour la base de données du monolithe afin que les anciennes fonctionnalités de génération de rapports opèrent sans afficher des données stagnantes ?

Synchronisation inverse et Couche Anti-Corruption (ACL)

Nous synchronisons les systèmes en mettant en place une Couche Anti-Corruption (ACL) basée sur des événements orchestrés par Azure Service Bus. Le nouveau microservice ne doit jamais se connecter directement à la base de données relationnelle héritée pour mettre à jour les tables. L’impératif architectural central veut que la création de dépendances directes entre bases de données entre systèmes détruise l’autonomie du microservice et pollue le nouveau domaine avec des schémas de données obsolètes. La solution exige que le nouveau service émette un Événement de Domaine pur (par exemple: PaymentCompleted) dans un topic du Service Bus. Un worker asynchrone en Python, agissant strictement comme l’ACL, consomme cet événement. Le worker détient la connaissance « sale » sur le fonctionnement du monolithe ; il traduit le JSON propre de l’événement en commandes SQL complexes et met à jour la base de données héritée (ou invoque des endpoints SOAP anciens). Cette topologie protège le nouvel écosystème et garantit que le monolithe soit alimenté par une cohérence éventuelle, maintenant l’intégrité opérationnelle de l’entreprise pendant les mois que dure la migration.

import os
import json
import asyncio
import logging
from azure.servicebus.aio import ServiceBusClient
from azure.identity.aio import DefaultAzureCredential
from sqlalchemy import create_engine, text

logger = logging.getLogger("AntiCorruptionLayer")
class LegacyDatabaseAdapter:
    def __init__(self, connection_string: str):
        self.engine = create_engine(connection_string)
    def sync_payment_to_legacy(self, invoice_id: str, amount: float):
        # LACL connaît les règles obscures du monolithe (par ex.: status_code 4 = payé)
        query = text("""
            UPDATE tbl_Legacy_Invoices 
            SET AmountPaid = :amount, StatusCode = 4, LastModified = GETDATE()
            WHERE InvoiceReference = :invoice_id
        """)
        with self.engine.begin() as conn:
            conn.execute(query, {"amount": amount, "invoice_id": invoice_id})
            logger.info(f"Sincronização rétrospective complète dans le monolithe pour la facture {invoice_id}")
async def main():
    credential = DefaultAzureCredential()
    sb_client = ServiceBusClient(os.environ["SERVICEBUS_FQDN"], credential=credential)
    legacy_adapter = LegacyDatabaseAdapter(os.environ["LEGACY_DB_CONNECTION"])
    async with sb_client:
        receiver = sb_client.get_subscription_receiver(
            topic_name="billing-events", 
            subscription_name="acl-legacy-sync"
        )
        async with receiver:
            async for msg in receiver:
                try:
                    event_data = json.loads(str(msg))
                    if event_data.get("eventType") == "PaymentCompleted":
                        legacy_adapter.sync_payment_to_legacy(
                            event_data["invoiceId"], 
                            event_data["totalPaid"]
                        )
                    await receiver.complete_message(msg)
                except Exception as e:
                    logger.error(f"Falha na Camada Anti-Corruption: {e}")
                    await receiver.abandon_message(msg)
if __name__ == "__main__":
    asyncio.run(main())

Si la couche de synchronisation échoue ou que le routage présente un comportement anormal, comment diagnostiquer des défaillances silencieuses ou des inversions de cache qui apparaissent subitement pendant cette transition d’état complexe ?

Résolution des problèmes courants

Une défaillance majeure lors de l’implémentation du motif Strangler se manifeste par des erreurs HTTP 404 Resource Not Found intermittentes provenant de l’APIM après l’ajout de nouvelles règles de routage. Invariablement, la cause ne réside pas dans l’inactivité du microservice cible, mais dans le suffixe de réécriture de l’URI dans la politique XML de l’APIM. Si la politique de rewrite-uri n’est pas configurée ou comporte des barres obliques finales (trailing slashes), l’APIM ajoutera le chemin de la façade entière au backend. Par exemple, un appel à /api/v1/billing sera envoyé au microservice comme https://app-backend/api/v1/billing au lieu de https://app-backend/. Utilisez la fonction « Test » sur le portail APIM en activant l’option « Trace » (Ocp-Apim-Trace) pour inspecter exactement quelle URL de backend le proxy a montée au moment de l’interception.

Autre étranglement systémique : des clients reçoivent des charges XML obsolètes du monolithe même après que l’APIM a été reconfiguré pour router le trafic vers les nouveaux microservices JSON. Ce symptôme d’inversion pointe directement vers le cache de bordure agressif sur Azure Front Door. Front Door ignore souvent les mises à jour de la topologie de backend de l’APIM car le cache se base sur l’URI exacte de la requête. Si la réponse de la route /api/v1/billing du monolithe a été mise en cache avec un TTL élevé peu avant le strangulation, le CDN ne consultera pas l’APIM avant l’expiration. La mitigation technique nécessite l’exécution d’une purge explicite du cache via CLI Azure ou via le pipeline CI/CD sur tous les nœuds de bordure globaux au moment exact où la politique de routage L7 est modifiée.

Conclusion

La triangulation architecturale utilisant Azure Front Door, Azure API Management et le maillage orienté événements constitue une voie sûre de modernisation pour les dettes techniques profondes. Le motif Strangler Fig protège la réputation de l’entreprise et le flux de trésorerie, veillant à ce que les refactorisations massives soient perçues par le marché extérieur comme des améliorations graduelles et invisibles dans les performances de la plateforme. Le point culminant de cette mise en œuvre mène à l’obsolescence et à l’éteinte physique éventuelle du serveur hérité. Pour les écosystèmes qui exigent une sécurité du trafic interne (East-West) durant la migration, l’architecture peut être étendue en provisionnant Azure API Management injecté directement dans un réseau virtuel (Mode interne du VNet), garantissant que la communication entre la façade, les nouveaux conteneurs et les serveurs sur site circule strictement via Azure ExpressRoute.

Fabien Delpont

Auteur

Fabien Delpont

Fabien Delpont, développeur et créateur du site Python Doctor.