Appliquer les principes de GitOps à l'infrastructure: Introduction à tf-controller
Sommaire
Ne plus utiliser Weave Gitops pour les ressources Flux. Il existe désormais un plugin Headlamp.
Terraform est probablement l'outil "Infrastructure As Code" le plus utilisé pour construire, modifier et versionner les changements d'infrastructure Cloud. Il s'agit d'un projet Open Source développé par Hashicorp et qui utilise le langage HCL pour déclarer l'état souhaité de ressources Cloud. L'état des ressources créées est stocké dans un fichier d'état (terraform state).
On peut considérer que Terraform est un outil "semi-déclaratif" car il n'y a pas de fonctionnalité de réconciliation automatique intégrée. Il existe différentes approches pour répondre à cette problématique, mais en règle générale, une modification sera appliquée en utilisant terraform apply
. Le code est bien décrit dans des fichiers de configuration HCL (déclaratif) mais l'exécution est faite de manière impérative.
De ce fait, il peut y avoir de la dérive entre l'état déclaré et le réel (par exemple, un collègue qui serait passé sur la console pour changer un paramètre 😉).
❓❓ Alors, comment m'assurer que ce qui est commit dans mon repo git est vraiment appliqué. Comment être alerté s'il y a un changement par rapport à l'état désiré et comment appliquer automatiquement ce qui est dans mon code (GitOps) ?
C'est la promesse de tf-controller, un operateur Kubernetes Open Source de Weaveworks, étroitement lié à Flux (un moteur GitOps de la même société). Flux est l'une des solutions que je plébiscite, et je vous invite donc à lire un précédent article.
L'ensemble des étapes décrites ci-dessous sont faites avec ce repo Git
🎯 Notre objectif
En suivant les étapes de cet article nous visons les objectifs suivant:
- Déployer un cluster Kubernetes qui servira de "Control plane". Pour résumer il hébergera le controlleur Terraform qui nous permettra de déclarer tous les éléments d'infrastructure souhaités.
- Utiliser Flux comme moteur GitOps pour toutes les ressources Kubernetes.
Concernant le controleur Terraform, nous allons voir:
- Quelle est le moyen de définir des dépendances entre modules
- Création de plusieurs ressources AWS: Zone route53, Certificat ACM, réseau, cluster EKS.
- Les différentes options de reconciliation (automatique, nécessitant une confirmation)
- Comment sauvegarder et restaurer un fichier d'état (tfstate)
🛠️ Installer le controleur Terraform
☸ Le cluster "Control Plane"
Afin de pouvoir utiliser le controleur Kubernetes tf-controller
, il nous faut d'abord un cluster Kubernetes 😆.
Nous allons donc créer un cluster control plane en utilisant la ligne de commande terraform
et les bonnes pratiques EKS.
Il est primordial que ce cluster soit résiliant, sécurisé et supervisé car il sera responsable de la gestion de l'ensemble des ressources AWS créées par la suite.
Sans entrer dans le détail, le cluster "control plane" a été créé un utilisant ce code. Celà-dit, il est important de noter que toutes les opérations de déploiement d'application se font en utilisant Flux.
En suivant les instructions du README, un cluster EKS sera créé mais pas uniquement!Il faut en effet donner les permissions au controlleur Terraform pour appliquer les changements d'infrastructure. De plus, Flux doit être installé et configuré afin d'appliquer la configuration définie ici.
Au final on se retrouve donc avec plusieurs éléments installés et configurés:
- les addons quasi indispensables que sont
aws-loadbalancer-controller
etexternal-dns
- les roles IRSA pour ces mêmes composants sont installés en utilisant
tf-controller
- La stack de supervision Prometheus / Grafana.
external-secrets
pour pouvoir récupérer des éléments sensibles depuis AWS secretsmanager.- Afin de démontrer tout cela au bout de quelques minutes l'interface web pour Flux est accessible via l'URL
gitops-<cluster_name>.<domain_name
>
Vérifier toute de même que le cluster est accessible et que Flux fonctionne correctement
1aws eks update-kubeconfig --name controlplane-0 --alias controlplane-0
2Updated context controlplane-0 in /home/smana/.kube/config
1flux check
2...
3✔ all checks passed
4
5flux get kustomizations
6NAME REVISION SUSPENDED READY MESSAGE
7flux-config main@sha1:e2cdaced False True Applied revision: main@sha1:e2cdaced
8flux-system main@sha1:e2cdaced False True Applied revision: main@sha1:e2cdaced
9infrastructure main@sha1:e2cdaced False True Applied revision: main@sha1:e2cdaced
10security main@sha1:e2cdaced False True Applied revision: main@sha1:e2cdaced
11tf-controller main@sha1:e2cdaced False True Applied revision: main@sha1:e2cdaced
12...
📦 Le chart Helm et Flux
Maintenant que notre cluster "controlplane" est opérationnel, l'ajout le contrôleur Terraform consiste à utiliser le chart Helm.
Il faut tout d'abord déclarer la source:
1apiVersion: source.toolkit.fluxcd.io/v1beta2
2kind: HelmRepository
3metadata:
4 name: tf-controller
5spec:
6 interval: 30m
7 url: https://weaveworks.github.io/tf-controller
Et définir la HelmRelease:
1apiVersion: helm.toolkit.fluxcd.io/v2beta1
2kind: HelmRelease
3metadata:
4 name: tf-controller
5spec:
6 releaseName: tf-controller
7 chart:
8 spec:
9 chart: tf-controller
10 sourceRef:
11 kind: HelmRepository
12 name: tf-controller
13 namespace: flux-system
14 version: "0.12.0"
15 interval: 10m0s
16 install:
17 remediation:
18 retries: 3
19 values:
20 resources:
21 limits:
22 memory: 1Gi
23 requests:
24 cpu: 200m
25 memory: 500Mi
26 runner:
27 serviceAccount:
28 annotations:
29 eks.amazonaws.com/role-arn: "arn:aws:iam::${aws_account_id}:role/tfcontroller_${cluster_name}"
Lorsque ce changement est écrit dans le repo Git, la HelmRelease sera déployée et le contrôlleur tf-controller
démarera
1kubectl get hr -n flux-system
2NAME AGE READY STATUS
3tf-controller 67m True Release reconciliation succeeded
4
5kubectl get po -n flux-system -l app.kubernetes.io/instance=tf-controller
6NAME READY STATUS RESTARTS AGE
7tf-controller-7ffdc69b54-c2brg 1/1 Running 0 2m6s
Dans le repo de demo il y a déjà un certain nombre de ressources AWS déclarées. Par conséquent, au bout de quelques minutes, le cluster se charge de la création de celles-cis:
Bien que la majorité des tâches puisse être réalisée de manière déclarative ou via les utilitaires de ligne de commande tels que kubectl
et flux
, un autre outil existe qui offre la possibilité d'interagir avec les ressources terraform : tfctl
🚀 Appliquer un changement
Parmis les bonnes pratiques avec Terraform, il y a l'usage de modules.Un module est un ensemble de ressources Terraform liées logigement afin d'obtenir une seule unité réutilisable. Cela permet d'abstraire la complexité, de prendre des entrées, effectuer des actions spécifiques et produire des sorties.
Il est possible de créer ses propres modules et de les mettre à disposition dans des Sources
ou d'utiliser les nombreux modules partagés et maintenus par les communautés.Il suffit alors d'indiquer quelques variables
afin de l'adapter au contexte.
Avec tf-controller
, la première étape consiste donc à indiquer la Source
du module. Ici nous allons configurer le socle réseau sur AWS (vpc, subnets...) avec le module terraform-aws-vpc.
sources/terraform-aws-vpc.yaml
1apiVersion: source.toolkit.fluxcd.io/v1
2kind: GitRepository
3metadata:
4 name: terraform-aws-vpc
5 namespace: flux-system
6spec:
7 interval: 30s
8 ref:
9 tag: v5.0.0
10 url: https://github.com/terraform-aws-modules/terraform-aws-vpc
Nous pouvons ensuite créer la ressource Terraform
qui en fait usage:
1apiVersion: infra.contrib.fluxcd.io/v1alpha2
2kind: Terraform
3metadata:
4 name: vpc-dev
5spec:
6 interval: 8m
7 path: .
8 destroyResourcesOnDeletion: true # You wouldn't do that on a prod env ;)
9 storeReadablePlan: human
10 sourceRef:
11 kind: GitRepository
12 name: terraform-aws-vpc
13 namespace: flux-system
14 vars:
15 - name: name
16 value: vpc-dev
17 - name: cidr
18 value: "10.42.0.0/16"
19 - name: azs
20 value:
21 - "eu-west-3a"
22 - "eu-west-3b"
23 - "eu-west-3c"
24 - name: private_subnets
25 value:
26 - "10.42.0.0/19"
27 - "10.42.32.0/19"
28 - "10.42.64.0/19"
29 - name: public_subnets
30 value:
31 - "10.42.96.0/24"
32 - "10.42.97.0/24"
33 - "10.42.98.0/24"
34 - name: enable_nat_gateway
35 value: true
36 - name: single_nat_gateway
37 value: true
38 - name: private_subnet_tags
39 value:
40 "kubernetes.io/role/elb": 1
41 "karpenter.sh/discovery": dev
42 - name: public_subnet_tags
43 value:
44 "kubernetes.io/role/elb": 1
45 writeOutputsToSecret:
46 name: vpc-dev
Si l'on devait résumer grossièrement: le code terraform provenant de la source terraform-aws-vpc
est utilisé avec les variables vars
.
Il y a ensuite plusieurs paramètres qui influent sur le fonctionnement de tf-controller
. Les principaux paramètres qui permettent de contrôler la façon dont sont appliquées les modifications sont .spec.approvePlan
et .spec.autoApprove
🚨 Détection de la dérive
Définir spec.approvePlan
avec une valeur à disable
permet uniquement de notifier que l'état actuel des ressources a dérivé par rapport au code Terraform.
Cela permet notamment de choisir le moment et la manière dont l'application des changements sera effectuée.
De mon point de vue il manque une section sur les notifications: La dérive, les plans en attentes, les problèmese de réconcilation. J'essaye d'identifier les méthodes possibles (de préférence avec Prometheus) et de mettre à jour cet article dès que possible.
🔧 Application manuelle
L'exemple donné précédemment (vpc-dev
) ne contient pas le paramètre .spec.approvePlan
et hérite donc de la valeur par défaut qui est false
.
Par conséquent, l'application concrète des modifications (apply
), n'est pas faite automatiquement.
Un plan
est exécuté et sera en attente d'une validation:
1tfctl get
2NAMESPACE NAME READY MESSAGE PLAN PENDING AGE
3...
4flux-system vpc-dev Unknown Plan generated: set approvePlan: "plan-v5.0.0-26c38a66f12e7c6c93b6a2ba127ad68981a48671" to approve this plan. true 2 minutes
Je conseille d'ailleurs de configurer le paramètre storeReadablePlan
à human
. Cela permet de visualiser simplement les modifications en attente en utilisant tfctl
:
1tfctl show plan vpc-dev
2
3Terraform used the selected providers to generate the following execution
4plan. ressource actions are indicated with the following symbols:
5 + create
6
7Terraform will perform the following actions:
8
9 # aws_default_network_acl.this[0] will be created
10 + ressource "aws_default_network_acl" "this" {
11 + arn = (known after apply)
12 + default_network_acl_id = (known after apply)
13 + id = (known after apply)
14 + owner_id = (known after apply)
15 + tags = {
16 + "Name" = "vpc-dev-default"
17 }
18 + tags_all = {
19 + "Name" = "vpc-dev-default"
20 }
21 + vpc_id = (known after apply)
22
23 + egress {
24 + action = "allow"
25 + from_port = 0
26 + ipv6_cidr_block = "::/0"
27 + protocol = "-1"
28 + rule_no = 101
29 + to_port = 0
30 }
31 + egress {
32...
33Plan generated: set approvePlan: "plan-v5.0.0@sha1:26c38a66f12e7c6c93b6a2ba127ad68981a48671" to approve this plan.
34To set the field, you can also run:
35
36 tfctl approve vpc-dev -f filename.yaml
Après revue des modifications ci-dessus, il suffit donc d'ajouter l'identifiant du plan
à valider et de pousser le changement sur git comme suit:
1apiVersion: infra.contrib.fluxcd.io/v1alpha2
2kind: Terraform
3metadata:
4 name: vpc-dev
5spec:
6...
7 approvePlan: plan-v5.0.0-26c38a66f1
8...
En quelques instants un runner
sera lancé qui se chargera d'appliquer les changements:
1kubectl logs -f -n flux-system vpc-dev-tf-runner
22023/07/01 15:33:36 Starting the runner... version sha
3...
4aws_vpc.this[0]: Creating...
5aws_vpc.this[0]: Still creating... [10s elapsed]
6...
7aws_route_table_association.private[1]: Creation complete after 0s [id=rtbassoc-01b7347a7e9960a13]
8aws_nat_gateway.this[0]: Still creating... [10s elapsed]
La réconciliation éffectuée, la ressource passe à l'état READY: True
1kubectl get tf -n flux-system vpc-dev
2NAME READY STATUS AGE
3vpc-dev True Outputs written: v5.0.0@sha1:26c38a66f12e7c6c93b6a2ba127ad68981a48671 17m
🤖 Application automatique
Nous pouvons aussi activer la réconciliation automatique. Pour ce faire il faut déclarer le paramètre .spec.autoApprove
à true
.
Toutes les ressources IRSA sont configurées de la sorte:
1piVersion: infra.contrib.fluxcd.io/v1alpha2
2kind: Terraform
3metadata:
4 name: irsa-external-secrets
5spec:
6 approvePlan: auto
7 destroyResourcesOnDeletion: true
8 interval: 8m
9 path: ./modules/iam-role-for-service-accounts-eks
10 sourceRef:
11 kind: GitRepository
12 name: terraform-aws-iam
13 namespace: flux-system
14 vars:
15 - name: role_name
16 value: ${cluster_name}-external-secrets
17 - name: attach_external_secrets_policy
18 value: true
19 - name: oidc_providers
20 value:
21 main:
22 provider_arn: ${oidc_provider_arn}
23 namespace_service_accounts: ["security:external-secrets"]
Donc si je fais le moindre changement sur la console AWS par exemple, celui-ci sera rapidement écrasé par celui géré par tf-controller
.
La politique de suppression d'une ressource Terraform est définie par le paramètre destroyResourcesOnDeletion
.
Par défaut elles sont conservées et il faut donc que ce paramètre ait pour valeur true
afin de détruire les éléments crées lorsque l'objet Kubernetes est supprimé.
Ici nous voulons la possibilité de supprimer les rôles IRSA. Ils sont en effet étroitement liés aux clusters.
🔄 Entrées et sorties: dépendances entre modules
Lorsque qu'on utilise Terraform, on a souvent besoin de passer des données d'un module à l'autre. Généralement ce sont les outputs du module qui exportent ces informations. Il faut donc un moyen de les importer dans un autre module.
Reprenons encore l'exemple donné ci-dessus (vpc-dev
). Nous notons en bas du YAML la directive suivante:
1...
2 writeOutputsToSecret:
3 name: vpc-dev
Lorsque cette ressource est appliquée nous aurons un message qui confirme que les outputs sont disponibles ("Outputs written"):
1kubectl get tf -n flux-system vpc-dev
2NAME READY STATUS AGE
3vpc-dev True Outputs written: v5.0.0@sha1:26c38a66f12e7c6c93b6a2ba127ad68981a48671 17m
En effet ce module exporte de nombreuses informations (126):
1kubectl get secrets -n flux-system vpc-dev
2NAME TYPE DATA AGE
3vpc-dev Opaque 126 15s
4
5kubectl get secret -n flux-system vpc-dev --template='{{.data.vpc_id}}' | base64 -d
6vpc-0c06a6d153b8cc4db
Certains de ces éléments d'informations sont ensuite utilisés pour créer un cluster EKS de dev:
1...
2 varsFrom:
3 - kind: Secret
4 name: vpc-dev
5 varsKeys:
6 - vpc_id
7 - private_subnets
8...
💾 Sauvegarder et restaurer un tfstate
Dans mon cas je ne souhaite pas recréer la zone et le certificat à chaque destruction du controlplane. Voici un exemple des étapes à mener pour que je puisse restaurer l'état de ces ressources lorsque j'utilise cette demo.
Il s'agit là d'une procédure manuelle afin de démontrer le comportement de tf-controller
par rapport aux fichiers d'état. Par défaut ces tfstates
sont stockés dans des secrets
mais on préferera configurer un backend GCS ou S3
La création initiale de l'environnement de démo m'a permis de sauvegarder les fichiers d'état (tfstate) de cette façon.
1WORKSPACE="default"
2STACK="route53-cloud-hostedzone"
3BACKUPDIR="${HOME}/tf-controller-backup"
4
5mkdir -p ${BACKUPDIR}
6
7kubectl get secrets -n flux-system tfstate-${WORKSPACE}-${STACK} -o jsonpath='{.data.tfstate}' | \
8base64 -d | gzip -d > ${BACKUPDIR}/${WORKSPACE}-${STACK}.tfstate
Lorsque le cluster est créé à nouveau, tf-controller essaye de créer la zone car le fichier d'état est vide.
1tfctl get
2NAMESPACE NAME READY MESSAGE PLAN PENDING AGE
3...
4flux-system route53-cloud-hostedzone Unknown Plan generated: set approvePlan: "plan-main@sha1:345394fb4a82b9b258014332ddd556dde87f73ab" to approve this plan. true 16 minutes
5
6tfctl show plan route53-cloud-hostedzone
7
8Terraform used the selected providers to generate the following execution
9plan. resource actions are indicated with the following symbols:
10 + create
11
12Terraform will perform the following actions:
13
14 # aws_route53_zone.this will be created
15 + resource "aws_route53_zone" "this" {
16 + arn = (known after apply)
17 + comment = "Experimentations for blog.ogenki.io"
18 + force_destroy = false
19 + id = (known after apply)
20 + name = "cloud.ogenki.io"
21 + name_servers = (known after apply)
22 + primary_name_server = (known after apply)
23 + tags = {
24 + "Name" = "cloud.ogenki.io"
25 }
26 + tags_all = {
27 + "Name" = "cloud.ogenki.io"
28 }
29 + zone_id = (known after apply)
30 }
31
32Plan: 1 to add, 0 to change, 0 to destroy.
33
34Changes to Outputs:
35 + domain_name = "cloud.ogenki.io"
36 + nameservers = (known after apply)
37 + zone_arn = (known after apply)
38 + zone_id = (known after apply)
39
40Plan generated: set approvePlan: "plan-main@345394fb4a82b9b258014332ddd556dde87f73ab" to approve this plan.
41To set the field, you can also run:
42
43 tfctl approve route53-cloud-hostedzone -f filename.yaml
La procédure de restauration consiste donc à créer le secret à nouveau:
1gzip ${BACKUPDIR}/${WORKSPACE}-${STACK}.tfstate
2
3cat <<EOF | kubectl apply -f -
4apiVersion: v1
5kind: Secret
6metadata:
7 name: tfstate-${WORKSPACE}-${STACK}
8 namespace: flux-system
9 annotations:
10 encoding: gzip
11type: Opaque
12data:
13 tfstate: $(cat ${BACKUPDIR}/${WORKSPACE}-${STACK}.tfstate.gz | base64 -w 0)
14EOF
Il faudra aussi relancer un plan de façon explicite pour mettre à jour l'état de la ressource en question
1tfctl replan route53-cloud-hostedzone
2 Replan requested for flux-system/route53-cloud-hostedzone
3Error: timed out waiting for the condition
Nous pouvons alors vérifier que le fichier d'état a bien été mis à jour
1tfctl get
2NAMESPACE NAME READY MESSAGE PLAN PENDING AGE
3flux-system route53-cloud-hostedzone True Outputs written: main@sha1:d0934f979d832feb870a8741ec01a927e9ee6644 false 19 minutes
🔍 Focus sur certaines fonctionnalités de Flux
Oui j'ai un peu menti sur l'agenda 😝. Il me semblait nécessaire de mettre en lumière 2 fonctionnalités que je n'avais pas exploité jusque là et qui sont fort utiles!
Substition de variables
Lorsque Flux est initiliasé un certain nombre de Kustomization
spécifique à ce cluster sont créés.
Il est possible d'y indiquer des variables de substitution qui pourront être utilisées dans l'ensemble des ressources déployées par cette Kustomization
. Cela permet d'éviter un maximum la déduplication de code.
J'ai découvert l'efficacité de cette fonctionnalité très récemment. Je vais décrire ici la façon dont je l'utilise:
Le code terraform qui crée un cluster EKS, génère aussi une ConfigMap
qui contient les variables propres au cluster.
On y retrouvera, bien sûr, le nom du cluster, mais aussi tous les paramètres qui varient entre les clusters et qui sont utilisés dans les manifests Kubernetes.
1resource "kubernetes_config_map" "flux_clusters_vars" {
2 metadata {
3 name = "eks-${var.cluster_name}-vars"
4 namespace = "flux-system"
5 }
6
7 data = {
8 cluster_name = var.cluster_name
9 oidc_provider_arn = module.eks.oidc_provider_arn
10 aws_account_id = data.aws_caller_identity.this.account_id
11 region = var.region
12 environment = var.env
13 vpc_id = module.vpc.vpc_id
14 }
15 depends_on = [flux_bootstrap_git.this]
16}
Comme spécifié précedemment, les variables de substition sont définies dans les Kustomization
. Prenons un exemple concret.
Ci-dessous on définie la Kustomization qui déploie toutes les ressources qui sont consommées par tf-controller
On déclare ici la ConfigMap eks-controlplane-0-vars
qui avait été généré à la création du cluster EKS.
1apiVersion: kustomize.toolkit.fluxcd.io/v1
2kind: Kustomization
3metadata:
4 name: tf-custom-resources
5 namespace: flux-system
6spec:
7 prune: true
8 interval: 4m0s
9 path: ./infrastructure/controlplane-0/opentofu/custom-resources
10 postBuild:
11 substitute:
12 domain_name: "cloud.ogenki.io"
13 substituteFrom:
14 - kind: ConfigMap
15 name: eks-controlplane-0-vars
16 - kind: Secret
17 name: eks-controlplane-0-vars
18 optional: true
19 sourceRef:
20 kind: GitRepository
21 name: flux-system
22 dependsOn:
23 - name: tf-controller
Enfin voici un exemple de ressource Kubernetes qui en fait usage. Cet unique manifest peut être utilisé par tous les clusters!.
1apiVersion: helm.toolkit.fluxcd.io/v2beta1
2kind: HelmRelease
3metadata:
4 name: external-dns
5spec:
6...
7 values:
8 global:
9 imageRegistry: public.ecr.aws
10 fullnameOverride: external-dns
11 aws:
12 region: ${region}
13 zoneType: "public"
14 batchChangeSize: 1000
15 domainFilters: ["${domain_name}"]
16 logFormat: json
17 txtOwnerId: "${cluster_name}"
18 serviceAccount:
19 annotations:
20 eks.amazonaws.com/role-arn: "arn:aws:iam::${aws_account_id}:role/${cluster_name}-external-dns"
Cela élimine totalement les overlays qui consistaient à ajouter les paramètres spécifiques au cluster.
Web UI (Weave GitOps)
Dans mon précédent article sur Flux, je mentionnais le fait que l'un des inconvénients (si l'on compare avec son principale concurrent: ArgoCD) est le manque d'une interface Web. Bien que je sois un adepte de la ligne de commande, c'est parfois bien utile d'avoir une vue synthétique et de pouvoir effectuer certaines opération en quelques clicks 🖱️
C'est désormais possible avec Weave Gitops! Bien entendu ce n'est pas comparable avec l'UI d'ArgoCD, mais l'essentiel est là: Mettre en pause la réconcilation, visualiser les manifests, les dépendances, les événements...
Il existe aussi le plugin VSCode comme alternative.
💭 Remarques
Et voilà, nous arrivons au bout de notre exploration de cet autre outil de gestion d'infrastructure sur Kubernetes. Malgré quelques petits soucis rencontrés en cours de route, que j'ai partagé sur le repo Git du projet, l'expérience m'a beaucoup plu. tf-controller
offre une réponse concrète à une question fréquente : comment gérer notre infra comme on gère notre code ?
J'aime beaucoup l'approche GitOps appliquée à l'infrastructure, j'avais d'ailleurs écrit un article sur Crossplane.
tf-controller
aborde la problématique sous un angle différent: utiliser du Terraform directement. Cela signifie qu'on peut utiliser nos connaissances actuelles et notre code existant. Pas besoin d'apprendre une nouvelle façon de déclarer nos ressources.C'est un critère à prendre en compte car migrer vers un nouvel outil lorsque l'on a un existant représente un éffort non négligeable. Cependant j'ajouterais aussi que tf-controller
s'adresse aux utilisateurs de Flux uniquement et, de ce fait, restreint le publique cible.
Aujourd'hui, j'utilise une combinaison de Terraform, Terragrunt et RunAtlantis. tf-controller
pourrait devenir une alternative viable: Nous avons en effet évoqué l'intérêt de Kustomize associé aux substitions de variables pour la factorisation de code. Dans la roadmap du projet il y a aussi l'objectif d'afficher les plans dans les pull-requests.
Autre problématique fréquente: la nécessité de passer des éléments sensibles aux modules. En utilisant une ressource Terraform
, on peut injecter des variables depuis des secrets Kubernetes. Ce qui permet d'utiliser certains outils, tels que external-secrets
, sealed-secrets
...
Je vous encourage donc à essayer tf-controller
vous-même, et peut-être même d'y apporter votre contribution 🙂.
- La démo que j'ai faite ici utilise pas mal de ressources, dont certaines assez cruciales (comme le réseau). Donc, gardez en tête que c'est juste pour la démo ! Je suggère une approche progressive si vous envisagez de le mettre en ouvre: commencez par utiliser la détection de dérives, puis créez des ressources simples.
- J'ai aussi pris quelques raccourcis en terme de sécurité à éviter absolument, notamment le fait de donner les droits admin au contrôleur.