AWS re:invent 2019 - AWS App Mesh

Cela fait déjà quasiment 2 ans que j’ai assisté chez Ippon à la présentation d’Istio par un expert google. J’avais été bluffé par sa présentation et les fonctionnalités qu’un service de “mesh” (maillage en français) pouvait apporter.

J’ai suivi la sortie du produit équivalent chez AWS : AppMesh avec beaucoup d’intérêts et testé leurs exemples disponibles ici : https://github.com/aws/aws-app-mesh-examples

C’est donc avec beaucoup d’excitation que j’ai assisté à la session du re:invent, dan l’un des plus grands casinos de Las Vegas le “Venetian”. Voici le teaser :

Service AppMesh - Présentation rapide

Ce service vient se brancher sur vos infrastructures du type EC2 tournant dans un Autoscaling Group, un cluster EKS ou un cluster ECS (Fargate ou EC2).

Vos services vont être “wrappés” par un système de proxy. Ce proxy va permettre de rendre votre applicatif beaucoup plus résilient. Les gros systèmes comme netflix, facebook, l’utilisent quotidiennement sur leur système de production. Citons quelques fonctionnalités :

  • Canary Deployment : c’est LA fonctionnalité dont tout le monde parle : déployez votre version N+1 dans votre cluster, et configurez AppMesh pour router 10% de votre trafic sur votre service N+1. Le routage peut être “intelligent” et se baser sur des informations attachées aux requêtes.
  • Gestion plus fine des défaillances : Une des tasks / pods s’emballe. Votre système de healthcheck voit votre service comme “Healthy” car les autres tasks / pods compensent. Les systèmes d’auto-scaling pouvant mettre un “certain temps” à réagir, AppMesh détectera la défaillance et re-routera le trafic sur les instances viables.
  • “Circuit Breaker” : Lors des défaillances des systèmes sous-jacents, force est de constater que les applications, micro-service ou non, se comportent mal en général. Vous l’aurez compris, le “circuit breaker” permet de renvoyer une réponse HTTP en évitant que le système défaillant s’engorge.
  • Encryption at Transit : Vos collègues développeurs ne respectent pas vos contraintes de sécurité ? Ils ne voient pas l’intérêt de le mettre en place? un service Mesh vous permettra d’ajouter de l’encryption SSL à la volée entre les appels intra-cluster.

AWS AppMesh est basé sur la stack envoy. Envoy va gérer les “Data Plane” et les autres composants d’AppMesh vont gérer le “Control Plane”. Je vous invite à consulter ce lien qui explique les différences entre ces 2 fonctionnalités : https://sdntutorials.com/difference-between-control-plane-and-data-plane/

Service AppMesh - Concrètement comment çà marche ?

Disons que vous avez 3 services. Vous allez définir 3 “virtual services” devant vos services.

Vous définirez ensuite des “Virtual Routers”, en charge de l’intelligence du routage entre vos services.

Ensuite vous devrez déclarer des “virtual routes”, c'est à dire l’ensemble des chemins entre ces “virtual routers”.

Note : un “virtual Service” ne peut correspondre qu’à un seul pattern de l’uri :

Chacun de vos “virtual services” seront joignables via des entrées DNS. AppMesh utilise le service “directory service” d’AWS Cloud Maps pour faire cela :

Enfin terminons par ajouter qu’AppMesh introduit de l’intégration avec les outils d’observabilité classiques AWS : X-Ray, CloudWatch Metrics & CloudWatch logs.

L’implémentation d’AppMesh se fait déclarativement. Voici un exemple de déclaration en cloudFormation :

---
Parameters:
  EnvironmentName:
    Type: String
    Description: Environment name that joins all the stacks

  ServicesDomain:
    Type: String
    Description: DNS namespace used by services e.g. default.svc.cluster.local

  AppMeshMeshName:
    Type: String
    Description: Name of mesh

Resources:

  ColorTellerBlackVirtualNode:
    Type: AWS::AppMesh::VirtualNode
    Properties:
      MeshName: !Ref AppMeshMeshName
      VirtualNodeName: colorteller-black-vn
      Spec:
        Listeners:
          - PortMapping:
              Port: 9080
              Protocol: http
            HealthCheck:
              Protocol: http
              Path: "/ping"
              HealthyThreshold: 2
              UnhealthyThreshold: 2
              TimeoutMillis: 2000
              IntervalMillis: 5000
        ServiceDiscovery:
          DNS:
            Hostname: !Sub "colorteller-black.${ServicesDomain}"

  ColorTellerVirtualRouter:
    Type: AWS::AppMesh::VirtualRouter
    Properties:
      MeshName: !Ref AppMeshMeshName
      VirtualRouterName: colorteller-vr
      Spec:
        Listeners:
          - PortMapping:
              Port: 9080
              Protocol: http

  ColorTellerRoute:
    Type: AWS::AppMesh::Route
    DependsOn:
      - ColorTellerVirtualRouter
      - ColorTellerWhiteVirtualNode
      - ColorTellerRedVirtualNode
      - ColorTellerBlueVirtualNode
    Properties:
      MeshName: !Ref AppMeshMeshName
      VirtualRouterName: colorteller-vr
      RouteName: colorteller-route
      Spec:
        HttpRoute:
          Action:
            WeightedTargets:
              - VirtualNode: colorteller-white-vn
                Weight: 1
              - VirtualNode: colorteller-blue-vn
                Weight: 1
              - VirtualNode: colorteller-red-vn
                Weight: 1
          Match:
            Prefix: "/"

  ColorTellerVirtualService:
    Type: AWS::AppMesh::VirtualService
    DependsOn:
      - ColorTellerVirtualRouter
    Properties:
      MeshName: !Ref AppMeshMeshName
      VirtualServiceName: !Sub "colorteller.${ServicesDomain}"
      Spec:
        Provider:
          VirtualRouter:
            VirtualRouterName: colorteller-vr

