Tutoriel : Déployer un site web en SSH avec Github Actions

Déployer un site web en ssh avec Github Actions.

Dans ce tutoriel, nous allons apprendre à créer une pipeline de déploiement en utilisant les Github Actions. L'objectif est de comprendre leur fonctionnement avec un exemple concret et facile à mettre en place.

Commençons avec un peu de théorie pour mieux comprendre les Github Actions et leur fonctionnement.

Qu'est ce que Github Actions ?

Github Actions est un plateforme dédiée à l'intégration et au déploiement continue. Elle nous permet de créer des workflows pour construire (build), tester et déployer des services web.

Les workflows sont déclenchés suite à un événement, par exemple un push sur la branche master, et sont construits avec un ou plusieurs jobs. Chaque job est une machine virtuelle indépendante qui peut être exécuté en parallèle avec d'autres jobs ou de manière séquentielle.

Une action est une application personnalisée pour la plateforme Github qui exécute une tâche fréquemment répété. Il est possible de développer ses propres Github Actions mais on peut aussi en retrouver sur le Github Marketplace.

Pour notre tutoriel, nous nous contenterons d'utiliser des actions présentes sur le Marketplace.

Il est important de noter que Github n'est pas le seul outil permettant de créer des workflows d'intégration continue et que, par exemple, Gitlab propose un outil similaire.

Maintenant que nous savons ce que sont les Github Actions et ce qu'elles nous permettent de faire, nous allons voir comment développer un petit workflow CI/CD qui s'occupera de build un petit projet Nuxt puis de le déployer sur un serveur Nginx (Le principe est exactement le même pour tout type de serveur).

Pre-requis

  • Serveur avec des accès SSH (Par exemple un droplet DigitalOcean)
  • Un compte Github
  • Un projet Web (nous utiliserons un projet Nuxt pour notre exemple)

Exemple : Déployer son projet avec Github actions sur un serveur en SSH

Pour commencer, nous allons créer le fichier dans lequel nous allons écrire notre workflow Github Actions.

A la racine de notre projet, nous allons créer un dossier .github/workflows . Ensuite, on ajoute un fichier ci.yml

  • A noter ! le nom du fichier n'a pas d'importance dans notre cas

Instancier un workflow Github actions

Pour commencer, nous allons ajouter la propriété on. Elle nous permet de décrire l’événement déclencheur de notre pipeline. Pour notre exemple, nous souhaitons que le workflow soit déclenché lorsque nous effectuons un push sur la branche master. Elle existe d'autres événements permettant de déclencher un workflow Github que vous pouvez retrouver dans la documentation officielle.

Nous allons aussi ajouter la propriété name qui permet simplement d'afficher un nom sur l'interface Github.

name: Project Deployement

on:
  push:
    branches: [ master ]

Ajouter un job Github

La suite de notre script va se découper en 2 parties (job). Notre premier job sera dédié et build du projet afin de créer le bundle final. Notre second job sera dédié au déploiement de notre bundle sur le serveur.

Nous allons donc ajouter à notre fichier notre nouveau job :

...
jobs:
	build:
		runs-on: ubuntu-latest
  • Le nom de notre jobbuild n'as pas d'importance

Un job est une machine virtuelle qui est construite à la volée afin de pouvoir lancer nos commandes et réaliser différentes actions. Il faut donc lui définir un environnement de travail, ici ubuntu-latest. Il est possible de travailler avec d'autres environnements comme windows ou mac-os.

Build notre projet Nuxt avec Github Action

On y arrive enfin, nous allons utiliser notre première Github Action.

La première action que nous souhaitons faire, c'est récupérer notre code depuis notre dépôt Git. Github nous fournit pour cela une action actions/[email protected] . Celle-ci va cloner notre projet dans notre job.

On définit notre première step avec la propriété name et on utilise la Github Action avec uses.

Notre seconde step nous permettant de générer le bundle utilise la propriété run qui nous permet de lancer une commande dans notre runner Ubuntu. Dans notre cas, nous installons les dépendances du projet avec yarn puis nous générons notre bundle avec yarn generate.

...
steps:
	 - name: Download project from git
     uses: actions/[email protected]

   - name: Build project     
	   run: |
       yarn
       yarn generate

A ce stade, notre projet est fonctionnel et nous allons pouvoir le tester avec Github. Youhou !!

Lancer notre premier workflow Github

Comme nous l'avons vu précédemment, nous avons défini comme événement déclencheur un push sur la branche Master. On sait donc ce qu'il nous reste à faire ;)

Une fois notre push réalisé, on peut se rendre sur la page du projet dans l'onglet Actions et nous devrions voir apparaître quelque chose comme :

Interface Github Actions avec le résumé des workflows
Interface Github Actions avec le résumé des workflows

Notre premier workflow Github a démarré !!

Si la pastille jaune est rouge de votre côté, c'est qu'il y a certainement une erreur dans le script. Vérifiez bien l'indentation de votre fichier et que vous n'avez oublié aucune étape.

  • En cliquant sur le workflow en cours, vous pouvez voir le détail de chaque ligne exécutée par le script.

Utiliser un artifact pour partager des données entre nos jobs

