Kevin Gautreau
Développeur Back freelance
Clermont-Ferrand (depuis 2015)
Spécialisé Drupal
Twitter / Github : @Kgaut
Mail : contact@kgaut.net
Accessible sur : https://slides.kgaut.net/node/16
But : construire toute une ci pour un projet
Autre chose ?
Mettre sous gestionnaire de version
Système de gestion de version à la mode.
Développé à l'origine par Linus Torvalds.
Démocratisé par Github.
Création d'un dépo : git init
** Code **
Création d'une version :
git commit
** Code **
Création d'une nouvelle version :
git commit
...
Copies locale ou distante du dépot, permettant de travailler à plusieurs
git remote add origin chemin/vers/remote
récupération d'un dépot distant
git clone chemin/vers/remote
Remotes possible : github, gitlab, dossier local / réseau...
Fichier à placer à la racine du dépot ou dans un sous-dossier
Contenant les dossiers / fichiers à ne pas versionner (images, fichiers de config, css...)
db/*.sql
web/uploads
web/sites/default/settings.php
Comment organiser son dépot pour gérer les cas ?
N'est pas une vérité absolue, à adapter en fonction du fonctionnement de l'entreprise et de l’environnement du projet
https://www.atlassian.com/fr/git/tutorials/comparing-workflows/gitflow-…
Solution SASS
Solution auto-hébergée
Repo publics gratuits, privés payants.
Automatiser la construction d'une "build"
Github + Travis CI (https://travis-ci.org/)
Plus récement : Github Actions
Attention : Gitlab utilise déjà ces hooks pour fonctionner, ne pas les modifier ! utiliser les "custom_hooks"
https://kgaut.net/blog/2015/les-hooks-git-et-comment-automatiser-son-workflow.html
Admin / Overview / Runners
sudo gitlab-runner register --url https://gitlab.kgaut.net/ --registration-token $REGISTRATION_TOKEN
En fonction du type :
Pensez à cocher « Indicates whether this runner can pick jobs without tags » dans les paramètres du runner pour les runners secondaires (docker ?)
Défini le comportement.
stages:
- deploy
prod-deployment:
stage: deploy
script:
- ssh slides_kgaut_net@slides.kgaut.net 'bash -s' < scripts/prod-deployment.sh
rules:
- if: $CI_COMMIT_BRANCH == "master"
mail:
script: "echo 'coucou' | mail -s 'test email' contact@kgaut.net"
variables: DESTINATAIRE: 'contact@kgaut.net' mail: script: "echo 'coucou' | mail -s 'test email' $DESTINATAIRE"
Settings > CI / CD / Variables
variables:
PROJECT_NAME: 'MonSite.com'
PROJECT_SHORTNAME: 'monsite'
DB_PATH: 'db'
DRUSH_EXEC: 'drush'
DIFFS_PATH: 'files/diffs'
PREPROD_URL: 'preprod.monsite.com'
PREPROD_DRUSH_ALIAS: '--uri="preprod.monsite.com"'
PREPROD_DRUSH_ROOT_ARG: '--root="/var/www/html/preprod.monsite.com" --uri="preprod.monsite.com"'
PREPROD_EMAIL_ALERT: 'contact+montsite-preprod@kgaut.net'
PREPROD_USER: 'admin'
PREPROD_IP: 'preprod.monsite.com'
PREPROD_SSH: 'ssh admin@preprod.monsite.com'
PREPROD_PROJECT_ROOT: '/var/www/html/preprod.monsite.com'
mail:
script: "echo 'coucou' | mail -s 'test email' contact@kgaut.net"
mail2:
script: "echo 'coucou' | mail -s 'test email 2' contact+test@kgaut.net"
mail:
script: "echo 'push sur master' | mail -s 'push sur master' contact@kgaut.net"
rules:
- if: $CI_COMMIT_BRANCH == "master"
mail2:
script: "echo 'coucou' | mail -s 'push une branche' contact+test@kgaut.net"
Groupement de jobs qui seront exécutés en parallèle.
Les noms des stages sont libres
Si plusieurs étapes, alors l'étape N+1 ne sera lancée que si l'étape N s'est correctement exécutée.
NB : la clé allow_failure : true
permet de ne pas impacter la suite au niveau d'un job
stages:
- etape_1
- etape_2
mail_admin:
script: "echo 'push sur master' | mail -s 'push sur master' contact@kgaut.net"
stage: etape_1
rules:
- if: $CI_COMMIT_BRANCH == "master"
fail:
script: "lorem"
stage: etape_1
mail_2:
script: "echo 'coucou' | mail -s 'push une branche' contact+test@kgaut.net"
stage: etape_2
Ensemble du process de déploiement
Au push :
Genérer une clé SSH :
sudo -u gitlab-runner -H ssh-keygen -t ed25519 -C "gitlab-runner@gitlab.moi.com"
Ajouter la clé au trousseau du serveur distant
sudo -u gitlab-runner -H ssh-copy-id user@serveur
Note : Il peut être pratique d'ajouter cette clé dans /etc/skel/.ssh/authorized_keys
.
Tester
sudo -u gitlab-runner -H ssh user@serveur
Il faut aussi que notre serveur puisse se connecter au dépôt git
Génération d'une clée :
ssh-keygen -t ed25519 -C "prod@monsite.com"
cat ~/.ssh/ed25519.pub
Ajout de cette clé aux clés de déploiements du dépôt.
Script bash qui sera executé sur le serveur distant :
ssh user@serveur 'bash -s' < scripts/prod-deployment.sh
#!/bin/bash
set -e
cd ~/httpdocs
git pull
composer install --no-dev
~/vendor/bin/drush deploy
Au push :
ssh-keygen -t ed25519 -C "monsite.prod"
cat /home/user/.ssh/id_ed25519.pub
On passe cette clé en variable gitlab : SSH_PRIVATE_KEY
backup prod:
before_script:
- apt-get update -qq
- apt-get install -qq git
# Setup SSH deploy keys
- 'which ssh-agent || ( apt-get install -qq openssh-client )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$SSH_PRIVATE_KEY")
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
stage: backup
script:
- $SSH_CHAIN "$PROJECT_ROOT/$DRUSH_EXEC --root=\"$PROJECT_ROOT\" sql-dump --gzip > \"$PROJECT_ROOT/files/dumps/`date +%Y-%m-%d_%H-%M-%S`-$PROJECT_URL-PRE-$CI_COMMIT_TAG.sql.gz\""
rules:
- if: '$CI_COMMIT_TAG =~ /^\d+.\d+.\d+/'
Via clée tags
prod assets generation:
stage : Deploy
tags:
- docker
image: kgaut/node:14
script:
- cd ./web/themes/custom/enise
- npm ci
- gulp build --production
- ls -al ./dist
extends:
- .prod-assets
artifacts:
paths:
- ./web/themes/custom/enise/dist
expire_in: 20 minutes
prod assets generation:
tags:
- docker
image: kgaut/node:14
script:
- cd ./web/themes/custom/enise
- npm ci
- gulp build --production
- ls -al ./dist
stage : Deploy
rules:
- if: '$CI_COMMIT_TAG =~ /^\d+.\d+.\d+/'
environment:
name: prod
generate_assets:
stage: postdeploy
image: node:10.15.2
script:
- node -v
- npm install -g gulp
- npm install --silent
- gulp build
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE != "schedule"
changes:
- web/themes/mon_theme/src/assets/css/**/*.scss
- web/themes/mon_theme/src/assets/js/**/*.js
https://kgaut.net/snippets/2019/gitlab-ci-ne-lancer-une-tache-que-lorsq…
prod deploy:
script:
- $SSH_CHAIN 'bash -s' < ./files/gitlab/scripts/deploy.sh $PROJECT_ROOT $DRUSH_ALIAS $DRUSH_EXEC $CI_ENVIRONMENT_NAME $CI_COMMIT_TAG $CI_COMMIT_SHORT_SHA
stage: Deploy
rules:
- if: '$CI_COMMIT_TAG =~ /^\d+.\d+.\d+/'
environment:
name: prod
#!/bin/bash
set -e
PROJECT_ROOT="$1"
PROJECT_DRUSH_ALIAS="$2"
DRUSH_EXEC="$3"
CI_ENVIRONMENT_NAME="$4"
CI_COMMIT_SHORT_SHA="$6"
cd "$PROJECT_ROOT"
if [ $CI_ENVIRONMENT_NAME = "prod" ]
then
TAG="$5"
git fetch --tags
git checkout "$TAG"
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" sset environment_indicator.current_release "$TAG"
else
BRANCH="$5"
git pull origin "$BRANCH"
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" sset environment_indicator.current_release "preprod-$CI_COMMIT_SHORT_SHA"
fi
composer install --no-dev
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" cr
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" updb --no-post-updates -y
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" cim -y
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" updb -y
$DRUSH_EXEC "$PROJECT_DRUSH_ALIAS" cr
generate_assets:
stage: deploy
image: node:10.15.2
script:
- node -v
- npm install -g gulp
- npm install --silent
- gulp build
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE != "schedule"
changes:
- web/themes/mon_theme/src/assets/css/**/*.scss
- web/themes/mon_theme/src/assets/js/**/*.js
artifacts:
paths:
- ./web/themes/custom/enise/dist
expire_in: 20 minutes
prod assets deploy:
stage: postdeploy
script:
- ls -alh ./web/themes/custom/enise/dist
- rsync -avhzi --delete --stats ./web/themes/custom/enise/dist -e ssh $SSH_USER@$SSH_HOST:$PROJECT_ROOT/web/themes/custom/enise
- $SSH_CHAIN "$DRUSH_EXEC $DRUSH_ALIAS cr"
extends:
rules:
- if: '$CI_COMMIT_TAG =~ /^\d+.\d+.\d+/'
environment:
name: prod
.prod:
rules:
- if: '$CI_COMMIT_TAG =~ /^\d+.\d+.\d+/'
environment:
name: prod
prod deploy:
script:
- $SSH_CHAIN 'bash -s' < ./files/gitlab/scripts/deploy.sh $PROJECT_ROOT $DRUSH_ALIAS $DRUSH_EXEC $CI_ENVIRONMENT_NAME $CI_COMMIT_TAG $CI_COMMIT_SHORT_SHA
stage: Deploy
extends:
- .prod
On peut extends plusieurs règles, et surcharger même des clés dans la définition initiale
include:
- local: '/files/gitlab/extends.yml'
- local: '/files/gitlab/jobs-backup.yml'
- local: '/files/gitlab/jobs-diff.yml'
- local: '/files/gitlab/jobs-deploy.yml'
- local: '/files/gitlab/jobs-postdeploy.yml'
- local: '/files/gitlab/jobs-scheduled.yml'
Crontab :
05 0 * * * gitlab-backup create BACKUP=dump GZIP_RSYNCABLE=yes
Dossiers à sauvegarder :
/etc/gitlab #fichiers avec les clés de chiffrements gitlab-secrets.json + config (gitlab.rb)
/var/opt/gitlab # dossier backups contenant les backups générés
/opt/gitlab # Ceinture et bretelle
CF : https://docs.gitlab.com/ee/raketasks/backup_restore.html