Terraform n'est pas en reste non plus :

resource "aws_appmesh_mesh" "simple" {
 name = "simpleapp"
}
 
 
resource "aws_appmesh_route" "serviceb" {
 name                = "serviceB-route"
 mesh_name           = "${aws_appmesh_mesh.simple.id}"
 virtual_router_name = "${aws_appmesh_virtual_router.serviceb.name}"
 
 spec {
   http_route {
     match {
       prefix = "/"
     }
 
     action {
       weighted_target {
         virtual_node = "${aws_appmesh_virtual_node.serviceb1.name}"
         weight       = 90
       }
 
       weighted_target {
         virtual_node = "${aws_appmesh_virtual_node.serviceb2.name}"
         weight       = 10
       }
     }
   }
 }
}
 
resource "aws_appmesh_virtual_node" "serviceb1" {
 name      = "serviceBv1"
 mesh_name = "${aws_appmesh_mesh.simple.id}"
 
 spec {
   backend {
     virtual_service {
       virtual_service_name = "servicea.simpleapp.local"
     }
   }
 
   listener {
     port_mapping {
       port     = 8080
       protocol = "http"
     }
   }
 
   service_discovery {
     dns {
       hostname = "serviceb.simpleapp.local"
     }
   }
 }
}
 
resource "aws_appmesh_virtual_router" "serviceb" {
 name      = "serviceB"
 mesh_name = "${aws_appmesh_mesh.simple.id}"
 
 spec {
   listener {
     port_mapping {
       port     = 8080
       protocol = "http"
     }
   }
 }
}
 
resource "aws_appmesh_virtual_service" "servicea" {
 name      = "servicea.simpleapp.local"
 mesh_name = "${aws_appmesh_mesh.simple.id}"
 
 spec {
   provider {
     virtual_node {
       virtual_node_name = "${aws_appmesh_virtual_node.serviceb1.name}"
     }
   }
 }
}

REX - Chick-Fill-A

“Chick-Fil-A” est une société américaine dans le domaine de la livraison de “sandwichs au poulet”. Cette société a connu une fulgurante ascension.

Leur architecture est basée sur un cluster EKS, ainsi que des tables dynamoDB et des bases de données RDS. Un système de datalake complète le tout.

Ils ont introduit AppMesh avec l’utilisation de la librairie flagger de weaveworks.

AppMesh leur apporte le “canary deployment” : ils avaient le besoin de livrer rapidement des évolutions de leurs services basées sur les analyses des données effectuées depuis leur datalake.

L’ensemble de leur déploiement sur EKS est piloté classiquement depuis un “Jenkins”.

et en zoomant :

Lors du déploiement d’une nouvelle version, Flagger va s’occuper de modifier le routage du traffic :

et basculer le traffic progressivement de manière automatique et progressive. L’interface de flagger permet de rollbacker et de suivre le déploiement. La démonstration faite en live s’est déroulée sans problème : simple mais efficace.

Citons les 2 derniers outils présentés lors de cette session :

  • kustomize : c’est un déployeur de la solution AppMesh, développé par la même société weaveworks, spécifiquement pour kubernetes.
  • kcp : opérateur Kubernetes pour la gestion d’un service Mesh dans un cluster Kubernetes.

Conclusion

J’ai pu constater que pas mal de chemin a été fait depuis le début de la RoadMap AppMesh. Le monde de l’open-source a développé les outils qui manquaient. Imaginez-vous gérer la bascule de votre trafic avec des "apply" successifs d’un code terraform ?

La mise en oeuvre d’un tel outil semble nécessiter une rigueur importante dans le design des architectures micro-service. Vos collègues devops devront investir un temps certain pour maîtriser ce produit.

En sortant de la salle, je reste néanmoins un peu sur ma faim. Les autres fonctionnalités, telles que le “circuit breaker” ou “l’encryption at transit” au sein du cluster, ne sont pas abordées et restent pour l’instant absentes.

D’autre part, l’utilisation d’AppMesh est souvent présentée dans le cadre d’EKS. Qu’en est-il des autres types d’infrastructure, notamment ECS Fargate ?

AppMesh est un outil encore un peu jeune mais la fonctionnalité du “canary deployment” fonctionne à merveille. Pour les utilisateurs des clusters EKS, je pense qu’AppMesh est prêt. Reste à l’évaluer sur du Fargate.