Modules Terraform Azure Production-ready

azure_terraform.png

Pourquoi

Claranet a récemment publié un certain nombre de modules Terraform pour Azure et a l'intention d'en publier d'autres : https://registry.terraform.io/search?q=claranet%20azure.

La création de modules encapsulant une ou plusieurs ressources Terraform est un moyen d'appliquer nos meilleures pratiques, d'harmoniser les implémentations des clients et d'être en mesure d'améliorer nos fonctionnalités de base et de suivre les changements.
Nous ne rappellerons pas les avantages de Terraform car vous pouvez facilement trouver des articles nombreux et complets à son sujet. Nous l'utilisons aussi parce que nous pensons que nous pouvons avoir un niveau d'abstraction suffisant pour nous permettre d'avoir des paquets (ici des modules) qui peuvent être partagés en interne et aussi avec le reste du monde.
Nous avons choisi de les mettre en open source pour faciliter la collaboration avec nos partenaires, clients et développeurs, pour que notre approche soit remise en question, pour bénéficier des contributions et peut-être pour atteindre nos futurs collègues.

Conçu pour la production

Les modules que nous publions ne sont pas destinés à couvrir l'intégralité des ressources sous-jacentes, mais à définir certains paramètres par défaut ou à faciliter la configuration de l'environnement de production, et ces deux derniers mots sont importants.

Il y a beaucoup de choses que nous aimerions mettre en œuvre dans un environnement de production : nommage cohérent, journalisation, surveillance, haute disponibilité et sécurité.
Même si ces modules Terraform sont des modules Terraform classiques et peuvent être utilisés n'importe où, nous les utilisons avec le wrapper Terraform de Claranet qui renforce l'arborescence des fichiers du projet et ajoute du sucre dans l'utilisation de Terraform.

Nommer

Pour nos modules, toutes les ressources créées ont leur nom généré à partir du nom du projet, du nom du client, de la région, de l'environnement et du type de ressource, comme recommandé par Azure.

Chaque ressource peut également avoir un préfixe devant le nom généré.

En outre, il est toujours possible de définir un nom personnalisé, ce qui peut être utile dans le cas d'un projet pratique dans lequel l'infrastructure est déjà construite sans Terraform mais ne respecte pas la convention de dénomination, ou si un client souhaite conserver sa convention.

Voici un exemple tiré de notre modèle Redis. Nous générons le nom attendu à l'aide de locals que nous injectons ensuite dans la ressource elle-même :

locals {
  name = coalesce(var.custom_name, "${local.name_prefix}${var.stack}-${var.client_name}-${var.location_short}-${var.environment}-redis")
  …
}
resource "azurerm_redis_cache" "redis" {
  name = local.name
  …
}

Ainsi, la lecture du nom d'une ressource, dans une alerte de surveillance, par exemple, nous permet d'identifier exactement de quelle ressource il s'agit et son objectif.

Logs et métriques

Nous voulons toujours, pour les ressources prêtes à la production, que la journalisation soit activée et agrégée avec des métriques détaillées et nombreuses.

Notre objectif est d'avoir dans chaque module la possibilité de spécifier le compte de stockage et/ou les sorties de l'espace de travail d'analyse de logs pour l'agrégation des logs. Azure Diagnostics Settings est l'implémentation la plus utilisée et est activée avec toutes les catégories de logs lorsque cela est possible.

Puisque la gestion des journaux dans Azure n'est pas uniforme, par exemple, les VMs ne gèrent pas leurs journaux avec Diagnostic Settings, nous visons également à fournir un moyen unifié de gérer les journaux pour ces services.

Pour les App Services et Azure Functions, une ressource Application Insights est toujours créée avec l'instance de service et liée à celle-ci.

Pour les machines virtuelles Windows et Linux, les extensions de diagnostic sont toujours configurées avec le plus haut niveau de métriques et de journaux activé.

Haute disponibilité

La plupart des services Azure offrent une haute disponibilité par le biais de la redondance de zone, d'instances multiples ou de la mise en grappe. Nous avons choisi d'avoir un service hautement disponible avec la configuration par défaut de chaque module.

Nous avons fait ce choix en raison de deux considérations :

  • Un outil automatisé de déploiement qui assure la haute disponibilité est plus fiable qu'un ingénieur DevOps qui suit la documentation lors de la création d'un environnement. Il suit le principe agile "Working software over comprehensive documentation". De plus, nous avons aussi la documentation.
  • Avoir une infrastructure non redondante devrait être un choix explicitement fait dans votre code.

