# 🐇 RabbitMQ dans AKS : le messaging sans dépendance

# Introduction

Dans un environnement Kubernetes tel qu’AKS, les micro-services communiquent souvent via des systèmes de messaging. Azure Service Bus est une solution robuste, mais elle reste fortement liée à l’écosystème Azure. Pour des architectures plus agnostiques ou multi-cloud, RabbitMQ s’impose comme une alternative crédible.

RabbitMQ est un broker open-source, léger et performant, qui supporte plusieurs protocoles de communication. Son intégration dans AKS est facilitée par l’usage de Helm charts, permettant un déploiement rapide et configurable.

Dans mon cas, j’ai opté pour RabbitMQ afin de garantir une meilleure portabilité de nos micro-services, tout en conservant un haut niveau de fiabilité. Le déploiement dans AKS inclut des considérations de sécurité (authentification TLS, gestion des secrets), de persistance (volumes persistants) et de scalabilité (horizontal pod autoscaler).

---

# Limitations d’Azure Service Bus dans un contexte multi-cloud ou agnostique

Azure Service Bus est une solution de messaging robuste et bien intégrée à l’écosystème Azure. Toutefois, dans des architectures orientées micro-services déployées sur AKS (Azure Kubernetes Service), et surtout dans des contextes multi-cloud ou agnostiques, certaines limitations deviennent rapidement contraignantes.

## Couplage fort à Azure

Azure Service Bus repose sur des services managés et des configurations spécifiques à Azure. Cela implique un **verrouillage technologique** qui rend difficile la portabilité vers d’autres environnements cloud ou on-premise. Les micro-services deviennent dépendants d’un fournisseur, ce qui limite la flexibilité stratégique et technique.

## Coût et flexibilité

Le modèle de tarification d’Azure Service Bus, basé sur le nombre de messages, les connexions et les opérations, peut devenir difficile à maîtriser dans des architectures à forte volumétrie. De plus, certaines fonctionnalités avancées (comme les topics ou les sessions) sont limitées à des niveaux de service premium, ce qui restreint la flexibilité pour les équipes techniques souhaitant expérimenter ou évoluer progressivement.

## Limitations de personnalisation

Azure Service Bus est une solution managée, ce qui signifie que Microsoft en contrôle l’infrastructure, les mises à jour et les fonctionnalités. Si cela simplifie la maintenance, cela limite aussi les possibilités de personnalisation pour les équipes techniques qui souhaitent adapter le comportement du broker à des besoins spécifiques.

Contrairement à des solutions comme RabbitMQ ou Apache Kafka, il n’est pas possible de modifier ou d’étendre le fonctionnement interne d’Azure Service Bus.

Par exemple :

* Impossible d’ajouter des plugins ou des extensions personnalisées.
    
* Pas de gestion fine des priorités de messages ou des politiques de retry.
    
* Pas de configuration avancée des dead-letter queues ou des mécanismes de routage.
    
    ```yaml
    # Politique spécifique pour les queues critiques
    apiVersion: rabbitmq.com/v1beta1
    kind: Policy
    metadata:
      name: critical-queue-policy
    spec:
      name: critical-queue-policy
      pattern: "^critical\\..*"  # Queues commençant par "critical."
      applyTo: queues
      definition:
        # Configuration Dead Letter Exchange pour queues critiques
        dead-letter-exchange: deadletter.exchange
        dead-letter-routing-key: deadletter.rejected
        # TTL plus long pour les queues critiques (48 heures)
        message-ttl: 172800000
        # Plus de tentatives pour les queues critiques
        max-delivery-attempts: 5
        # Haute disponibilité
        ha-mode: exactly
        ha-params: 3
        ha-sync-mode: automatic
      priority: 10  # Priorité plus élevée que la politique générale
      rabbitmqClusterReference:
        name: rabbitmq
    ```
    

---

# Pourquoi RabbitMQ ?

Dans une architecture de micro-services déployée sur AKS, le choix du système de messaging est stratégique. RabbitMQ s’impose comme une **solution agnostique, performante et flexible**, particulièrement adaptée aux environnements cloud hybrides ou multi-cloud.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756289765166/1003f162-d97f-4e09-a70a-e8f6ba4f70db.png align="center")

## Open-source, mature et largement adopté

RabbitMQ est un broker open-source basé sur Erlang, reconnu pour sa stabilité et sa robustesse. Il est utilisé dans des milliers d’organisations à travers le monde, ce qui garantit :

