Un site de documentation sous Jekyll, comme github pages

Un site de documentation auto-hébergé, basé sur Jekyll avec un exemple de workflow utilisant des git-hooks serveur.

Un site de documentation sous Jekyll, comme github pages

Vous aimez bien les pages github qui permettent d'avoir des sites static (ie. sans techno server) pour de la présentation de projet ou de la documentation. Seulement vous souhaitez les garder sur un réseaux privé. Nous vous présentons ici une solution en installant Jekyll, un thème sympa, la génération de la doc en PDF et un exemple de workflow pour la mise à jour de la doc.

1/ Installation de Jekyll

Jekyll est un moteur de site statique qui permet d'écrire ses pages en Markdown. C'est aussi le moteur sous le capot des github pages.

Sur votre serveur de publication, nous construisons une image Docker à partir de celle disponible sur le hub et ce afin d'y ajouter quelques libs :

FROM jekyll/jekyll:3.8.5

RUN echo "Install extra libs" \
&& apk --update add build-base ruby-dev \
&& gem install bundler \
&& gem install jekyll-paginate \
&& gem install jekyll-gist \
&& gem install redcarpet

Puis nous lançons l'image construite avec la commande docker build -t goovy/jekyll:1.0 . par ce script:

docker run -d \
	    	--restart=unless-stopped \
  	    	--volume="$PWD/doc-site:/srv/jekyll" \
	    	-e "JEKYLL_ENV=prodcution" \
	    	-p 80:4000 \
		--name doc-site \
  	    	goovy/jekyll:1.0 \
	    	jekyll serve --watch

Testez votre déploiement en allant sur localhost et vous devriez avoir ceci:

2/ Utilisation d'un thème sympa

Il existe plein de thèmes mais celui de idratherbewriting.com est plutôt pas mal et complet: Une topnav pour une navigation principale, un second menu contextuel sur le côté et le contenu au centre. Il explique bien l'installation donc pour faire simple:

  • clonez (ou downloadez) le thème et copiez l'intégralité dans le volume docker (doc-site)
  • supprimez les 2 fichiers Gemfile et Gemfile.lock
  • démarrez l'image docker

et vous devriez avoir ceci :

3/ Un exemple de workflow de travail

Maintenant que le site de la doc est en place, comment ajouter du contenu. L'idée est de maintenir sa doc comme son code (ie. versionné avec git). Dès que la documentation est validée (push dans le remote) nous souhaitons avoir le site à jour. Le problème est que le site est hébergé sur un serveur, que notre doc est écrite sur des postes de travail. C'est là que les git hooks viennent à notre secours (un hook est un crochet appelé par le système sous-jacent, ici git, à des étapes précises).

Résumé du workflow:

Commençons par la droite du schema ci-dessus en configurant la publication automatique. Sur le server d'hebergement de la doc, il faut d'abord créer un répertoire dédié pour le repo git qui contient les scripts des hooks.

// initialize the git repo folder
$ git init --bare doc-repo.git

et vous voila avec le répertoire ci-dessous:

Les hooks sont des scripts se trouvant dans le répertoire "hooks"... Celui qui nous intéresse est le post-receive. Il suffit d'avoir ce fichier ainsi nommé et après un push il sera automatiquement exécuté par git.

Nous copions le code mis à jour dans le répertoire de Jekyll et affichons un message de retour à la personne qui a pushé.

Contenu du fichier post-receive (remplacez les "xxx" par votre chemin) :

#!/bin/bash
#
# Script to copy the push received into the doc-site (production) folder

while read oldrev newrev ref
do
    if [[ $ref =~ .*/master$ ]];
    then
        echo -e "\nMaster ref received.  Deploying master branch to the website in production...i\n"

