Retour au Blog

Déployer NuxtJs avec Gitlab CI/Cd, sur un S3 avec un CDN Cloudfront

Déployer NuxtJs avec Gitlab CI/Cd, sur un S3 avec un CDN Cloudfront

Cet article va nous permettre de publier un site vueJs ou dans notre cas un site en nuxtJs sur un S3 Amazon, avec un cache CDN sous le nom de CloudFront.Tout ceci de manière automatisée avec Gitlab CI/CD.

La configuration Amazon

Pour ceci, nous allons avoir besoin de 3 choses :

  • un bucket S3 disponible en public
  • un CDN redirigeant vers ce s3
  • un utilisateur IAM pour faire tourner le Gitlab Runner

Le bucket S3

Une fois connecté, vous pouvez aller sur la section S3 > "Créer un compartiment".

  • Nommez-le comme bon vous semble, mais pour example nous allons prendre "nuxt-website-efficience-it", nous lui attribuerons plus tard une variable que l'on nomme AWS_BUCKET_NAME
  • Débloquez tous les accès publics et créez votre Bucket S3.
  • Ensuite vous devez vous rendre sur le bucket dans l'onglet "Propriétés", descendez: "Hébergement de site Web statique" et activez cette option en spécifiant index.html comme point d'accès.
  • Apres, dans l'onglet "Permissions", insérer ce Json dans la "Stratégie de Compartiment" en renommant avec votre nom de bucket.

{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Sid": "PublicReadGetObject",
           "Effect": "Allow",
           "Principal": "*",
           "Action": "s3:GetObject",
           "Resource": "arn:aws:s3:::nuxt-website-efficience-it/*"
       }
   ]
}

{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Sid": "PublicReadGetObject",
           "Effect": "Allow",
           "Principal": "*",
           "Action": "s3:GetObject",
           "Resource": "arn:aws:s3:::nuxt-website-efficience-it/*"
       }
   ]
}

Ainsi vous pourrez cliquer sur le lien spécifié dans votre S3 : voici celui de l'example

http://nuxt-website-efficience-it.s3-website.eu-west-3.amazonaws.com/

Vous devez avoir une erreur 404 vous disant que le fichier racine (index.html) n'existe pas, ce qui est normal.

   404 Not Found
   Code: NoSuchKey
   Message: The specified key does not exist.
   Key: index.html

Je vous invite donc à créer un fichier index.html et y insérer ce que vous souhaitez afin de le déposer à la racine du S3 et vérifier que vous avez bien votre page qui s'affiche.

Le CDN CloudFront

Cloudfront sert en fait, à faire un cache réseau pour votre contenu css, js et html. Nous allons donc le configurer pour gagner en performance et également pour éviter de payer à chaque fois qu'une personne souhaite aller sur le site.

Dans la section CloudFront de votre Console Amazon, vous pouvez

  • créer une distribution
  • attribuer le S3 que vous venez de créer
  • rediriger http vers https
  • et attribuer un nom de domaine, avec son certificat SSL.

Je vous invite à lire de la doc sur le sujet si vous souhaitez aller plus loin et attribuer un nom de domaine, un certificat SSL.

Avant de partir, vous devez récupérer l'identifiant de la distribution que nous mettrons plus tard dans une variable nommmée AWS_CLOUDFRONT_INVALIDATION_ID

L'utilisateur IAM gitlab-runner

Dans votre console toujours, je vous invite à taper IAM, pour ajouter un utilisateur, le 'gitlab-runner'. Vous devrez lui ajouter ces autorisations, à savoir :

  • CloudFrontInvalidation
  • AmazonS3FullAccess

Il faudra ensuite que vous alliez dans "Informations d'identification de sécurité" pour y créer une clés d'accès que nous nommerons AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY.

Ces accès vous permettront d'utiliser l'utilisateur gitlab-runner avec les droits d'accés que nous venons de configurer. Il sera autorisé ainsi à déposer des éléments dans votre S3 et invalider le cache CDN pour que vos prochains visiteurs bénéficient de votre nouveau contenu.

Partons sur la CI/CD, le déploiement automatisé et continu

Une première étape, le build

Afin de générer les fichiers que nous allons pousser sur le S3, nous allons créer une première étape qui est le 'build'. Dans cette étape, nous installons les dépendances, puis nous générons le projet dans un dossier '/dist' qui va être transmis dans ce qu'on appelle un artifact.

C'est un genre de résultat de l'étape que l'on va réutiliser ensuite pour déployer le projet.

La Ci permet également de bénéficier du cache d'un run à l'autre. Ce que nous allons utiliser ici avec /node_modules, afin d'optimiser le temps de déploiement.

stages:
   - build
cache:
   paths:
       - node_modules/

build_site:
   image: node:lts
   before_script:
       - npm install
   script:
       - npm run generate --fail-on-error --quiet --no-optional
   artifacts:
       paths:
           - dist