Une communauté active et une documentation riche, Une évolution continue sans dépendance à un fournisseur cloud, Une interopérabilité forte avec les outils DevOps et les frameworks modernes. Cette maturité en fait un choix rassurant pour les équipes techniques souhaitant une solution éprouvée et indépendante.

## Support de multiples protocoles

RabbitMQ supporte plusieurs protocoles de communication, ce qui le rend particulièrement **flexible** :

* **AMQP 0.9.1** : le protocole natif, fiable et performant,
    
* **MQTT** : idéal pour les architectures IoT ou les communications légères,
    
* **STOMP, HTTP, WebSockets** : pour des cas d’usage spécifiques ou des intégrations front-end.
    

Cette diversité permet de connecter facilement des micro-services hétérogènes, sans imposer un protocole unique ou propriétaire.

## Facilité d’intégration avec des micro-services

RabbitMQ s’intègre naturellement dans des architectures Kubernetes :

* Déploiement via **Helm charts** ou opérateurs,
    
* Intégration avec des frameworks comme **.Net**, **Spring Boot**, **NestJS**, **Node.js**, **Go**, etc.
    
* Compatibilité avec des outils de monitoring comme **Prometheus**, **Grafana**, ou **Datadog**.
    

Il permet également une **gestion fine des files d’attente**, des **stratégies de retry**, du **routing dynamique** et des **dead-letter queues**, offrant une grande souplesse pour orchestrer les échanges entre micro-services.

### Exemple simplifié en C#

1. Secret Kubernetes
    
    ```yaml
    apiVersion: v1
    kind: Secret
    metadata:
      name: rabbitmq-credentials
      namespace: default
    type: Opaque
    stringData:
      RABBITMQ_HOST: rabbitmq.default.svc.cluster.local
      RABBITMQ_USER: myuser
      RABBITMQ_PASSWORD: mypassword
    ```
    
2. Publisher
    
    ```csharp
    using RabbitMQ.Client;
    using System;
    using System.Text;
    
    class Publisher
    {
        static void Main(string[] args)
        {
            var host = Environment.GetEnvironmentVariable("RABBITMQ_HOST");
            var user = Environment.GetEnvironmentVariable("RABBITMQ_USER");
            var password = Environment.GetEnvironmentVariable("RABBITMQ_PASSWORD");
    
            var factory = new ConnectionFactory()
            {
                HostName = host,
                UserName = user,
                Password = password,
                VirtualHost = "/",
                Port = 5672,
                Ssl = new SslOption
                {
                    Enabled = false // mettre à true si TLS est activé
                }
            };
    
            using var connection = factory.CreateConnection();
            using var channel = connection.CreateModel();
    
            channel.QueueDeclare(queue: "my-queue",
                                 durable: true,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
    
            string message = "Hello RabbitMQ!";
            var body = Encoding.UTF8.GetBytes(message);
    
            channel.BasicPublish(exchange: "",
                                 routingKey: "my-queue",
                                 basicProperties: null,
                                 body: body);
    
            Console.WriteLine($"[x] Sent: {message}");
        }
    }
    ```
    
3. Consumer
    
    ```csharp
    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using System;
    using System.Text;
    
    class Consumer
    {
        static void Main(string[] args)
        {
            var host = Environment.GetEnvironmentVariable("RABBITMQ_HOST");
            var user = Environment.GetEnvironmentVariable("RABBITMQ_USER");
            var password = Environment.GetEnvironmentVariable("RABBITMQ_PASSWORD");
    
            var factory = new ConnectionFactory()
            {
                HostName = host,
                UserName = user,
                Password = password,
                VirtualHost = "/",
                Port = 5672,
                Ssl = new SslOption
                {
                    Enabled = false // mettre à true si TLS est activé
                }
            };
    
            using var connection = factory.CreateConnection();
            using var channel = connection.CreateModel();
    
            channel.QueueDeclare(queue: "my-queue",
                                 durable: true,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
    
            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body.ToArray();
                var message = Encoding.UTF8.GetString(body);
                Console.WriteLine($"[x] Received: {message}");
            };
    
            channel.BasicConsume(queue: "my-queue",
                                 autoAck: true,
                                 consumer: consumer);
    
            Console.WriteLine("Press [enter] to exit.");
            Console.ReadLine();
        }
    }
    ```
    