Maintenant que notre bundle est généré et prêt pour la production, nous allons pouvoir le déployer. Mais avant toute chose, il va falloir partager notre bundle à notre job de déploiement. En effet, un job est une machine virtuelle construite à la volée et ne partage donc pas ses ressources avec les autres jobs.

C'est la qu'intervient notre deuxième Github Action : action/[email protected].

L'artifact est comme un dossier sur le cloud où notre job build va envoyer le bundle et où notre job deploy le récupérera.

Schema d'explication d'un artifact
Schema d'explication d'un artifact

On créé une deuxième step toujours avec les propriétés uses et name. Puis on précise avec la propriété with le nom que l'on souhaite donner à notre artifact ainsi que le chemin du dossier que l'on souhaite sauvegarder.

...
  - name: Download project as artifact
    uses: actions/upload-[email protected]
    with:
      name: bundle
      path: ./dist
  • Le nom de l'artifact est important car c'est la référence au dossier que nous sauvegardons.

Notre premier job est terminé. Nous pouvons de nouveau faire un push sur master afin de tester notre script.

Détail d'un workflow Github Actions
Détail d'un workflow Github Actions

Une fois notre workflow terminé, notre interface Github devrait ressembler à la capture ci-dessus. On y retrouve notre fichier ci.yml avec notre job build qui s'est bien déroulé et en dessous, notre artifact.

Déployer notre projet en SSH avec Github Actions

Pour notre deuxième job, on n'oublie pas les acquis et on reprend la même structure que le premier à une petite différence : le propriété needs.

...
deploy:
     runs-on: ubuntu-latest
     needs: build

Ici, on précise que notre job a besoin du job build pour fonctionner. deploy sera alors lancé uniquement lorsque build sera terminé.

Tout d'abord, on va utiliser l'action actions/[email protected] afin de télécharger notre bundle dans notre runner Github. Avec with, comme pour l'upload, on précise le nom de l'artifact ainsi que le chemin où l'on souhaite importer notre dossier.

...
steps:
   - name: Download artifact
     uses: actions/download-[email protected]
     with:
	     name: bundle
       path: ./dist

Enfin, notre deuxième et dernière step est pour déployer notre projet en SSH. Pour ce faire, nous allons utiliser l'action easingthemes/[email protected]. Pour fonctionner cette Github Action a besoin de certains paramètres que vous pouvez retrouver dans leur documentation.

Les trois variables d'environnements SSH_PRIVATE_KEY, REMOTE_HOST et REMOTE_USER sont requises et varient évidemment en fonction de votre fournisseur et de votre clé SSH générée.

La variable SOURCE définie le chemin du dossier qui doit être envoyé sur le serveur et TARGET son chemin sur le serveur.

...
	 - name: Deploy project with SSH
     uses: easingthemes/ssh-[email protected]
     env:
	     SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
       REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
       REMOTE_USER: ${{ secrets.REMOTE_USER }}
       SOURCE: "dist"
       TARGET: "~/"

Afin de définir nos variables d'environnements, il faut se rendre dans les paramètres de notre projet Github (Settings > Secrets). On appuie ensuite sur le bouton New repository secret et on peut ajouter nos trois variables d'environnement (SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER)

Interface des variables d'environnement Github
Interface des variables d'environnement Github

Pour rappel :

  • SSH_PRIVATE_KEY: correspond à la clé privée SSH que vous avez généré qui commence par '——-BEGIN OPENSSH PRIVATE KEY———'
  • REMOTE_HOST: correspond à votre host, une adresse ip par exemple.
  • REMOTE_USER: correspond à l'utilisateur vous permettant de vous connecter à votre serveur.

Vous n'avez plus qu'à push sur la branche master. Et c'est partiiii !!

À la fin du build et du déploiement, vous devriez retrouver l'interface de Github Actions avec quelque chose de similaire à l'image ci-dessous. On retrouve nos deux jobs : build et deploy et notre artifact bundle.

Détail d'un workflow réussi
Détail d'un workflow réussi

Si vous vous rendez sur votre serveur, vous devriez retrouver votre dossier /dist.

Conclusion

Dans ce tutoriel, nous avons découvert la plateforme Github Actions qui permet de créer des workflow d'intégration. Nous avons vu comment déployer simplement un site web sur un serveur de production avec pour exemple un projet Nuxt. Le script présenté dans ce tutoriel et évidemment adaptable à d'autres Framework front et des sites web classique.

Github Actions nous offre beaucoup d'autres possibilités actions pour améliorer nos workflows en intégrant, par exemple, des tests unitaires ou des tests d'intégrations.

Vous pouvez retrouver l'intégralité du projet sur mon github.

Et pour finir, voici le script dans sa totalité :

name: Project Deployment

on:
  push:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Download project from git       
        uses: actions/[email protected]
      
      - name: Build project
        run: |
          yarn
          yarn generate

      - name: Download project as artifact
        uses: actions/upload-[email protected]
        with:
          name: bundle
          path: ./dist

  deploy:
    runs-on: ubuntu-latest
    needs: build

    steps:
      - name: Download artifact
        uses: actions/download-[email protected]
        with:
          name: bundle
          path: ./dist

      - name: Deploy project with SSH
        uses: easingthemes/ssh-[email protected]
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          SOURCE: "dist"
          TARGET: "~/"

Apprenez à programmer avec des exemples simples et concrets.

English / Français