La seconde étape, le déploiement

Dans celle-ci, nous reprenons l'articfact généré dans l'étape précédente, pour l'envoyer sur notre S3. La deploy part alors d'une machine python, dans lequel, on installe awscli (ce sont des commandes bash pour interagir avec l'API Amazon).

  • Puis nous récupèrons le dossier dist de notre artifact et on le synchronise avec la bucket concerné. Cela va mettre à jour le S3, en supprimant les éléments qui n'y sont plus.
  • Et enfin, nous vidons le cache du CDN.

stages:
   - deploy

variables:
   AWS_DEFAULT_REGION: eu-central-1

deploy_s3:
   image: python:latest
   stage: deploy
   before_script:
       - pip install awscli
   script:
       - aws s3 sync dist s3://${AWS_BUCKET_NAME} --delete --cache-control "max-age=31536000" --expires 2030-01-01T00:00:00Z
       - aws cloudfront create-invalidation  --distribution-id ${AWS_CLOUDFRONT_INVALIDATION_ID} --paths "/*"

Configuration de Gitlab

Pour cela, vous allez devoir configurer les variables qui seront protégées et non visibles dans votre repository.

  • Allez dans "Settings > CI/CD"
  • et dans Variables, vous insérer les clés / valeurs de AWS_CLOUDFRONT_INVALIDATION_ID, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_BUCKET_NAME

Avec ceci, dès que vous ferez un commit/push sur votre gitlab, vous verrez dans votre pipeline, le Build puis le Deploy tourner.

Pour aller plus loin, un déploiement par branche 'dev', 'master' et une branche 'feature/...'  que vous pouvez déployer manuellement

Le principe est de faire un bucket et un CloudFront pour vos environnements de développement et un autre pour votre environnement de production.Selon ce principe, vous avez votre branche master déployé sur la prod et la branche develop sur votre environnement de développement de manière automatisée.

Et enfin, lorsque vous créez une branche avec votre nouvelle feature/etc ou un fix/etc, vous avez un bouton manuel sur votre interface Gitlab qui vous permet de déployer cette branche sur votre environnement de developpement.Et lorsque vous la fusionnerez avec la branche develop lors de votre MR, la branche develop se redéploiera sur votre environnement de développement avant que vous ne mergiez sur la master pour que cela soit déployé en prod.

Le fichier final .gitlab-ci.yml

stages:
   - build
   - deploy
cache:
   paths:
       - node_modules/
.build_site:
   stage: build
   image: node:lts
   before_script:
       - npm install
   artifacts:
       paths:
           - dist

build_site_prod:
   extends: .build_site
   script:
       - npm run generate --fail-on-error --quiet --no-optional
   only:
       - master

build_site_dev:
   extends: .build_site
   script:
       - npm run generate --fail-on-error --quiet --no-optional
   only:
       - dev

build_site_branch:
   extends: .build_site
   script:
       - npm run generate --fail-on-error --quiet --no-optional
   when: manual
   except:
       - master
       - dev

variables:
   AWS_DEFAULT_REGION: eu-central-1

.deploy_s3:
   image: python:latest
   stage: deploy
   before_script:
       - pip install awscli

deploy_s3_branch:
   needs:
       - build_site_branch
   extends: .deploy_s3
   when: on_success
   except:
       - master
       - dev
   script:
       - aws s3 sync dist s3://dev.exemple.com --delete --cache-control "max-age=31536000" --expires 2030-01-01T00:00:00Z
       - aws cloudfront create-invalidation  --distribution-id ${AWS_CLOUDFRONT_INVALIDATION_ID_DEV} --paths "/*"
   environment:
       name: developement
       url: https://dev.exemple.com

deploy_s3_dev:
   needs:
       - build_site_dev
   extends: .deploy_s3
   when: on_success
   only:
       - dev
   script:
       - aws s3 sync dist s3://dev.exemple.com --delete --cache-control "max-age=31536000" --expires 2030-01-01T00:00:00Z
       - aws cloudfront create-invalidation  --distribution-id ${AWS_CLOUDFRONT_INVALIDATION_ID_DEV} --paths "/*"
   environment:
       name: developement
       url: https://dev.exemple.com

deploy_s3_prod:
   extends: .deploy_s3
   only:
       - master
   before_script:
       - pip install awscli
   script:
       - aws s3 sync dist s3://www.exemple.com --delete --cache-control "max-age=31536000" --expires 2030-01-01T00:00:00Z
       - aws cloudfront create-invalidation  --distribution-id ${AWS_CLOUDFRONT_INVALIDATION_ID_PROD} --paths "/*"
   environment:
       name: production
       url: https://www.exemple.com

S'inscrire à la Newsletter

Profitez des news, des nouveaux articles, et des nouveaux posts.

Thanks for joining our newsletter.
Oops! Something went wrong.