4. Déploiement dans AKS, injectez les variables d’environnement à partir du secret :
    
    ```yaml
    env:
      - name: RABBITMQ_HOST
        valueFrom:
          secretKeyRef:
            name: rabbitmq-credentials
            key: RABBITMQ_HOST
      - name: RABBITMQ_USER
        valueFrom:
          secretKeyRef:
            name: rabbitmq-credentials
            key: RABBITMQ_USER
      - name: RABBITMQ_PASSWORD
        valueFrom:
          secretKeyRef:
            name: rabbitmq-credentials
            key: RABBITMQ_PASSWORD
    ```
    

---

# Architecture proposée dans AKS

Dans une approche agnostique du messaging, RabbitMQ s’intègre parfaitement dans un cluster AKS (Azure Kubernetes Service). L’architecture proposée repose sur un déploiement maîtrisé, sécurisé et évolutif, adapté aux environnements de production.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1756290488331/5dcc65be-7f14-4ce1-b394-c9dc41b38ffa.png align="center")

### Déploiement de RabbitMQ via Helm

RabbitMQ peut être déployé dans AKS à l’aide du **Helm chart officiel**, ce qui facilite la configuration, la mise à jour et la gestion du cycle de vie.

* **Chart utilisé** : `bitnami/rabbitmq` ou `rabbitmq/rabbitmq`
    
* **Commandes typiques** :
    
    ```bash
    helm repo add bitnami https://charts.bitnami.com/bitnamihelm install rabbitmq bitnami/rabbitmq --namespace rabbitmq --create-namespace
    ```
    
* **Avantages** :
    
    * Déploiement rapide et reproductible
        
    * Paramétrage via `values.yaml` pour la persistance, la sécurité, les ressources
        
    * Intégration native avec Kubernetes (services, secrets, configmaps)
        

### Configuration des services

L’architecture repose sur une séparation claire des rôles :

* **RabbitMQ** : déployé comme StatefulSet avec un service interne (`ClusterIP`) pour les communications internes.
    
