Automatisation de la livraison continue dans des conteneurs avec CodeBuild, ECR et CodeDeploy

L'intégration continue/livraison continue (CI/CD) est le processus d'automatisation des mises à jour d'applications, des changements dans le contrôle des sources aux builds automatisés, en passant par les déploiements automatisés sur vos serveurs. AWS fournit un service pour cela, appelé CodePipeline, qui peut être configuré pour fonctionner avec des conteneurs.
Livraison continue dans des conteneurs
Les conteneurs sont un peu plus compliqués que les applications traditionnelles. De nombreuses applications conteneurisées utiliseront en fait deux images de conteneur. La première, appelée image de base, est essentiellement une AMI personnalisée préchargée avec des dépendances et d'autres applications. Ceci est fait pour accélérer les temps de construction, car si vous ne faites que mettre à jour votre code d'application, vous n'avez pas besoin de réinstaller NGINX et tous les autres logiciels sur le conteneur. La deuxième image est l'image réelle de l'application, qui étend l'image de base et contient votre propre code.
Ainsi, le pipeline CI/CD que nous allons mettre en place sera en réalité deux pipelines. Le premier surveillera les changements dans l'image de base et déclenchera une reconstruction et une mise à jour vers ECR lorsque cela se produira. Le deuxième pipeline contiendra deux étapes source : une qui surveille les modifications dans le référentiel ECR de l'image de base et une qui écoute les mises à jour dans le code source de l'image de l'application. De cette façon, si vous ne faites que mettre à jour l'image de l'application, l'image de base n'a pas besoin d'être reconstruite.
Avec deux pipelines, CodePipeline déclenchera les mises à jour d'application de l'une des deux manières suivantes :
- Les modifications apportées à l'image de l'application déclencheront une reconstruction de l'image de l'application, à l'aide de la dernière image de base, qui n'a pas besoin d'être reconstruite. La mise à jour sera transmise à ECR, avec un déploiement facultatif sur ECS ou un autre service de conteneur.
- Les modifications apportées à l'image de base déclencheront une reconstruction de l'image de base, qui déploiera les mises à jour sur ECR. Cela déclenchera à son tour une reconstruction de l'image de l'application, qui sera transmise à ECR, puis à ECS.
Cependant, cette configuration à double pipeline peut ne pas être nécessaire pour toutes les applications, et si vous utilisez simplement une image de système d'exploitation de base prédéfinie comme Ubuntu, vous n'aurez besoin que d'un seul pipeline pour tout gérer.
Configuration du rôle IAM
Tout d'abord, vous devrez configurer un rôle de service pour donner à CodeBuild les autorisations nécessaires pour interagir avec d'autres services AWS (comme ECR) en votre nom. Ouvrez la console de gestion IAM, puis créez un nouveau rôle sous « Rôles ». Choisissez AWS Service et sélectionnez CodeBuild dans la liste.

Pour les stratégies, vous souhaiterez créer une nouvelle stratégie avec les autorisations suivantes :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudWatchLogsPolicy",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"*"
]
},
{
"Sid": "CodeCommitPolicy",
"Effect": "Allow",
"Action": [
"codecommit:GitPull"
],
"Resource": [
"*"
]
},
{
"Sid": "S3GetObjectPolicy",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": [
"*"
]
},
{
"Sid": "S3PutObjectPolicy",
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"*"
]
},
{
"Sid": "ECRPullPolicy",
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": [
"*"
]
},
{
"Sid": "ECRAuthPolicy",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken"
],
"Resource": [
"*"
]
},
{
"Sid": "S3BucketIdentity",
"Effect": "Allow",
"Action": [
"s3:GetBucketAcl",
"s3:GetBucketLocation"
],
"Resource":
"*"
}
]
}
Collez-le sous l'onglet JSON dans l'éditeur de stratégie. Donnez-lui un nom et attachez-le au rôle. Vous voudrez également joindre la stratégie prédéfinie, AmazonEC2ContainerRegistryPowerUser
.

