Guide de bonnes pratiques : déploiement et orchestration de vos applications avec AWS ECS

Vous avez probablement déjà entendu parler des avantages des conteneurs et décidé de les tester localement. Si vous lisez cet article, vous recherchez probablement la bonne manière, sur AWS, pour déployer et orchestrer votre application nouvellement dockerisée. Et le service magique c’est : AWS Elastic Container Service (ECS).

Dans ce guide de bonnes pratiques, nous allons utiliser un projet docker prédéfini avec un backend Symfony (framework PHP). Le projet se compose de 2 conteneurs Docker : un backend PHP et un serveur web Caddy. Ce qui suit fournit un bel exemple de migration de vos ressources Docker vers AWS ECS. Si vous n’avez pas d’expérience avec PHP ou Caddy, pas d’inquiètude, ils servent simplement d’exemple et ce guide peut s’appliquer à vos besoins.

Je m’appelle Ziad, je suis membre de plusieurs communautés AWS en France et à l’international et je suis consultant Cloud DevOps Engineer chez Daveo. Démarrons ensemble le déploiement de votre appli.

Prérequis

      • Docker

      • Git

      • Un compte AWS

      • Une AWS CLI configurée

      • Un nom de domaine (pour lier notre déploiement à un nom de domaine sur Route 53)

      • Un certificat TLS pour votre nom de domaine créé sur AWS Certificate Manager

    Exemple de clonage de projet

    Commençons par installer le projet sur notre machine locale.

    Pour cela, accédez au répertoire souhaité et exécutez :

        • Git init pour initialiser un dépôt git local

        • Git pull https://github.com/dunglas/symfony-docker.git pour cloner le projet

        • docker-compose build –pull –no-cache pour construire les images docker avec un projet squelette Symphony

      Puis, pour créer les conteneurs à partir des images, exécutez :

          • docker-compose up –build

        Vous saurez que c’est prêt lorsque le serveur php_1 répondra 200 à vos pings.

        Rendez-vous ensuite sur le lien http://localhost sur votre navigateur pour visualiser la page d’accueil de Symfony (note : Caddy devrait automatiquement vous rediriger vers https car il crée automatiquement son propre certificat SSL).

        Envoyer les images Docker vers Elastic Container registry (ECR)

        Pour cette partie, nous partons du principe que l’AWS CLI est déjà installée et correctement configurée sur votre machine.

        Tout d’abord, authentifiez-vous auprès de votre registre par défaut, exécutez :

        aws ecr get-login-password –region <region> | docker login –username AWS –password-stdin <aws_account_id>.dkr.ecr.<region>.amazonaws.com

        et remplacez <region> et <aws_account_id> par vos valeurs.

        Ensuite, nous allons créer un registre de conteneur dans ECR. Vous aurez besoin d’un référentiel pour chaque conteneur, donc deux dans notre cas.

        La commande est :

        aws ecr create-repository –repository-name PHP –image-scanning-configuration scanOnPush=true –region <region>

        Assurez-vous de spécifier la bonne région et choisissez le nom du référentiel.

        Cette commande crée un référentiel appelé PHP. Exécutez-là une fois de plus et remplacez le nom du référentiel par “caddy” (vous pouvez le nommer comme vous le souhaitez, j’ai choisi des noms qui reflètent les conteneurs locaux).

        Pour la partie suivante, il est important de savoir que vous devez étiqueter (tag) vos images Docker d’une manière très spécifique pour pouvoir les valider dans le bon référentiel ECR.

        Pour identifier les noms des conteneurs que nous avons pour ce projet, exécutez : docker images.

        Dans notre cas :

            • migratedockerprojecttoecs_php_1

              • migratedockerprojecttoecs_caddy_1

            Puis, exécutez la commande :

            docker tag <migratedockerprojecttoecs_php_1>:latest <aws_account_id>.dkr.ecr.<region>.amazonaws.com/php

            Assurez-vous de remplacer migratedockerprojecttoecs_php_1 par le nom de votre image de conteneur, aws_account_id par votre identifiant de compte AWS, région par la bonne région et PHP par le nom du référentiel ECR que vous choisissez pour le conteneur PHP.

            Maintenant, répétez cette étape pour le conteneur Caddy.
            La commande est la suivante :

            docker tag <migratedockerprojecttoecs_caddy_1>:latest <aws_account_id>.dkr.ecr.<region>.amazonaws.com/caddy

            Enfin, vous pouvez pousser les images vers ECR, une par une, en utilisant la commande suivante :

                • docker push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/php

              Cette commande pousse le conteneur PHP vers le référentiel PHP sur ECR. Exécutez-la une fois de plus, en remplaçant PHP par le nom du référentiel Caddy. Dans notre cas :

                  • docker push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/caddy

                Maintenant, si vous accédez à ECR dans la console AWS, sous Référentiels (Repositories), vous devriez pouvoir voir les référentiels que vous avez créés. Notez l’URL à côté de chaque référentiel, vous en aurez bientôt besoin.

                Préparation de notre environnement AWS

                Pour cette partie, il est important de noter que Caddy nécessite que vous ayez un nom de domaine pour le configurer. Ainsi, nous allons créer un load balancer (équilibreur de charge) vide et pointer un nom de domaine vers celui-ci. Nous allons ensuite pointer ECS vers cet load balancer. De plus, afin d’activer le https, vous devez disposer d’un certificat TLS disponible pour ce domaine. Vous pouvez en créer un dans Certificate Manager, mais ce guide ne vous expliquera pas comment procéder.

                    • Pour créer votre load balancer : dirigez-vous vers la console EC2 -> load balancers-> create a load balancer-> équilibreur de charge d’application

                  Choisissez ensuite un nom pour votre ALB. Sous Network mapping, assurez-vous de spécifier le bon VPC où se trouve le reste de vos ressources. Pour Security group, assurez-vous de spécifier un groupe de sécurité qui accepte tout le trafic sur les ports 80 et 443.

                  Laissez tout le reste par défaut et cliquez sur Create a load balancer. Attendez maintenant que votre load balancer soit créé, puis : cliquez dessus -> cliquez sur Listeners -> sélectionnez les listeners qui s’y trouvent et supprimez-les.

                  Nous effectuons cette dernière étape car ECS créera automatiquement des listeners et générera une erreur s’ils existent déjà. Enfin, accédez à route 53, choisissez un domaine et faites pointer ce domaine vers votre load balancer. Nous n’expliquerons pas comment procéder dans cet article, car cela sort du cadre de cet article.

                  De docker-compose.yml à un Task définition ECS

                  Dans ce qui suit, nous allons vous montrer comment convertir votre ficher docker-compose en task definition ECS.

                  Dans notre projet, si vous ouvrez le dossier docker-compose.yml, vous trouverez deux services définis : PHP et Caddy. Chacun de ces deux services représente un conteneur et sa configuration. Pour le task definition, vous aurez principalement besoin des volumes, des ports et de l’environnement (variables d’environnement).

                  Sur la console AWS, dirigeons-nous vers ECS -> Task definitions -> Create new task definition.

                  Donnez un nom à votre task definition, puis commençez par le premier conteneur.

                  Pour le conteneur 1, indiquez :

                      • Nom : PHP (ou ce que vous voulez)

                        • URL de l’image : copiez l’URI du référentiel PHP dans ECR

                          • Pour le mappage des ports

                            • Port de conteneur 5432 (si vous utilisez un postgresql)

                              • Protocole TCP

                            Pour les variables d’environnement, copiez celles présentes dans le fichier docker-compose avec ces informations :

                                • DATABASE_URL : insérez ici l’url de base de données de votre base de données. Cela dépendra du type de ressource et de l’endroit où la base est hébergée.

                              Veuillez noter que si votre base de données est également sur un conteneur et que vous souhaitez la déployer dans le task definition, l’URL doit commencer par localhost car les conteneurs de la même définition de tâche communiquent entre eux sur localhost.

                                  • MERCURE_URL : http://caddy/.well-known/mercure

                                    • URL_PUBLIC_MERCURE : https://SERVER_NAME/. well-known/mercure. Avec SERVER_NAME étant le nom de domaine vers lequel vous avez pointé l’équilibreur de charge.

                                      • MERCURE_JWT_SECRET : !ChangeMoi !

                                    Nous devons maintenant créer le conteneur de Caddy. Ajoutez un conteneur et marquez-le comme conteneur essentiel, puis :

                                    Pour le conteneur 2, indiquez

                                        • Nom : caddie

                                          • URL de l’image : lien du référentiel Caddy dans ECR

                                        Pour le mappage des ports :

                                            • Port 80, TCP

                                              • Port 443, TCP

                                                • Port 443, UDP

                                              Pour les variables d’environnement :

                                                  • MERCURE_SUBSCRIBER_JWT_KEY : !Changez-moi !

                                                    • MERCURE_PUBLISHER_JWT_KEY : ! Changez-moi !

                                                      • NOM_SERVEUR : http://SERVER&_NAME. SERVER_NAME étant le nom de domaine vers lequel vous avez pointé l’équilibreur de charge.

                                                    A noter.

                                                    Assurez-vous de spécifier http:// avec le nom du serveur, et pas https. Avec Caddy, si vous spécifiez https, Caddy essaiera de provisionner son propre certificat TLS, ce qui compliquera la mise en place de Caddy derrière un Load balancer. En spécifiant http, l’équilibreur de charge communique avec le serveur Caddy en interne sur http, et les utilisateurs communiquent avec l’équilibreur de charge sur https (le certificat sera attaché à l’équilibreur de charge).

                                                    Ceci est considéré comme une bonne pratique avec AWS car la communication interne entre l’équilibreur de charge et le serveur n’a pas besoin d’être chiffrée.

                                                    Rappel.

                                                    Vous devez mettre en service votre propre certificat dans AWS Certificate Manager pour que cela fonctionne, mais nous n’en parlerons pas dans ce guide car cela dépasse le cadre, mais je préciserai comment lier le certificat au load balancer.

                                                    Remarque.

                                                    Lorsque vous trouvez un format de ${NAME :-something_else} dans docker-compose, vous indiquer à Docker d’utiliser la variable “NAME” si elle est définie, et sinon d’utiliser “something_else” comme valeur par défaut. Nous n’en aurons pas besoin dans notre Task definition car nous savons déjà quelles valeurs nous voulons.

                                                    Maintenant, cliquez sur Suivant.

                                                        • Pour l’environnement d’application, spécifiez AWS Fargate (serverless)

                                                        • Pour le système d’exploitation, choisissez Linux/X86_64

                                                        • Pour Task size, spécifiez les valeurs correspondant aux besoins de votre charge de travail. Pour cet exemple,  on le laisse à 1 vCPU et 3 Go de mémoire

                                                      Sous Stockage, nous allons spécifier nos volumes pour qu’ils correspondent à notre fichier docker-compose.yml.

                                                      Pour le volume php_socket :

                                                          • Appuyez sur Add volume

                                                          • Volume type: Bind mount

                                                          • Volume name: php_socket

                                                          • Cliquez sur add mount point

                                                          • Choisissez conteneur php

                                                          • Container path: /var/run/php

                                                          • Read Only : no

                                                        Si vous regardez attentivement le fichier docker-compose, vous remarquerez que ce volume est également associé au conteneur Caddy, nous devons donc lui ajouter un point de montage.

                                                            • Cliquez sur add mount point

                                                            • Choisissez le conteneur caddy

                                                            • Container path: /var/run/php

                                                            • Read Only : no

                                                          Nous devons maintenant répéter ces étapes pour les volumes restants. Les deux volumes restants se trouvent sous le conteneur Caddy : caddy_data et caddy_config.

                                                          Pour le volume caddy_data:

                                                              • Cliquez sur Add volume

                                                              • Volume type: Bind mount

                                                              • Volume name: caddy_data

                                                              • Cliquez sur add mount point

                                                              • Choisissez le conteneur caddy

                                                              • Container path: /data

                                                              • Read only: no

                                                            Pour le volume caddy_config:

                                                                • Cliquez sur Add volume

                                                                • Volume type: Bind mount

                                                                • Volume name: caddy_config

                                                                • Cliquez sur add mount point

                                                                • Choisissez le conteneur caddy

                                                                • Container path: /config

                                                                • Read only: no

                                                              Cliquez maintenant sur Suivant et Créer.

                                                              Nous y sommes presque ! Il ne reste plus qu’à déployer notre Task definition.

                                                              Déploiement de notre task definition

                                                              Avant de pouvoir déployer sur ECS, nous devons créer un cluster sur lequel effectuer le déploiement.

                                                              Dans ECS, accédez à Clusters -> Create a cluster

                                                                  • Choisissez un nom

                                                                  • Associez le VPC et les Subnets corrects. Assurez-vous de sélectionner les mêmes Subnets du Load balancer que nous avons déployé précédemment

                                                                  • Assurez-vous que sous Infrastructure, seul AWS Fargate est coché

                                                                  • Appuyez sur Create

                                                                Ensuite, cliquez sur le cluster nouvellement créé et sous services, appuyez sur Deploy.

                                                                Dans ECS, un service utilise notre Task definition pour déployer des conteneurs sur ECS.

                                                                    • Pour le type d’application, choisissez Service

                                                                    • Choisissez un nom de service

                                                                    • Pour le Task definition, sous Family, choisissez le nom du Task definition que nous venons de créer

                                                                  Sous Load balancing :

                                                                      • Type de Load balancer : Application Load balancer

                                                                      • Choisissez Use an existing Load balancer

                                                                      • Choisissez le Load balancer que nous avons créé précédemment

                                                                      • Sous Listener, spécifiez le port 443 et le protocole https

                                                                      • Appuyez sur choose from ACM certificates et choisissez le certificat que vous avez créé pour le nom de domaine du serveur. Rappelons que ce guide n’a pas expliqué comment créer un certificat dans AWS Certificate Manager

                                                                      • Pour le target group, choisissez un nom de target group et spécifiez le protocole http

                                                                    Remarque.

                                                                    Comme indiqué précédemment, lorsque les utilisateurs tentent d’accéder au site Web via un nom de domaine, ils sont redirigés vers un Load balancer sur https, et le Load balancer communique en interne avec le serveur sur http. C’est pourquoi nous avons configuré le listener du Load balancer sur https et lui avons associé un certificat, et pourquoi nous avons configuré le target group sur http.

                                                                    Sous Networking, assurez-vous que :

                                                                        • les subnets choisis sont les mêmes que ceux du load balancer et qu’il s’agit de subnets publics

                                                                        • le security group autorise le trafic entrant depuis le security group du load balancer

                                                                        • Assign public IP est activé

                                                                      Autre remarque.

                                                                      Du point de vue de la sécurité, les instances n’ont pas besoin d’une IP publique car elles ne seront accessibles qu’à partir du load balancer. Cependant, nous devons garder à l’esprit que les instances ont besoin d’une connexion Internet pour extraire les images des conteneurs d’ECR et ont également besoin d’une connexion Internet pour télécharger les dépendances et créer les conteneurs.

                                                                      Comme bonne pratique, vous devriez déployer les instances dans un subnet privé avec un NAT Gateway. Étant donné que cela coûterait plus cher et augmenterait la complexité de notre démo, nous ne l’avons pas implémenté ici.

                                                                      Notez également qu’il est possible de créer un VPC endpoint ECR, de sorte qu’ECS peut extraire les images d’ECR sans avoir besoin d’une connexion Internet. La connexion Internet serait toujours nécessaire pour télécharger les dépendances, mais au moins de cette façon, notre facture NAT serait beaucoup plus petite.

                                                                      Maintenant, appuyez simplement sur Deploy et nous avons terminé !

                                                                      Amélioration facultative du load balancer

                                                                      En attendant la fin du déploiement, vous pouvez retourner sur la console EC2 et ajouter un listener http à notre load balancer sur le port 80 pour qu’il redirige le trafic vers https.

                                                                      Allez dans EC2 -> load balancer -> sélectionnez le load balancer -> Listeners -> add listener

                                                                          • Protocole: http

                                                                          • Port: 80

                                                                          • Default action: redirect

                                                                          • Redirect to: https, 443, Original host, status code 301

                                                                        Vous devriez maintenant pouvoir accéder au site Web via le domaine que vous avez choisi sur route 53 avec une connexion https sécurisée.

                                                                        Toutes nos félicitations !

                                                                        Article Précedent

                                                                        Introduction au livre blanc sur la migration cloud durable

                                                                        Article Précedent

                                                                        De nouvelles nominations partout en France pour Daveo

                                                                        Articles associés

                                                                        Shopping Basket