Les répertoire persistants
Pour des modifications des fichiers Ghost qui survivent à la recréation de conteneur (Stateful), l'équipe de Ghost conseille de faire un bind mount du répertoire /var/lib/ghost/content.
Ainsi, quand vous ajoutez du contenu à votre blog, ce contenu sera en fait écrit sur l'hôte. Si le conteneur vient à être effacé, ou recréé, le contenu est toujours là. Il peut même être sauvegardé à partir de l'hôte. Ghost appelle ça un répertoire Stateful, et Docker appelle ça un répertoire Persistent. Plusieurs façons de faire du persistent, dont le fameux répertoire Bind Mount.
Exemple du Bind Mount conseillé par Ghost :
/data/ghost/main:/var/lib/ghost/content
Cela signifie que le répertoire /data/ghost/main
sur l'hôte sera /var/lib/ghost/content
dans le conteneur.
Dans le docker-compose.yml
servant à créer votre conteneur, cela se traduit par la configuration suivante :
(...)
volumes:
- /data/ghost/main:/var/lib/ghost/content
(...)
Problème du répertoire par défaut Casper
Le problème, c'est que le thème par défaut Casper n'est pas installé dans ce répertoire.
En effet, dans /var/lib/ghost/content
(votre répertoire persistent côté conteneur), le répertoire themes/casper
est en fait un lien symbolique vers /var/lib/ghost/current/content/themes/casper
, qui lui n'est pas un répertoire bind mount partagé avec l'hôte.
Constatons.
Dans le conteneur :
root@7555949f3798:~# ls -lh /var/lib/ghost/content/themes/casper
lrwxrwxrwx 1 node node 44 May 17 19:52 /var/lib/ghost/content/themes/casper -> /var/lib/ghost/current/content/themes/casper
root@7555949f3798:~#
Même répertoire dans l'hôte :
# ls -lh /data/ghost/main/themes/casper
lrwxrwxrwx 1 ubuntu ubuntu 44 May 17 21:52 /data/ghost/main/themes/casper -> /var/lib/ghost/current/content/themes/casper
# ls /var/lib/ghost/current/content/themes/casper
ls: cannot access '/var/lib/ghost/current/content/themes/casper': No such file or directory
Illustration du problème
Cela ne pose de problème si vous ne désirez pas modifier ce thème par défaut.
En revanche, quand vous voulez (par exemple) ajouter la possibilité à vos lecteur de laisser des commentaires, il faut aller trifouiller le code du thème.
Vous modifiez ainsi /var/lib/ghost/current/content/themes/casper/post.hbs
. Ca marche, c'est magnifique.
Sauf qu'à la prochaine recréation de votre conteneur, ces modifications ont disparu.
En effet, le répertoire /var/lib/ghost/current/content/themes/casper/
est simplement recréé à partir de l'image du conteneur.
NB : Notons que le problème n'existe pas pour des thèmes ajoutés, qui seront installés directement dans /var/lib/ghost/content
.
Solution
Pour avoir des fichiers Casper qui survivent à la destruction, vous avez ainsi deux options :
- Supprimer le lien symbolique
/var/lib/ghost/content/themes/casper
et créer deux bind mounts :- Le bind mount d'origine :
/data/ghost/main:/var/lib/ghost/content
- Et un bind mount pour Casper :
/data/ghost/casper:/var/lib/ghost/content/themes/casper
- Cette solution est sale : vous vous retrouvez avec un bind mount à l'intérieur d'un autre bind mount. Même si en théorie ça marche, ça pourrait sans doute vous créer une arborescence qui pointe vers elle-même. Cela risque de créer un trou noir qui aspirerait tout autour, jusqu'à l'Internet lui-même.
- Créer un bind mount de la cible du lien symbolique et laisser le symlink faire son travail :
- Le bind mount d'origine :
/data/ghost/main:/var/lib/ghost/content
- Et un bind mount pour la cible du symlink Casper
/var/lib/ghost/current/content/themes/casper
:
/data/ghost/casper:/var/lib/ghost/current/content/themes/casper
Mise en oeuvre de la solution
Avec le conteneur Ghost démarré (dont le nom est ici acme_ghost_prod
) :
- Sur l'hôte : copiez le répertoire Casper (qui n'existe que dans le conteneur) vers l'hôte :
cd /data/ghost/
docker cp acme_ghost_prod:/var/lib/ghost/current/content/themes/casper/ .
- Sur l'hôte : modifier les permissions sur le répertoire :
- Mettez les mêmes droits que le répertoire de données original déjà existant
/data/ghost/main
# ls -ltrhd /data/ghost/main drwx------ 11 ubuntu ubuntu 4.0K May 18 01:34 /data/ghost/main # chown -R ubuntu:ubuntu /data/ghost/casper # chmod 700 /data/ghost/casper
- Mettez les mêmes droits que le répertoire de données original déjà existant
NB : attention, ne pas utiliser l'option -R
avec le chmod
pour ne pas écraser les permissions existantes. Changez seulement les propriétaires.
- Modifiez le
docker-compose.yml
de votre conteneuracme_ghost_prod
.
Dans la liste des volumes, ajoutez le bind mount Casper après le bind mount d'origine :
(...)
volumes:
- /data/ghost/main:/var/lib/ghost/content
- /data/ghost/casper:/var/lib/ghost/current/content/themes/casper/
(...)
- Recréez maintenant le conteneur à partir du docker-compose.yml (les modifications dans
docker-compose.yml
sont détectées pardocker-compose
, le conteneur est alors détruit et recréé) :
docker-compose up -d
Résultat
Connectez-vous à votre site pour vérifier que tout va bien, que Ghost peut bien accéder au thème Casper.
Si ce n'est pas le cas, vérifiez bien les chemins (à partir de l'intérieur du conteneur) et les permissions.
Voici ce que vous obtenez :
A l'intérieur du conteneur, quand vous modifiez un fichier du thème Casper, ces modifications sont également écrites dans l'hôte. Ainsi, si le conteneur est détruit, les modifications survivent.
Par exemple, dans l'objectif d'ajouter les commentaires Disqus à mes articles, je vais réaliser une copie de sauvegarde du fichier, à partir de l'intérieur du conteneur :
user@host$ docker exec -it acme_ghost_prod /bin/bash
root@bcf642faf42e:~# cd /var/lib/ghost/content/themes/casper
root@bcf642faf42e:/var/lib/ghost/content/themes/casper# cp post.hbs post.hbs.bak
root@bcf642faf42e:/var/lib/ghost/content/themes/casper# exit
exit
user@host$
Dans l'hôte maintenant, je verrai ce nouveau fichier post.hbs.bak
:
user@host$ cd /data/ghost/casper
user@host$ ls
assets author.hbs default.hbs error-404.hbs error.hbs gulpfile.js index.hbs LICENSE package.json page.hbs partials post.hbs post.hbs.bak README.md tag.hbs yarn.lock
Si je décide de supprimer mon conteneur et de le recréer, je verrai toujours mon fichier de secours post.hbs.bak
, et toute modification dans mon fichier post.hbs
sera toujours là :
user@host$ docker-compose down
Removing acme_ghost_prod ... done
user@host$ docker-compose up -d
Creating acme_ghost_prod ... done
user@host$ docker exec -it acme_ghost_prod /bin/bash
root@79915c9ec7a4:/var/lib/ghost# ls /var/lib/ghost/content/themes/casper
LICENSE README.md assets author.hbs default.hbs error-404.hbs error.hbs gulpfile.js index.hbs package.json page.hbs partials post.hbs post.hbs.bak tag.hbs yarn.lock
root@79915c9ec7a4:/var/lib/ghost#