Ce blog est le deuxième d'une série de blogs qui couvrent divers aspects de ce qu'il nous a fallu pour créer et exploiter notre service SaaS :
Dans un blog précédent , nous avions fourni quelques informations sur nos besoins qui nous ont conduit à créer une nouvelle plateforme. Grâce à cette plateforme, nous permettons à nos clients de créer un ensemble complexe et diversifié d'applications, telles que la fabrication intelligente, la criminalistique vidéo pour la sécurité publique, le trading algorithmique ou les réseaux de télécommunications 5G.
Le premier blog de cette série couvrait un plan de contrôle distribué pour fournir plusieurs clusters d’applications multi-locataires basés sur Kubernetes dans le cloud public, nos PoP de réseau privé et nos sites périphériques.
Ce blog spécifique abordera les défis de la connexion et de la sécurisation de ces clusters d'applications distribués selon trois points de vue : application à application, utilisateur/machine à application et application à l'Internet public. Nous présenterons un tout nouveau chemin de données L3-L7+ entièrement intégré, un plan de contrôle distribué à l'échelle mondiale et notre réseau mondial hautes performances. Ces trois éléments se combinent pour offrir un ensemble complet de services réseau et de sécurité en périphérie, au sein de n’importe quel VPC cloud ou dans nos PoP de réseau mondial. Après avoir fonctionné en production avec plus de 35 clients pendant plus d'un an, nous avons commencé à étendre le déploiement et avons estimé que le moment était venu de partager notre parcours.
Alors que nos clients créent des applications assez complexes et critiques (comme la fabrication intelligente, la vidéo-criminalité pour la sécurité publique, le trading algorithmique, la transition 5G des télécommunications), nous devons offrir une expérience toujours active, connectée et fiable pour les applications et les utilisateurs finaux de ces applications. Certaines de ces applications exécutent des pipelines de données sur des clusters au sein d'un cloud, ou doivent sauvegarder des données sur plusieurs fournisseurs de cloud, ou ont besoin d'une livraison fiable des requêtes d'une base d'utilisateurs mondiale aux backends d'applications, ou ont besoin d'une connectivité haute performance de leurs machines aux backends exécutés dans des clouds centralisés.
Afin de répondre à ces besoins, deux exigences visaient le réseau physique :
R1 — Cloud to Cloud — Connectivité haute performance et à la demande des applications sur des sites de cloud public ou privé à travers le monde
R2 — Internet vers le cloud — Pour que les appareils et les machines situés dans des emplacements périphériques se connectent de manière fiable au backend de l'application, nous devions fournir plusieurs chemins redondants et terminer les connexions au plus près de ces utilisateurs au lieu de renvoyer le trafic jusqu'aux backends via Internet.
Nous aurions pu résoudre les exigences R1 et R2 en faisant appel à un fournisseur de services réseau comme AT&T, mais ils n’auraient pas pu nous fournir une expérience réseau transparente et une intégration avec nos services d’application (configuration basée sur l’API, télémétrie en streaming, possibilité d’ajouter facilement nos propres préfixes IP ou ceux de nos clients, services réseau basés sur l’API, etc.). De plus, obtenir une couverture mondiale auprès des fournisseurs de services est très difficile ou extrêmement coûteux. Nous aurions pu faire appel à deux ou trois fournisseurs de services différents pour résoudre tous ces problèmes, mais nous nous serions alors retrouvés avec un fouillis de systèmes différents qui se comportent différemment, ont des modes de défaillance différents, des SLA différents, des systèmes de support différents et des API différentes (ou inexistantes).
Nous avons donc fini par avoir besoin de construire notre propre réseau, ce qui signifiait que le réseau devait avoir trois propriétés :
Pour répondre à ces trois propriétés, nous avons dû faire beaucoup de choses. Nous mettrons cependant en évidence cinq grands points :
Nous avons réalisé très tôt dans notre développement que construire et exploiter un réseau mondial nécessitait du temps et des compétences et nous devions apporter cette expertise. Après des mois de discussions avec les fondateurs d'Acorus Networks (fournisseur de sécurité basé à Paris, France), nous avons fini par fusionner Acorus avec Volterra. Cela nous a aidé à résoudre le problème de notre infrastructure mondiale et du déploiement de notre réseau. Acorus avait mis en place un excellent réseau et une équipe d'exploitation qui avait entièrement automatisé la configuration du réseau physique à l'aide d'Ansible et créé des API externes pour la télémétrie et la configuration qui pouvaient être utilisées par notre équipe logicielle.
Maintenant que nous disposions d’une équipe concentrée sur la construction d’un réseau privé mondial avec une fiabilité et des performances élevées, nous pouvions facilement résoudre les problèmes de trafic d’application à application et d’utilisateur/machine à application sur les sites périphériques ou dans le cloud, comme le montre la figure 1. De plus, l'infrastructure de calcul et de stockage de nos points de présence réseau nous a également permis d'ajouter la terminaison d'API, la sécurité des applications et le déchargement de la charge de travail (depuis la périphérie ou le cloud) à notre réseau. Cela nous permettra de continuer à faire évoluer nos capacités pendant longtemps et d’étendre facilement notre empreinte réseau et notre catalogue de services en fonction de la demande.
Une fois que nous avions un réseau mondial fonctionnel, nous devions commencer à ajouter des clusters d’applications et nos charges de travail. Ces charges de travail nécessitent leur propre ensemble de services de connectivité et de sécurité au niveau des applications.
Comme nous l'avons expliqué dans notre blog précédent , notre objectif avec la plateforme était d'améliorer la productivité et de réduire la complexité pour nos équipes qui gèrent des charges de travail exécutées dans plusieurs environnements (cloud, edge et nos PoP réseau).
Chaque fournisseur de cloud doit configurer, gérer et surveiller de nombreuses ressources cloud différentes pour une connectivité sécurisée aux clusters d'applications. Par exemple, dans Google Cloud, pour configurer un service réseau de bout en bout pour un cluster d’applications, nous devrons gérer de nombreux ensembles de services différents :
C'est génial, même si cela aurait été un gros défi, nous aurions pu décider de nous attaquer à ce problème en créant une couche de configuration et d'opérations pour harmoniser chaque fournisseur de cloud. Cependant, nous savions que cela n'aurait pas résolu nos problèmes car les services des fournisseurs de cloud ne répondaient pas à tous nos besoins (par exemple, la capacité à assurer la sécurité des applications et des API fait défaut chez les CSP), ils ne sont pas les meilleurs du marché et sont en constante évolution.
De plus, qu'en est-il de nos PoP réseau et de nos sites périphériques ? Nous devrions aller chercher des capacités similaires auprès de fournisseurs de matériel ou de logiciels et les intégrer toutes ensemble, par exemple Cisco/Juniper pour le routage + NAT + VPN, F5 pour l'équilibrage de charge et le pare-feu, etc. Aux endroits périphériques, le problème est aggravé car ni les fournisseurs de cloud ni les grands fournisseurs de réseau ne peuvent résoudre les problèmes de services réseau dans un environnement aux ressources limitées. Une autre option potentielle pour la périphérie aurait pu être de déplacer toute la connectivité des applications, la sécurité et les services réseau vers notre réseau mondial, mais il était clair que cela ne fonctionnerait pas car le trafic d'application à application au sein du même site périphérique nécessitait également certains de ces services.
Après de nombreuses discussions et une étude du paysage, nous avons réalisé que l’intégration de nombreux fournisseurs et prestataires de services (configuration, télémétrie, surveillance, alerte) et le suivi de leur feuille de route et des modifications de leur API allaient à l’encontre de notre objectif de simplicité et de rapidité.
Un autre problème que nous devions résoudre sur l’ensemble de la plateforme était le multi-locataire. C’était plus facile à faire pour les services WAN et le routage réseau, mais difficile pour les services de mise en réseau d’applications étant donné que la plupart des équilibreurs de charge sur le marché n’ont aucun support ou un support très limité pour le multi-locataire.
Nous avons donc décidé de relever ce défi et de créer un chemin de données réseau hautes performances qui fournit non seulement un service de routage réseau, mais également des services d’application, de sécurité et de réseau étendu. Cela nous permettrait d’unifier le portefeuille de services dans notre environnement cloud hybride et distribué et nous obligerait à dépendre d’un ensemble minimal de services natifs dans les clouds publics.
Étant donné que l’équipe avait une bonne expérience en matière de réseau et que nous avions été confrontés à de tels problèmes dans nos vies antérieures avec Contrail/Juniper, nous avons pensé que la meilleure façon de résoudre ce problème serait de repartir à zéro et de créer une toute nouvelle solution de réseau qui intègre les services L3 à L7+ dans un seul chemin de données qui peut s’exécuter dans n’importe quel cloud ou périphérique tout en étant géré de manière centralisée par notre plateforme.
Nous avons sélectionné les meilleurs projets pour démarrer la conception de ce nouveau chemin de données : OpenContrail vRouter (pour L3-L4) que nous avions déjà passé 6 ans à développer et Envoy pour L7 car il bénéficie d'un énorme soutien de la communauté. Cela dit, nous avons dû effectuer plusieurs modifications et ajouts pour créer un nouveau chemin de données L3-L7+ unifié : multi-location pour Envoy, dpdk pour Envoy, pile TCP dpdk en espace utilisateur, politique réseau, VPN SSL/IPSec, connexion http, proxy inverse dynamique, proxy de transfert transparent, passerelle API, politique d'application programmable, ACL rapides pour la protection DDoS, intégration d'identité PKI, moteur Chrome v8, sécurité des applications et du réseau, etc.
Ce chemin de données (comme illustré dans la Figure 2 ) est déployé comme passerelle d'entrée/sortie pour nos clusters d'applications, passerelle logicielle en périphérie, pour fournir une capacité de maillage de services au sein d'un cluster ou sur plusieurs clusters, ou pour fournir des services réseau à partir de nos PoP mondiaux.
Afin de répondre à notre besoin de multi-location pour la plateforme (abordé dans le blog précédent), nous devions également fournir un multi-location complet pour ce chemin de données réseau. Cela était relativement simple pour la couche de routage puisque le vRouter prenait déjà en charge les VRF . Cependant, nous avons dû apporter des modifications dans Envoy pour le rendre multi-locataire. Comme nous n'utilisions pas la pile TCP du noyau, nous avons modifié l'interface du socket TCP d'Envoy et ajouté la prise en charge VRF.
Ce chemin de données devait également assurer la sécurité des API, les pare-feu d'application et la sécurité du réseau. Nous avons utilisé une combinaison de techniques algorithmiques et d'inférence machine pour cela et nous aborderons ce sujet dans un prochain article de blog.
Nous avons obtenu de nombreux avantages en construisant ce chemin de données réseau :
Capacités L3-L7+ complètes avec configuration, contrôle et observabilité uniformes
La prise en charge de l'évolutivité horizontale au sein d'un seul cluster nous permet de prendre en charge une gamme allant d'un très petit encombrement et de périphériques de périphérie à faible performance jusqu'à 100 Gbit/s ou plus de capacité dans notre réseau ou nos emplacements de cloud public
Ajoutez rapidement de nouvelles fonctionnalités au chemin de données réseau sans dépendre d'un fournisseur de réseau et/ou d'un fournisseur de cloud
Solution commune avec des caractéristiques de défaillance et de performances similaires dans n’importe quel environnement, ce qui est très important pour nos équipes d’exploitation.
Maintenant que nous pouvions déployer plusieurs clusters d’applications avec ce nouveau chemin de données réseau, il était essentiel de créer un plan de contrôle distribué à l’échelle mondiale pour les configurer, les contrôler et les surveiller.
Notre équipe de plateforme a dû résoudre plusieurs problèmes dans le cadre de la création d'un plan de contrôle distribué pour gérer un grand nombre de nœuds de traitement de chemin de données distribués. Étant donné que nous avons créé un nouveau chemin de données, il n’existait aucun plan de contrôle prêt à l’emploi pouvant être exploité et nous avons dû écrire le nôtre : Plan de contrôle local pour gérer plusieurs chemins de données exécutés au sein d'un seul cluster (cloud, périphérie ou PoP réseau). Ces nœuds de chemin de données avaient besoin d'un plan de contrôle local pour gérer les modifications de configuration, les mises à jour d'itinéraire, effectuer des contrôles de santé, effectuer la découverte de services, établir des échanges avec d'autres périphériques réseau à l'aide d'un protocole comme BGP, agréger les métriques et les journaux d'accès, etc. Plan de contrôle distribué pour gérer plusieurs plans de contrôle locaux — Il existe un plan de contrôle distribué exécuté dans nos PoP de réseau mondial ( Figure 3 ) et ce plan de contrôle est responsable de la gestion de la configuration des plans de contrôle locaux, de la distribution de l'état opérationnel sur chacun des plans de contrôle locaux et de la collecte de données à partir de chacun des nœuds. Pour distribuer l’état opérationnel, nous avons décidé d’utiliser BGP car il est finalement cohérent et robuste. Étant donné que nous avions construit une implémentation à très grande échelle et multithread de BGP dans le cadre d'OpenContrail, nous l'avons exploitée et avons ajouté des extensions pour l'équilibrage de charge : distribution de contrôles de santé, points de terminaison http/api, propagation de politiques, etc.
En outre, il existe un plan de gestion centralisé exécuté dans deux régions cloud (AWS et Azure) qui est utilisé parallèlement au plan de contrôle distribué pour fournir une multilocation, comme illustré dans la Figure 4 . Notre équipe SRE peut créer plusieurs locataires et chaque locataire est complètement isolé d'un autre locataire sur notre réseau mondial. Ils ne peuvent s'acheminer les uns vers les autres qu'en utilisant un « réseau public ». Au sein d'un locataire, les services des espaces de noms peuvent communiquer entre eux en fonction des règles de routage et de sécurité http/api/réseau.
Les plans de contrôle s'exécutent en tant que charges de travail Kubernetes dans un locataire distinct et un espace de noms isolé qui est sous le contrôle de nos seules équipes SRE. Par conséquent, aucun développeur et/ou client ne peut perturber ce service. De plus, comme le plan de contrôle est distribué, une panne d’un plan de contrôle à un endroit n’a pas d’impact sur le service global.
Une fois que nous avons déterminé les besoins de notre réseau mondial et défini les exigences des services réseau L3-L7+ pour les clusters d'applications (un nouveau chemin de données et un plan de contrôle distribué), notre équipe produit a proposé d'autres exigences qui ont rendu notre vie encore plus passionnante. Fondamentalement, ils voulaient que nous fournissions un service mesh inter-cluster global avec les fonctionnalités suivantes :
Avec les exigences n°2 et n°3, l’objectif était d’améliorer le temps de réponse et les performances de la connectivité client-serveur, ce qui est vraiment essentiel dans la communication d’application à application ou pour les applications SaaS à grande échelle. Afin de répondre aux exigences n° 2 et n° 3, il était clair que la meilleure approche était de créer un proxy distribué (Figure 5) — un proxy d’entrée, un proxy de sortie et un itinéraire basé sur l’adressage d’application et non sur l’adressage réseau. De plus, nous avons décidé de distribuer la santé des points de terminaison de service (ou serveurs) en exploitant le plan de contrôle distribué et les extensions BGP (comme décrit précédemment). Cette implémentation du proxy distribué est illustrée dans le diagramme ci-dessous.
Étant donné qu'il s'agit d'un proxy distribué avec une pile réseau L3-L7+ complète, nous l'appelons une passerelle d'application distribuée à l'échelle mondiale. Toutes les fonctionnalités disponibles dans notre chemin de données réseau sont désormais disponibles sur l'ensemble de notre réseau mondial : par exemple, l'équilibrage de charge et le routage basés sur HTTP ou les API, l'application des politiques à la périphérie, la transformation des API, la terminaison TLS plus proche de l'utilisateur, etc.
L’équipe a pu réaliser de nombreux gains grâce à la mise en œuvre d’une passerelle d’application distribuée à l’échelle mondiale. Ces gains ont concerné les améliorations opérationnelles, la sécurité, les performances et le coût total de possession :
Cette série de blogs couvrira divers aspects de ce qu'il nous a fallu pour créer et exploiter notre service SaaS distribué à l'échelle mondiale avec de nombreux clusters d'applications dans le cloud public, nos PoP de réseau privé et nos sites périphériques. La prochaine étape est la sécurité des plateformes et des données …