Une fois ces deux stratégies attachées, donnez un nom au rôle et cliquez sur créer.
Configuration du contrôle de code source et de CodeBuild
CodePipeline prend en charge l'extraction des mises à jour de code depuis GitHub, BitBucket et le propre contrôle de source CodeCommit d'AWS. Vous aurez la meilleure expérience en utilisant CodeCommit comme référentiel de version secondaire, mais GitHub fonctionnera très bien. Si vous utilisez GitLab ou un autre fournisseur, vous devrez utiliser CodeCommit pour pousser les mises à jour.
Pour cette étape, vous souhaiterez disposer de deux référentiels différents, un pour votre image de base et un pour votre image d'application. Si vous n'utilisez pas d'image de base personnalisée, vous pouvez ignorer la configuration correspondante.
Pour l'image de base, vous souhaiterez créer un fichier buildspec, essentiellement une liste de commandes que CodeBuild exécutera lors de la création de votre image. Vous pouvez le saisir manuellement lors de la configuration de CodeBuild, mais il est préférable de l'enregistrer dans un fichier appelé buildspec.yml
à la racine de votre référentiel.
Votre configuration exacte peut varier en fonction des exigences de votre application, mais elle devrait ressembler à ceci :
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws --version
- $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
- REPOSITORY_URI=012345678910.dkr.ecr.us-east-1.amazonaws.com/base-image
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $REPOSITORY_URI:latest .
- docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker images...
- docker push $REPOSITORY_URI:latest
- docker push $REPOSITORY_URI:$IMAGE_TAG
Cet exemple se connecte à ECR, définit la balise d'image sur l'ID de build CodeBuild, crée l'image Docker, puis transmet les modifications à votre référentiel ECR. Vous voudrez modifier la déclaration de variable REPOSITORY_URI
pour qu'elle soit l'URI de votre référentiel ECR cible.
Enregistrez-le sous buildspec.yml
et placez-le à la racine de votre référentiel d'images de base et de votre référentiel d'images d'application. Vous pouvez tester votre buildspec en lançant manuellement une génération à partir de la console CodeBuild, ou simplement procéder à la configuration du pipeline et corriger les erreurs qui peuvent survenir.
Configuration du pipeline
Une fois que vous avez votre buildspec en ordre, ouvrez la console CodePipeline et créez un nouveau pipeline pour l'image de base. Donnez-lui un nom et laissez-le créer un nouveau rôle de service. Pour l'étape de contrôle de code source, choisissez le type que vous utilisez, puis sélectionnez un référentiel et une branche. Si vous le souhaitez, vous pouvez configurer une branche supplémentaire pour suivre les versions, et CodePipeline ignorera les modifications apportées au maître.
Pour l'étape de construction, sélectionnez Créer un projet. Cela fera apparaître une boîte de dialogue dans laquelle vous pourrez configurer CodeBuild.

Normalement, vous devez lier CodeBuild à votre contrôle de source, mais cela est géré automatiquement par le pipeline lors de la création d'un nouveau projet de cette façon. Vous devrez configurer l'environnement dans lequel votre build s'exécute. Vous pouvez choisir une image Docker personnalisée, chargée avec tous les programmes requis pour le build, ou vous pouvez les installer manuellement dans la phase de pré-build de votre buildspec.yml
. Si vous n'avez besoin de rien de spécial, vous pouvez sélectionner Amazon Linux 2 et le runtime par défaut, qui est fourni avec la plupart des runtimes de langage de programmation ainsi que Docker préinstallé.

Vous devrez également sélectionner le rôle de service que vous avez créé précédemment :

Enfin, vous pouvez modifier manuellement le nom du fichier buildspec, si vous ne le souhaitez pas dans le répertoire racine de votre source ou si vous avez plusieurs fichiers à différencier. Vous pouvez également insérer manuellement des commandes de construction ici, mais nous vous conseillons de les suivre sous forme de fichier sur git.

Pour l'étape de déploiement, vous voudrez l'ignorer pour l'image de base. Le fichier buildspec créera et transmettra les modifications à ECR, ce qui est tout ce dont vous avez besoin pour cette étape. Vous pouvez tester le pipeline en transmettant les modifications à votre référentiel d'images de base.
Configuration du pipeline d'images d'application
Ensuite, vous allez configurer un pipeline supplémentaire pour votre image d'application. Créez un nouveau pipeline à partir de la console et sélectionnez ECR comme source. Sélectionnez votre référentiel d'images de base et laissez la balise d'image vide, ce qui la mettra par défaut à la plus récente.

Pour l'étape de génération, vous souhaiterez configurer CodeBuild de la même manière que l'étape d'image de base : créez un nouveau projet de génération, sélectionnez l'environnement par défaut et entrez le rôle de service que vous avez créé précédemment.
L'étape de déploiement est facultative. Sans cela, les modifications apportées à l'image de base ou à l'image de l'application déclencheront simplement la reconstruction de l'image de l'application et la transmission des modifications à ECR. Cependant, si vous utilisez ECS pour le déploiement, vous pouvez ajouter une autre étape qui prendra votre image construite et mettra à jour vos serveurs.

Dans tous les cas, cliquez sur créer pour créer le pipeline. Certaines modifications sont nécessaires avant que cela ne fonctionne, alors cliquez sur Modifier sur le pipeline, puis sur Modifier l'étape pour l'étape de contrôle de source :

Dans l'état actuel des choses, l'étage de contrôle de la source tire simplement de l'ECR pour l'image de base. Ceci est nécessaire, mais il a également besoin du code de l'application pour faire quoi que ce soit d'utile et également répondre aux changements dans le code de l'application (pas seulement l'image de base).
Cliquez sur Ajouter une action :

Choisissez CodeCommit (ou un autre contrôle de code source) comme type d'action, puis sélectionnez votre référentiel et votre branche. Pour Output Artifacts, vous devez saisir SourceArtifact
pour indiquer qu'il s'agit du code source de l'application.
Vous voudrez également modifier l'étape ECR pour spécifier que l'artefact de sortie est une Image de base
.

Cela devrait être tout ce dont CodeBuild a besoin pour s'exécuter, et une fois que vous avez mis à jour votre pipeline, il devrait s'exécuter à nouveau, espérons-le sans erreur.

Si vous rencontrez des erreurs, il est probable que votre buildspec pour CodeBuild ne fonctionne pas correctement. Vous pouvez afficher les journaux de génération à partir de la console CodeBuild ou consulter la référence de spécification de génération d'AWS pour plus d'informations sur le fonctionnement de tout cela.