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.
- Créez votre aws_ecs_cluster
- Changez votre module compute pour créer vos conteneurs plutôt que des instances EC2 via un ASG
- Créez votre aws_ecs_service
- Créez votre aws_ecs_task_definition
- Changez le target_type de votre
aws_lb_target_group
enip
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 :
L'utilisation se fera donc dans la définition du container de cette façon :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 !