* **Micro-services** : communiquent avec RabbitMQ via des producers/consumers, en utilisant des bibliothèques comme `RabbitMQ.Client` (C#), `amqplib` (Node.js), ou `pika` (Python).
    
* **Service Mesh (optionnel)** : Istio ou Linkerd peuvent être utilisés pour gérer les communications, la sécurité et l’observabilité.
    

Les échanges sont orchestrés via des **queues** et des **exchanges** configurés dynamiquement ou via des scripts d’initialisation.

### Sécurité

La sécurité est assurée à plusieurs niveaux :

* **Authentification** : RabbitMQ utilise des credentials stockés dans des `Kubernetes Secrets`.
    
* **Chiffrement** :
    
    * TLS pour les connexions entre micro-services et RabbitMQ
        
    * Possibilité d’activer TLS entre les nœuds RabbitMQ
        
* **Réseau** :
    
    * Utilisation de `NetworkPolicies` pour limiter les accès
        
    * Intégration possible avec Azure Private Link ou Azure Firewall
        

### Persistance

RabbitMQ peut être configuré pour utiliser un **PersistentVolumeClaim (PVC)** afin de garantir la durabilité des messages et des métadonnées :

* Stockage Azure Disk ou Azure Files
    
* Exemple de configuration :
    
    ```yaml
    ---
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: rabbitmq-azurefile-premium
    provisioner: file.csi.azure.com
    parameters:
      skuName: Premium_LRS  # available values: Standard_LRS, Premium_LRS, Standard_GRS, Standard_RAGRS
      protocol: smb # available values: smb, nfs
      resourceGroup: {{ .Values.resourceGroup }}  # e.g. myresourcegroup
      storageAccount: {{ .Values.storageAccount }}  # e.g. mystorageaccount
      server: {{ .Values.storageAccount }}.privatelink.file.core.windows.net
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    allowVolumeExpansion: true
    mountOptions:
      - dir_mode=0777
      - file_mode=0777
      - mfsymlinks
      - cache=strict  # https://linux.die.net/man/8/mount.cifs
      - nosharesock  # reduce probability of reconnect race
      - actimeo=30  # reduce latency for metadata-heavy workload
    ---
    ```
    

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Cela permet de redémarrer les pods sans perte de données.</div>
</div>

### Scalabilité

RabbitMQ peut être scalé horizontalement et verticalement :

* **Verticale** : ajustement des ressources CPU/mémoire via les `resources` dans le chart Helm.
    
* **Horizontale** :
    
    * Utilisation du mode **cluster** de RabbitMQ (avec plusieurs nœuds)
        
    * Déploiement en **HA** avec des policies de mirroring
        
    * Intégration avec des outils comme **KEDA** pour scaler les consumers en fonction du nombre de messages
        
        ```yaml
        apiVersion: keda.sh/v1alpha1
        kind: ScaledObject
        metadata:
          name: rabbitmq-consumer-scaler
          namespace: default
        spec:
          scaleTargetRef:
            name: rabbitmq-consumer-deployment  # Nom du Deployment à scaler
          pollingInterval: 30                   # Intervalle de vérification (en secondes)
          cooldownPeriod: 300                   # Temps avant de réduire le nombre de pods
          minReplicaCount: 1
          maxReplicaCount: 10
          triggers:
            - type: rabbitmq
              metadata:
                queueName: my-queue             # Nom de la file RabbitMQ à surveiller
                host: RabbitMQConnection        # Nom du secret contenant la connexion
                protocol: amqp
                mode: QueueLength               # Mode de déclenchement basé sur la longueur de la file
                value: "5"                      # Seuil de messages pour déclencher le scaling
        ```
        

### Performance

La performance d’un système de messaging comme RabbitMQ dépend fortement de son dimensionnement initial et de sa capacité à évoluer en fonction de la charge. Dans un environnement AKS, plusieurs leviers permettent d’optimiser les performances tout en garantissant la stabilité du système.

**Facteurs influençant la performance**

1. #### Volume de messages
    

* **Taille moyenne des messages** : les messages volumineux (&gt; 1 Mo) peuvent impacter la latence.
    
* **Fréquence d’envoi** : un pic de plusieurs milliers de messages par seconde nécessite un sizing adapté.
    

2. #### Complexité des échanges
    

* **Nombre de queues et exchanges** : plus ils sont nombreux, plus la charge CPU/mémoire augmente.
    
* **Routing dynamique** : les exchanges de type `topic` ou `headers` sont plus coûteux que les `direct`.
    

3. #### Mode de consommation
    

* **AutoAck vs ManualAck** : le mode manuel permet un meilleur contrôle mais consomme plus de ressources.
    
* **Prefetch count** : un réglage fin permet d’optimiser le débit sans surcharger les consumers.
    

**Sizing recommandé dans AKS**

* **CPU** : 1 à 2 vCPU minimum par nœud RabbitMQ
    
* **Mémoire** : 2 à 4 Go RAM par instance pour des charges moyennes
    
* **Stockage** : Azure Disk (Premium SSD) avec persistance activée (`8–32 Gi` selon le volume)
    

**Optimisations mises en œuvre**

* **Activation du clustering RabbitMQ** : pour répartir la charge et améliorer la tolérance aux pannes.
    
* **Utilisation de** `lazy queues` : pour les files à forte volumétrie, stockées sur disque plutôt qu’en mémoire.
    
* **Monitoring des métriques clés** : taux de delivery, latence, saturation des queues, via Datadog ou Prometheus.
    
* **Réglage du** `prefetch` côté consumer : pour éviter les surcharges et optimiser le débit.
    

**Utiliser l’outil pivotalrabbitmq/perf-test**

Pour valider les capacités de traitement de RabbitMQ dans notre cluster AKS, j’ai utilisé l’outil ​[https://github.com/rabbitmq/rabbitmq-perf-test​](https://github.com/rabbitmq/rabbitmq-perf-test%E2%80%8B), qui permet de simuler des charges réalistes et de mesurer précisément le débit, la latence et la stabilité du système dans différents scénarios.

```bash
docker run -it --rm pivotalrabbitmq/perf-test:latest \
  --uri amqp://user:pass@host.docker.internal:5672 \
  --producers 8 --consumers 8 \
  --rate 75 --consumer-rate 75 \
  --time 180 --size 1024 \
  --queue-pattern 'scale-test-%d' \
  --queue-pattern-from 1 --queue-pattern-to 5
```

* `--uri` : URI de connexion à RabbitMQ (peut être injectée via des variables d’environnement ou des secrets Kubernetes).
    
* `--producers` / `--consumers` : nombre de producteurs et consommateurs simulés.
    
* `--rate` : nombre de messages par seconde à produire.
    
* `--size` : taille des messages en octets.
    
* `--queue` : nom de la file cible.
    
* `--time` : durée du test en secondes.
    

---

# Retour d’expérience / bénéfices observés

La mise en place de RabbitMQ dans AKS a permis de répondre efficacement aux besoins de messaging dans un environnement agnostique et distribué. Voici les principaux bénéfices constatés après plusieurs mois d’exploitation en production.

## Performance

Le déploiement de RabbitMQ dans AKS a démontré une **excellente réactivité** dans le traitement des messages :

* **Latence faible** : les échanges entre micro-services sont quasi instantanés, même en cas de forte charge.
    
* **Débit élevé** : le système a supporté plusieurs milliers de messages par seconde sans saturation, grâce à une configuration optimisée des queues et des exchanges.
    
* **Scalabilité maîtrisée** : l’ajout de nœuds RabbitMQ dans le cluster permet d’absorber les pics de trafic sans interruption de service.
    

Ces performances ont été rendues possibles par l’utilisation de **Persistent Volumes**, de **ressources Kubernetes ajustées** et d’un **monitoring proactif**.

## Monitoring

L’intégration de RabbitMQ avec **Datadog** a permis de mettre en place un **monitoring centralisé et granulaire**, adapté aux environnements distribués.

* **Métriques RabbitMQ** : grâce à l’agent Datadog déployé dans le cluster AKS, les métriques clés (nombre de messages, taux d’erreur, temps de traitement, saturation des queues) sont collectées et visualisées dans des dashboards personnalisés.
    
* **Logs centralisés** : les logs des pods RabbitMQ sont collectés via l’agent Datadog et envoyés vers la plateforme, permettant une **corrélation directe entre logs et métriques**. Cela facilite les analyses post-mortem et le diagnostic en temps réel.
    
* **Alerting intelligent** : des alertes ont été configurées dans Datadog pour détecter les anomalies (latence élevée, erreurs de connexion, queues bloquées), avec envoi de notifications vers Slack ou Microsoft Teams.
    
* **Traces distribuées (optionnel)** : pour les micro-services intégrés avec OpenTelemetry, Datadog permet de suivre les traces de bout en bout, incluant les interactions avec RabbitMQ.
    

Cette solution offre une **visibilité complète** sur le comportement du système, tout en s’intégrant naturellement dans les workflows DevOps existants.

![](https://imgix.datadoghq.com/img/blog/rabbitmq-monitoring/rabbitmq-prometheus-dark.png?auto=compress%2Cformat&cs=origin&lossless=true&fit=max&q=75&w=1026&dpr=1 align="left")

## Résilience

La résilience du système a été validée dans plusieurs scénarios :

* **Redémarrage de pods RabbitMQ** sans perte de messages, grâce à la persistance activée.
    
* **Failover automatique** entre nœuds RabbitMQ en cas de panne, avec maintien de la disponibilité.
    
* **Retry intelligent** côté consommateurs, avec gestion des dead-letter queues pour les messages non traitables.
    

Ces mécanismes ont permis de garantir une **haute disponibilité** et une **continuité de service**, même en cas de défaillance partielle du cluster AKS.

---

# Conclusion

La mise en œuvre de RabbitMQ dans AKS s’est révélée être une solution **robuste, flexible et agnostique**, parfaitement adaptée aux architectures micro-services modernes. Ce choix a permis de répondre aux exigences de performance, de résilience et de visibilité, tout en s’affranchissant des limitations des solutions managées comme Azure Service Bus.

## Résumé des avantages

* **Performance** : traitement rapide et fluide des messages, même en forte charge.
    
* **Scalabilité** : adaptation dynamique du nombre de consumers grâce à KEDA.
    
* **Monitoring** : visibilité complète via Datadog, avec alerting et corrélation des logs.
    
* **Résilience** : haute disponibilité assurée par la persistance et le clustering RabbitMQ.
    
* **Flexibilité** : support de multiples protocoles et intégration facile avec les micro-services C#.
    

## Prochaines étapes

Dans une logique d’amélioration continue, plusieurs évolutions sont envisagées :

* **Migration du monitoring vers Prometheus & Grafana** : afin de renforcer l’indépendance vis-à-vis des solutions SaaS et de centraliser les métriques dans une stack open-source.
    
* **Optimisation du clustering RabbitMQ** : pour améliorer la tolérance aux pannes et la répartition de la charge.
    
* **Automatisation des dashboards et des alertes** : via des templates Grafana et des règles Prometheus, pour faciliter le déploiement multi-environnement.
    

Ces évolutions permettront de consolider l’architecture tout en gardant une maîtrise complète de l’infrastructure et des outils de supervision.