echo "      _                                _       _           _  "
echo "     | |                              | |     | |         | | "
echo "   __| | ___   ___     _   _ _ __   __| | __ _| |_ ___  __| | "
echo "  / _  |/ _ \ / __|   | | | | '_ \ / _  |/ _  | __/ _ \/ _  | "
echo " | (_| | (_) | (__    | |_| | |_) | (_| | (_| | ||  __/ (_| | "
echo "  \__,_|\___/ \___|    \__,_| .__/ \__,_|\__,_|\__\___|\__,_| "
echo "                            | |                               "
echo "                            |_|                               "


        git --work-tree=/home/xxx/Jekyll/doc-site --git-dir=/home/xxx/Jekyll/doc-repo checkout -f
    else
        echo "Ref $ref successfully received.  Doing nothing: only the master branch may be deployed on this server."
    fi
done

Coté client, il faut ajouter un git remote vers le serveur de publication. Ainsi, lors d'un git push, il va à la fois publier vers le repository central (un gitlag, github, bitbucket...) et vers le serveur Jekyll.

Dans votre répertoire de travail, vous devez avoir une copie du thème précédent. Initialisez git et ajoutez "_site" (version compilée du site) dans le fichier .gitignore.
Ajoutez le remote vers votre repository central. Vous devriez avoir ceci:

Ajoutez un remote vers votre serveur de documentation (localhost dans cet exemple) en push uniquement. On veut publier sur 2 serveurs en même temps mais faire un fetch que du repo central (gitlab dans l'exemple).

Pour ajouter le remote:

// ajoutez l'url déjà présente (bizarre mais sans cela git remplace malgré le --add)
# git remote set-url --add --push origin git@gitlab.com:user/doc-repo.git
// ajoutez la seconde url
# git remote set-url --add --push origin ssh://user@localhost/doc-repo.git

et vous pouvez vérifer avec git-remote -v :

Modifiez ensuite un fichier dans votre répertoire de travail (par exemple le fichier index.md), committez et pushez et vous obtiendrez ce message et le site sera également à jour !

4/ Génération de PDF

Nous utilisons Prince qui utilise des feuilles de styles CSS pour la mise en page et qui sont déjà prise en compte dans notre thème Jekyll.

Il y a aussi des scripts shell pour l'utilisation de Prince mais nous allons les adapter pour les utiliser avec le container. Nous générons le pdf dans un process à part avec une instance différente du site :

  1. pour cela nous stoppons le site
  2. nous démarrons une instance dédiée à la génération du PDF
  3. nous lançons la génération du PDF
  4. nous revenons ensuite sur le site de départ.

L'instance dédiée pour le PDF se lance avec le script suivant:

#!/bin/sh

docker run      -d \
                -v $PWD/doc-site:/srv/jekyll \
                -p 4010:4010 \
                --name doc-site-pdf \
                -e "JEKYLL_ENV=production" \
                goovy/jekyll:1.0 jekyll serve --config _config.yml,pdfconfigs/_config_mydoc_pdf.yml

Pour la génération via PrinceXML, nous devons créer une image docker avec ce Dockerfile

# Container for PrinceXML (tools to generate PDF file)
# Used with Jekyll for the documentation website
FROM ubuntu:16.04
VERSION=prince_12.5-1_ubuntu16.04_amd64.deb
RUN \
        DEBIAN_FRONTEND=noninteractive apt-get update && \
        apt-get install -y wget && \
        wget -q https://www.princexml.com/download/$VERSION && \
        dpkg -i --force-depends $VERSION && \
        apt-get install -yf

# Define default command.
CMD ["prince"]

que nous exécutons ensuite par ce script:

#!/bin/sh

docker run      -it --rm \
                -v $PWD/doc-site:/data \
                --link doc-site-pdf:localhost \
                goovy/princexml \
                prince --javascript --input-list=/data/_site/pdfconfigs/prince-list.txt -o /data/pdf/mydoc.pdf

N'oubliez pas de stopper l'instance dédiée au PDF et de redémarrer celle normale. Il doit être possible de lancer les 2 en même temps et d'automatiser mieux cette partie, ce qui vous fera un bon exercice.