AWS EKS Cluster, Node Group et Terraform
AWS EKS Cluster, Node Group et Terraform

AWS EKS Cluster, Node Group et Terraform

Ou comment automatiser un cluster Kubernetes autoscalable sur AWS.

Introduction

Cela fait un moment qu’AWS EKS est sorti — je me souviens de ma première soirée sur us-east-1 — et même si les premières installations ont été laborieuses, il n’en demeurait pas moins qu’AWS avait dès lors son propre service managé Kubernetes.

De nombreux labs et quelques infrastructures de production ont vu le jour autour de cette technologie ainsi que la mise en place de Continuous Integration / Continuous Delivery associés à ceux-ci.

Force est de constater que l’écosystème AWS autour de EKS (et des containers) a beaucoup évolué et est extrêmement dynamique. Il a apporté son lot de bonnes nouvelles, parmi lesquelles :

  • Le CNI pour l’utilisation du VPC au sein du cluster K8S.
  • Les CSI drivers (EBS + EFS).
  • Le Cluster Autoscaler.
  • AWS ALB Ingress Controller.
  • AWS IAM Authenticator for Kubernetes.

J’en oublie probablement un tas d’autre que vous utilisez au quotidien.

Aussi, me prit-il l’envie de mettre cela en place en y incluant la nouvelle ressource Terraform aws_eks_node_group et de pipeliner tout cela sous GitLab-CI par là-même occasion.

Implémentation

AWS

Il nous faudra un compte AWS pour déployer les ressources déclarées dans Terraform. Celles-ci seront déployées dans la région eu-west-1 (Ireland) dans le cadre de cet article.

Les credentials nécessaires au déploiement des ressources AWS via Terraform dans GitLab seront fournis via le rôle IAM de l’instance runner GitLab.

GitLab Repositories

Premier chantier à implémenter, la création des repos dans GitLab.

Ici, et sans aucune contrainte autre que le plaisir de le faire (et d’organiser le travail), j’ai créé 3 repositories:

  • Un pour le code de « base » comprenant la partie réseau (VPC), les permissions de base (IAM), une zone DNS (Route53) et un certificat (ACM).
  • Un pour le code du cluster EKS (master + nodes + add-ons).
  • Un pour une première application (jeu : 2048-game) usant de l’ALB Ingress Controller.

Nous avons donc 3 repos qui représenteront 3 projets Terraform.La structure de ceux-ci est classique :

Base repository (VPC, IAM, Route53)

EKS repository (EKS, IAM, K8S add-ons)

2048-game repository (Kustomize, Route53)

Pour le présent article, il n’y a pas de gestion spécifique du gitflow et donc de gestion d’environnement associé. On fait tout sur master pour un seul environnement.

GitLab Pipelines

On met en place des variables d’environnement pour nos repos qui serviront aux pipelines.

image

Ex : 2048-game repository

On fait en sorte d’avoir une pipeline qui prenne en compte à la fois du Terraform et du Kubernetes.

image

Ex : Pipeline du repository EKS

On gère aussi les Environment GitLab pour avoir des informations utiles sur les étapes majeures de notre pipeline (commit, URL).

image

Ex : 2048-game repository Environment page

Nous avons maintenant nos outils nécessaires en place pour déployer notre cluster EKS. Alors, GO !

base

Pour la partie que je nomme par raccourci base, j’utilise le module VPC validé de la registry Terraform. Il est juste à noter que nous devons prêter une attention à la politique de tagging nécessaire au bon fonctionnement d’EKS sur les ressources VPC.

En effet, au moment du déploiement des ressources liées au VPC, nous n’avons pas déployé et n’avons pas conscience qu’une ressource tierce (EKS) va venir modifier les tags de plusieurs de nos ressources locales.

Les TAGs étant connus et identifiables (préfixe en kubernetes.io) j’use d’un paramètre lié au provider me permettant d’ignorer globalement des TAGs ayant un prefix précis.

image

Sans cela, le projet Terraform base passerait son temps à écraser les TAGs mis en place par le projet Terraform eks. Ce dernier ne pourrait alors plus fonctionner correctement.

image

Je déploie aussi dans ce projet Terraform des ressources AWS Route53 et un certificat depuis l’AWS Certificat Manager ainsi que des ressources IAM.

eks

C’est ici que le travail commence à être le plus fun.

Je vais faire en sorte de déployer un cluster EKS managé (master), un Node Group managé par AZ de la région eu-west-1 (pour le bon fonctionnement de Cluster-Autoscaler) et finalement, la brique d’ALB Ingress Controller.

Je finaliserai cette partie avec quelques IAM/RBAC customs afin de donner des droits aux intervenants sur le cluster EKS en fonction des credentials AWS qu’ils possèdent (Rôle IAM et/ou utilisateur IAM).

Ayant un CLI AWS récent (> 1.16.308), je profite de l’usage de la nouvelle commande aws eks get-tokenen lieu et place de l’ aws-iam-authenticator pour cet usage.

La partie cluster EKS (master) est assez simple.