Par exemple, nous avons fait les choix suivants selon la documentation d'Azure :

  • Pour le module App Service, nous avons choisi de fixer le nombre d'instances par défaut à 2.
  • locals {
      default_sku_capacity = var.sku["tier"] == "Dynamic" ? null : 2
    }

    Pour les machines virtuelles, nous les obligeons à être dans un Availability Set car nous devons toujours avoir plus d'une instance.

    • Pour Redis Cache, un cluster de 3 shards est la configuration par défaut, tout en tenant compte des spécifications de Redis.

    variable "cluster_shard_count" {
      default     = "3"
      description = "Number of cluster shards desired"
      type        = string
    }
    resource "azurerm_redis_cache" "redis" {
      ...
      shard_count = var.sku_name == "Premium" ? var.cluster_shard_count : 0
      ...
    }

    Non intrusif

    Nous ne supposons pas que l'utilisateur dispose de droits étendus sur l'environnement Azure. Ainsi, les modules n'utilisent pas en interne d'opération de lecture ou d'écriture dans Azure Active Directory comme cela peut être fait pour la gestion RBAC de certaines ressources.

    De même, nous n'appliquons pas la gestion des groupes de ressources, nous supposons seulement que l'utilisateur a suffisamment de droits pour créer les ressources couvertes par le module dans le groupe de ressources cible.

    Modularité

    Nos modules sont conçus pour tous. C'est pourquoi, même si nous avons fait certaines recommandations en définissant des valeurs par défaut, nous ne codons rien en dur, laissant les utilisateurs choisir comment ils veulent utiliser le module.

    Il y aura toujours des façons que nous n'avons pas pu prévoir, vous pouvez remplacer toute valeur par défaut que nous avons ajoutée dans le module pour définir la vôtre.

    Nous essayons également, dans la mesure du possible, de suivre toutes les nouvelles capacités du fournisseur de terraforme AzureRM afin de mettre à jour nos modules en conséquence.

    Outils d'exploitation

    Les plateformes de production ont besoin d'outils pour les faire fonctionner comme les logs, les sauvegardes et le monitoring. Pour la surveillance, nous utilisons Datadog (SignalFx maintenant, article de blog à venir...) comme solution externe et ne nous appuyons pas directement sur Azure Monitor.

    Nous avons regroupé dans des modules, à des fins d'exécution, les services suivants : Key Vault, Log Analytics Workspace, Storage Account (pour les logs) et Recovery Vault.

    La plupart des modules que nous avons créés peuvent (et doivent) être mappés avec ces outils précédents car ils peuvent fournir un moyen pratique d'être branché, c'est-à-dire qu'un jeton SAS est créé pour le compte de stockage des journaux.

    Cycle de vie des applications

    Les modules sont publiés sur Github et dans le registre Terraform avec le versioning semver.

    Nous prévoyons de maintenir chaque module avec des corrections de bogues et des améliorations. Les corrections de bogues apportées par Azure ou le fournisseur Terraform seront implémentées dans les modules publiés afin que les piles de production qui les utilisent puissent en disposer uniquement par des sauts de version.

    Étant donné que les modules sont classés par version et fournis avec un Changelog complet, les mises à jour sont faciles à suivre. De même, le code Terraform qui utilise ces modules doit être versionné, afin qu'il soit facile de savoir qui a apporté une modification et quand.

    En outre, certaines fonctionnalités d'Azure ne sont actuellement pas couvertes par le fournisseur Terraform. Nous mettons en œuvre certaines de ces fonctionnalités en utilisant des commandes CLI ou PowerShell en concevant une interface comme si la fonctionnalité était déjà disponible avec Terraform. L'avantage est que nous pouvons mettre en œuvre de nouvelles fonctionnalités sans aucun changement radical pour l'utilisateur qui bénéficiera toujours d'une compatibilité ascendante, même si la mise en œuvre peut être très différente.

    Conçu pour les humains

    Enfin, nous concevons les modules comme des API faciles à comprendre et axées sur les besoins de l'utilisateur et non sur le mécanisme Terraform ou l'API Azure sous-jacente.

    De plus, nous avons l'intention de masquer l'hétérogénéité de la mise en œuvre en fournissant une interface unifiée pour des fonctionnalités similaires, la gestion des journaux ou les accès au stockage par exemple.

    Quelques exemples :

    • La variable `ssl_enforcement` pour la connexion MySql (qui peut être "Enabled" ou "Disabled") est changée en un simple booléen `force_ssl`, facile à comprendre et qui peut être implémenté sans aucun risque de faute de frappe.
    • Les variables Sku pour MySql ou les ressources SQL qui ont besoin de fournir des informations redondantes sont modifiées pour fournir le moins d'informations possible, comme la taille et la famille, et soit deviner ou appliquer d'autres informations.
    • Les liens de stockage pour les journaux, les sauvegardes ou tout autre comportement interne nécessitent parfois l'identifiant de la ressource, et parfois le nom du stockage. L'accès se fait parfois par un jeton SAS, parfois par une clé d'accès. Nous masquons cette diversité en utilisant toujours les mêmes variables d'entrée, quelle que soit l'implémentation.

    Conclusion

    La publication des modules Terraform est un travail énorme qui nous prend beaucoup de temps, mais nous pouvons constater chaque jour les avantages et nous pensons que cela en vaut la peine. Nous pouvons observer dans un court laps de temps :

    • Des architectures uniformes pour tous nos clients qui facilitent la prise en main pour les personnes qui doivent travailler dessus. Liste non exhaustive : nommage des ressources, rétention des sauvegardes, journalisation activée, seuils de surveillance et portée ...
    • Code de base uniforme pour tous nos projets
    • Application des meilleures pratiques en matière de haute disponibilité et de sécurité
    • Environnements créés avec des fonctionnalités et des outils Azure toujours à jour, et vous savez que cela va incroyablement vite sur ce point.

    N'hésitez pas à utiliser ces modules Terraform et à nous contacter pour en discuter ou contribuer par un problème ou une demande de modification, vous êtes les bienvenus.

    Vous pouvez trouver tous les modules décrits ci-dessus ici https://claranet.tf/#azure

    Pour lire l'article en anglais, rendez-vous sur Medium.

    Managed Services sur le cloud Azure