Partage

'Icône Linkedin 'Icône Twitter 'Icône Facebook

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

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 configuré sur ce s3
  • un utilisateur IAM pour 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, prenons "nuxt-website-efficience-it", nous le nommerons AWS_BUCKET_NAME
  • Débloquez tous les accès publics et créez votre Bucket S3.
  • Ensuite allez sur le bucket puis 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"
{
    "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'exemple

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 nommons 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

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 etre 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. Nous plaçons également le '/node_modules' en cache 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 d'avant, 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 on récupère le dossier dist de notre artifact et on le synchronise avec la bucket concerné.
  • et on vide 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 ou un fix, 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

Poursuivez votre lecture sur ce(s) sujet(s) :