image

Ici, j’active les 2 endpoint pour d’une part, pouvoir interagir avec le cluster EKS depuis internet via le endpoint_public_access (celui activé par défaut) et d’autre part, permettre aux Worker Nodes de communiquer avec le master à travers le endpoint_private_access de manière plus sécurisée (pas par défaut).

Il y a aussi toutes les ressources Terraform nécessaires à son bon déploiement :

image

Viens ensuite la partie Node Group. Il existe 2 écoles, celle qui ne fait qu’un seul Node Group qui s’étale sur plusieurs AZ (sans Cluster-Autoscaler) avec une gestion externe à Kubernetes des politiques de mise à l’échelle des Node Groups et celle qui fait un Node Group par AZ comme l’oblige à faire le Cluster-Autoscaler (ici).

J’opte pour cette deuxième solution du fait que je souhaite mettre à l’échelle mon cluster Kubernetes de manière la plus native et kubernetes friendly.

image

Je lui adjoins les ressources AWS nécessaires à son bon fonctionnement et déploiement.

image

Je déploie une ressource AWS OpenID Connect permettant de pouvoir faire le lien entre des rôles AWS IAM et des services accountsKubernetes pour un usage au sein des applications K8S de ressources AWS (S3 par exemple).

image

Le thumbprint_list est une valeur connue, mais non implicite (explication donnée ici). Il n’y a pas actuellement de data source Terraform permettant de récupérer cette valeur.

Il ne nous reste plus qu’à déployer les stacks Cluster-Autoscaler et ALB-Ingress-Controller et les références IAM / RBAC pour l’administration du cluster.

Il faut simplement préparer des templates Terraform correspondant aux fichiers YAML de déploiement Kubernetes pour ces composants.

Les nourrir dynamiquement des variables nécessaires présentes dans les ressources managées par Terraform:

  • Les ARN des rôles IAM pour les servicesaccounts.
  • Le nom du cluster EKS
  • L’ID du VPC.
  • La région AWS.

Et lancer leur déploiement au travers une null_resource ayant pour objectif de déployer les fichiers YAML générés par Terraform dans le cluster Kubernetes EKS fraichement installé.

image

Le depends_on force l’execution de cette ressource après l’apparition des Node Groups pour ne pas que les déploiements Kubernetes bloquent (j’ai eu le cas sur l’ALB Ingress Controller qui ne se déployait pas, car il avait trop essayé de se déployer avant la disponibilité des Worker Nodes).

Le triggers fait en sorte que si l’une des configurations Kubernetes générée change, alors elle sera redéployée.

Nous aurons ici à subir le fait qu’une ressource local_file est constamment en création dans Terraform (Note indiquée dans la doc Terraform).

Je déploie ensuite les ressources nécessaires à l’association IAM / RBAC. J’ai fait simple pour le cadre de ce test. Un rôle ReadOnly sur tout EKS ( ClusterRole ) et un compte Administrateur sur un namespace spécifique ( Role ). Le plus gros problème, c’est qu’il n’y pas de moyen simple d’automatiser la mise à jour de la ConfigMap aws-auth. J’utilise donc un template Terraform avec une convention de nommage forte pour définir l’ensemble des droits associés entre IAM et RBAC de Kubernetes.

Ici, il ne faudra surtout pas oublier de reporter la configuration concernant le mapping entre le rôle IAM des Worker Nodes et le group K8S associé. Sans cela, le cluster ne sera plus fonctionnel. Cela implique aussi de définir à des endroits différents la pile applicative K8S et les droits qui lui sont associés.

2048-game

Il nous reste à déployer une application de test pour valider notre déploiement EKS. J’utilise kustomize de manière basique pour effectuer le déploiement applicatif à travers un pipeline GitLab.

Ici, il faut en amont créer le namespace et les identités permettant l’administration de ce namespace. Il faut pour cela revenir dans le projet Terraform EKS et modifier la partie liée aux IAM / RBAC.

image
image

Dans le repository de l’application K8S, nous aurons une partie dédiée aux ressources Kubernetes (deployment, ingress, service) via kustomize et une partie dédiée aux ressources Terraform (record Route53) qui mappe via AWS SSM Parameter Store l’ALB crée par l’ingress controller.

Voici la ligne de commande qui envoie après déploiement de l’application K8S l’information concernant le fqdn de l’ALB déployé via l’ingress dans AWS SSM :

image

Nous utilisons cette valeur dans un petit projet Terraform de création de record DNS :

image

À ce stade, nous avons un cluster Kubernetes pleinement fonctionnel sur AWS via des services managés et une gestion des droits AWS possible au niveau des droits du cluster et des ressources AWS disponibles pour les applications.

image

Nous avons un ALB Ingress Controller prêt à recevoir des demandes de ingress spécifiques.

image

Et une application Kubernetes usant de cet ingress.

image

Merci pour votre lecture. Si cet article vous a plu, merci de le partager sur vos réseaux 😉

Philippe Vidal - Jan 13, 2020 initialement publié ici

image