Aller au contenu principal

Déployer l’application sur une VM avec Docker Compose (CD)

Description générale
Passer de la CI à la CD en orchestrant le déploiement automatisé de l’application Flask + Redis sur une machine virtuelle via un job spécifique dans GitLab CI.


Déploiement automatisé de l’application avec Docker Compose

Description générale
L’objectif est d’automatiser la mise à jour du Docker Compose sur un serveur cible. On utilisera un script bash qui clone ou met à jour le dépôt, puis relance Docker Compose si le fichier est modifié.


Etape 0 : Ajouter le docker compose au dépôt

Attention : pensez à mettre le registry de Gitlab dans l'image du service.


Etape 1 : Créer un lien entre le serveur cible et GitLab

  • Action : Générer un Deploy Token dans GitLab pour permettre l’accès au dépôt via Settings > Repository > Deploy tokens
  • Observation : Le mot de passe pour authentifier les actions Git est affiché et on peut faire un git pull depuis le serveur avec git clone https://USER:PASS@gitlab.company.com/GROUP/PROJECT
  • Contraintes :
    • Nom du token : "gitlab+deploy-token"
    • Date d'expiration : sans
    • Scopes : read_repository + read_repository

Etape 2 : Créer un script sur le serveur qui clone ou pull le code

  • Action : Sur la VM (ou serveur cible), écrire un script bash qui :
    1. Vérifie si le répertoire du projet existe.
    2. Fait un git clone s’il est absent, ou un git pull s’il est présent.
  • Observation : Le script doit utiliser le Deploy Token pour s’authentifier.
  • Contraintes :
    • Le dossier est /home/stagiaire/myproject
    • Le script est deploy.sh
    • Stocker l’utilisateur et le mot de passe du Deploy Token dans un fichier d'environnement .env
    • Utiliser la commande git ex: git clone https://USER:PASS@gitlab.company.com/GROUP/PROJECT

Etape 3 : Redémarrer Docker Compose si le fichier a changé

  • Action : Dans le même script, comparer si le docker-compose.yml a été modifié après un pull.
  • Observation : Relancer Docker Compose uniquement si des changements sont détectés.
  • Contraintes :
    • Utiliser git show --pretty="" --name-only | grep 'docker-compose.yml' pour détecter un changement récent du fichier
    • Utiliser docker-compose pull pour télécharger les nouvelles images d'abord.
    • Utiliser docker-compose up -d --remove-orphans pour recharger les services.

Etape 4 : Créer une clé SSH sur le serveur

  • Action : Gérer une clé SSH pour permettre au pipeline GitLab d’exécuter le script à distance.
    Utilisez ssh-keygen -t ecdsa
  • Observation : La clé privée et la clé publique sont crées
  • Contraintes :
    • Générer la clé sans mot de passe
    • Ajoutez le contenu de la clef publique dans le fichier /home/stagiaire/.ssh/authorized_keys

Etape 5 : Créer une variable GitLab pour la clé privée

  • Action : Ajouter la clé privée au projet GitLab (Settings > CI/CD > Variables).
  • Observation : La clef apparaît dans la liste des variables du projet
  • Contraintes :
    • Nom de la variable : GITLAB_SSH_KEY
    • Protéger cette variable pour éviter qu’elle ne soit exposée dans les forks ou branches non protégées.

Etape 6 : Modifier le fichier de CI pour faire de la CD

  • Action : Créer dans .gitlab-ci.yml un nouveau stage pour le déploiement et un job nommé qui l'utilise.
  • Observation : Le job est lancé après le build Docker et les tests
  • Contraintes :
    • Nom du stage : deploy
    • Position du stage : après les autres
    • Nom du job : compose
    • Image docker : alpine:latest
    • Le job “deploy” ne s’exécute que sur la branche principale (ex. only: [main]).
    • Script : apk add --no-cache openssh-client"

Etape 7 : Appeler le script bash de mise à jour en SSH

  • Action : Ajouter au job une clef SSH locale et exécuter une commande ssh pour lancer le script d’update sur le serveur.
  • Observation : Le script va cloner/pull puis relancer Docker Compose si nécessaire.
  • Contraintes :
    • Créer des variables CICD:
      • SSH_USER : formateur
      • SSH_SERVER : ip du serveur
    • Créer un fichier /tmp/id_ecdsa qui contient la clef privée de la variable $GITLAB_SSH_KEY
    • Changer les droits du fichier avec chmod 600
    • Utiliser les options suivantes pour ssh :
      • -o StrictHostKeyChecking=no pour ne pas vérifier l’empreinte du serveur
      • -i /tmp/id_ecdsa pour utiliser la clef privée
    • Appeler le script distant /home/stagiaire/myproject/deploy.sh avec la commande ssh utilisant les variables, et les diverses options.

Solution

Afficher

Exemple de script bash sur le serveur (deploy.sh)

#!/usr/bin/env bash

# source .env
PROJECT_DIR="/home/stagiaire/myproject"
DEPLOY_USER="gitlab+deploy-token-12345"
DEPLOY_PASS="super-secret-password"
GIT_REPO="https://${DEPLOY_USER}:${DEPLOY_PASS}@gitlab.com/mygroup/myproject.git"

if [ ! -d "$PROJECT_DIR" ]; then
git clone "$GIT_REPO" "$PROJECT_DIR"
cd "$PROJECT_DIR"
else
cd "$PROJECT_DIR"
git pull
fi

# Vérifier si docker-compose.yml a changé
CHANGED=$(git diff HEAD@{1} HEAD --name-only | grep 'docker-compose.yml' || true)
if [ "$CHANGED" != "" ]; then
docker-compose up -d --remove-orphans
fi

#! /usr/bin/env bash
source .env
PROJECT_DIR="/home/stagiaire/myproject"
DEPLOY_USER="gitlab+deploy-token-12345"
DEPLOY_PASS="super-secret-password"
PROJECT_GROUPE="uptimeformation"
PROJECT_NAME="testci"
GIT_REPO="https://${DEPLOY_USER}:${DEPLOY_PASS}@gitlab.company.com/$PROJECT_GROUPE/$PROJECT_NAME.git"

if [ ! -d "$PROJECT_DIR/$PROJECT_NAME" ]; then
cd "$PROJECT_DIR"
git clone "$GIT_REPO" "$PROJECT_NAME"
cd "$PROJECT_DIR/$PROJECT_NAME"
else
cd "$PROJECT_DIR/$PROJECT_NAME"
git pull
fi

# Vérifier si docker-compose.yml a changé
CHANGED=$(git show --pretty="" --name-only | grep 'docker-compose.yml' || true)
if [ "$CHANGED" != "" ]; then
docker-compose pull
docker-compose up -d --remove-orphans
fi

Exemple .gitlab-ci.yml

stages:
- build
- test
- deploy

...


compose:
stage: deploy
only:
- main
image: alpine:latest
services:
- docker:dind
before_script:
- apk add --no-cache openssh-client
# On écrit la clé privée stockée dans la variable GITLAB_SSH_KEY
- echo "$GITLAB_SSH_KEY" > /tmp/id_ecdsa
- chmod 600 /tmp/id_ecdsa
script:
- ssh -o StrictHostKeyChecking=no -i /tmp/id_ecdsa $SSH_USER@$SSH_SERVER "bash /home/stagiaire/myproject/deploy.sh"