Aller au contenu

Step 7 : Orchestration / ECS

Jusqu'ici, nous avons lancé 1 container par instance que nous avons créé.

Pas très optimisé ou cloud-native tout ça. On préfère utiliser un orchestrateur de conteneurs.

ECS, Elastic Container Service et EKS, Elastic Kubernetes Service, sont les services managés principaux d'AWS pour déployer ses conteneurs. Bien que plus complexe qu'ECS, la solution plébiscitée aujourd'hui pour lancer et orchestrer ses conteneurs est Kubernetes. Nous avons une autre formation qui y est dédiée : Kubernetes et GitOps.

ECS a été lancé par AWS en 2015 bien avant EKS, lui 2018. Mais vu de l'essor de Kubernetes et même de son adoption sur AWS, AWS a lancé son Service de Kubernetes managé EKS.

Pour cette étape, nous nous concentrons sur ECS qui est plus simple et mieux intégré à AWS.

Concepts

ECS, Elastic Container Service, permet donc de faire de l'orchestration de conteneurs, c'est-à-dire la création, gestion et mise à l'échelle de ceux-ci au sein d'un cluster, afin de garantir une bonne résilience et haute disponibilité de nos applications.

AWS établi 3 couches pour ECS :

  • Provisioning : la façon dont nous créons nos applications/conteneurs
  • Capacité : l'infrastructure de notre cluster qui fait tourner nos conteneurs
  • Contrôleur : le Scheduler ECS géré par AWS qui déploie et gére nos conteneurs sur la capacité que l'on définit.

Capacité

Pour l'infrastructure qui fait tourner nos conteneurs, on parle de Launch Types/Capacity providers, nous avons plusieurs choix :

  • Instances EC2
  • Fargate
  • On-Premise sur nos VM ou serveurs dédiés via Amazon ECS Anywhere

Via les instances EC2, nous payons ces instances et avons un fort contrôle dessus : nombre d'instances, type, network, disk...

Fargate est une manière plus simple de gérer ces conteneurs où AWS gère totalement l'infrastructure. On parle encore une fois de serverless, la création, configuration et scaling des machines executant nos conteneurs sont complètement géré par AWS.

Note

Fargate est également disponible pour les clusters EKS.

Fargate fait, comme les Lambda, usage de Firecracker, une solution open-sourcée par AWS permettant la gestion de micro-VMs permettant une isolation forte de nos applications et workloads.

Cela permet à AWS et nous une meilleure optimisation et mutualisation des infrastructures faisant tourner les conteneurs.

D'un point de coût, la prévalence de Fargate dépend beaucoup de la capacité non réservée par instance. Globalement, sans compter les coûts de gestion/maintenance d'infrastructure, Fargate est plus avantageux, car on ne perd pas la capacité non réservée des nœuds, mais pour des nœuds dont celle-ci est très bien utilisée le provisioning via ec2 est plus intéressant. Plus de détails ici

Provisioning

Nous définissons nos conteneurs via des task definitions.

On y définit d'abord les prérequis d'infrastructure :

  • Le Launch type vu plus haut, les capacités mémoire et CPU pour la tâche,
  • L'execution role, pour les droits qu'auront ECS/Fargate autour de la gestion des conteneurs (envoi des logs, pull d'images, ...)
  • Le task role, à l'instar de l'instance profile, définit les droits qu'auront les conteneurs sur les services AWS.
  • L'architecture OS
  • ...

Ensuite, nous définissons les conteneurs de notre tâche avec leur :

  • Nom
  • Image
  • Port mappings
  • Variables d'environnement
  • Healthcheck
  • ...

Une fois la définition créée, nous pouvons nous en servir en taĉhe ou service.

Une tâche ECS est une instance ou plusieurs d'une definition. On y définit les subnets et security groupes pour la tâche plus avec de potentielles surcharges sur les configurations de roles, commandes, variables environnements, etc.

Un service ECS maintient le nombre d'instances de taĉhes configurées. Sur erreurs ou problèmes d'une tâche ECS en relance une autre suivant la définition. On peut y servir les requêtes d'un ELB. Celui-ci distribuera les requêtes aux tâches.

Il y a 2 stratégies disponibles : replicas ou daemon. La première maintient un nombre désirée de taches dans le cluster et la deuxième ( indisponible pour Fargate) place une tâche par instance.

TP

À vous de jouer

Vous pouvez repartir de votre step4 et backport les certificats. Nous pouvons détruire le bucket S3 et la distribution CloudFront pour cette étape.

L'idée de cette étape en effet est d'utiliser des services ECS pour déployer nos conteneurs avec Fargate.

Note

Fargate n'autorise que certaines configurations pour le couple cpu/memory, définissez les valeurs suivantes :

  • Frontend : 256/512
  • Backend : 1024/2048
Note

Snippet pour la déclaration de l'execution role

# Rôle IAM pour les tâches ECS
resource "aws_iam_role" "ecs_task_execution_role" {
  name = "${var.prefix}-ecs-task-execution-role"

  assume_role_policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        },
      },
    ],
  })
}

resource "aws_iam_policy" "ecs_cloudwatch_logs_policy" {
  name        = "ecs-cloudwatch-logs-policy"
  description = "Policy pour permettre aux tâches ECS de créer et gérer les logs dans CloudWatch"

  policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ],
        Resource = "*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "secretsmanager:GetSecretValue"
        ],
        "Resource" : [
          data.aws_secretsmanager_secret.pull_image_credentials.arn,
        ]
      }
    ],
  })
}

# Attacher la politique CloudWatch Logs au rôle ECS Task Execution
resource "aws_iam_role_policy_attachment" "ecs_cloudwatch_logs_policy_attachment" {
  role       = aws_iam_role.ecs_task_execution_role.name
  policy_arn = aws_iam_policy.ecs_cloudwatch_logs_policy.arn
}

Tip

Le champ container_definitions attend tout un json. Vous avez plusieurs choix s'offrants à vous :

  • Utiliser un fichier déjà prêt à l'emploi file(path)
  • Utiliser un template et le résoudre comme vu plus tôt templatefile(path, vars)
  • Utiliser la fonction jsonencode déclarer le
  • Utiliser une heredoc string comme cet exemple

On préfère éviter si possible les heredoc qui rendent le code Terraform moins lisible, d'autant plus que jsonencode permet de le faire mieux.

Tip

La déclaration des credentials à utiliser pour pouvoir récupérer l'image est repositoryCredentials

Vous pouvez déclarer la récupération du secret comme cela :

data "aws_secretsmanager_secret" "pull_image_credentials" {
  name = "takima-school-gitlab-image-registry"
}
L'utilisation se fera donc dans la définition du container de cette façon :
repositoryCredentials = {
  credentialsParameter = data.aws_secretsmanager_secret.pull_image_credentials.arn
}

Success

Vous avez désormais utilisé un orchestrateur pour gérer vos containers !

En utilisant Fargate votre backend et frontend sont maintenant gérés en serverless !

Bonus