XataZhttps://fediverse.blog/~/XataZ@catlife.drycat.fr/atom.xml2020-12-01T15:21:58.492028+00:00<![CDATA[ Restic, remplaçant de borg et duplicati]]>https://catlife.drycat.fr/~/XataZ/restic-remplaçant-de-borg-et-duplicati/2020-12-01T15:21:58.492028+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-12-01T15:21:58.492028+00:00<![CDATA[<p>J'avais très vaguement parlé de <a href="https://restic.net/" rel="noopener noreferrer">restic</a> lors de mon article sur ma gestion des sauvegardes. Restic est un outil de sauvegardes dans le même genre que <a href="https://www.borgbackup.org/" rel="noopener noreferrer">borg</a>, il fonctionne de la même manière, c'est à dire via des chunks, et gère correctement la déduplication.<br>
Lors de mes premiers tests, <code>restic</code> était en version 0.9, et je l'avais trouvé beaucoup plus lent que <code>borg</code> (entre 2 et 4 fois plus lent), mais j'ai décidé de le garder sous le coude. La version 0.11 de <code>restic</code> est sortie, avec comme objectif d'améliorer les performances, et vous savez quoi ?! Ils ont réussi.<br>
Je ferais surement un article comparatif entre <code>restic</code> et <code>borg</code>, mais la conclusion est que <code>restic</code> est désormais environ 2 fois plus rapide que <code>borg</code>.</p>
<h1>Pourquoi remplacer borg et duplicati</h1>
<p>Borg fonctionne très bien, duplicati aussi d'ailleurs, mais le problème vient surtout du fait de faire une sauvegarde d'une sauvegarde pour pouvoir faire une copie dans le cloud. Je préfère partir sur 2 sauvegardes indépendantes, car si je perds ma sauvegarde locale de 2To, puisque <code>borg</code> en plus de chiffrer, utilise son organisation, il me faudra restaurer toute la sauvegarde de <code>duplicati</code> avant de pouvoir restaurer via <code>borg</code>, pas très pratique.<br>
Et c'est là que <code>restic</code> intervient, car en plus de faire comme <code>borg</code> (sauvegarde locale et via ssh), il permet d'utiliser <a href="https://rclone.org/" rel="noopener noreferrer">rclone</a> pour faire des sauvegardes sur le cloud (gdrive, onedrive, s3, mega etc ....) et même certains en natif (backblaze, s3, minio etc ...). C'est super efficace, et super simple à utiliser.</p>
<p>Je passerai sur l'installation, c'est du <code>Go</code>, donc un simple binaire à copier, je conseille cependant d'installer minimum la version 0.11, les versions sous debian et ubuntu sont beaucoup moins performantes. Je ferai beaucoup de comparaison avec <code>borg</code>, car comme j'ai dit, ces outils sont très similaires.</p>
<h1>Utilisation</h1>
<p>Contrairement à <code>borg</code>, <code>restic</code> n'a pas besoin d'avoir de serveur d'installé sur la machine cible, il utilise directement sftp.</p>
<p>Tout comme <code>borg</code>, il est possible d'utiliser un seul repo pour plusieurs hôtes ou pour plusieurs sauvegardes différentes, même si cela n'est pas forcément conseillé.</p>
<h2>Initialisation du repo</h2>
<p>L'initialisation d'un repo se fait simplement, un peu comme <code>borg</code>, pour un repository local ça donnerait :</p>
<pre><code><span class="">$ restic -r ./restic_save init
enter password for new repository:
enter password again:
created restic repository 0e31d6c2b0 at ./restic_save
Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.
</span></code></pre>
<p>Tout comme <code>borg</code>, il est possible de simplifier ça avec des <a href="https://restic.readthedocs.io/en/stable/040_backup.html?highlight=environment#environment-variables" rel="noopener noreferrer">variables d'environnements</a> :</p>
<ul>
<li>RESTIC_PASSWORD : Pour le mdp du repo</li>
<li>RESTIC_PASSWORD_COMMAND : Pour récupérer le mot de passe via une commande</li>
<li>RESTIC_PASSWORD_FILE : Pour stocker le mot de passe dans un fichier</li>
<li>RESTIC_REPOSITORY : Pour le nom du repo</li>
<li>.... : Plein d'autres, voir <a href="https://restic.readthedocs.io/en/stable/040_backup.html?highlight=environment#environment-variables" rel="noopener noreferrer">docs</a></li>
</ul>
<p>Et pour un repo distant, nous utiliserons ce format pour le repository <code>type:IP|NOM|URI|autre[:repository]</code> :</p>
<ul>
<li>ssh : <code>restic -r ssh:user@192.168.1.123:/folder/saves init</code> ou <code>export RESTIC_REPOSITORY=ssh:user@192.168.1.123:/folder/saves && restic init</code></li>
<li>rest : <code>restic -r rest:http://user:pass@save.local:8080/saves init</code> (Pour l'utilisation de l'API Rest compatible <code>restic</code>, <code>rclone</code> par exemple le permets)</li>
<li>rclone : <code>restic -r rclone:gdrive:/foler/saves init</code> (Il faut rclone sur la machine également)</li>
<li>.... : Plein d'autres, voir <a href="https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html" rel="noopener noreferrer">docs</a></li>
</ul>
<blockquote>
<p>Attention cependant avec le cloud, c'est beaucoup plus lent qu'en local ou en ssh, par exemple, la sauvegarde initiale que je fais après, m'a pris 7min en local, mais la même via <code>rclone</code> sur un onedrive à pris 50min (pour presque 9Go), en ssh les performances sont les mêmes que en local, à quelques secondes près.</p>
</blockquote>
<h2>Sauvegardes</h2>
<p>Pour sauvegarder, nous utiliserons l'option <code>backup</code> :</p>
<pre><code><span class="">$ restic -r ./restic_save backup /home/xataz/Images/
enter password for repository:
repository 0e31d6c2 opened successfully, password is correct
created new cache in /home/xataz/.cache/restic
Files: 2012 new, 0 changed, 0 unmodified
Dirs: 49 new, 0 changed, 0 unmodified
Added to the repo: 8.780 GiB
processed 2012 files, 8.781 GiB in 7:10
snapshot 85a1c2ee saved
</span></code></pre>
<p>Si j'ajoute des fichiers et que je relance, en ajoutant des variables d'environnement :</p>
<pre><code><span class="">$ export RESTIC_PASSWORD=azerty
$ export RESTIC_REPOSITORY=./restic_save
$ restic backup /home/xataz/Images/
repository 0e31d6c2 opened successfully, password is correct
Files: 14 new, 0 changed, 2012 unmodified
Dirs: 0 new, 3 changed, 46 unmodified
Added to the repo: 3.081 MiB
processed 2026 files, 8.784 GiB in 0:00
snapshot b427d8af saved
</span></code></pre>
<p>Déjà c'est beaucoup plus rapide, il a vraiment mis moins d'une seconde pour sauvegarder mes 14 nouveaux fichiers.</p>
<h3>Lister les sauvegardes</h3>
<p>Il faut pouvoir lister les sauvegardes :</p>
<pre><code><span class="">$ restic snapshots
repository 0e31d6c2 opened successfully, password is correct
ID Time Host Tags Paths
---------------------------------------------------------------------------
85a1c2ee 2020-11-19 14:31:25 xataz-laptop /home/xataz/Images
b427d8af 2020-11-19 14:50:13 xataz-laptop /home/xataz/Images
---------------------------------------------------------------------------
2 snapshots
</span></code></pre>
<p>Contrairement à <code>borg</code>, on ne nomme pas les sauvegardes, donc <code>restic</code> génère un ID unique pour ça, ce n'est pas toujours pratique, donc pour cela nous avons ...</p>
<h3>Les tags</h3>
<p>Les tags vont permettre de s'organiser ou de filtrer les sauvegardes, on les ajoute à la création d'un backup :</p>
<pre><code><span class="">$ restic backup --tag $(date +%Y%m%d) --tag images --tag $(date +%A) /home/xataz/Images/
repository 0e31d6c2 opened successfully, password is correct
Files: 38 new, 0 changed, 2026 unmodified
Dirs: 0 new, 3 changed, 46 unmodified
Added to the repo: 7.690 MiB
processed 2064 files, 8.793 GiB in 0:00
snapshot 0f024556 saved
$ restic snapshots
repository 0e31d6c2 opened successfully, password is correct
ID Time Host Tags Paths
--------------------------------------------------------------------------------------
85a1c2ee 2020-11-19 14:31:25 xataz-laptop /home/xataz/Images
b427d8af 2020-11-19 14:50:13 xataz-laptop /home/xataz/Images
0f024556 2020-11-19 16:07:15 xataz-laptop 20201119,images,jeudi /home/xataz/Images
--------------------------------------------------------------------------------------
3 snapshots
</span></code></pre>
<p>Pour l'instant je n'ai que 3 sauvegardes, donc c'est encore visible, mais je pourrais tester ceci :</p>
<pre><code><span class="">$ restic snapshots --tag 20201119
repository 0e31d6c2 opened successfully, password is correct
ID Time Host Tags Paths
--------------------------------------------------------------------------------------
0f024556 2020-11-19 16:07:15 xataz-laptop 20201119,images,jeudi /home/xataz/Images
--------------------------------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>Le <em>Host</em> est aussi une sorte de tag, elle n'a aucune incidence sur la sauvegarde et peut être <em>overwrité</em>.</p>
<h3>Rotation</h3>
<p>Pour vous montrer la rotation, je vais recréer un autre repo, et faire des sauvegardes antidatées (c'est possible avec restic) sur 390 jours:</p>
<pre><code><span class="">$ export RESTIC_PASSWORD=azerty
$ export RESTIC_REPOSITORY=./restic_save2
$ restic init
created restic repository 66dd4a3e3a at ./restic_save2
Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.
$ for i in $(seq 1 390); do
DATE=$(date "+%Y-%m-%d 00:30:00" --date "-390 days +$i days")
filename=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
head -c 1M < /dev/urandom > ../files/$filename
echo "Création de la sauvegarde n°$i/390"
restic backup --tag $(date --date "$DATE" +%Y%m%d) --time "$DATE" ../files/;
done
</span></code></pre>
<blockquote>
<p>Cette petite boucle va boucler 390 fois, et va donc me créer une sauvegarde antidatée depuis 390 jours, entre chaque sauvegarde, il va me créer un nouveau fichier aléatoire de 1Mo. Pour info, cette boucle a duré environ 5min.</p>
</blockquote>
<p>Une fois ceci fait, on se retrouve avec beaucoup de backups, il faut donc activer une rotation des backups, pour ceci nous avons <code>forget</code> qui est l'équivalent de <code>prune</code> pour <code>borg</code> :</p>
<pre><code><span class="">$ restic forget --prune --keep-daily 30 --keep-weekly 4 --keep-monthly 12 --keep-yearly 2
repository 7dbb4021 opened successfully, password is correct
Applying Policy: keep 30 daily, 4 weekly, 12 monthly, 2 yearly snapshots
keep 40 snapshots:
ID Time Host Tags Reasons Paths
------------------------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 monthly snapshot /home/xataz/Documents/Projects/testsave/files
yearly snapshot
6167c834 2020-01-31 00:30:00 xataz-laptop 20200131 monthly snapshot /home/xataz/Documents/Projects/testsave/files
56f2b973 2020-02-29 00:30:00 xataz-laptop 20200229 monthly snapshot /home/xataz/Documents/Projects/testsave/files
[....]
d117adb0 2020-11-19 00:30:00 xataz-laptop 20201119 daily snapshot /home/xataz/Documents/Projects/testsave/files
weekly snapshot
monthly snapshot
yearly snapshot
------------------------------------------------------------------------------------------------------------------------
40 snapshots
remove 350 snapshots:
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
4d112069 2019-10-27 00:30:00 xataz-laptop 20191027 /home/xataz/Documents/Projects/testsave/files
63fd465f 2019-10-28 00:30:00 xataz-laptop 20191028 /home/xataz/Documents/Projects/testsave/files
[....]
21b010bf 2020-10-13 00:30:00 xataz-laptop 20201013 /home/xataz/Documents/Projects/testsave/files
93d86e1f 2020-10-14 00:30:00 xataz-laptop 20201014 /home/xataz/Documents/Projects/testsave/files
8f48f592 2020-10-15 00:30:00 xataz-laptop 20201015 /home/xataz/Documents/Projects/testsave/files
a572b1b0 2020-10-16 00:30:00 xataz-laptop 20201016 /home/xataz/Documents/Projects/testsave/files
4ee60761 2020-10-17 00:30:00 xataz-laptop 20201017 /home/xataz/Documents/Projects/testsave/files
7b7295cd 2020-10-18 00:30:00 xataz-laptop 20201018 /home/xataz/Documents/Projects/testsave/files
3f224e7d 2020-10-19 00:30:00 xataz-laptop 20201019 /home/xataz/Documents/Projects/testsave/files
b0698bdd 2020-10-20 00:30:00 xataz-laptop 20201020 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
350 snapshots
[0:00] 100.00% 350 / 350 files deleted
counting files in repo
building new index for repo
[0:02] 100.00% 877 / 877 packs
repository contains 877 packs (1371 blobs) with 440.198 MiB
processed 1371 blobs: 0 duplicate blobs, 0 B duplicate
load all snapshots
find data that is still in use for 40 snapshots
[0:00] 100.00% 40 / 40 snapshots
found 671 of 1371 data blobs still in use, removing 700 blobs
will remove 0 invalid files
will delete 350 packs and rewrite 0 packs, this frees 28.321 MiB
counting files in repo
[0:00] 100.00% 527 / 527 packs
finding old index files
saved new indexes as [debf8d28]
remove 390 old index files
[0:00] 100.00% 390 / 390 files deleted
remove 350 old packs
[0:00] 100.00% 350 / 350 files deleted
done
</span></code></pre>
<p>Et si je vérifie mes sauvegardes :</p>
<pre><code><span class="">$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
6167c834 2020-01-31 00:30:00 xataz-laptop 20200131 /home/xataz/Documents/Projects/testsave/files
56f2b973 2020-02-29 00:30:00 xataz-laptop 20200229 /home/xataz/Documents/Projects/testsave/files
0782bbe8 2020-03-31 00:30:00 xataz-laptop 20200331 /home/xataz/Documents/Projects/testsave/files
d38ae4cd 2020-04-30 00:30:00 xataz-laptop 20200430 /home/xataz/Documents/Projects/testsave/files
c6969e02 2020-05-31 00:30:00 xataz-laptop 20200531 /home/xataz/Documents/Projects/testsave/files
8db5e2cb 2020-06-30 00:30:00 xataz-laptop 20200630 /home/xataz/Documents/Projects/testsave/files
a0bfd39d 2020-07-31 00:30:00 xataz-laptop 20200731 /home/xataz/Documents/Projects/testsave/files
7e3c2a16 2020-08-31 00:30:00 xataz-laptop 20200831 /home/xataz/Documents/Projects/testsave/files
0e4cc400 2020-09-30 00:30:00 xataz-laptop 20200930 /home/xataz/Documents/Projects/testsave/files
77dc12b6 2020-10-21 00:30:00 xataz-laptop 20201021 /home/xataz/Documents/Projects/testsave/files
bdd230cf 2020-10-22 00:30:00 xataz-laptop 20201022 /home/xataz/Documents/Projects/testsave/files
f89c1f56 2020-10-23 00:30:00 xataz-laptop 20201023 /home/xataz/Documents/Projects/testsave/files
515db7b4 2020-10-24 00:30:00 xataz-laptop 20201024 /home/xataz/Documents/Projects/testsave/files
f40ca279 2020-10-25 00:30:00 xataz-laptop 20201025 /home/xataz/Documents/Projects/testsave/files
270b2d88 2020-10-26 00:30:00 xataz-laptop 20201026 /home/xataz/Documents/Projects/testsave/files
d2e61cab 2020-10-27 00:30:00 xataz-laptop 20201027 /home/xataz/Documents/Projects/testsave/files
ce055060 2020-10-28 00:30:00 xataz-laptop 20201028 /home/xataz/Documents/Projects/testsave/files
40b19a49 2020-10-29 00:30:00 xataz-laptop 20201029 /home/xataz/Documents/Projects/testsave/files
532bea0c 2020-10-30 00:30:00 xataz-laptop 20201030 /home/xataz/Documents/Projects/testsave/files
cc04a2fb 2020-10-31 00:30:00 xataz-laptop 20201031 /home/xataz/Documents/Projects/testsave/files
3cc179b1 2020-11-01 00:30:00 xataz-laptop 20201101 /home/xataz/Documents/Projects/testsave/files
8eb3a6a7 2020-11-02 00:30:00 xataz-laptop 20201102 /home/xataz/Documents/Projects/testsave/files
d8104ee6 2020-11-03 00:30:00 xataz-laptop 20201103 /home/xataz/Documents/Projects/testsave/files
6db0ef08 2020-11-04 00:30:00 xataz-laptop 20201104 /home/xataz/Documents/Projects/testsave/files
9125355a 2020-11-05 00:30:00 xataz-laptop 20201105 /home/xataz/Documents/Projects/testsave/files
984ef545 2020-11-06 00:30:00 xataz-laptop 20201106 /home/xataz/Documents/Projects/testsave/files
a7616509 2020-11-07 00:30:00 xataz-laptop 20201107 /home/xataz/Documents/Projects/testsave/files
8deff2c8 2020-11-08 00:30:00 xataz-laptop 20201108 /home/xataz/Documents/Projects/testsave/files
3eb12566 2020-11-09 00:30:00 xataz-laptop 20201109 /home/xataz/Documents/Projects/testsave/files
5ce603c1 2020-11-10 00:30:00 xataz-laptop 20201110 /home/xataz/Documents/Projects/testsave/files
a995bfce 2020-11-11 00:30:00 xataz-laptop 20201111 /home/xataz/Documents/Projects/testsave/files
9a50768a 2020-11-12 00:30:00 xataz-laptop 20201112 /home/xataz/Documents/Projects/testsave/files
cb6576b0 2020-11-13 00:30:00 xataz-laptop 20201113 /home/xataz/Documents/Projects/testsave/files
58c2c310 2020-11-14 00:30:00 xataz-laptop 20201114 /home/xataz/Documents/Projects/testsave/files
4015059a 2020-11-15 00:30:00 xataz-laptop 20201115 /home/xataz/Documents/Projects/testsave/files
060fe973 2020-11-16 00:30:00 xataz-laptop 20201116 /home/xataz/Documents/Projects/testsave/files
f0382a1d 2020-11-17 00:30:00 xataz-laptop 20201117 /home/xataz/Documents/Projects/testsave/files
00c19642 2020-11-18 00:30:00 xataz-laptop 20201118 /home/xataz/Documents/Projects/testsave/files
d117adb0 2020-11-19 00:30:00 xataz-laptop 20201119 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
40 snapshots
</span></code></pre>
<h4>Comment ça marche</h4>
<p>Donc là j'ai mis 4 options, <code>--keep-daily 30</code>, <code>--keep-weekly 4</code>, <code>--keep-monthly 12</code>, <code>--keep-yearly 2</code>, cela veut dire que je garde 30 sauvegardes journalières, 4 sauvegardes hebdomadaires, 12 sauvegardes mensuelles et 2 sauvegardes annuelles.</p>
<blockquote>
<p>Oui mais là on devrait avoir 48 sauvegardes (30+4+12+2) ?!!</p>
</blockquote>
<p>Et bien non, car certaines sauvegardes ont plusieurs fréquences.</p>
<ul>
<li>Journalières : du 21/10/2020 au 19/11/2020</li>
<li>Hebdomadaires : 20200119, 20201115, 20201108 et 20201101 (Les derniers jours de la semaine où il y a eu une sauvegarde)</li>
<li>Mensuel : 20191231, 20200131, 20200229, 20200331, 20200430, 20200531, 20200630, 20200731, 20200831, 20200930, 20201031 et 20201119 (Les derniers jours du mois où il y a eu une sauvegarde)</li>
<li>Annuel : 20191231 et 20201119 (Derniers jours de l'année où il y a eu une sauvegarde)</li>
</ul>
<p>Pour vérifier, nous allons réduire ce nombre :</p>
<pre><code><span class="">$ restic forget --prune --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 2
repository 7dbb4021 opened successfully, password is correct
Applying Policy: keep 7 daily, 4 weekly, 12 monthly, 2 yearly snapshots
keep 20 snapshots:
[....]
done
$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
6167c834 2020-01-31 00:30:00 xataz-laptop 20200131 /home/xataz/Documents/Projects/testsave/files
56f2b973 2020-02-29 00:30:00 xataz-laptop 20200229 /home/xataz/Documents/Projects/testsave/files
0782bbe8 2020-03-31 00:30:00 xataz-laptop 20200331 /home/xataz/Documents/Projects/testsave/files
d38ae4cd 2020-04-30 00:30:00 xataz-laptop 20200430 /home/xataz/Documents/Projects/testsave/files
c6969e02 2020-05-31 00:30:00 xataz-laptop 20200531 /home/xataz/Documents/Projects/testsave/files
8db5e2cb 2020-06-30 00:30:00 xataz-laptop 20200630 /home/xataz/Documents/Projects/testsave/files
a0bfd39d 2020-07-31 00:30:00 xataz-laptop 20200731 /home/xataz/Documents/Projects/testsave/files
7e3c2a16 2020-08-31 00:30:00 xataz-laptop 20200831 /home/xataz/Documents/Projects/testsave/files
0e4cc400 2020-09-30 00:30:00 xataz-laptop 20200930 /home/xataz/Documents/Projects/testsave/files
cc04a2fb 2020-10-31 00:30:00 xataz-laptop 20201031 /home/xataz/Documents/Projects/testsave/files
3cc179b1 2020-11-01 00:30:00 xataz-laptop 20201101 /home/xataz/Documents/Projects/testsave/files
8deff2c8 2020-11-08 00:30:00 xataz-laptop 20201108 /home/xataz/Documents/Projects/testsave/files
cb6576b0 2020-11-13 00:30:00 xataz-laptop 20201113 /home/xataz/Documents/Projects/testsave/files
58c2c310 2020-11-14 00:30:00 xataz-laptop 20201114 /home/xataz/Documents/Projects/testsave/files
4015059a 2020-11-15 00:30:00 xataz-laptop 20201115 /home/xataz/Documents/Projects/testsave/files
060fe973 2020-11-16 00:30:00 xataz-laptop 20201116 /home/xataz/Documents/Projects/testsave/files
f0382a1d 2020-11-17 00:30:00 xataz-laptop 20201117 /home/xataz/Documents/Projects/testsave/files
00c19642 2020-11-18 00:30:00 xataz-laptop 20201118 /home/xataz/Documents/Projects/testsave/files
d117adb0 2020-11-19 00:30:00 xataz-laptop 20201119 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
20 snapshots
</span></code></pre>
<p>On peut refaire le même exercice :</p>
<ul>
<li>Journalières : 20201113, 20201114, 20201115, 20201116, 20201117, 20201118 et 20201119 ==> 7</li>
<li>Hebdomadaires : 20200119, 20201115, 20201108 et 20201101 => 4</li>
<li>Mensuel : 20191231, 20200131, 20200229, 20200331, 20200430, 20200531, 20200630, 20200731, 20200831, 20200930, 20201031 et 20201119 => 12</li>
<li>Annuel : 20191231 et 20201119 => 2</li>
</ul>
<p>Ce qui nous donnerait un total de 24 sauvegardes, mais si nous enlevons les doublons, nous avons bien 20 sauvegardes.</p>
<p>Comme tout système de sauvegarde, il faut bien faire attention à la rétention, dans cette configuration, si je crée un fichier en début de semaine dernière et que je le supprime 2 jours après, ba là j'ai plus le fichier.</p>
<h4>Jouer avec les tags</h4>
<p>On peut également jouer avec les tags pour la rotation, par exemple je crée ma sauvegarde de photos avec un tag photo :</p>
<pre><code><span class="">$ restic backup --tag $(date --date "$DATE" +%Y%m%d) --tag photos ~/photos
</span></code></pre>
<p>Et que dans le même repos je sauvegarde mes documents :</p>
<pre><code><span class="">$ restic backup --tag $(date --date "$DATE" +%Y%m%d) --tag documents ~/documents
</span></code></pre>
<p>Mon répertoire photos n'est pas un répertoire que je sauvegarde souvent, puisque rarement modifié, je pourrais par exemple demander de garder les sauvegardes journalières pendant seulement 7 jours, et les sauvegardes hebdomadaires indéfiniment :</p>
<pre><code><span class="">$ restic forget --keep-daily 7 --keep-weekly -1 --tag photos --prune
</span></code></pre>
<p>Là je n'agis donc que sur les backups avec le tag photos.</p>
<h2>Restauration</h2>
<p>Faire des sauvegardes c'est bien, mais il faut pouvoir les restaurer, c'est indispensable. Nous avons plusieurs outils qui nous permet de le faire.</p>
<h3>Rechercher un fichier</h3>
<p>J'ai supprimé par erreur le fichier nommé <strong>j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC</strong>, il faut donc rechercher ce fichier, <code>restic</code> fourni la commande <code>find</code> pour ceci :</p>
<pre><code><span class="">$ restic find j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
repository 7dbb4021 opened successfully, password is correct
Found matching entries in snapshot 00c19642 from 2020-11-18 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 060fe973 from 2020-11-16 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 0e4cc400 from 2020-09-30 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 3cc179b1 from 2020-11-01 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 4015059a from 2020-11-15 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 58c2c310 from 2020-11-14 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 7e3c2a16 from 2020-08-31 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 8db5e2cb from 2020-06-30 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot 8deff2c8 from 2020-11-08 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot a0bfd39d from 2020-07-31 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot c6969e02 from 2020-05-31 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot cb6576b0 from 2020-11-13 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot cc04a2fb from 2020-10-31 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot d117adb0 from 2020-11-19 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
Found matching entries in snapshot d38ae4cd from 2020-04-30 00:30:00
/files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
</span></code></pre>
<p>On retrouve bien notre fichier, ouf !!!</p>
<p>On peut affiner la recherche avec quelques options :</p>
<p><code>--host</code> : Dans le cas d'un repos multihost (Pas forcément recommandé)<br>
<code>--tag</code> : Pour filtrer sur un certain tag<br>
<code>--newest</code> ou <code>--oldest</code> : Pour rechercher le plus vieux ou le plus récent fichier</p>
<p>Et bien sûr d'autres que vous pouvez obtenir via <code>restic find --help</code>.</p>
<h3>Comparer des sauvegardes</h3>
<p>On peut comparer deux sauvegardes avec <code>diff</code>. Malheureusement il faudra utiliser les IDs des backups pour ce faire :</p>
<pre><code><span class="">$ restic diff 00c19642 d117adb0
repository 7dbb4021 opened successfully, password is correct
comparing snapshot 00c19642 to d117adb0:
+ /files/6Ocl3G8kMNUEjTbsbZ5nrKN2CSEcF9Zg
Files: 1 new, 0 removed, 0 changed
Dirs: 0 new, 0 removed
Others: 0 new, 0 removed
Data Blobs: 2 new, 0 removed
Tree Blobs: 1 new, 1 removed
Added: 1.166 MiB
Removed: 169.658 KiB
</span></code></pre>
<h3>Restaurer via mount</h3>
<p>Tout comme <code>borg</code>, il est possible de monter une sauvegarde :</p>
<pre><code><span class="">$ restic mount testmount
repository 7dbb4021 opened successfully, password is correct
Now serving the repository at testmount
When finished, quit with Ctrl-c or umount the mountpoint.
</span></code></pre>
<p>Par contre <code>restic</code> ne rend pas la main, donc dans un autre shell :</p>
<pre><code><span class="">$ ls -lrt
total 0
dr-xr-xr-x 1 xataz xataz 0 déc. 1 10:34 tags
dr-xr-xr-x 1 xataz xataz 0 déc. 1 10:34 snapshots
dr-xr-xr-x 1 xataz xataz 0 déc. 1 10:34 ids
dr-xr-xr-x 1 xataz xataz 0 déc. 1 10:34 hosts
</span></code></pre>
<p>Nous pouvons voir 4 répertoires :</p>
<ul>
<li>tags : Les sauvegardes sont triées par tags, donc puisque je mets la date en tag, j'ai un répertoire par date, ensuite j'ai les sauvegardes correspondants à ce tag, qui sont triées par date.</li>
<li>snapshots : Nous avons directement accès à toutes les sauvegardes, ici triées par date.</li>
<li>ids : Moins pratique, ici les sauvegardes sont triées par ids uniques.</li>
<li>hosts : C'est surtout dans le cas d'un repo pour plusieurs hôtes, un répertoire par hôte, et ensuite la liste des sauvegardes par date.</li>
</ul>
<p>Donc pour restaurer ici, il suffit de faire un <code>cp</code> du fichier désiré, et de la copier où vous voulez.</p>
<h3>Restaurer via restore</h3>
<p>Cette commande est pratique quand vous savez exactement le ou les fichiers qu'il vous faut.</p>
<p>Pour tout restaurer la sauvegarde du 30/04/2020 (d38ae4cd) dans un répertoire temporaire :</p>
<pre><code><span class="">$ restic restore --target restore d38ae4cd
repository 7dbb4021 opened successfully, password is correct
restoring <Snapshot d38ae4cd of [/home/xataz/Documents/Projects/testsave/files] at 2020-04-30 00:30:00 +0200 CEST by xataz@xataz-laptop> to restore
</span></code></pre>
<p>Petit exemple pour restaurer le fichier <strong>j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC</strong> précédemment cherché en date du 30/04/2020 (id d38ae4cd) :</p>
<pre><code><span class="">$ restic restore --include j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC --target restore d38ae4cd
repository 7dbb4021 opened successfully, password is correct
restoring <Snapshot d38ae4cd of [/home/xataz/Documents/Projects/testsave/files] at 2020-04-30 00:30:00 +0200 CEST by xataz@xataz-laptop> to restore
$ ls restore/files/
j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
</span></code></pre>
<h3>Restaurer via dump</h3>
<p><code>dump</code> est particulier, car il permet de lire et d'afficher un fichier, super pratique pour par exemple restaurer une base de données qu'on aurait exportée en <code>.sql</code></p>
<pre><code><span class="">$ restic dump d38ae4cd files/j2J4IPrcZLmJdH31Ld0xu8Bok33jdezC
### Contenu du fichier
</span></code></pre>
<p>Pour un exemple plus concret, j'ai effectué ma sauvegarde mysql comme ceci :</p>
<pre><code><span class="">$ mysqldump -d dbname -u dbuser -p dbpass | restic backup --stdin --stdin-filename database_dump.sql --tag $(date +%Y%m%d) --tag mysql
</span></code></pre>
<p>Vous pourrez restaurer comme ceci :</p>
<pre><code><span class="">$ restic dump latest database_dump.sql | mysql --local-infile=1 -u dbuser -p dbpass -d dbname -e "LOAD DATA LOCAL INFILE '/dev/stdin' INTO TABLE mytable FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"';"
</span></code></pre>
<blockquote>
<p>Je n'ai pas testé ceci, mais ça devrait fonctionner sans soucis.</p>
</blockquote>
<h2>Divers</h2>
<h3>Gérer les accès</h3>
<p><code>Restic</code> a un petit avantage face à <code>borg</code>, il permet d'avoir plusieurs comptes pour accéder à une archive, par exemple vous avez une clé par serveur sauvegardé, et une clé pour vous, sur votre PC client qui permettra d'y accéder. L'avantage, c'est que si une clé est compromise, il vous suffit de ne révoquer que celle ci.</p>
<p>Commençons par lister les clés :</p>
<pre><code><span class="">$ restic key list
repository 7dbb4021 opened successfully, password is correct
ID User Host Created
---------------------------------------------------
*fa335932 xataz xataz-laptop 2020-11-19 16:40:39
---------------------------------------------------
</span></code></pre>
<p>L'hôte et le User n'ont aucune incidence sur le fonctionnement, ce sont des tags pour la gestion, l'organisation.</p>
<p>Donc nous allons créer une clé pour toto :</p>
<pre><code><span class="">$ restic key add --user toto
repository 7dbb4021 opened successfully, password is correct
enter new password:
enter password again:
saved new key as <Key of toto@xataz-laptop, created on 2020-12-01 11:07:46.936851027 +0100 CET m=+12.941241627>
</span></code></pre>
<p>Je liste les clés :</p>
<pre><code><span class="">$ restic key list
repository 7dbb4021 opened successfully, password is correct
ID User Host Created
---------------------------------------------------
9f917fae toto xataz-laptop 2020-12-01 11:07:46
*fa335932 xataz xataz-laptop 2020-11-19 16:40:39
---------------------------------------------------
</span></code></pre>
<p>Pour tester la clé, je vais l'ajouter dans les variables d'environnements :</p>
<pre><code><span class="">$ export RESTIC_PASSWORD=qsdfgh
</span></code></pre>
<p>Et j'essaie de lister les snapshots :</p>
<pre><code><span class="">$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
6167c834 2020-01-31 00:30:00 xataz-laptop 20200131 /home/xataz/Documents/Projects/testsave/files
56f2b973 2020-02-29 00:30:00 xataz-laptop 20200229 /home/xataz/Documents/Projects/testsave/files
0782bbe8 2020-03-31 00:30:00 xataz-laptop 20200331 /home/xataz/Documents/Projects/testsave/files
d38ae4cd 2020-04-30 00:30:00 xataz-laptop 20200430 /home/xataz/Documents/Projects/testsave/files
c6969e02 2020-05-31 00:30:00 xataz-laptop 20200531 /home/xataz/Documents/Projects/testsave/files
8db5e2cb 2020-06-30 00:30:00 xataz-laptop 20200630 /home/xataz/Documents/Projects/testsave/files
a0bfd39d 2020-07-31 00:30:00 xataz-laptop 20200731 /home/xataz/Documents/Projects/testsave/files
7e3c2a16 2020-08-31 00:30:00 xataz-laptop 20200831 /home/xataz/Documents/Projects/testsave/files
0e4cc400 2020-09-30 00:30:00 xataz-laptop 20200930 /home/xataz/Documents/Projects/testsave/files
cc04a2fb 2020-10-31 00:30:00 xataz-laptop 20201031 /home/xataz/Documents/Projects/testsave/files
3cc179b1 2020-11-01 00:30:00 xataz-laptop 20201101 /home/xataz/Documents/Projects/testsave/files
8deff2c8 2020-11-08 00:30:00 xataz-laptop 20201108 /home/xataz/Documents/Projects/testsave/files
cb6576b0 2020-11-13 00:30:00 xataz-laptop 20201113 /home/xataz/Documents/Projects/testsave/files
58c2c310 2020-11-14 00:30:00 xataz-laptop 20201114 /home/xataz/Documents/Projects/testsave/files
4015059a 2020-11-15 00:30:00 xataz-laptop 20201115 /home/xataz/Documents/Projects/testsave/files
060fe973 2020-11-16 00:30:00 xataz-laptop 20201116 /home/xataz/Documents/Projects/testsave/files
f0382a1d 2020-11-17 00:30:00 xataz-laptop 20201117 /home/xataz/Documents/Projects/testsave/files
00c19642 2020-11-18 00:30:00 xataz-laptop 20201118 /home/xataz/Documents/Projects/testsave/files
d117adb0 2020-11-19 00:30:00 xataz-laptop 20201119 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
20 snapshots
</span></code></pre>
<p>Puis si je supprime la clé de xataz :</p>
<pre><code><span class="">$ $ restic key remove fa335932
repository 7dbb4021 opened successfully, password is correct
removed key fa335932c23f7ed6063d1d0ee541ef8864f9c832d357351aca44471bb4006123
</span></code></pre>
<p>Et que je retente avec mon ancien mot de passe :</p>
<pre><code><span class="">$ export RESTIC_PASSWORD=azerty
$ restic snapshots
Fatal: wrong password or no key found
$ export RESTIC_PASSWORD=qsdfgh
$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
[....]
d117adb0 2020-11-19 00:30:00 xataz-laptop 20201119 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
20 snapshots
</span></code></pre>
<p>Je peux changer de passphrase également :</p>
<pre><code><span class="">$ restic key passwd
repository 7dbb4021 opened successfully, password is correct
enter new password:
enter password again:
saved new key as <Key of xataz@xataz-laptop, created on 2020-12-01 11:18:15.004958077 +0100 CET m=+10.588438048>
</span></code></pre>
<p>Avec le mdp actuel, ça ne fonctionne plus :</p>
<pre><code><span class="">$ restic snapshots
Fatal: wrong password or no key found
</span></code></pre>
<p>Mais si j'exporte le bon :</p>
<pre><code><span class="">$ export RESTIC_PASSWORD=jaimerestic
$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
[....]
d117adb0 2020-11-19 00:30:00 xataz-laptop 20201119 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
20 snapshots
</span></code></pre>
<h3>Tags</h3>
<p>Nous pouvons ajouter des tags après sauvegarde, ou en supprimer</p>
<pre><code><span class="">$ restic tag --add newtag latest
repository 7dbb4021 opened successfully, password is correct
create exclusive lock for repository
modified tags on 1 snapshots
$ restic snapshots latest
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
-----------------------------------------------------------------------------------------------------------
dbe8e35f 2020-11-19 00:30:00 xataz-laptop 20201119,newtag /home/xataz/Documents/Projects/testsave/files
-----------------------------------------------------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>Je peux le supprimer :</p>
<pre><code><span class="">$ restic tag --remove newtag latest
repository 7dbb4021 opened successfully, password is correct
create exclusive lock for repository
modified tags on 1 snapshots
$ restic snapshots latest
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
aeead31a 2020-11-19 00:30:00 xataz-laptop 20201119 /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>Je peux en ajouter plusieurs d'un coup :</p>
<pre><code><span class="">$ restic tag --add tag1 --add tag2 --add tag3 latest
repository 7dbb4021 opened successfully, password is correct
create exclusive lock for repository
modified tags on 1 snapshots
$ restic snapshots latest
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
-------------------------------------------------------------------------------------------------------------------
2ac8c161 2020-11-19 00:30:00 xataz-laptop 20201119,tag1,tag2,tag3 /home/xataz/Documents/Projects/testsave/files
-------------------------------------------------------------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>Ou même en ajouter et supprimer en même temps :</p>
<pre><code><span class="">$ restic tag --add tag4 --remove tag1 latest
repository 7dbb4021 opened successfully, password is correct
create exclusive lock for repository
modified tags on 1 snapshots
$ restic snapshots latest
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
-------------------------------------------------------------------------------------------------------------------
6b258d75 2020-11-19 00:30:00 xataz-laptop 20201119,tag4,tag2,tag3 /home/xataz/Documents/Projects/testsave/files
-------------------------------------------------------------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>Ou alors tout remplacer d'un coup :</p>
<pre><code><span class="">$ restic tag --set newnewtag latest
repository 7dbb4021 opened successfully, password is correct
create exclusive lock for repository
modified tags on 1 snapshots
$ restic snapshots latest
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
edf390e4 2020-11-19 00:30:00 xataz-laptop newnewtag /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>L'utilité peut être multiple, par exemple, ajouter un tag "skip", pour que celui-ci ne rentre pas en compte dans la rotation des sauvegardes (via un <code>--keep-tag skip</code> par exemple), et garder indéfiniment, voir le contraire, car elle ne sert à rien, donc la supprimer directement.</p>
<h3>Stats</h3>
<p>Cela permet d'avoir quelques stats sur le repos, notamment la taille de celui-ci :</p>
<pre><code><span class="">$ restic stats
repository 7dbb4021 opened successfully, password is correct
scanning...
Stats in restore-size mode:
Snapshots processed: 20
Total File Count: 6219
Total Size: 406.062 MiB
$ restic stats --mode raw-data
repository 7dbb4021 opened successfully, password is correct
scanning...
Stats in raw-data mode:
Snapshots processed: 20
Total Blob Count: 631
Total Size: 408.600 MiB
</span></code></pre>
<p>Faut être honnête, <code>borg</code> est beaucoup plus verbeux sur les stats, et permets d'avoir une meilleure visu et plus d'info en un coup d'oeil.</p>
<h3>Recover</h3>
<p>Ceci est un peu particulier, la commande <code>recover</code> va permettre de créer un snapshot qui contient tout les objets du repository complet.</p>
<p>Pour l'exemple, je vais supprimer tout les fichiers, en créer un nouveau, et faire une sauvegarde, je me retrouve donc avec ceci :</p>
<pre><code><span class="">$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
6167c834 2020-01-31 00:30:00 xataz-laptop 20200131 /home/xataz/Documents/Projects/testsave/files
56f2b973 2020-02-29 00:30:00 xataz-laptop 20200229 /home/xataz/Documents/Projects/testsave/files
0782bbe8 2020-03-31 00:30:00 xataz-laptop 20200331 /home/xataz/Documents/Projects/testsave/files
d38ae4cd 2020-04-30 00:30:00 xataz-laptop 20200430 /home/xataz/Documents/Projects/testsave/files
c6969e02 2020-05-31 00:30:00 xataz-laptop 20200531 /home/xataz/Documents/Projects/testsave/files
8db5e2cb 2020-06-30 00:30:00 xataz-laptop 20200630 /home/xataz/Documents/Projects/testsave/files
a0bfd39d 2020-07-31 00:30:00 xataz-laptop 20200731 /home/xataz/Documents/Projects/testsave/files
7e3c2a16 2020-08-31 00:30:00 xataz-laptop 20200831 /home/xataz/Documents/Projects/testsave/files
0e4cc400 2020-09-30 00:30:00 xataz-laptop 20200930 /home/xataz/Documents/Projects/testsave/files
cc04a2fb 2020-10-31 00:30:00 xataz-laptop 20201031 /home/xataz/Documents/Projects/testsave/files
3cc179b1 2020-11-01 00:30:00 xataz-laptop 20201101 /home/xataz/Documents/Projects/testsave/files
8deff2c8 2020-11-08 00:30:00 xataz-laptop 20201108 /home/xataz/Documents/Projects/testsave/files
cb6576b0 2020-11-13 00:30:00 xataz-laptop 20201113 /home/xataz/Documents/Projects/testsave/files
58c2c310 2020-11-14 00:30:00 xataz-laptop 20201114 /home/xataz/Documents/Projects/testsave/files
4015059a 2020-11-15 00:30:00 xataz-laptop 20201115 /home/xataz/Documents/Projects/testsave/files
060fe973 2020-11-16 00:30:00 xataz-laptop 20201116 /home/xataz/Documents/Projects/testsave/files
f0382a1d 2020-11-17 00:30:00 xataz-laptop 20201117 /home/xataz/Documents/Projects/testsave/files
00c19642 2020-11-18 00:30:00 xataz-laptop 20201118 /home/xataz/Documents/Projects/testsave/files
edf390e4 2020-11-19 00:30:00 xataz-laptop newnewtag /home/xataz/Documents/Projects/testsave/files
1aa49e09 2020-12-01 11:37:25 xataz-laptop test /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
21 snapshots
</span></code></pre>
<p>Je lance donc mon recover, et liste le dernier snapshot :</p>
<pre><code><span class="">$ restic recover
repository 7dbb4021 opened successfully, password is correct
load index files
load 43 trees
tree (43/43)
done
found 2 roots
saved new snapshot 69b027d6
$ restic snapshots latest
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
-----------------------------------------------------------------
69b027d6 2020-12-01 11:38:30 xataz-laptop /recover
-----------------------------------------------------------------
1 snapshots
</span></code></pre>
<p>On peut en lister les fichiers :</p>
<pre><code><span class="">$ restic ls latest
[.....]
/0f1709b6/files/test
[.....]
/15fa7252/fac5a21d/files/xrxLQ2A6owZENtgglG9ZtDTtJzPCtdXV
/15fa7252/fac5a21d/files/xuojEiZFDdKSIbHoiNqRkSnASzV2X5AG
/15fa7252/fac5a21d/files/xwxlMXfmUZyjXpgVfVwRi1qpJivh73ke
[.....]
/15fa7252/f9f7d197/files/vd0MmI5OKlbHis6Ik5ljfhbxvm8xW4vG
/15fa7252/f9f7d197/files/yCbGYDOpTBeResfAagxu2LgNxDHHQ67B
/15fa7252/f9f7d197/files/yXn7ZzTvzoEy05MnII4X1VSTd9ih6N5k
/15fa7252/f9f7d197/files/yvXTelkYE99lQMA6gE8vO7sgQZbrTNtZ
</span></code></pre>
<p>J'avoue que je ne sais pas trop comment il gère sa tambouille, mais là nous nous retrouvons avec tous les fichiers déjà sauvegardés.</p>
<p>Testons un peu plus loin, je supprime ce recover, et je vais faire un forget pour ne garder que la dernière sauvegarde, mais sans prune :</p>
<pre><code><span class="">$ restic forget latest
repository 7dbb4021 opened successfully, password is correct
[0:00] 100.00% 1 / 1 files deleted
$ restic forget --keep-last 1
repository 7dbb4021 opened successfully, password is correct
Applying Policy: keep 1 latest snapshots
keep 1 snapshots:
ID Time Host Tags Reasons Paths
---------------------------------------------------------------------------------------------------------------------
1aa49e09 2020-12-01 11:37:25 xataz-laptop test last snapshot /home/xataz/Documents/Projects/testsave/files
---------------------------------------------------------------------------------------------------------------------
1 snapshots
remove 20 snapshots:
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
2003f87e 2019-12-31 00:30:00 xataz-laptop 20191231 /home/xataz/Documents/Projects/testsave/files
6167c834 2020-01-31 00:30:00 xataz-laptop 20200131 /home/xataz/Documents/Projects/testsave/files
56f2b973 2020-02-29 00:30:00 xataz-laptop 20200229 /home/xataz/Documents/Projects/testsave/files
0782bbe8 2020-03-31 00:30:00 xataz-laptop 20200331 /home/xataz/Documents/Projects/testsave/files
d38ae4cd 2020-04-30 00:30:00 xataz-laptop 20200430 /home/xataz/Documents/Projects/testsave/files
c6969e02 2020-05-31 00:30:00 xataz-laptop 20200531 /home/xataz/Documents/Projects/testsave/files
8db5e2cb 2020-06-30 00:30:00 xataz-laptop 20200630 /home/xataz/Documents/Projects/testsave/files
a0bfd39d 2020-07-31 00:30:00 xataz-laptop 20200731 /home/xataz/Documents/Projects/testsave/files
7e3c2a16 2020-08-31 00:30:00 xataz-laptop 20200831 /home/xataz/Documents/Projects/testsave/files
0e4cc400 2020-09-30 00:30:00 xataz-laptop 20200930 /home/xataz/Documents/Projects/testsave/files
cc04a2fb 2020-10-31 00:30:00 xataz-laptop 20201031 /home/xataz/Documents/Projects/testsave/files
3cc179b1 2020-11-01 00:30:00 xataz-laptop 20201101 /home/xataz/Documents/Projects/testsave/files
8deff2c8 2020-11-08 00:30:00 xataz-laptop 20201108 /home/xataz/Documents/Projects/testsave/files
cb6576b0 2020-11-13 00:30:00 xataz-laptop 20201113 /home/xataz/Documents/Projects/testsave/files
58c2c310 2020-11-14 00:30:00 xataz-laptop 20201114 /home/xataz/Documents/Projects/testsave/files
4015059a 2020-11-15 00:30:00 xataz-laptop 20201115 /home/xataz/Documents/Projects/testsave/files
060fe973 2020-11-16 00:30:00 xataz-laptop 20201116 /home/xataz/Documents/Projects/testsave/files
f0382a1d 2020-11-17 00:30:00 xataz-laptop 20201117 /home/xataz/Documents/Projects/testsave/files
00c19642 2020-11-18 00:30:00 xataz-laptop 20201118 /home/xataz/Documents/Projects/testsave/files
edf390e4 2020-11-19 00:30:00 xataz-laptop newnewtag /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
20 snapshots
[0:00] 100.00% 20 / 20 files deleted
$ restic snapshots
repository 7dbb4021 opened successfully, password is correct
ID Time Host Tags Paths
------------------------------------------------------------------------------------------------------
1aa49e09 2020-12-01 11:37:25 xataz-laptop test /home/xataz/Documents/Projects/testsave/files
------------------------------------------------------------------------------------------------------
1 snapshots
$ restic ls latest
repository 7dbb4021 opened successfully, password is correct
snapshot 1aa49e09 of [/home/xataz/Documents/Projects/testsave/files] filtered by [] at 2020-12-01 11:37:25.253919577 +0100 CET):
/files
/files/test
</span></code></pre>
<p>Et si je lance un recover :</p>
<pre><code><span class="">$ restic recover
repository 7dbb4021 opened successfully, password is correct
load index files
load 45 trees
tree (45/45)
done
found 1 roots
saved new snapshot 9927251d
</span></code></pre>
<p>Et si nous vérifions tout les fichiers dans ce nouveau snapshot :</p>
<pre><code><span class="">$ restic ls latest
[.....]
/0f1709b6/files/test
[.....]
/15fa7252/fac5a21d/files/xrxLQ2A6owZENtgglG9ZtDTtJzPCtdXV
/15fa7252/fac5a21d/files/xuojEiZFDdKSIbHoiNqRkSnASzV2X5AG
/15fa7252/fac5a21d/files/xwxlMXfmUZyjXpgVfVwRi1qpJivh73ke
[.....]
/15fa7252/f9f7d197/files/vd0MmI5OKlbHis6Ik5ljfhbxvm8xW4vG
/15fa7252/f9f7d197/files/yCbGYDOpTBeResfAagxu2LgNxDHHQ67B
/15fa7252/f9f7d197/files/yXn7ZzTvzoEy05MnII4X1VSTd9ih6N5k
/15fa7252/f9f7d197/files/yvXTelkYE99lQMA6gE8vO7sgQZbrTNtZ
</span></code></pre>
<p>Nous retrouvons tout nos fichiers.</p>
<p>Cependant dans le cas d'un prune, c'est différent :</p>
<pre><code><span class="">$ restic forget latest
repository 7dbb4021 opened successfully, password is correct
[0:00] 100.00% 1 / 1 files deleted
$ restic prune
repository 7dbb4021 opened successfully, password is correct
counting files in repo
building new index for repo
[0:02] 100.00% 514 / 514 packs
repository contains 514 packs (639 blobs) with 408.668 MiB
processed 639 blobs: 0 duplicate blobs, 0 B duplicate
load all snapshots
find data that is still in use for 1 snapshots
[0:00] 100.00% 1 / 1 snapshots
found 3 of 639 data blobs still in use, removing 636 blobs
will remove 0 invalid files
will delete 512 packs and rewrite 0 packs, this frees 408.627 MiB
counting files in repo
[0:00] 100.00% 2 / 2 packs
finding old index files
saved new indexes as [aab34713]
remove 6 old index files
[0:00] 100.00% 6 / 6 files deleted
remove 512 old packs
[0:00] 100.00% 512 / 512 files deleted
done
$ restic recover
repository 7dbb4021 opened successfully, password is correct
load index files
load 2 trees
tree (2/2)
done
found 1 roots
saved new snapshot e707fee1
$ restic ls latest
repository 7dbb4021 opened successfully, password is correct
snapshot e707fee1 of [/recover] filtered by [] at 2020-12-01 11:52:46.318654368 +0100 CET):
/0f1709b6
/0f1709b6/files
/0f1709b6/files/test
</span></code></pre>
<p>Comme nous pouvons le voir, si nous faisons un prune (avec <code>restic prune</code> ou <code>restic forget --prune</code>), nous perdons tout.</p>
<h1>Conclusion</h1>
<p>Comme nous pouvons le voir, <code>restic</code> est un outil de sauvegarde en mode push très complet, et très performant, il se place au moins au même niveau que <code>borg</code> selon moi.<br>
J'espère que cet article vous donnera au moins envie d'essayer cet outil.<br>
De mon coté, je commence à remplacer petit à petit mes <code>borg</code> par <code>restic</code>, et j'ai déjà supprimé <code>duplicati</code> depuis.</p>
]]><![CDATA[Stack TICK sur k3s]]>https://catlife.drycat.fr/~/XataZ/stack-tick-sur-kubernetes/2020-11-06T15:20:14.856478+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-11-06T15:20:14.856478+00:00<![CDATA[<p>Suite aux vidéos de <a href="https://www.youtube.com/channel/UCs_AZuYXi6NA9tkdbhjItHQ" rel="noopener noreferrer">Xavki</a> sur l'installation d'une stack Node-exporter/Prometheus/Grafana que j'ai trouvé très interessantes, j'ai voulu mettre à jour mon monitoring en m'y inspirant. Cependant je préfères la stack TICK (Télégraf, Influxdb, Chronograf et Kapacitor), la stack de influxdata, principalement pour l'intégration complète et puissante des notifications directement dans chronograf. Le fait aussi de n'avoir qu'un seul agent (Télégraf), au lieu de plusieurs exporter (docker-exporter, node-exporter etc ...).<br>
Dernier point, je n'ai pas trouvé beaucoup d'information sur le sujet, donc cela m'a permis de beaucoup monté en compétence, notamment sur la gestion des rôles avec la création d'un rbac pour ça.<br>
Nous allons donc voir ici, comment installer la stack TICK, le tout dans un cluster kubernetes, et sans HELM ou autre outils facilitant l'installation.</p>
<p>Je passerais rapidement sur beaucoup de chose, si vous n'avez pas les bases, je vous invite à regarder les vidéos de <a href="https://www.youtube.com/channel/UCs_AZuYXi6NA9tkdbhjItHQ" rel="noopener noreferrer">xavki</a>.</p>
<h1>Organisation</h1>
<p>J'ai une certaine organisation, je ne sais pas si c'est une bonne pratique mais c'est la mienne.<br>
Déjà j'ai un namespace par stack, et chaque déploiement de la stack se passera dedans. Pour l'organisation des fichiers, je crée un répertoire par stack/namespace, dedans j'ai mes fichiers qui seront globaux à la stack, et ensuite un répertoire par déploiement avec les fichiers nécessaires à celui là.
Donc en gros nous aurons :</p>
<ul>
<li>monitor
<ul>
<li>ns.yml</li>
<li>telegraf
<ul>
<li>10-volumes.yml</li>
<li>20-daemonset.yml</li>
</ul>
</li>
<li>kapacitor
<ul>
<li>10-volumes.yml</li>
<li>20-deployment.yml</li>
<li>30-services.yml</li>
</ul>
</li>
<li>chronograf
<ul>
<li>.....</li>
</ul>
</li>
<li>influxdb
<ul>
<li>.....</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1>Architecture</h1>
<p>Pour ce tutoriel, j'utilise ma production (pas bien), en gros j'ai un cluster k3s avec un master et 3 workers, tout les fichiers seront stockés sur ma VMs qui sers de fileserver avec un serveur NFS.</p>
<p>J'ai donc 5 VMs :</p>
<ul>
<li>k3s-master : 192.168.1.121</li>
<li>k3s-node1 : 192.168.1.131</li>
<li>k3s-node2 : 192.168.1.132</li>
<li>k3s-node3 : 192.168.1.133</li>
<li>filer : 192.168.1.105</li>
</ul>
<h1>Création du namespace</h1>
<p>Pour le namespace, c'est plutôt simple, nous créons notre fichier <code>ns.yml</code> avec ceci dedans :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Namespace</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string">monitor</span>
</span></code></pre>
<p>et on applique :</p>
<pre><code><span class="">$ kubectl apply -f ns.yml
namespace/monitor created
</span></code></pre>
<h1>Déploiement de influxdb</h1>
<p>Comme dit j'ai mon organisation, donc dans mon répertoire <code>monitor</code>, je crée un autre répertoire <code>influxdb</code>, dans lequel je vais mettre tout les fichiers suivants qui concernent influxdb.</p>
<h2>10-volume.yml</h2>
<p>Nous avons besoin d'un volume, comme dit je stock tout sur mon serveur NFS, donc je commence par créer un fichier <code>10-volumes.yml</code> :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">PersistentVolume</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-influxdb-pv</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storageClassName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-influxdb</span></span>
<span class="string"><span class="entity name tag">capacity</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">1Gi</span></span>
<span class="string"><span class="entity name tag">accessModes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">ReadWriteMany</span></span>
<span class="string"><span class="entity name tag">nfs</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">server</span></span><span class="punctuation">:</span> <span class="constant numeric">192.168.1.105</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>/data/influxdb<span class="punctuation string">"</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">PersistentVolumeClaim</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-influxdb-pvc</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storageClassName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-influxdb</span></span>
<span class="string"><span class="entity name tag">accessModes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">ReadWriteMany</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string">500Mi</span>
</span></code></pre>
<p>A adapter pour votre besoin</p>
<h2>20-deployment.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Deployment</span></span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">apps/v1</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb</span></span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">replicas</span></span><span class="punctuation">:</span> <span class="constant numeric">1</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">matchLabels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb</span></span>
<span class="string"><span class="entity name tag">template</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">containers</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb</span></span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb:1.8-alpine</span></span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">containerPort</span></span><span class="punctuation">:</span> <span class="constant numeric">8086</span>
<span class="string"><span class="entity name tag">volumeMounts</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/var/lib/influxdb</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">300M</span></span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.2</span>
<span class="string"><span class="entity name tag">limits</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">800M</span></span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.5</span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data</span></span>
<span class="string"><span class="entity name tag">persistentVolumeClaim</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">claimName</span></span><span class="punctuation">:</span> <span class="string">data-influxdb-pvc</span>
</span></code></pre>
<p>Rien de particulier, on a juste un volume (NFS) monté dans /var/lib/influxdb.</p>
<h2>30-services.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Service</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb-web</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">protocol</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">TCP</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">web</span></span>
<span class="string"><span class="entity name tag">port</span></span><span class="punctuation">:</span> <span class="constant numeric">8086</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Service</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">influxdb-externe</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">protocol</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">TCP</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">web</span></span>
<span class="string"><span class="entity name tag">port</span></span><span class="punctuation">:</span> <span class="constant numeric">8086</span>
<span class="string"><span class="entity name tag">type</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">LoadBalancer</span></span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string">influxdb</span>
</span></code></pre>
<p>J'ajoute ici un service de type loadbalancer afin de pouvoir y accéder depuis l'exterieur du cluster, car j'ai d'autres machines à monitorer.</p>
<h2>On applique</h2>
<pre><code><span class="">$ kubectl apply -f .
persistentvolume/config-influxdb-pv created
persistentvolumeclaim/config-influxdb-pvc created
deployment.apps/influxdb created
service/influxdb-web created
service/influxdb-externe created
</span></code></pre>
<p>Et normalement on a bien notre influxdb :</p>
<pre><code><span class="">$ kubectl get all -n monitor
NAME READY STATUS RESTARTS AGE
pod/influxdb-6d45d54c68-dsm69 1/1 Running 0 69m
pod/svclb-influxdb-externe-bgfz2 1/1 Running 0 85s
pod/svclb-influxdb-externe-bprrk 1/1 Running 0 85s
pod/svclb-influxdb-externe-7rx8h 1/1 Running 0 85s
pod/svclb-influxdb-externe-vdsbc 1/1 Running 0 85s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/influxdb-web ClusterIP 10.43.62.69 <none> 8086/TCP 3h36m
service/influxdb-externe LoadBalancer 10.43.211.61 192.168.1.131 8086:30874/TCP 86s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/svclb-influxdb-externe 4 4 4 4 4 <none> 27m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/influxdb 1/1 1 1 3h36m
NAME DESIRED CURRENT READY AGE
replicaset.apps/influxdb-6d45d54c68 1 1 1 3h36m
</span></code></pre>
<p>Comme dit je suis sur k3s, qui utilise <code>klipperlb</code> pour la gestion du LoadBalancing.</p>
<h1>Telegraf</h1>
<p>Là ça va être la partie la plus complexe, et celle dont j'ai le plus galéré.<br>
Toujours dans ma logique, je suis dans un répertoire <code>telegraf</code> dédié à l'application elle-même.</p>
<h2>00-rbac.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">rbac.authorization.k8s.io/v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ClusterRole</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">rules</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">apiGroups</span></span><span class="punctuation">:</span> <span class=""><span class="punctuation">[</span><span class="string"><span class="punctuation string">"</span><span class="punctuation string">"</span></span><span class="punctuation">]</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">nodes</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">nodes/proxy</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">services</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">endpoints</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">pods</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">persistentvolumes</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">persistentvolumeclaims</span></span>
<span class="string"><span class="entity name tag">verbs</span></span><span class="punctuation">:</span> <span class=""><span class="punctuation">[</span><span class="string"><span class="punctuation string">"</span>get<span class="punctuation string">"</span></span><span class="punctuation">,</span> <span class="string"><span class="punctuation string">"</span>list<span class="punctuation string">"</span></span><span class="punctuation">]</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">apiGroups</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">apps</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">deployments</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">daemonsets</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">replicasets</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">statefulsets</span></span>
<span class="string"><span class="entity name tag">verbs</span></span><span class="punctuation">:</span> <span class=""><span class="punctuation">[</span><span class="string"><span class="punctuation string">"</span>get<span class="punctuation string">"</span></span><span class="punctuation">,</span> <span class="string"><span class="punctuation string">"</span>list<span class="punctuation string">"</span></span><span class="punctuation">]</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">nonResourceURLs</span></span><span class="punctuation">:</span> <span class=""><span class="punctuation">[</span><span class="string"><span class="punctuation string">"</span>/metrics<span class="punctuation string">"</span></span><span class="punctuation">]</span></span>
<span class="string"><span class="entity name tag">verbs</span></span><span class="punctuation">:</span> <span class=""><span class="punctuation">[</span><span class="string"><span class="punctuation string">"</span>get<span class="punctuation string">"</span></span><span class="punctuation">]</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ServiceAccount</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegrafaccount</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">rbac.authorization.k8s.io/v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ClusterRoleBinding</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">roleRef</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">apiGroup</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">rbac.authorization.k8s.io</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ClusterRole</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">subjects</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ServiceAccount</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegrafaccount</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string">monitor</span>
</span></code></pre>
<p>On commence par les autorisations, le but étant de donner certains droit à <code>telegraf</code> dans le conteneur. Ici nous lui donnons la possibilités de récupérer plusieurs informations, mais en aucun cas de créer quelques choses.</p>
<h2>12-configmap.yml</h2>
<p>Ici nous avons une configuration static, donc nous allons utiliser un configmap :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ConfigMap</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf-config</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">data</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">telegraf.conf</span></span><span class="punctuation">:</span> <span class="keyword control">|</span>
<span class="string"> [global_tags]
[agent]
interval = "10s"
round_interval = true
metric_batch_size = 1000
metric_buffer_limit = 10000
collection_jitter = "0s"
flush_interval = "10s"
flush_jitter = "0s"
precision = ""
hostname = "${NODE_NAME}"
omit_hostname = false
[[outputs.influxdb]]
urls = [ "http://influxdb-web:8086" ]
database = "telegraf"
[[inputs.cpu]]
percpu = true
totalcpu = true
collect_cpu_time = false
report_active = false
[[inputs.disk]]
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs", "nfs"]
[[inputs.diskio]]
[[inputs.kernel]]
[[inputs.mem]]
[[inputs.processes]]
[[inputs.swap]]
[[inputs.system]]
[[inputs.kubernetes]]
url = "https://kubernetes.default.svc.cluster.local/api/v1/nodes/$NODE_NAME/proxy"
insecure_skip_verify = true
[[inputs.kube_inventory]]
url = "https://kubernetes.default.svc.cluster.local"
insecure_skip_verify = true
namespace= ""
</span></span></code></pre>
<p>C'est la configuration de telegraf, donc je vous invite à en regarder la docs (cf annexes).<br>
Nous avons ici quelques spécificité, comme le <code>hostname = "${NODE_NAME}</code>, ceci est une variable que l'on récupère au niveau du déploiement (enfin du daemonset, nous verrons ceci).<br>
Autrement nous avons l'url de kubernetes, en gros nous tapons sur le namespace default pour pouvoir accéder à l'API.</p>
<h2>20-daemonset.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">apps/v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">DaemonSet</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">matchLabels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">template</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">hostPID</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">hostIPC</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">serviceAccountName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegrafaccount</span></span>
<span class="string"><span class="entity name tag">containers</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.15</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">128M</span></span>
<span class="string"><span class="entity name tag">env</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">NODE_NAME</span></span>
<span class="string"><span class="entity name tag">valueFrom</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">fieldRef</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">fieldPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">spec.nodeName</span></span>
<span class="string"><span class="entity name tag">securityContext</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">privileged</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf:1.16-alpine</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf</span></span>
<span class="string"><span class="entity name tag">volumeMounts</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">dev</span></span>
<span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/host/dev</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">proc</span></span>
<span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/host/proc</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">sys</span></span>
<span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/host/sys</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">rootfs</span></span>
<span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/rootfs</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">config</span></span>
<span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/etc/telegraf</span></span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">config</span></span>
<span class="string"><span class="entity name tag">configMap</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">telegraf-config</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">proc</span></span>
<span class="string"><span class="entity name tag">hostPath</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/proc</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">dev</span></span>
<span class="string"><span class="entity name tag">hostPath</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/dev</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">sys</span></span>
<span class="string"><span class="entity name tag">hostPath</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/sys</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">rootfs</span></span>
<span class="string"><span class="entity name tag">hostPath</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string">/</span>
</span></code></pre>
<p>Alors là nous créons un <code>daemonset</code> au lui d'un <code>deployment</code>, ceci permets d'avoir une instance par noeud.<br>
En pus de ceci, nous utilisons donc le <code>serviceAccount</code> créer tout à l'heure.<br>
Le but étant de monitorer aussi bien l'hôte que kube lui même, j'ai ajouté <code>hostPID</code> et <code>hostIPC</code>, ainsi que les points de montage <code>/proc</code>, <code>/dev</code>, <code>/sys</code> et <code>/</code>. J'aurais pu également utiliser <code>hostNetwork</code>, mais ceci fait sortir mon conteneur du réseau du cluster, je verrais par la suite pour le mettre ou non, mais cela ajoutera des modifications à la configuration de <code>telegraf</code>.<br>
Ensuite dans le env, j'ajoute une variable <code>NODE_NAME</code>, pour récupérer le nom de l'hôte sur lequel le pod tourne, ce qui me permets d'overwrite le hostname, et au lieu d'avoir un tag <code>host</code> avec le nom du pod, j'ai bien le nom du noeud.</p>
<p>Au lieu de faire ceci, j'aurais pu effectivement installer <code>telegraf</code> sur l'hôte directement, mais je trouvais ça interressant de le faire via kube.</p>
<h2>On applique</h2>
<pre><code><span class="">$ kubectl apply -f .
clusterrole.rbac.authorization.k8s.io/telegraf created
serviceaccount/telegrafaccount created
clusterrolebinding.rbac.authorization.k8s.io/telegraf created
persistentvolume/telegraf-pv created
persistentvolumeclaim/telegraf-pvc created
configmap/telegraf-config created
daemonset.apps/telegraf created
</span></code></pre>
<p>Ce qui donne :</p>
<pre><code><span class="">$ kubectl get all -n monitor
NAME READY STATUS RESTARTS AGE
pod/influxdb-6d45d54c68-dsm69 1/1 Running 0 99m
pod/svclb-influxdb-externe-bgfz2 1/1 Running 0 27m
pod/svclb-influxdb-externe-bprrk 1/1 Running 0 27m
pod/svclb-influxdb-externe-7rx8h 1/1 Running 0 27m
pod/svclb-influxdb-externe-vdsbc 1/1 Running 0 27m
pod/telegraf-kk8j2 1/1 Running 0 31s
pod/telegraf-mz47w 1/1 Running 0 31s
pod/telegraf-lm727 1/1 Running 0 31s
pod/telegraf-hjnxj 1/1 Running 0 30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/influxdb-web ClusterIP 10.43.62.69 <none> 8086/TCP 4h5m
service/influxdb-externe LoadBalancer 10.43.211.61 192.168.1.131 8086:30874/TCP 27m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/svclb-influxdb-externe 4 4 4 4 4 <none> 27m
daemonset.apps/telegraf 4 4 4 4 4 <none> 31s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/influxdb 1/1 1 1 4h5m
NAME DESIRED CURRENT READY AGE
replicaset.apps/influxdb-6d45d54c68 1 1 1 4h5m
</span></code></pre>
<h1>Kapacitor</h1>
<p>Je passerai très rapidement dessus, avec simplement les fichiers de conf</p>
<h2>10-volumes.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">PersistentVolume</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-kapacitor-pv</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storageClassName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-kapacitor</span></span>
<span class="string"><span class="entity name tag">capacity</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">1Gi</span></span>
<span class="string"><span class="entity name tag">accessModes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">ReadWriteMany</span></span>
<span class="string"><span class="entity name tag">nfs</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">server</span></span><span class="punctuation">:</span> <span class="constant numeric">192.168.1.105</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>/data/kapacitor<span class="punctuation string">"</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">PersistentVolumeClaim</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-kapacitor-pvc</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storageClassName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-kapacitor</span></span>
<span class="string"><span class="entity name tag">accessModes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">ReadWriteMany</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string">500Mi</span>
</span></code></pre>
<h2>12-config.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">ConfigMap</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor-config</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">data</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">kapacitor.conf</span></span><span class="punctuation">:</span> <span class="keyword control">|</span>
<span class="string"> data_dir = "/var/lib/kapacitor"
[replay]
dir = "/var/lib/kapacitor/replay"
[storage]
boltdb = "/var/lib/kapacitor/kapacitor.db"
</span></span></code></pre>
<h2>20-deployment.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Deployment</span></span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">apps/v1</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor</span></span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">replicas</span></span><span class="punctuation">:</span> <span class="constant numeric">1</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">matchLabels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor</span></span>
<span class="string"><span class="entity name tag">template</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">containers</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor</span></span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor:1.5-alpine</span></span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">containerPort</span></span><span class="punctuation">:</span> <span class="constant numeric">9092</span>
<span class="string"><span class="entity name tag">env</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">KAPACITOR_INFLUXDB_0_URLS_0</span></span>
<span class="string"><span class="entity name tag">value</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>http://influxdb-web:8086<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">volumeMounts</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/etc/kapacitor/</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">config</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/var/lib/kapacitor/</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">150M</span></span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.2</span>
<span class="string"><span class="entity name tag">limits</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">500M</span></span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.5</span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">config</span></span>
<span class="string"><span class="entity name tag">configMap</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor-config</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data</span></span>
<span class="string"><span class="entity name tag">persistentVolumeClaim</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">claimName</span></span><span class="punctuation">:</span> <span class="string">data-kapacitor-pvc</span>
</span></code></pre>
<h2>30-service.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Service</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">kapacitor-web</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">protocol</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">TCP</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">web</span></span>
<span class="string"><span class="entity name tag">port</span></span><span class="punctuation">:</span> <span class="constant numeric">9092</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string">kapacitor</span>
</span></code></pre>
<h2>On applique</h2>
<pre><code><span class="">$ kubectl apply -f .
persistentvolume/data-kapacitor-pv created
persistentvolumeclaim/data-kapacitor-pvc created
configmap/kapacitor-config created
deployment.apps/kapacitor created
service/kapacitor-web created
$ kubectl get all -n monitor
NAME READY STATUS RESTARTS AGE
pod/influxdb-6d45d54c68-dsm69 1/1 Running 0 107m
pod/svclb-influxdb-externe-bgfz2 1/1 Running 0 35m
pod/svclb-influxdb-externe-bprrk 1/1 Running 0 35m
pod/svclb-influxdb-externe-7rx8h 1/1 Running 0 35m
pod/svclb-influxdb-externe-vdsbc 1/1 Running 0 35m
pod/telegraf-kk8j2 1/1 Running 0 9m12s
pod/telegraf-mz47w 1/1 Running 0 9m12s
pod/telegraf-lm727 1/1 Running 0 9m12s
pod/telegraf-hjnxj 1/1 Running 0 9m11s
pod/kapacitor-f6c7dfcb9-pvnwr 1/1 Running 0 37s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/influxdb-web ClusterIP 10.43.62.69 <none> 8086/TCP 4h14m
service/influxdb-externe LoadBalancer 10.43.211.61 192.168.1.131 8086:30874/TCP 35m
service/kapacitor-web ClusterIP 10.43.167.162 <none> 9092/TCP 38s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/svclb-influxdb-externe 4 4 4 4 4 <none> 35m
daemonset.apps/telegraf 4 4 4 4 4 <none> 9m12s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/influxdb 1/1 1 1 4h14m
deployment.apps/kapacitor 1/1 1 1 38s
NAME DESIRED CURRENT READY AGE
replicaset.apps/influxdb-6d45d54c68 1 1 1 4h14m
replicaset.apps/kapacitor-f6c7dfcb9 1 1 1 38s
</span></code></pre>
<h1>Chronograf</h1>
<p>Pareil, je montre juste les fichiers de déploiement, car ça reste un service plutôt basique.</p>
<h2>10-volumes.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">PersistentVolume</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-chronograf-pv</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storageClassName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-chronograf</span></span>
<span class="string"><span class="entity name tag">capacity</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">1Gi</span></span>
<span class="string"><span class="entity name tag">accessModes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">ReadWriteMany</span></span>
<span class="string"><span class="entity name tag">nfs</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">server</span></span><span class="punctuation">:</span> <span class="constant numeric">192.168.1.105</span>
<span class="string"><span class="entity name tag">path</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>/data/config/chronograf<span class="punctuation string">"</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">PersistentVolumeClaim</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-chronograf-pvc</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storageClassName</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data-chronograf</span></span>
<span class="string"><span class="entity name tag">accessModes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">ReadWriteMany</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string">500Mi</span>
</span></code></pre>
<h2>20-deployment.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Deployment</span></span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">apps/v1</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf</span></span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">replicas</span></span><span class="punctuation">:</span> <span class="constant numeric">1</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">matchLabels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf</span></span>
<span class="string"><span class="entity name tag">template</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">labels</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">containers</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf</span></span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf:1.8-alpine</span></span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">containerPort</span></span><span class="punctuation">:</span> <span class="constant numeric">8888</span>
<span class="string"><span class="entity name tag">env</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">INFLUXDB_URL</span></span>
<span class="string"><span class="entity name tag">value</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">http://influxdb-web:8086</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">KAPACITOR_URL</span></span>
<span class="string"><span class="entity name tag">value</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">http://kapacitor:9092</span></span>
<span class="string"><span class="entity name tag">volumeMounts</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">mountPath</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/var/lib/chronograf/</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data</span></span>
<span class="string"><span class="entity name tag">resources</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">requests</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">150M</span></span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.2</span>
<span class="string"><span class="entity name tag">limits</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">memory</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">500M</span></span>
<span class="string"><span class="entity name tag">cpu</span></span><span class="punctuation">:</span> <span class="constant numeric">0.5</span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">data</span></span>
<span class="string"><span class="entity name tag">persistentVolumeClaim</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">claimName</span></span><span class="punctuation">:</span> <span class="string">data-chronograf-pvc</span>
</span></code></pre>
<h2>30-service.yml</h2>
<pre><code><span class="source"><span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Service</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf-web</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">protocol</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">TCP</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">web</span></span>
<span class="string"><span class="entity name tag">port</span></span><span class="punctuation">:</span> <span class="constant numeric">8888</span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf</span></span>
<span class="entity">---</span>
<span class="string"><span class="entity name tag">apiVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">v1</span></span>
<span class="string"><span class="entity name tag">kind</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">Service</span></span>
<span class="string"><span class="entity name tag">metadata</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">chronograf-externe</span></span>
<span class="string"><span class="entity name tag">namespace</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">monitor</span></span>
<span class="string"><span class="entity name tag">spec</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">protocol</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">TCP</span></span>
<span class="string"><span class="entity name tag">name</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">web</span></span>
<span class="string"><span class="entity name tag">port</span></span><span class="punctuation">:</span> <span class="constant numeric">8888</span>
<span class="string"><span class="entity name tag">type</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">LoadBalancer</span></span>
<span class="string"><span class="entity name tag">selector</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">app</span></span><span class="punctuation">:</span> <span class="string">chronograf</span>
</span></code></pre>
<h2>On applique</h2>
<pre><code><span class="">$ kubectl apply -f .
persistentvolume/data-chronograf-pv created
persistentvolumeclaim/data-chronograf-pvc created
deployment.apps/chronograf created
service/chronograf-web created
service/chronograf-externe created
$ kubectl get all -n monitor
NAME READY STATUS RESTARTS AGE
pod/influxdb-6d45d54c68-dsm69 1/1 Running 0 114m
pod/svclb-influxdb-externe-bgfz2 1/1 Running 0 42m
pod/svclb-influxdb-externe-bprrk 1/1 Running 0 42m
pod/svclb-influxdb-externe-7rx8h 1/1 Running 0 42m
pod/svclb-influxdb-externe-vdsbc 1/1 Running 0 42m
pod/telegraf-kk8j2 1/1 Running 0 15m
pod/telegraf-mz47w 1/1 Running 0 15m
pod/telegraf-lm727 1/1 Running 0 15m
pod/telegraf-hjnxj 1/1 Running 0 15m
pod/kapacitor-f6c7dfcb9-pvnwr 1/1 Running 0 7m
pod/chronograf-85567dd664-s2xdd 1/1 Running 0 34s
pod/svclb-chronograf-externe-2gfsk 1/1 Running 0 33s
pod/svclb-chronograf-externe-kg4jq 1/1 Running 0 33s
pod/svclb-chronograf-externe-jxmzf 1/1 Running 0 33s
pod/svclb-chronograf-externe-hcvz7 1/1 Running 0 33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/influxdb-web ClusterIP 10.43.62.69 <none> 8086/TCP 4h21m
service/influxdb-externe LoadBalancer 10.43.211.61 192.168.1.131 8086:30874/TCP 42m
service/kapacitor-web ClusterIP 10.43.167.162 <none> 9092/TCP 7m1s
service/chronograf-web ClusterIP 10.43.144.238 <none> 8888/TCP 34s
service/chronograf-externe LoadBalancer 10.43.185.201 192.168.1.133 8888:31980/TCP 33s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/svclb-influxdb-externe 4 4 4 4 4 <none> 42m
daemonset.apps/telegraf 4 4 4 4 4 <none> 15m
daemonset.apps/svclb-chronograf-externe 4 4 4 4 4 <none> 33s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/influxdb 1/1 1 1 4h21m
deployment.apps/kapacitor 1/1 1 1 7m1s
deployment.apps/chronograf 1/1 1 1 34s
NAME DESIRED CURRENT READY AGE
replicaset.apps/influxdb-6d45d54c68 1 1 1 4h21m
replicaset.apps/kapacitor-f6c7dfcb9 1 1 1 7m1s
replicaset.apps/chronograf-85567dd664 1 1 1 34s
</span></code></pre>
<h1>Normalement ça fonctionne</h1>
<p>Normalement vous devriez pouvoir y accéder via http://ipexterne:8888, et vous devriez avoir la possibilité de créer vos jolies dashboard.<br>
Ici la partie interressant est vraiment l'installation de telegraf, qui est plus complexe que le reste :</p>
<p><img src="https://catlife.drycat.fr/static/media/4EC430DC-D905-CC36-4804-3962A6968DA5.png" alt="chronograf1"></p>
<p><img src="https://catlife.drycat.fr/static/media/A9C5D6BF-755E-376F-480C-A6C6D3D29F33.png" alt="chronograf2"></p>
<h1>Annexe</h1>
<ul>
<li><a href="https://www.youtube.com/watch?v=Q21mpBL7p3k&list=PLn6POgpklwWqfzaosSgX2XEKpse5VY2v5&index=60" rel="noopener noreferrer">Xavki</a> : Il vous faudra peux être être membre de la chaine (0,99€ minimum).</li>
<li><a href="https://docs.influxdata.com/telegraf/v1.16/" rel="noopener noreferrer">Telegraf docs</a></li>
<li><a href="https://docs.influxdata.com/telegraf/v1.14/plugins/plugin-list/" rel="noopener noreferrer">Plugins telegraf</a></li>
</ul>
]]><![CDATA[La gestion de mes sauvegardes]]>https://catlife.drycat.fr/~/XataZ/la-gestion-de-mes-sauvegardes/2020-08-25T11:51:04.693967+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-08-25T11:51:04.693967+00:00<![CDATA[<p>Cela fait des années que je me dis qu'il faut que je prennes du temps pour mettre en place un vrai système de sauvegarde, et j'ai enfin trouvé le temps (youhou \o/).</p>
<p>Je me suis donc lancé dans la quête du meilleur outil pour faire ceci, pour cela, j'ai évalué mon besoin.</p>
<h1>Analyse du besoin</h1>
<h2>Quoi sauvegarder ?</h2>
<h3>Les machines à sauvegarder</h3>
<p>Déjà quels périphériques faut-il sauvegarder, dans mon cas, j'ai besoin de sauvegarder mes smartphones, tablettes, PCs (Linux et windows) et mes serveurs. Il me font donc une solution cross-platform.</p>
<h3>Les données</h3>
<p>Ensuite il y a la question des fichiers, là j'ai surtout besoin de sauvegarder mes données personnelles (photos, documents, sextape etc ...), car si je perds ces données, ba je l'ai dans le cul.<br>
Tout ce qui est films, séries et musiques, c'est toujours récupérable, donc OSEF.</p>
<p>La configuration de certaines de mes applications peut aussi être importantes, nous avons ici 2 types de fichier de configuration, que je nomme dynamique et statique. Par exemple, un fichier de configuration de sshd, c'est générable, c'est d'ailleurs ce que fait un de mes rôles ansible. Mais un fichier de configuration qui est généré par une application, qui évolue avec le temps, ça il faut le sauvegarder.</p>
<h2>Quand sauvegarder ?</h2>
<p>Alors là c'est simple pour un serveur qui tourne H24, on le sauvegarde quand il n'y a pas trop d'activités dessus, souvent la nuit.</p>
<p>Mais un PCs, on ne peux pas faire tourner la nuit, car souvent il est éteint. On ne peux pas faire tourner une sauvegarde pendant qu'on joue, c'est assez consommateur de ressource.<br>
J'ai d'abord pensé à une sauvegarde à l'extinction du PC, d'autant pour un PC fixe ça fonctionne sans soucis, mais un PC portable, si je l'éteins pour partir avec, je ne vais pas attendre 1h avant de partir quand même.<br>
Je ne veux pas non plus d'une sauvegarde manuel, c'est toujours au moment de faire la sauvegarde que ça plante.</p>
<p>Pour les smartphones/tablettes, c'est un peu la même chose, mais en plus nous avons la question de la batterie, qui risque de consommer beaucoup.</p>
<h2>Où sauvegarder ?</h2>
<p>J'aimerai sauvegarder mes données à plusieurs endroits, chez moi pour y avoir accès rapidement, mais aussi ailleurs pour sécuriser physiquement celle-ci.<br>
Pour le local c'est faisable, j'ai mon serveur chez moi. Pour le ailleurs, l'utilisation d'un cloud serait pas mal, en y ajoutant du chiffrement bien évidemment.</p>
<h1>Mes choix</h1>
<p>Je n'ai malheureusement pas trouvé l'outil parfait, mais un trio de 3 outils, qui me permettent de faire exactement ce que je veux.<br>
Je sauvegarde donc sur une VM créer pour ceci, et je sauvegarde mes sauvegardes sur un google drive illimité.</p>
<h2>Les outils</h2>
<h3>Syncthing</h3>
<p>Le premier outils que j'utilise est <code>syncthing</code>, il est installé sur chacune de mes machines clientes (PCs, smartphones et tablettes), ainsi que sur ma VM qui me sert de fileserver.<br>
Le <code>syncthing</code> installé sur mon fileserver est un simple réceptable, il réceptionne les fichiers, mais n'en envoie aucun, avec une rétention de fichier de 2 jours, si un fichier est supprimé du client, il est gardé de coté pendant 2 jours, au cas où c'est une erreur.<br>
Sur les clients, <code>syncthing</code> est seulement en envoie, et en temps réel, dès qu'il y a un nouveau fichier il l'envoie.</p>
<p>L'avantage de <code>syncthing</code>, c'est que grace au relay, même sans être sur le réseau, la pseudo synchronisation fonctionne quand même.</p>
<h3>Borgbackup</h3>
<p><code>BorgBackup</code> est installé sur chacun de mes serveurs (virtuel et physique), et via une tâche cron, est sauvegardé toute les nuits à 2h. Il les envoies sur ma VM de sauvegarde (nommé <strong>saver</strong>, oui j'ai de l'imagination).<br>
Et donc tous mes fichiers synchronisés par <code>Syncthing</code> sur fileserver sont sauvegardés également.</p>
<p>Tout ceci est géré et installé par mon role ansible, par défaut je ne sauvegarde que mon /config, car je centralise généralement ma configuration dynamique dans ce répertoire sur mes serveurs. Mais je peux ajouter des répertoires via une variable.</p>
<h3>Duplicati</h3>
<p><code>Duplicati</code> est le dernier outil que j'utilises, il n'est installé que sur le <strong>saver</strong>, et il me permets donc d'envoyer le répertoire de <code>BorgBackup</code> dans le cloud (google drive).<br>
En gros, <code>Duplicati</code> me permets de faire une sauvegarde de sauvegardes, ce n'est pas le mieux, mais ça fonctionne parfaitement.</p>
<p>Lui tourne toute les nuits à 4h du matin.</p>
<h1>Petit schéma de mes sauvegardes</h1>
<p><img src="https://catlife.drycat.fr/static/media/BD80AFE7-B2A5-38D8-E471-29B27F0F622C.png" alt="Save scheme"></p>
<h1>Amélioration</h1>
<p>Mon système de sauvegarde n'est pas parfait, j'ai encore des améliorations à effectuer, notamment sur la partie ordonnancement. Le top serait de pouvoir centralisé l'ordonnancement, et de pouvoir améliorer le temps d'éxecution de toute la chaine, car là je joue sur l'heure avec cron, en estimant au mieux le temps des sauvegardes, mais je risquerais un jour d'avoir un problème et des étapes qui se chevauche. J'ai pensé à rundeck, mais je trouve ça lourd pour une 20ène de job.</p>
<p>L'autre amélioration, c'est la déduplication des données, <code>BorgBackup</code> le fait, <code>Duplicati</code> également, mais pas <code>Syncthing</code>.<br>
De base de mon coté, j'essaie au maximum d'éviter de dupliquer mes fichiers, mais ma copine c'est autre chose. J'ai compris comment elle gérait le tri de ses photos, et c'est catastrophique, en gros un répertoire par évenement (là je trouve ça normal), mais ensuite elle copie les photos dans des répertoires par personnes, donc une photo avec 50 personnes dessus, on se retrouve avec 51 fois la photo. C'est comme ça que sur son PC (et le fileserver), je me retrouve avec 1To, mais une fois sauvegardé et dédupliqué par <code>BorgBackup</code>, je n'ai plus que 200Go de fichier.</p>
<p>Mon système de sauvegarde n'est pas sur un choix arrêté, cela fait 2 semaines que ça tourne comme ça, et pour l'instant ça me va. Cependant je suis en train de regarder restic, qui couplé à rclone pourrait faire des miracles.</p>
<h1>Conclusion</h1>
<p>J'espère que cet article t'a plu, et que cela te donneras des idées.<br>
N'hésites pas à me faire un retour, sur ton système de sauvegarde, ou sur des idées pour améliorer le mien.</p>
]]><![CDATA[La jungle des conteneurs]]>https://catlife.drycat.fr/~/XataZ/la-jungle-des-conteneurs/2020-06-23T12:25:31.920488+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-06-23T12:25:31.920488+00:00<![CDATA[<p>Quand on parle de conteneurs, bien souvent 3 technologies nous viennent à l'esprit : <code>docker</code>, <code>kubernetes</code> et <code>lxc</code>.<br>
Cependant nous avons beaucoup plus de technologies que ça.</p>
<p>Nous ne parlerons pas ici de ce que j'appelle les conteneurs systèmes (Conteneurs comme LXC qui viennent avec tout l'OS), mais des conteneurs applicatifs (comme docker par exemple). Nous essaierons de comprendre le fonctionnement des conteneurs, en regardant les spécifications de ceux-ci, et en regardant les alternatives qui existe.</p>
<h1>Docker</h1>
<p>C'est indéniable, les conteneurs applicatifs sont ce qu'ils sont grâce à docker.</p>
<h2>Historique simplifié</h2>
<p>Docker était à la base une sorte d'interface de gestion à LXC, toujours pour faire du conteneurs applicatifs, mais avec comme backend LXC, il était donc très dépendant du développement de LXC. Par la suite, docker à lancer <code>libcontainers</code>, qui permettait de lancer les conteneurs sans LXC.<br>
Cependant à cette époque, beaucoup de reproches étaient fait à docker, notamment pour son binaire monolithique. Le même binaire servait à la fois de CLI, et à la fois de daemon.<br>
Docker a bien écouté ce reproche, et a commencé par découper le daemon et la CLI.</p>
<p>Par la suite, l'Open Container Initiative fut créée, afin de créer un standard du conteneur applicatif. Docker a été un acteur principal dans cette définition.</p>
<p>De cette initiative, sont nées 2 spécifications, le runtime-spec, et le image-spec, qui permettent la standardisation du lancement d'un conteneur, et de la création d'image, c'est ce qu'on appelle le modèle OCI.</p>
<h2>Aujourd'hui</h2>
<p>Docker n'est aujourd'hui plus ce gros bloc monolithique qu'il était, et on pourrait même dire qu'il ne fait plus grand chose.<br>
Docker utilise désormais <code>containerd</code> et <code>runc</code> pour lancer ces conteneur, et si je ne me trompe pas, il ne garde pour lui que la gestion des images et des réseaux.</p>
<h1>Les runtimes et outils</h1>
<p>Avec ce découpage, nous avons maintenant beaucoup de runtime et d'outils qui existent.</p>
<h2>Runtime de bas niveau</h2>
<p>Les runtimes de bas niveau, sont les outils qui permettrons l'exécution du conteneur au format OCI, rien de plus, rien de moins.</p>
<p>Nous en avons beaucoup, avec certains qui sont très particuliers :</p>
<ul>
<li>runc : est le runtime issue de l'OCI, celui par défaut</li>
<li>crun : L'implémentation de <code>runc</code> en C qui semble environ 2 fois plus rapide que runc</li>
<li>gvisor : Le runtime de google, avec une isolation supplémentaire</li>
<li>kata-container : Un runtime qui crée un VM par conteneur pour une isolation complète</li>
<li>runV : Idem (mais ne semble plus maintenu)</li>
<li>clear-container : Idem (ne semble plus maintenu)</li>
<li>Et surement beaucoup d'autres ...</li>
</ul>
<h2>Runtime de haut niveau</h2>
<p>Les runtimes de haut niveau ont un rôle plus global, il permettent la gestion des images, de monter les volumes, de gérer les couches de fs, etc ...</p>
<p>Nous en avons quelques-un également :</p>
<ul>
<li>containerd : Celui utilisé par défaut avec docker et k3s, il fonctionne également en mode API exposé par un daemon.</li>
<li>conmon : Celui utilisé par défaut par podman, comme podman, il est daemonless.</li>
<li>cri-o : CRI-O est l'implémentation du modèle CRI de kubernetes, fonctionne avec k8s.</li>
<li>...</li>
</ul>
<h2>Les controlleurs</h2>
<p>Les controlleurs sont le nom que je leur donne, je ne sais pas s'il y a vraiment un nom pour ceci. Ce sont les outils qui permettent de controler les conteneurs. Nous trouvons dans ce niveau, des orchestrateurs et des simples lanceurs de conteneurs.<br>
C'est ce que tout le monde connais :</p>
<ul>
<li>docker</li>
<li>podman</li>
<li>kubernetes et dérivés (k3s, minikube etc ...)</li>
<li>crictl : Pour controler cri-o</li>
<li>ctr : Pour controler containerd</li>
<li>rkt</li>
<li>...</li>
</ul>
<h2>Les builders d'image</h2>
<p>Désormais il existe beaucoup de builder d'image :</p>
<ul>
<li>docker : Toujours aussi bien foutu avec les Dockerfiles</li>
<li><a href="https://buildah.io/" rel="noopener noreferrer">buildah</a> : Mon petit chouchou, rootless, daemonless, compatible dockerfile, que demandé de plus (un excellent <a href="https://www.grottedubarbu.fr/buildah-basics/" rel="noopener noreferrer">tutoriel</a> )</li>
<li><a href="https://github.com/genuinetools/img" rel="noopener noreferrer">img</a> : Pareil, rootless et daemonless, basé sur les dockerfiles, et en plus cross build</li>
<li><a href="https://github.com/cyphar/orca-build" rel="noopener noreferrer">orca-build</a> : Je n'ai pas testé celui ci, mais compatible avec dockerfiles, semble un peu plus lourd à mettre en place.</li>
<li><a href="https://github.com/moby/buildkit" rel="noopener noreferrer">buildkit</a></li>
<li><a href="https://github.com/GoogleContainerTools/kaniko" rel="noopener noreferrer">kaniko</a></li>
<li>...</li>
</ul>
<h2>Mais alors, que choisir ?</h2>
<p>Tout n'est pas changeable pour tout, par exemple, pour docker ou podman vous n'avez pas le choix, il faut utiliser <code>containerd</code> (docker) ou <code>conmon</code> (podman), mais vous pouvez changer de runtime de bas niveau, par exemple en fonction de votre besoin, nous pouvons utiliser <code>crun</code> pour gagner en performance, ou alors <code>gvisor</code> ou <code>kata-container</code> pour une meilleur isolation.<br>
Pour kubernetes, là nous avons plusieurs choix, nous pouvons utiliser <code>docker</code>, ou alors directement <code>containerd</code>. Nous pouvons également choisir d'utiliser <code>cri-o</code> qui est selon moi le couple gagnant. Derrière <code>cri-o</code>, il est possible de changer de runtime de bas niveau également. Nous pourions également utiliser <code>rkt</code>, je l'ai mis dans les controlleurs, mais en réalité rkt est totalement monolithique, et est à la fois un runtime de haut et bas niveaux.<br>
K3s de base utilise <code>containerd</code> directement, je n'ai pas regarder mais je suppose que tout est changeable également, je pense que le trio <code>k3s</code>, <code>cri-o</code> et <code>crun</code> doit faire une très bonne équipe.</p>
<p>Pour ce qui est du build, si vous utilisez docker ou podman, autant utiliser ceux intégré, à moins que comme moi, vous voulez externaliser les builds, dans ce cas du daemonless peux être top, comme <code>buildah</code> ou <code>img</code>.</p>
<h1>Cas pratiques</h1>
<p>Ici nous allons voir quelques exemples, il n'ont pas forcément de lien entre eux.</p>
<h2>Utilisation de runc à la main</h2>
<p>Runc est totalement utilisable sans docker, même si peu pratique, car c'est simplement un lanceur de conteneur, il ne gère pas les images ni le réseau.</p>
<p>Nous allons donc créer un petit conteneur alpine, pour ce faire nous commençons par créer notre répertoire :</p>
<pre><code><span class="">$ mkdir ~/runctest/alpine -p
$ cd ~/runctest/alpine
</span></code></pre>
<p>Puis nous générons les specs OCI (génération d'un fichier config.json) :</p>
<pre><code><span class="">$ runc spec --rootless
$ ls
config.json
</span></code></pre>
<p>Nous téléchargeons l'image minirootfs d'alpine :</p>
<pre><code><span class="">$ wget http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/alpine-minirootfs-3.12.0-x86_64.tar.gz
$ mkdir rootfs
$ tar xzf alpine-minirootfs-3.12.0-x86_64.tar.gz -C rootfs
</span></code></pre>
<p>et nous pouvons lancer notre conteneur :</p>
<pre><code><span class="">$ runc run alpine
#
</span></code></pre>
<p>Et nous voilà dans notre conteneur, fonctionnel, et avec le réseau. Cependant le réseau est en mode host, pas de namespace utilisé :</p>
<pre><code><span class=""># ip addr
[...]
2: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 34:f3:9a:a4:7a:9f brd ff:ff:ff:ff:ff:ff
inet 192.168.1.50/24 brd 192.168.1.255 scope global dynamic wlp2s0
valid_lft 76769sec preferred_lft 76769sec
inet6 fe80::2bf9:b989:530c:e0f8/64 scope link
valid_lft forever preferred_lft forever
[...]
</span></code></pre>
<p>Je trouve que c'est moyen, allons donc modifier un peu le fichier de configuration :</p>
<pre><code><span class="source"><span class=""><span class="punctuation">[</span><span class="invalid">.</span><span class="invalid">.</span><span class="invalid">.</span><span class="punctuation">]</span></span>
<span class="string"><span class="punctuation string">"</span>root<span class="punctuation string">"</span></span>: <span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>path<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>rootfs<span class="punctuation string">"</span></span><span class="punctuation">,</span></span>
<span class=""><span class="string"><span class="punctuation string">"</span>readonly<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="constant language">false</span>
</span><span class="punctuation">}</span></span>,
<span class=""><span class="punctuation">[</span><span class="invalid">.</span><span class="invalid">.</span><span class="invalid">.</span><span class="punctuation">]</span></span>
<span class="string"><span class="punctuation string">"</span>namespaces<span class="punctuation string">"</span></span>: <span class=""><span class="punctuation">[</span>
<span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>type<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>pid<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span><span class="punctuation">,</span>
<span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>type<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>ipc<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span><span class="punctuation">,</span>
<span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>type<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>uts<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span><span class="punctuation">,</span>
<span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>type<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>mount<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span><span class="punctuation">,</span>
<span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>type<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>user<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span><span class="punctuation">,</span>
<span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>type<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>network<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span>
<span class="punctuation">]</span></span>,
<span class=""><span class="punctuation">[</span><span class="invalid">.</span><span class="invalid">.</span><span class="invalid">.</span><span class="punctuation">]</span></span>
</span></code></pre>
<p>J'ai ajouté dans la partie namespaces, un namespace de type <code>network</code>. J'ai également modifier le readonly, car de base le FS est en lecture seul, pas toujours pratique pour les tests.<br>
Désormais nous n'avons plus de réseau sur notre conteneur :</p>
<pre><code><span class="">$ runc run alpine
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
</span></code></pre>
<h3>Ajoutons du réseau</h3>
<p>Puisque nous sommes en rootless, nous allons utiliser <a href="https://github.com/rootless-containers/slirp4netns" rel="noopener noreferrer">slirp4netns</a> :</p>
<p>On lance notre conteneur dans un premier terminal :</p>
<pre><code><span class="">$ runc run --pid-file /tmp/alpine.pid alpine
# ping 9.9.9.9
</span></code></pre>
<p>Puis dans un second :</p>
<pre><code><span class="">$ slirp4netns --configure --mtu=65520 --disable-host-loopback $(cat /tmp/alpine.pid) tap0
sent tapfd=5 for tap0
received tapfd=5
Starting slirp
* MTU: 65520
* Network: 10.0.2.0
* Netmask: 255.255.255.0
* Gateway: 10.0.2.2
* DNS: 10.0.2.3
* Recommended IP: 10.0.2.100
</span></code></pre>
<p>Si nous retournons dans notre conteneur :</p>
<pre><code><span class=""># ip addr
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: tap0: <BROADCAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN qlen 1000
link/ether 4e:3f:be:b7:dd:04 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.100/24 brd 10.0.2.255 scope global tap0
valid_lft forever preferred_lft forever
inet6 fd00::4c3f:beff:feb7:dd04/64 scope global dynamic
valid_lft 86389sec preferred_lft 14389sec
inet6 fe80::4c3f:beff:feb7:dd04/64 scope link
valid_lft forever preferred_lft forever
# apk update
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
v3.12.0-86-g64c1a9607a [http://dl-cdn.alpinelinux.org/alpine/v3.12/main]
v3.12.0-89-g636a7dc328 [http://dl-cdn.alpinelinux.org/alpine/v3.12/community]
OK: 12736 distinct packages available
</span></code></pre>
<h2>Gérer vos conteneurs avec containerd</h2>
<p>Si vous avez utilisez docker, vous utilisez containerd sans le savoir.<br>
Containerd est également un daemon, qui lancera une instance <code>runc</code> en mode detach via <code>containerd-shim</code>. En gros nous nous retrouvons avec ceci :</p>
<p><img src="https://catlife.drycat.fr/static/media/EB3FD0B0-473C-9B8A-E63A-A0B977264A00.png" alt="docker-containerd-shim"></p>
<p>Nous pouvons cependant directement utiliser containerd, c'est plus limité, mais c'est fonctionnel.</p>
<h3>Pull d'image</h3>
<p>Avec containerd, il faut indiqué le registry sur lequel on télécharger l'image et surtout le tag de celle-ci :</p>
<pre><code><span class="">$ ctr -a /var/run/docker/containerd/containerd.sock images pull docker.io/library/alpine:latest
docker.io/library/alpine:latest: resolved |++++++++++++++++++++++++++++++++++++++|
index-sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321: done |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:a15790640a6690aa1730c38cf0a440e2aa44aaca9b0e8931a9f2b0d7cc90fd65: done |++++++++++++++++++++++++++++++++++++++|
layer-sha256:df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c: done |++++++++++++++++++++++++++++++++++++++|
config-sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e: done |++++++++++++++++++++++++++++++++++++++|
elapsed: 2.1 s total: 2.7 Mi (1.3 MiB/s)
unpacking linux/amd64 sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321...
done
</span></code></pre>
<h3>Lancement du conteneur</h3>
<p>On commence par créer notre conteneur</p>
<pre><code><span class="">$ ctr -a /var/run/docker/containerd/containerd.sock run -tdocker.io/library/alpine:latest test sh
#
</span></code></pre>
<p>Rien de bien compliqué</p>
<h2>Utilisation de gvisor</h2>
<h3>Installation</h3>
<pre><code><span class="">$ apt install golang
$ echo "module runsc" > go.mod
$ GO111MODULE=on go get -v gvisor.dev/gvisor/runsc@go
$ CGO_ENABLED=0 GO111MODULE=on go install -v gvisor.dev/gvisor/runsc
$ cp go/bin/runsc /usr/local/bin/
</span></code></pre>
<p>Puis on modifie ou crée le fichier /etc/docker/daemon.json :</p>
<pre><code><span class="source"><span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>default-runtime<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>runc<span class="punctuation string">"</span></span><span class="punctuation">,</span></span>
<span class=""><span class="string"><span class="punctuation string">"</span>runtimes<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>gvisor<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class=""><span class="punctuation">{</span>
<span class=""><span class="string"><span class="punctuation string">"</span>path<span class="punctuation string">"</span></span></span><span class=""><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>/usr/local/bin/runsc<span class="punctuation string">"</span></span>
</span><span class="punctuation">}</span></span>
</span><span class="punctuation">}</span></span>
</span><span class="punctuation">}</span></span>
</span></code></pre>
<p>On relance docker :</p>
<pre><code><span class="">$ systemctl restart docker
</span></code></pre>
<p>Si on vérifie :</p>
<pre><code><span class="">$ docker info
[...]
Runtimes: gvisor runc
Default Runtime: runc
[...]
</span></code></pre>
<h3>Utilisation</h3>
<p>Nous le lancerons ici un conteneur alpine avec runc, et l'autre avec gvisor, afin de pouvoir analyser le tout :</p>
<pre><code><span class="">$ docker run -d --rm -m 128M --cpuset-cpus 0 alpine ping 1.1.1.1
$ docker run -d --rm --runtime gvisor -m 128M --cpuset-cpus 0 alpine ping 9.9.9.9
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fcf50706c70d alpine "ping 9.9.9.9" 4 seconds ago Up 3 seconds great_davinci
084da1b082c6 alpine "ping 1.1.1.1" 17 seconds ago Up 16 seconds heuristic_euclid
</span></code></pre>
<p>Première chose que nous pouvons constater, c'est qu'on ne vois que le processus lancé via runc (<code>ping 1.1.1.1</code>) sur l'hôte, l'autre est invisible (<code>ping 9.9.9.9</code>) :</p>
<pre><code>$ ps aux | grep ping
root 20302 0.0 0.0 1568 4 ? Ss 10:19 0:00 ping 1.1.1.1
root 20379 0.0 0.0 8160 736 pts/0 S+ 10:27 0:00 grep --color=auto ping
</code></pre>
<p>Ensuite nous pouvons voir que même docker est incapable de voir ce qui se passe dans le conteneur :</p>
<pre><code><span class="">$ docker top fc
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:20 ? 00:00:08 /sbin/init
$ docker top 08
UID PID PPID C STIME TTY TIME CMD
root 25759 25739 0 15:45 ? 00:00:00 ping 1.1.1.1
</span></code></pre>
<p>Nous pouvons voir également une différence dans la gestion du CPU et de la RAM :</p>
<pre><code><span class="">$ docker exec -ti fc free -m
total used free shared buff/cache available
Mem: 128 1 126 0 0 126
Swap: 0 0 0
$ docker exec -ti 08 free -m
total used free shared buff/cache available
Mem: 7844 2540 2733 630 2571 4556
Swap: 0 0 0
</span></code></pre>
<p>Sur notre conteneur lancé avec <code>runc</code>, nous voyons toute la ram disponible sur la machine, avec <code>gvisor</code> seul la ram vraiment disponible.<br>
Pareil donc pour le CPU :</p>
<pre><code><span class="">$ docker exec -ti fc cat /proc/cpuinfo | grep -c processor
1
$ docker exec -ti 08 cat /proc/cpuinfo | grep -c processor
4
</span></code></pre>
<p>Seulement 1 cpu n'est dispo sur le conteneur <code>gvisor</code> contre les 4 sur celui lancé avec <code>runc</code>.</p>
<p>De plus, si nous utilisons <code>--pid host</code>, seul le conteneur lancé par <code>runc</code> sera capable de voir les process de l'hôte, et non le conteneur lancé avec <code>gvisor</code> :</p>
<pre><code><span class="">$ docker run -ti --rm --runtime gvisor --pid host alpine ps aux
PID USER TIME COMMAND
1 root 0:00 ps aux
</span></code></pre>
<p>Tandis qu'avec <code>runc</code> :</p>
<pre><code><span class="">$ docker run -ti --rm --runtime runc --pid host alpine ps aux
PID USER TIME COMMAND
1 root 0:09 {systemd} /sbin/init
2 root 0:00 [kthreadd]
3 root 0:00 [rcu_gp]
4 root 0:00 [rcu_par_gp]
6 root 0:00 [kworker/0:0H-kb]
8 root 0:00 [mm_percpu_wq]
9 root 0:00 [ksoftirqd/0]
10 root 0:00 [rcuc/0]
11 root 0:01 [rcu_preempt]
12 root 0:00 [rcub/0]
13 root 0:00 [migration/0]
14 root 0:00 [idle_inject/0]
[...]
</span></code></pre>
<p>Nous pouvons également comparé le noyau Linux :</p>
<pre><code><span class="">$ docker run -ti --rm --runtime runc alpine uname -a
Linux 20b700aaf75a 5.6.16-1-MANJARO #1 SMP PREEMPT Wed Jun 3 14:26:28 UTC 2020 x86_64 Linux
$ docker run -ti --rm --runtime gvisor alpine uname -a
Linux 72c518a36cb0 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 Linux
</span></code></pre>
<p>Nous voyons clairement que <code>gvisor</code> intègre son propre noyau, ce qui prouve que l'isolation est bien là.</p>
<h1>Quelques ressoures</h1>
<ul>
<li><a href="https://www.youtube.com/watch?v=tH94D4Iaxpk" rel="noopener noreferrer">Docker est mort, vive docker</a></li>
<li><a href="https://www.youtube.com/watch?v=GtWQ7et4-hQ" rel="noopener noreferrer">Cri-o, un bon remplaçant à docker</a></li>
</ul>
<h1>Conclusion</h1>
<p>Faire cette article m'a poussé à faire pas mal de recherche, et j'ai testé beaucoup de chose.<br>
Je suis en se moment en train de tester le trio <code>docker</code>, <code>containerd</code> et <code>gvisor</code>, qui me semble le meilleur compromis en terme d'isolation et de performances. </p>
]]><![CDATA[Multipass sans ubuntu]]>https://catlife.drycat.fr/~/XataZ/multipass-sans-ubuntu/2020-06-22T16:07:17.146613+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-06-22T16:07:17.146613+00:00<![CDATA[<p>J'entends parler de multipass partout, mais vraiment partout, j'ai donc voulu tester ceci, mais le fait de ne pouvoir lancer que des VMs ubuntu me parraissait trop limité.</p>
<p>Après quelques recherches, j'ai vu que ce n'était en fait pas vraiment le cas, nous pouvons installer ce que nous voulons en fait, tant que c'est une image avec cloud-init intégré.</p>
<p>Voici donc un tout petit article sur l'utilisation de <code>multipass</code> sans ubuntu.</p>
<h1>Installation de multipass</h1>
<p>Malheureusement il n'y a pas 36 solutions, soit on compile, soit on installe par snap, ou avec un peu de chance, vous être sur une base archlinux, et c'est dispo dans AUR.</p>
<p>Pour tester, je l'ai installé avec snap :</p>
<pre><code><span class="">$ snap install multipass
</span></code></pre>
<h1>Créer une VM debian</h1>
<p>Pour ceci c'est très simple, on télécharge l'image openstack :</p>
<pre><code><span class="">$ wget https://cloud.debian.org/images/cloud/OpenStack/current-10/debian-10-openstack-amd64.qcow2
</span></code></pre>
<p>Puis on lance notre VMs :</p>
<pre><code><span class="">$ multipass launch -n debian file://$PWD/debian-10-openstack-amd64.qcow2
</span></code></pre>
<p>Et c'est tout, puisqu'il y a cloud-init dans l'image openstack de debian, multipass à réussi à tout configurer comme il faut.</p>
<p>Nous pouvons bien évidemment rajouter un script cloud-init :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">package_update</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">packages</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string">vim</span>
<span class="punctuation">-</span> <span class="string">git</span>
</span></code></pre>
<pre><code><span class="">$ multipass launch -n debian2 --cloud-init cloud.yml file://$PWD/debian-10-openstack-amd64.qcow2
Launched: debian2
$ multipass list
Name State IPv4 Image
debian Running 10.25.119.170 Not Available
debian2 Running 10.25.119.207 Not Available
ubuntu Running 10.25.119.206 Ubuntu 20.04 LTS
$ multipass exec debian2 git version
git version 2.20.1
</span></code></pre>
<h1>Créer une VM centos</h1>
<p>Il est même possible de directement télécharger l'image depuis le repo :</p>
<pre><code><span class="">$ multipass launch -n centos --cloud-init cloud.yml -d 10G https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2.xz
$ multipass exec centos cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
</span></code></pre>
<h1>Conclusion</h1>
<p>Et voilà pour ce très cours article, mais rien que le fait de savoir ceci, me fait adorer multipass ^^.<br>
Si demain, multipass permets en plus de gérer correctement le réseau, je pourrais bien me passer de proxmox, et tout gérer par multipass.</p>
]]><![CDATA[Traefik v2, un vrai reverse proxy]]>https://catlife.drycat.fr/~/XataZ/traefik-v2-un-vrai-reverse-proxy/2020-06-08T13:09:02.084668+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-06-08T13:09:02.084668+00:00<![CDATA[<p>Je suis très longtemps resté sur mon bon vieux nginx pour faire mon reverse proxy, ça fonctionne parfaitement.<br>
J'avais déjà testé traefik en version 1.5, et je l'avais trouvé plutôt lent et limité, mais récemment, je me suis dit que j'allais retesté tout ça, à l'heure ou j'écris ces lignes, nous sommes à la version 2.2, nommée chevrotin.</p>
<p>J'ai eu beaucoup de mal à bien comprendre le fonctionnement de traefik, car la quasi totalité des tutoriels sont identiques niveau configuration, ce qui changeait c'est l'application mis derrière. Mais aucun réel tutoriel qui en explique le fonctionnement. Nous allons ici tenter de réellement comprendre ce que nous faisons, avec une approche totalement différente.</p>
<p>Je ne reviendrais sur ce qu'est traefik, si vous êtes tombé sur ce tutoriel, c'est que vous savez ce que c'est.</p>
<h1>Vocabulaire</h1>
<p>Pour comprendre le fonctionnement de traefik, nous aurons besoin d'un peu de vocabulaire :</p>
<h2>les entrypoints</h2>
<p>Les entrypoints sont comme le nom l'indique les points d'entrées, ce sont les adresses et ports exposés par traefik, qui permettrons d'exposer nos applications. Bien souvent nous utilisons les ports 443 et 80.</p>
<h2>les services</h2>
<p>Les services sont nos applications, par exemple nextcloud. Dans la version 1.X de traefik, c'était nommé les backends.<br>
Nous avons 3 types de services :</p>
<ul>
<li>http</li>
<li>tcp</li>
<li>udp</li>
</ul>
<p>Nous ne sommes donc pas limité au web, nous pouvons redirigé du ssh, du ftp , what else ?!!!</p>
<h2>les routers</h2>
<p>Les routers sont les règles de redirection du reverse, nous pointons un router vers un service. A ce router nous lui donnons des URLs, des entrypoints.</p>
<h2>les providers</h2>
<p>Les providers sont les sources de génération de la configuration. C'est ce qui fait la force de traefik, il en existe plusieurs, de plusieurs type :</p>
<ul>
<li>Moteur de conteneur :
<ul>
<li>docker : La plus connu, on donne accès au socket de docker à traefik, et lui va gérer la création des services et routers en lisant celui-ci, en fonction des labels utilisés.</li>
<li>kubernetes : Fonctionne de manière similaire à docker.</li>
<li>rancher : Je n'ai pas encore regardé le fonctionnement, mais je suppose que le fonctionnement est identique à kubernetes</li>
<li>marathon : Pareil que pour rancher</li>
</ul>
</li>
<li>Base de clé/valeur : Je n'ai pas regardé exactement le fonctionnement de ce type de provider
<ul>
<li>consul</li>
<li>consulcatalog</li>
<li>etcd</li>
<li>redis</li>
<li>zookeeper</li>
</ul>
</li>
<li>file : Permets de lire un fichier ou un répertoire contenant des fichiers de configuration à la volée.</li>
</ul>
<h2>les middlewares</h2>
<p>Les middlewares seront des étapes intermédiaires entre le router et le service, ça peux être un peu tout et n'importe quoi, comme de la compression, de la sécurisation, de la configuration, ou même de l'authentification (cela fera l'objet d'un autre article).</p>
<h1>Configuration</h1>
<p>Pour configurer traefik, nous avons deux méthodes, la méthode interactive, et la méthode déclarative.</p>
<h2>Interactive</h2>
<p>Cette méthode permets de passer la configuration directement en paramètre de l'exécutable, par exemple nous pourrions avoir ceci :</p>
<pre><code><span class="">$ traefik --accesslog=true \
--api=true \
--api.insecure=true \
--api.dashboard=true \
--api.debug=true \
--log.level=INFO \
--providers.docker.endpoint=unix:///var/run/docker.sock \
--providers.docker.exposedbydefault=false \
--providers.docker.watch=true \
--providers.docker.swarmmode=true \
--providers.file.filename=/etc/traefik/traefik_dynamic.yml \
--providers.file.watch=true \
--entrypoints.web.address=:80 \
--entrypoints.websecure.address=:443 \
--entrypoints.web.http.redirections.entrypoint.scheme=https \
--entrypoints.web.http.redirections.entrypoint.to=websecure \
--certificatesresolvers.letsencrypt.acme.email=xataz@monmail.net \
--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory \
--certificatesresolvers.letsencrypt.acme.storage=/acme.json \
--certificatesresolvers.letsencrypt.acme.keytype=EC384 \
--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \
--certificatesresolvers.letsencrypt.acme.tlschallenge=true
</span></code></pre>
<p>C'est personnellement la méthode que j'utilise.<br>
Cette méthode devient déclarative si on utilise docker et docker-compose, ou même kubernetes.</p>
<h2>Déclarative</h2>
<p>Nous pouvons également passer un fichier de paramètre à traefik, au format <code>toml</code> ou <code>yaml</code>, ce qui donnerais pour la même configuration :</p>
<h3>TOML</h3>
<pre><code><span class="">[accesslog]
[api]
insecure=true
dashboard=true
debug=true
[log]
level="INFO"
[providers]
[providers.docker]
endpoint="unix:///var/run/docker.sock"
exposedbydefault=false
watch=true
swarmmode=true
[providers.file]
filename=/etc/traefik/traefik_dynamic.yml
watch=true
[entryPoints]
[entryPoints.web]
address=":80"
[entryPoints.web.http.redirections.entrypoint]
scheme="https"
to="websecure"
[entryPoints.websecure]
address=":443"
[certificatesResolvers]
[certificatesResolvers.letsencrypt]
[certificatesResolvers.letsencrypt.acme]
email = "mail@nomdedomaine.org"
caServer = "https://acme-v02.api.letsencrypt.org/directory"
storage = "acme.json"
keyType = "EC384"
[certificatesResolvers.letsencrypt.acme.httpChallenge]
entryPoint = "web"
</span></code></pre>
<p>Perso je n'aime pas du tout ce format, c'est ce qui m'avait fait fuire traefik à l'époque.</p>
<h3>YAML</h3>
<pre><code><span class="source"><span class="string"><span class="entity name tag">accesslog</span></span><span class="punctuation">:</span> <span class=""><span class="punctuation">{</span><span class="punctuation">}</span></span>
<span class="string"><span class="entity name tag">api</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">insecure</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">dashboard</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">debug</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">log</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">level</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>INFO<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">providers</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">docker</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">endpoint</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>unix:///var/run/docker.sock<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">exposedbydefault</span></span><span class="punctuation">:</span> <span class="constant language">false</span>
<span class="string"><span class="entity name tag">watch</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">swarmmode</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">file</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">filename</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">/etc/traefik/traefik_dynamic.yml</span></span>
<span class="string"><span class="entity name tag">watch</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">entryPoints</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">web</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">address</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>:80<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">redirections</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">entrypoint</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">scheme</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>https<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">to</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>websecure<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">websecure</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">address</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>:443<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">certificatesResolvers</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">letsencrypt</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">acme</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">email</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>mail@nomdedomaine.org<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">caServer</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>https://acme-v02.api.letsencrypt.org/directory<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">storage</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>acme.json<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">keyType</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>EC384<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">httpChallenge</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">entryPoint</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>web<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Je trouve le yaml beaucoup plus clair et simple.</p>
<h1>Cas pratique</h1>
<p>Rien de mieux qu'un exemple pour comprendre, nous allons faire une petite stack avec traefik, nextcloud et postgres.<br>
Dans cette exemple, nous utiliserons docker pour installer les services, mais pas pour la configuration automatique de traefik.</p>
<blockquote>
<p>Pouquoi donc ?!</p>
</blockquote>
<p>Déjà je n'aime pas le fait de mettre mon socket docker dans un conteneur, même en lecture seul, le socket à toutes les informations des conteneurs. Autrement, je n'aime pas trop alourdir mes docker-compose, j'aime quand c'est clair, net et précis.<br>
Selon moi, l'utilisation des labels va être utile seulement si on installe régulièrement (plusieurs fois par jours) des conteneurs, qu'on en supprime, en gros quand on est un cloud publique. Dans une utilisation personnelle, la configuration d'un reverse ne change pas souvent.</p>
<p>De plus, on a souvent tendance dès lors qu'on parle de traefik, de le lier directement à docker ou kubernetes, hors traefik est avant tout un reverse proxy, il est utilisable sans docker, sans conteneur, en baremetal.</p>
<h2>Notre stack de base (docker-compose)</h2>
<p>Nous partirons donc de cette configuration de docker-compose :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">version</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>3.8<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">networks</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">traefik</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">services</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">traefik</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">traefik:chevrotin</span></span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">/srv/docker/traefik/acme.json:/etc/traefik/acme.json</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">/srv/docker/traefik/certs:/etc/traefik/certs</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">/var/run/docker.sock:/var/run/docker.sock</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">/srv/docker/traefik/conf.d:/etc/traefik/conf.d</span></span>
<span class="string"><span class="entity name tag">ports</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string">80:80</span>
<span class="punctuation">-</span> <span class="string">443:443</span>
<span class="punctuation">-</span> <span class="string">8080:8080</span> <span class="comment"><span class="punctuation comment">#</span> le temps de tester
</span> <span class="string"><span class="entity name tag">networks</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">traefik</span></span>
<span class="string"><span class="entity name tag">command</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--global.sendanonymoususage=false<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> désactivation de l'envoi de donnée
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--global.checknewversion=false<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> puisque dockerisé, on désactive le check de mise à jour
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--accesslog=true<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Pour avoir les logs d'accès
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--api=true<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Pour activer l'api
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--api.insecure=true<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Activer pour exposer l'api sur 8080
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--api.dashboard=true<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Pour activer le dashboard
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--log.level=INFO<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--providers.file.directory=/etc/traefik/conf.d/<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Permets de charger les configurations dans le répertoire (tout les yaml et toml)
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--providers.file.watch=true<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Permets de surveiller le répertoire précédent pour charger dynamiquement les configurations
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--entrypoints.web.address=:80<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Création de l'entrypoint nommé web sur le port 80
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--entrypoints.websecure.address=:443<span class="punctuation string">"</span></span> <span class="comment"><span class="punctuation comment">#</span> Création de l'entrypoint nommé websecure sur le port 443
</span> <span class="comment"><span class="punctuation comment">#</span>- "--entrypoints.web.http.redirections.entrypoint.scheme=https" # Pour créer une redirection vers https
</span> <span class="comment"><span class="punctuation comment">#</span>- "--entrypoints.web.http.redirections.entrypoint.to=websecure" # Pour rediriger vers l'entrypoint websecure (port 443)
</span> <span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-ecdsa.acme.email=xataz@monmail.net<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-ecdsa.acme.caserver=https://acme-v02.api.letsencrypt.org/directory<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-ecdsa.acme.storage=/acme.json<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-ecdsa.acme.keytype=EC384<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-ecdsa.acme.httpchallenge.entrypoint=web<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-ecdsa.acme.tlschallenge=true<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-rsa2048.acme.email=xataz@monmail.net<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-rsa2048.acme.caserver=https://acme-v02.api.letsencrypt.org/directory<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-rsa2048.acme.storage=/acme.json<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-rsa2048.acme.keytype=RSA2048<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-rsa2048.acme.httpchallenge.entrypoint=web<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>--certificatesresolvers.letsencrypt-rsa2048.acme.tlschallenge=true<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">db_nextcloud</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">postgres:12</span></span>
<span class="string"><span class="entity name tag">networks</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">traefik</span></span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">/srv/docker/db_nextcloud/:/var/lib/postgresql/</span></span>
<span class="string"><span class="entity name tag">environment</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_PASSWORD=nextcloud</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_DB=nextcloud</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_USER=nextcloud</span></span>
<span class="string"><span class="entity name tag">nextcloud</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">image</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">nextcloud:19</span></span>
<span class="string"><span class="entity name tag">networks</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">traefik</span></span>
<span class="string"><span class="entity name tag">environment</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_HOST=db_nextcloud</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_DB=nextcloud</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_USER=nextcloud</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">POSTGRES_PASSWORD=nextcloud</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">NEXTCLOUD_ADMIN_USER=admin</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">NEXTCLOUD_ADMIN_PASSWORD=admin</span></span>
<span class="string"><span class="entity name tag">volumes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string">/srv/docker/nextcloud:/var/www/html</span>
</span></code></pre>
<blockquote>
<p>Traefik utilise lego pour la génération des certificats ssl via acme, il est donc compatible avec les challenges DNS, et avec les API de différent provider de DNS, pour ceci vous pouvez regarder ce <a href="https://docs.traefik.io/https/acme/#providers" rel="noopener noreferrer">tableau</a></p>
</blockquote>
<p>Nous créons 2 resolvers, un pour générer du ecdsa 384, et l'autre du RSA2048, car par exemple certains client n'aime pas trop le ECDSA.<br>
Malheureusement traefik ne supporte pas la configuration dynamic des resolvers, nous sommes donc obligé de l'ajouter manuellement.</p>
<p>Maintenant que nous avons notre docker-compose, nous pouvons nous attaquer à la configuration de traefik. Nous pouvons dès à présent lancer notre stack avec docker-compose.</p>
<h2>Configuration de traefik</h2>
<p>Dans la configuration de traefik, nous avons mis un répertoire en écoute <code>--providers.file.directory=/etc/traefik/conf.d/</code> (qui est monté sur l'hote dans <code>/srv/docker/traefik/conf.d</code>), donc toute la configuration de ce répertoire sera chargé dynamiquement <code>--providers.file.watch=true</code>, dès qu'on ajoutera ou modifira un fichier, il sera pris à chaud, sans avoir à redémarrer sa stack.</p>
<p>Nous allons ici ajouter quelques configurations, notammant sur le TLS, et quelques middleware pour la configuration.</p>
<h3>Configuration TLS</h3>
<p>Nous créons donc un premiers fichiers tls.yml dans notre répertoire écouté par traefik (pour rappel <code>/srv/docker/traefik/conf.d</code>)</p>
<h4>tls.yml</h4>
<pre><code><span class="source"><span class="string"><span class="entity name tag">tls</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">options</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">default</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">minVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>VersionTLS12<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">sniStrict</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">cipherSuites</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_AES_128_GCM_SHA256<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_AES_256_GCM_SHA384<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>TLS_CHACHA20_POLY1305_SHA256<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">curvePreferences</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">X25519</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">CurveP521</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">CurveP384</span></span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">CurveP256</span></span>
<span class="string"><span class="entity name tag">mintls13</span></span><span class="punctuation">:</span> <span class="comment"><span class="punctuation comment">#</span> Arbitraire également, toto fonctionne aussi
</span> <span class="string"><span class="entity name tag">minVersion</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>VersionTLS13<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Cette configuration est plutôt simple à comprendre, nous avons les ciphers autorisés dans la configuration par defaut, avec une version de TLS minimum en version 1.2, et nous créons une configuration qui forcera l'utilisation de TLSv1.3.</p>
<h3>Quelques middlewares</h3>
<p>Maintenant que nous avons notre configuration TLS, il faut configurer quelques middlewares, comme précédemment dis, nous pouvons créer des middlewares pour beaucoup de chose.</p>
<p>Ici je vais créer un fichier par middleware, pour une raison simple, c'est que si je me foire dans la configuration, il ne chargera pas que le middleware qui pose problème, et non tous.</p>
<p>Le format de fichier d'un middleware est :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag"><nomdumiddleware></span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag"><typedumiddleware></span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag"><options></span></span>
<span class="string"><span class="entity name tag"><nomdu2ememiddleware></span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag"><typedumiddleware></span></span><span class="punctuation">:</span>
<span class="string"><options></span>
</span></code></pre>
<h4>Middleware de compression</h4>
<p><code>/srv/docker/traefik/conf.d/compression.yml</code> :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">compression</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">compress</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">excludedContentTypes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>text/event-stream<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Pas beaucoup d'options pour la compression, et la compression est systématiquement en GZIP, pas de brotli pour le moment.</p>
<h4>Middleware hsts</h4>
<p><code>/srv/docker/traefik/conf.d/hsts.yml</code></p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">hsts</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">headers</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">forceSTSHeader</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">stsSeconds</span></span><span class="punctuation">:</span> <span class="constant numeric">315360000</span>
<span class="string"><span class="entity name tag">stsIncludeSubdomains</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">stsPreload</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
</span></code></pre>
<p>Ici nous activons donc le hsts, le but du tutoriel n'est pas d'expliquer son fonctionnement.</p>
<h4>Middleware pour la redirection http vers https</h4>
<p><code>/srv/docker/traefik/conf.d/redirect-to-https.yml</code></p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">redirect-to-https</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">redirectScheme</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">scheme</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">https</span></span>
<span class="string"><span class="entity name tag">permanent</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
</span></code></pre>
<p>Nous aurions pu également créer une règle global, en lançant traefik avec les options <code>--entrypoints.web.http.redirections.entrypoint.scheme=https</code> et <code>--entrypoints.web.http.redirections.entrypoint.to=websecure</code>, mais il peux être possible que certains services n'est pas besoin d'accéder en https.</p>
<h4>Middleware pour quelques sécurités supplémentaire</h4>
<p><code>/srv/docker/traefik/conf.d/security.yml</code></p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">security</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">headers</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">accessControlMaxAge</span></span><span class="punctuation">:</span> <span class="constant numeric">100</span>
<span class="string"><span class="entity name tag">addVaryHeader</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">browserXssFilter</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">contentTypeNosniff</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">frameDeny</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">sslRedirect</span></span><span class="punctuation">:</span> <span class="constant language">true</span>
<span class="string"><span class="entity name tag">customFrameOptionsValue</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>SAMEORIGIN<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">referrerPolicy</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>same-origin<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">featurePolicy</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>vibrate 'self'<span class="punctuation string">"</span></span>
</span></code></pre>
<h4>Middleware pour l'authentification</h4>
<p>Pour ici, nous avons pleins de possibilités de gestion. Cette exemple permets justement de voir la puissance des middlewares.</p>
<p>Nous pouvons par exemple créer un middleware par groupe d'utilisateur :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">admin-users</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicAuth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>xataz:$apr1$FprQWnRT$3FZXlQg0.qCkkytl4iMLc1<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>toto:$apr1$pbpEY6eD$DFz44UOcGC5KC5jasAhgQ/<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">dev-users</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicAuth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>tata:$apr1$inMBbv02$C/oh3LLEfmmOyloAtqW/V/<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Et quand on en aura besoin, on les appelleras.</p>
<p>Nous pouvons également créer un middlewares par users :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">xataz-user</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicAuth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>xataz:$apr1$FprQWnRT$3FZXlQg0.qCkkytl4iMLc1<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">toto-user</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicAuth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>toto:$apr1$pbpEY6eD$DFz44UOcGC5KC5jasAhgQ/<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">tata-user</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicAuth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>tata:$apr1$inMBbv02$C/oh3LLEfmmOyloAtqW/V/<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Et créer des groupes de middlewares :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">admin-group</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">chain</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>xataz-user@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>toto-user@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">devs-group</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">chain</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>toto-user@file<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Pour ce tuto, nous simplifierons avec un seul fichier avec la méthode d'un middleware par groupe :
<code>/serv/docker/traefik/conf.d/auth.yml</code></p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">admin-users</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicAuth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>xataz:$apr1$FprQWnRT$3FZXlQg0.qCkkytl4iMLc1<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>toto:$apr1$pbpEY6eD$DFz44UOcGC5KC5jasAhgQ/<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">dev-users</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">basicauth</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">users</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>tata:$apr1$inMBbv02$C/oh3LLEfmmOyloAtqW/V/<span class="punctuation string">"</span></span>
</span></code></pre>
<h4>Pleins d'autres middlewares</h4>
<p>Traefik propose pas mal de middlewares, là nous en avons vu que très peu, mais nous avons aussi la possibilité de rediriger l'authentification, de gérer les erreurs http, de limiter les IPs, etc ...., nous en verrons d'autres par la suite.</p>
<p>La liste complète des middlewares est disponible <a href="https://docs.traefik.io/middlewares/overview/#available-middlewares" rel="noopener noreferrer">ici</a>.</p>
<h3>Les services et les routes</h3>
<p>Personnellement j'aime bien créer les routers et les services dans le même fichier, mais un fichier par application.</p>
<h4>Dashboard traefik</h4>
<p>Nous allons d'abord créer notre configuration pour accéder au dashboard de traefik :</p>
<p><code>/serv/docker/traefik/conf.d/traefik.yml</code></p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">services</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">traefik</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">loadBalancer</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">servers</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">url</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>http://localhost:8080<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">routers</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">traefik</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">rule</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>Host(`traefik.exemple.fr`)<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">entryPoints</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>web<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>redirect-to-https@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">service</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>noop@internal<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">traefik-secure</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">rule</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>Host(`traefik.exemple.fr`)<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">entryPoints</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>websecure<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>hsts@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>security@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>compression@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>admins-users@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">service</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>traefik@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">tls</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">certResolver</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">letsencrypt-ecdsa</span></span>
<span class="string"><span class="entity name tag">options</span></span><span class="punctuation">:</span> <span class="string">mintls13</span>
</span></code></pre>
<blockquote>
<p>Alors qu'avons nous dans ce fichier ?</p>
</blockquote>
<p>D'abord nous avons la déclaration du service, que j'ai nommé <code>traefik</code> ici (très original), de type <code>loadBalancer</code>, qui pointe vers <strong>localhost:8080</strong> (adresse exposé par traefik).</p>
<p>Puis nous avons 2 routes, <code>traefik</code> et <code>traefik-secure</code>. <code>traefik</code> écoute sur le port 80 (entrypoint <strong>web</strong>), réponds à l'url <strong>http://traefik.exemple.fr</strong> et utilise le middleware <code>redirect-to-https@file</code>, pour ce rediriger vers https. Le <code>@file</code> permets de définir sur qu'elle provider on tape, si c'est sur le provider docker, on utiliserais <code>@docker</code>.<br>
Ensuite nous avons le service, là nous tappons sur <code>noop@internal</code>, alors là c'est un service particulier qui ne pointe sur rien, et puisque nous avons la redirection, je préfère tapper sur rien, pour éviter de me retrouver connecté sur le dashboard sans tls.</p>
<p>Puis nous avons <code>traefik-secure</code>, nous répondons toujours au requête de <strong>https://traefik.exemple.fr</strong>, mais sur l'entrypoint <strong>websecure</strong>. Ici nous avons plusieurs middlewares, <code>hsts@file</code> pour les règles hsts, <code>security@file</code> pour quelques sécurités, <code>compression@file</code> pour compresser les requêtes et <code>admin-users@file</code> pour limité l'accès au <strong>admins</strong>.</p>
<p>Et pour finir nous avons la configuration TLS, avec le <code>certResolver</code> qui appel <strong>letsencrypt-ecdsa</strong> pour générer automatiquement le certificat SSL ecdsa de 384 bits, et on active l'option <strong>mintls13</strong> (du fichier <code>tls.yml</code>) pour n'autoriser les connexions qu'en TLS 1.3.</p>
<p>Si tout est bon, et sans redémarrer traefik, vous devriez pouvoir accéder à votre dashboard en TLS.</p>
<h4>nextcloud</h4>
<p>Pour nextcloud, nous allons faire une configuration un peu différente, histoire de voir quelques possibilité de traefik.<br>
De base nextcloud écoute sur <strong>http://nextcloud:80/</strong>, mais nous allons ajouter un prefix <strong>/cloud</strong>.</p>
<p>Voici la configuration à utiliser :</p>
<pre><code><span class="source"><span class="string"><span class="entity name tag">http</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">services</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">nextcloud</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">loadBalancer</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">servers</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="entity name tag">url</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>http://nextcloud<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">routers</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">nextcloud</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">rule</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>Host(`cloud.exemple.fr`) && PathPrefix(`/cloud`)<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">entryPoints</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>web<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>redirect-to-https@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">service</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>noop@internal<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">nextcloud-secure</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">rule</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>Host(`cloud.exemple.fr`) && PathPrefix(`/cloud`)<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">entryPoints</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>websecure<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>hsts@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>security@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>compression@file<span class="punctuation string">"</span></span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>strip-cloud@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">service</span></span><span class="punctuation">:</span> <span class="string"><span class="punctuation string">"</span>nextcloud@file<span class="punctuation string">"</span></span>
<span class="string"><span class="entity name tag">tls</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">certResolver</span></span><span class="punctuation">:</span> <span class="string"><span class="entity name tag">letsencrypt-rsa2048</span></span>
<span class="string"><span class="entity name tag">middlewares</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">strip-cloud</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">stripPrefix</span></span><span class="punctuation">:</span>
<span class="string"><span class="entity name tag">prefixes</span></span><span class="punctuation">:</span>
<span class="punctuation">-</span> <span class="string"><span class="punctuation string">"</span>/cloud<span class="punctuation string">"</span></span>
</span></code></pre>
<p>Là nous avons ajouté deux choses, dans <code>rule</code>, nous avons ajouté le Prefix <strong>/cloud</strong>, pour que seulement <em>cloud.exemple.fr/cloud</em> soit redirigé, mais ensuite nous créons un middlewares nommé <code>strip-cloud</code> de type stripPrefix.<br>
Pour bien comprendre, le <code>PathPrefix</code> se passe au niveau du front, mais de base, le reverse proxy va rediriger <em>https://cloud.exemple.fr/cloud</em> vers <em>http://nextcloud:80/cloud</em>, sauf que nextcloud ne connais pas se chemin.<br>
Le stripPrefix va donc enlever ce prefix (<strong>/cloud</strong>), entre traefik et nextcloud, afin que nextcloud puisse retrouver son chemin.</p>
<h1>Conclusion</h1>
<p>Nous n'avons ici effleuré que de très prêt les possibilités de traefik. Mais nous avons pu voir que traefik est un reverse proxy à part entière, et que ce n'est pas seulement un outil pour les conteneurs.<br>
Nous avons vu ici une méthode de configuration très différente de ce que l'on vois partout. Le but n'est pas de dénigrer la configuration par label ou autre, au contraire cette configuration à beaucoup d'avantages, mais de permettre un découpage plus propres de la configuration et surtout de montrer que traefik != docker.</p>
]]><![CDATA[L'ange Podman]]>https://catlife.drycat.fr/~/XataZ/l'ange-podman/2020-04-14T19:37:14.926616+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-04-14T19:37:14.926616+00:00<![CDATA[<p>Depuis peu, j'ai choisi de passer de docker à <a href="https://podman.io" rel="noopener noreferrer">podman</a>, j'ai donc décidé d'écrire un petit article dessus.</p>
<p>Podman est au même titre que docker un outil pour créer et gérer des conteneurs, avec des images au format OCI.</p>
<h1>Différences podman / docker</h1>
<p>Avant de parler des différences, nous allons parler des points communs, podman et docker utilisent exactement la même CLI, c'est à dire que créer un alias docker pointant vers podman fonctionnera parfaitement :</p>
<ul>
<li><code>docker run -ti alpine</code> devient <code>podman run -ti alpine</code></li>
<li><code>docker pull alpine</code> devient <code>podman pull alpine</code></li>
<li>etc ...</li>
</ul>
<h2>Pas de clustering</h2>
<p>Par contre avec podman, pas de clustering, podman <code>swarm</code> n'existe pas.</p>
<h2>Daemonless</h2>
<p>Mais nous avons une différence de taille, podman est <code>daemonless</code>. Contrairement à docker, il n'a pas besoin d'exposer une API, nous avons donc une architecture beaucoup plus simple.<br>
Sous docker, nous avons la commandline <code>docker</code> qui appelle l'API exposé par <code>dockerd</code> qui lui même appelle l'API exposé par <code>containerd</code>, qui lance <code>containerd-shim</code> qui lui lance <code>runc</code> qui lance enfin notre processus.<br>
Sous podman, nous avons notre commandline <code>podman</code> qui lance <code>conmon</code>, qui lui lance <code>runc</code> pour lancer notre conteneur. Et c'est tout.</p>
<p>Nous avons donc beaucoup moins d'étape avec podman qu'avec docker, et donc nous réduisons la surface d'attaque.<br>
De plus sous docker, <code>containerd</code> devient un SPOF, car il devient le maitre du lancement de tout les conteneurs, contrairement à podman qui lance un process <code>conmon</code> par conteneur.</p>
<h2>Rootless</h2>
<p>Même si docker le permets désormais (mais toujours avec son daemon) (cf <a href="https://docs.docker.com/engine/security/rootless/" rel="noopener noreferrer">documentation</a>), <code>podman</code> est entièrement <strong>rootless</strong> Out-of-box. Cela veut dire que vous lancez vos conteneurs avec vos droits utilisateurs, pas de <code>sudo</code>, pas de groupe <code>docker</code> (qui vous donner beaucoup trop de permissions), vous lancez vos conteneurs, et ils tournerons avec vos permissions.<br>
Dans votre conteneur, vous aurez tout de même l'utilisateur root, mais niveau host, il correspondra à votre utilisateur.<br>
Petit exemple, mon utilisateur est <strong>xataz</strong>, il à l'UID <strong>1000</strong> sur ma machine Je lance donc mon conteneur comme ceci :</p>
<pre><code>$ podman container run -d alpine ping 9.9.9.9
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6430b1dca84e docker.io/library/alpine:latest ping 9.9.9.9 6 seconds ago Up 5 seconds ago clever_euler
</code></pre>
<p>Si je fais un <code>podman container top clever_euler</code>, j'obtiens :</p>
<pre><code>USER PID PPID %CPU ELAPSED TTY TIME COMMAND
root 1 0 0.000 1m48.153058015s ? 0s ping 9.9.9.9
</code></pre>
<p>Dans le conteneur, on nous dit que c'est l'utilisateur <strong>root</strong> qui lance le <code>ping</code>, mais si on regarde sur l'hôte :</p>
<pre><code>$ ps aux | grep 9.9.9.9
xataz 106366 106354 0 00:28 ? 00:00:00 ping 9.9.9.9
</code></pre>
<p>Nous avons donc l'utilisateur <strong>root</strong> du conteneur qui se retrouve mappé sur l'utilisateur qui lance le conteneur.</p>
<p>Cependant, le mode rootless à quelques limitations :</p>
<ul>
<li>Pas de gestion de réseau, sur l'hôte seul root peut gérer ceci.</li>
<li>Un support partiel des cgroups, via les cgroups v2, mais tout n'est pas limitable.</li>
<li>Le mappage des ports limités au port supérieur à 1024.</li>
</ul>
<p>Donc pour communiquer entre deux conteneurs, nous n'avons que 3 solutions :</p>
<ul>
<li>Mappé les ports sur l'hôte et contacter directement l'IP de l'hôte (ex : <code>podman container run -d -p 3306:3306 mariadb</code>)</li>
<li>Utiliser le network host, pour que les ports soit directement mappé (ex : <code>podman container run --network host mariadb</code>), comme ceci chaque conteneur partage le localhost.</li>
<li>Utiliser les pods, nous verrons donc cette méthode ensuite.</li>
</ul>
<p>D'ailleurs, tout les tests réalisé dans cette article l'on été en mode <strong>rootless</strong>, je n'ai fait aucun test en <strong>rootfull</strong>.</p>
<h1>Les Pods</h1>
<p>Le concept de POD vient de kubernetes. C'est un groupe de un ou plusieurs conteneurs qui partagerons plusieurs ressources, notamment le réseau, avec un namespace partagé, mais aussi les cgroups par exemple.</p>
<h2>Création et gestion d'un pod</h2>
<p>Pour gérer un pod, c'est assez simple, nous avons la commande <code>podman pod</code>, avec les sous-commandes <code>create</code>, <code>ps</code>, <code>start</code>, <code>stop</code>, <code>rm</code> etc ...<br>
Nous restons dans la même logique que docker, les commandes restent simples et explicites.</p>
<p>Nous allons pour tester rapidement un pod nommé <strong>test</strong>, avec un conteneur nginx, et un conteneur qui fait un curl sur le localhost. Ce pod exposera donc le port 8080.</p>
<p>Nous commençons donc par créer notre pod :</p>
<pre><code>$ podman pod create --name test -p 8080:80
480348ec0517b5815053755386d0bc563f5f22e17d7db35c44662680ec05d796
</code></pre>
<p>Puis nous lançons notre premier conteneur dans notre pod test :</p>
<pre><code>$ podman container run -d --pod test nginx
</code></pre>
<p>A ce stade nous avons donc notre pod <strong>test</strong>, et un conteneur nginx dedans, nous pouvons vérifier avec :</p>
<pre><code>$ podman ps --pod
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD POD NAME
df295bc43cfa docker.io/library/nginx:latest nginx -g daemon o... About a minute ago Up About a minute ago 0.0.0.0:8080->80/tcp vibrant_bardeen 480348ec0517 test
</code></pre>
<p>Nous pouvons donc en local sur notre hôte acceder à locahost:8080, qui nous fournira la jolie page <strong>Welcome to nginx!</strong>.</p>
<p>Mais si d'un autre conteneur je veux accéder à cette page, comment faire ??<br>
Il faudra taper sur le port 80, et non le port 8080 car celui n'est monté que sur l'hôte.<br>
Donc si je fais un <code>podman container run -ti --rm --pod test alpine wget 127.0.0.1 -O-</code>, nous avons bien notre page <strong>Welcome to nginx!</strong> qui s'affiche.</p>
<p>Ce pod n'étant qu'un test, nous pouvons le supprimer, et supprimer tout les conteneurs associés :</p>
<pre><code>$ podman pod rm -f test
</code></pre>
<h2>Nextcloud + redis + postgres</h2>
<p>Pour un exemple un peu plus concret, nous allons créer un pod nommé <strong>cloud</strong>, avec 3 conteneurs, nextcloud, redis et postgres.<br>
Nous utiliserons les images officiels pour ces 3 conteneurs.</p>
<h3>Création du pod</h3>
<p>Nous avons donc besoin de notre pod, nous savons déjà que nous aurons besoin de rediriger le port 80 du conteneur vers l'exterieur, nous utiliserons ici le port 8080.</p>
<p>Donc pour créer notre pod, nous lançons :</p>
<pre><code>$ podman pod create --name cloud -p 8080:80
14130d03a965cad53f1b3792533d1fef5494650c8f7ae32b9f242d025b22b33e
</code></pre>
<h3>Création du conteneur mariadb</h3>
<p>Ceci n'étant qu'un test, je vais faire une configuration plutôt simpliste, pas de mot de passe complexe, je lance donc mon conteneur mariadb :</p>
<pre><code>$ podman container run -d \
--pod cloud \
--name nextclouddb \
-e POSTGRES_USER="nextcloud" \
-e POSTGRES_PASSWORD="nextcloud" \
postgres
b4a4ef68b1b19226e8c3f259824ad289b56eff045ab077562b92aeca8a152f74
</code></pre>
<h3>Création du conteneur redis</h3>
<p>Pareil pour redis, nous utilisons l'image officiel :</p>
<pre><code>$ podman container run -d \
--pod cloud \
--name nextcloudredis \
redis
b7eacdeb95e57128b30d9d0d2f6a46571764349ead3dbc2f1b73769fc66b2266
</code></pre>
<h3>Création du conteneur Nextcloud</h3>
<p>Puis la création la plus compliqué, mais pas insurmontable non plus, puisque c'est pour du test :</p>
<pre><code>$ podman container run -d \
--pod cloud \
--name nextcloud \
-e POSTGRES_HOST="127.0.0.1" \
-e POSTGRES_DB="nextcloud" \
-e POSTGRES_USER="nextcloud" \
-e POSTGRES_PASSWORD="nextcloud" \
-e NEXTCLOUD_ADMIN_USER="xataz" \
-e NEXTCLOUD_ADMIN_PASSWORD="xataz" \
-e REDIS_HOST="127.0.0.1" \
nextcloud
</code></pre>
<p>Normalement, vous devriez pouvoir accéder à votre nextcloud avec l'IP de l'hôte sur le port 8080.</p>
<h3>Analyse des conteneurs et du pod</h3>
<p>Que pouvons nous voir de ces conteneurs ??<br>
Déjà nous pouvons voir qu'il partage le même pod :</p>
<pre><code>$ podman ps --pod
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD POD NAME
4658539082d1 docker.io/library/nextcloud:latest apache2-foregroun... 16 hours ago Up 16 hours ago 0.0.0.0:8080->80/tcp nextcloud e234d8f0f183 cloud
0844854e09aa docker.io/library/redis:latest redis-server 16 hours ago Up 16 hours ago 0.0.0.0:8080->80/tcp nextcloudredis e234d8f0f183 cloud
3b265454c8c0 docker.io/library/postgres:latest postgres 16 hours ago Up 16 hours ago 0.0.0.0:8080->80/tcp nextclouddb e234d8f0f183 cloud
</code></pre>
<p>Nous pouvons également voir que les conteneurs partages des namespaces :</p>
<pre><code>$ podman ps --ns
CONTAINER ID NAMES PID CGROUPNS IPC MNT NET PIDNS USERNS UTS
4658539082d1 nextcloud 134799 4026531835 4026533078 4026533084 4026532736 4026533085 4026532734 4026533077
0844854e09aa nextcloudredis 134529 4026531835 4026533078 4026533082 4026532736 4026533083 4026532734 4026533077
3b265454c8c0 nextclouddb 134427 4026531835 4026533078 4026533080 4026532736 4026533081 4026532734 4026533077
</code></pre>
<blockquote>
<p>Ici nous constatons que les namespaces CGROUP, IPC, NET, USER et UTS sont les mêmes.</p>
</blockquote>
<p>Nous constatons également que nous avons 4 conteneurs dans notre pod :</p>
<pre><code>$ podman pod ps
POD ID NAME STATUS CREATED <a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> OF CONTAINERS INFRA ID
e234d8f0f183 cloud Running 16 hours ago 4 e82ce3139620
</code></pre>
<blockquote>
<p>Pourquoi 4 conteneurs ? Nous n'en avons créés que 3 !!!</p>
</blockquote>
<p>Tout simplement que dans un pod, nous avons un conteneur qui ne sert qu'à maintenir les namespaces partagés ouvert, car un namespace est forcément utilisé, sinon il est supprimé.<br>
Nous pourrions utiliser une autre image, par exemple une image qui permet la gestion du pod, ou même un reverse proxy par exemple, je n'ai pas d'image en tête, mais cela reste une possibilité.</p>
<h1>Bonus</h1>
<h2>L'intégration avec systemd</h2>
<p>Podman intègre une fonction sympathique qui permets de générer des fichiers de configuration systemd, afin de l'utiliser en tant que service.</p>
<pre><code>podman generate systemd --help
Generate a systemd unit file for a Podman container
Description:
Command generates a systemd unit file for a Podman container
Usage:
podman generate systemd [flags] CONTAINER | POD
Examples:
podman generate systemd ctrID
Flags:
-f, --files generate files instead of printing to stdout
-n, --name use the container/pod name instead of ID
--new create a new container instead of starting an existing one
--restart-policy string applicable systemd restart-policy (default "on-failure")
-t, --timeout int stop timeout override (default -1)
</code></pre>
<p>L'utilisation est plutôt simple.</p>
<p>La génération simple n'est pas des plus recommandé, car il ne permet que de lancer et stopper le conteneur déjà créé, il ne le créera pas :</p>
<pre><code>$ podman generate systemd nextcloud
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> container-4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4.service
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> autogenerated by Podman 1.8.2
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Tue Apr 14 20:27:46 CEST 2020
[Unit]
Description=Podman container-4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4.service
Documentation=man:podman-generate-systemd(1)
Wants=network.target
After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
ExecStart=/usr/bin/podman start 4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4
ExecStop=/usr/bin/podman stop -t 10 4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4
PIDFile=/run/user/1000/containers/vfs-containers/4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4/userdata/conmon.pid
KillMode=none
Type=forking
[Install]
WantedBy=multi-user.target default.target
</code></pre>
<p>Nous pouvons donc via l'option <code>--new</code> créer un service qui le créera proprement :</p>
<pre><code>$ podman generate systemd --new nextcloud
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> container-4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4.service
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> autogenerated by Podman 1.8.2
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Tue Apr 14 20:28:02 CEST 2020
[Unit]
Description=Podman container-4658539082d1f28bbd6c3d5fa59b525affa8cc1b7aa4247110cc5a87e049e3b4.service
Documentation=man:podman-generate-systemd(1)
Wants=network.target
After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon -d --pod cloud --name nextcloud -e POSTGRES_HOST=127.0.0.1 -e POSTGRES_DB=nextcloud -e POSTGRES_USER=nextcloud -e POSTGRES_PASSWORD=nextcloud -e NEXTCLOUD_ADMIN_USER=xataz -e NEXTCLOUD_ADMIN_PASSWORD=xataz -e REDIS_HOST=127.0.0.1 nextcloud
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
PIDFile=%t/%n-pid
KillMode=none
Type=forking
[Install]
WantedBy=multi-user.target default.target
</code></pre>
<p>L'option <code>--name</code> est vraiment pas mal également, rends les services générés beaucoup plus clair :</p>
<pre><code>$ podman generate systemd --new --name nextcloud
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> container-nextcloud.service
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> autogenerated by Podman 1.8.2
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Tue Apr 14 20:28:45 CEST 2020
[Unit]
Description=Podman container-nextcloud.service
Documentation=man:podman-generate-systemd(1)
Wants=network.target
After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon -d --pod cloud --name nextcloud -e POSTGRES_HOST=127.0.0.1 -e POSTGRES_DB=nextcloud -e POSTGRES_USER=nextcloud -e POSTGRES_PASSWORD=nextcloud -e NEXTCLOUD_ADMIN_USER=xataz -e NEXTCLOUD_ADMIN_PASSWORD=xataz -e REDIS_HOST=127.0.0.1 nextcloud
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
PIDFile=%t/%n-pid
KillMode=none
Type=forking
[Install]
WantedBy=multi-user.target default.target
</code></pre>
<p>Nous pouvons bien évidemment générer directement le fichier :</p>
<pre><code>$ podman generate systemd --new --name --files nextcloud
/home/xataz/Documents/Projects/podman/container-nextcloud.service
</code></pre>
<p>Pour l'utiliser il suffit donc de le mettre dans <code>~/.config/systemd/user/</code>, si le répertoire n'existe pas, il faudra le créer.<br>
Puis le lancer avec <code>systemctl --user start container-nextcloud</code>.</p>
<p>Nous pouvons également en générer plusieurs pour un pod complet, malheureusement je trouve dommage qu'il n'est pas possible d'utiliser l'option <code>--new</code> avec un pod (Peut être dans une prochaine version):</p>
<pre><code>$ podman generate systemd --new --name --files cloud
Error: error generating systemd unit files: cannot generate generic files for a pod
$ podman generate systemd --name --files cloud
/home/xataz/Documents/Projects/podman/pod-cloud.service
/home/xataz/Documents/Projects/podman/container-nextcloudredis.service
/home/xataz/Documents/Projects/podman/container-nextclouddb.service
/home/xataz/Documents/Projects/podman/container-nextcloud.service
</code></pre>
<h2>Génération de fichier kubernetes</h2>
<p>Podman permets également de générer des fichiers de configuration pour kubernetes, la commande est similaire à celle de systemd :</p>
<pre><code>$ podman generate kube --help
Generate Kubernetes pod YAML from a container or pod
Description:
Command generates Kubernetes Pod YAML (v1 specification) from a podman container or pod.
Whether the input is for a container or pod, Podman will always generate the specification as a Pod. The input may be in the form of a pod or container name or ID.
Usage:
podman generate kube [flags] CONTAINER | POD
Examples:
podman generate kube ctrID
podman generate kube podID
podman generate kube --service podID
Flags:
-f, --filename string Filename to output to
-s, --service Generate YAML for kubernetes service object
</code></pre>
<p>Nous pouvons générer un fichier que pour notre conteneur (<code>podman create --name test alpine</code>) :</p>
<pre><code>$ podman generate kube alpine
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Generation of Kubernetes YAML is still under development!
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Save the output of this file and use kubectl create -f to import
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> it into Kubernetes.
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Created with podman-1.8.2
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2020-04-14T18:47:56Z"
labels:
app: alpine
name: alpine
spec:
containers:
- command:
- /bin/sh
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: TERM
value: xterm
- name: container
value: podman
- name: HOSTNAME
image: docker.io/library/alpine:latest
name: alpine
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
seLinuxOptions: {}
workingDir: /
status: {}
</code></pre>
<p>Ou alors pour notre pod directement :</p>
<pre><code>$ podman generate kube cloud
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Generation of Kubernetes YAML is still under development!
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Save the output of this file and use kubectl create -f to import
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> it into Kubernetes.
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Created with podman-1.8.2
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2020-04-14T18:48:26Z"
labels:
app: cloud
name: cloud
spec:
containers:
- command:
- redis-server
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: TERM
value: xterm
- name: container
value: podman
- name: GOSU_VERSION
value: "1.11"
- name: REDIS_VERSION
value: 5.0.8
- name: REDIS_DOWNLOAD_URL
value: http://download.redis.io/releases/redis-5.0.8.tar.gz
- name: REDIS_DOWNLOAD_SHA
value: f3c7eac42f433326a8d981b50dba0169fdfaf46abb23fcda2f933a7552ee4ed7
- name: HOSTNAME
value: cloud
image: docker.io/library/redis:latest
name: nextcloudredis
ports:
- containerPort: 80
hostPort: 8080
protocol: TCP
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
seLinuxOptions: {}
workingDir: /data
- command:
- postgres
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/12/bin
- name: TERM
value: xterm
- name: LANG
value: en_US.utf8
- name: PG_MAJOR
value: "12"
- name: GOSU_VERSION
value: "1.11"
- name: PGDATA
value: /var/lib/postgresql/data
- name: POSTGRES_PASSWORD
value: nextcloud
- name: PG_VERSION
value: 12.2-2.pgdg100+1
- name: POSTGRES_USER
value: nextcloud
- name: container
value: podman
- name: HOSTNAME
value: cloud
image: docker.io/library/postgres:latest
name: nextclouddb
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
seLinuxOptions: {}
workingDir: /
- command:
- apache2-foreground
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: TERM
value: xterm
- name: APACHE_CONFDIR
value: /etc/apache2
- name: PHP_EXTRA_CONFIGURE_ARGS
value: --with-apxs2 --disable-cgi
- name: NEXTCLOUD_VERSION
value: 18.0.3
- name: PHP_CFLAGS
value: -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
- name: REDIS_HOST
value: 127.0.0.1
- name: PHP_LDFLAGS
value: -Wl,-O1 -Wl,--hash-style=both -pie
- name: PHP_INI_DIR
value: /usr/local/etc/php
- name: PHP_EXTRA_BUILD_DEPS
value: apache2-dev
- name: POSTGRES_HOST
value: 127.0.0.1
- name: NEXTCLOUD_ADMIN_USER
value: xataz
- name: GPG_KEYS
value: CBAF69F173A0FEA4B537F470D66C9593118BCCB6 F38252826ACD957EF380D39F2F7956BC5DA04B5D
- name: PHP_VERSION
value: 7.3.16
- name: POSTGRES_DB
value: nextcloud
- name: NEXTCLOUD_ADMIN_PASSWORD
value: xataz
- name: PHP_ASC_URL
value: https://www.php.net/get/php-7.3.16.tar.xz.asc/from/this/mirror
- name: PHP_MD5
- name: POSTGRES_USER
value: nextcloud
- name: APACHE_ENVVARS
value: /etc/apache2/envvars
- name: PHP_SHA256
value: 91aaee3dbdc71b69b4f3292f9d99211172a2fa926c3f3bbdb0e85dab03dd2bcb
- name: container
value: podman
- name: PHP_CPPFLAGS
value: -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
- name: PHPIZE_DEPS
value: "autoconf \t\tdpkg-dev \t\tfile \t\tg++ \t\tgcc \t\tlibc-dev \t\tmake
\t\tpkg-config \t\tre2c"
- name: POSTGRES_PASSWORD
value: nextcloud
- name: PHP_URL
value: https://www.php.net/get/php-7.3.16.tar.xz/from/this/mirror
- name: HOSTNAME
value: cloud
image: docker.io/library/nextcloud:latest
name: nextcloud
resources: {}
securityContext:
allowPrivilegeEscalation: true
capabilities: {}
privileged: false
readOnlyRootFilesystem: false
seLinuxOptions: {}
workingDir: /var/www/html
status: {}
</code></pre>
<p>Avec un fichier c'est mieux :</p>
<pre><code>$ podman generate kube --filename cloud.yaml cloud
</code></pre>
<p>Cependant, comme nous pouvons le voir, la génération n'est pas totalement complète et correcte, car nous avons mappé les ports sur le pod, et non sur le conteneur <strong>redis</strong>, nous avons bien l'option <code>--service</code>, mais celui ci monte les ports sur des ports aléatoires :</p>
<pre><code>$ podman generate kube --service cloud
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Generation of Kubernetes YAML is still under development!
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Save the output of this file and use kubectl create -f to import
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> it into Kubernetes.
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> Created with podman-1.8.2
[...]
---
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2020-04-14T18:54:47Z"
labels:
app: cloud
name: cloud
spec:
ports:
- name: "80"
nodePort: 30004
port: 80
protocol: TCP
targetPort: 0
selector:
app: cloud
type: NodePort
status:
loadBalancer: {}
</code></pre>
<p>J'espère sincèrement que tout ceci sera amélioré dans de futures versions.</p>
<h2>podman-compose</h2>
<p>Comme précedemment dit, il existe un <a href="https://github.com/containers/podman-compose" rel="noopener noreferrer">podman-compose</a>. Je ne vais pas expliquer ici l'installation de l'outil, ou même son fonctionnement, car il est 100% compatible avec docker-compose.</p>
<p>Podman-compose n'est différent que dans la gestion des conteneurs, il part du principe que chaque fichier yaml est un pod, et donc va créer un pod et y mettre les conteneurs dedans. Pour un soucis de transparence avec docker, il va cependant ajouter les noms des conteneurs dans le fichier <code>/etc/hosts</code> afin de pouvoir simuler un réseau docker (en <strong>rootless</strong> évidemment).</p>
<p>Cependant j'ai remarqué un petit défaut, par exemple j'avais l'habitude avec docker-compose de simplement lancer un <code>docker-compose up -d</code> pour mettre à jour les modifications apporté, il gérait donc automatiquement les conteneurs à mettre à jour ou non. Avec <code>podman-compose</code>, cela ne fonctionne malheureusement pas, il faut d'abord supprimer le pod, puis le relancer.</p>
<h2>TroubleShooting</h2>
<p>J'ai pu observer quelques bugs :</p>
<ul>
<li>Problème de purge des répertoires, j'avais beau avoir supprimer mes images et conteneurs, ainsi que volumes, mon répertoire home était toujours pleins, et pleins de layers liés à podman. Je n'ai pas observé ce problème sous Manjaro ou CentOS 8.</li>
<li>Des problèmes aléatoires sur le mappage de port, enfin plutôt des fonctionnements aléatoires. J'ai créer un pod en mappant des ports, au premier lancement les ports se sont correctement mappés, mais il m'a fallu environ 50 lancements pour qu'ils remappent correctement. Pareil, que sur debian et apparemment ubuntu, je n'ai pas vu le soucis sur Manjaro et CentOS.</li>
<li>Un soucis également avec le localhost dans un pod, qui ne pointe pas sur 127.0.0.1, donc j'ai pris l'habitude d'utiliser 127.0.0.1.</li>
</ul>
<h3>Problème avec le rootless</h3>
<p>Il faudra peut être que vous autorisiez les utilisateurs à créer des namespacesv pour ceci il suffit de modifier le fichier en root <code>/proc/sys/kernel/unprivileged_userns_clone</code> en y écrivant un <code>1</code> dedans :</p>
<pre><code>echo 1 > /proc/sys/kernel/unprivileged_userns_clone
</code></pre>
<p>Ceci ne sera modifier que jusqu'au reboot de la machine.</p>
<p>Pour le modifier définitivement, soit vous modifiez le fichier /etc/sysctl.conf en y ajoutant <code>kernel.unprivileged_userns_clone = 1</code>, toujours en root</p>
<h2>Conclusion</h2>
<p>Podman est vraiment un très bon outil, je l'ai testé que en mode <strong>rootless</strong>, ceci manque cruellement de maturité pour un usage en production.<br>
Pour le l'usage personnel, c'est vraiment top, je l'utilise sur mon PC portable depuis quelques temps, j'ai remplacé mes docker par podman, même si je pense de plus en plus à passer sur du k3s pour clusterer le tout.<br>
Podman a vraiment un énorme potentiel, déjà il rend le <strong>rootless</strong> facilement accessible, puis en plus il est <strong>daemonless</strong>, ce qui en fait l'outils parfait pour le développement.</p>
<p>Je l'ai déjà dis, j'ai tout testé en mode <strong>rootless</strong>, peux être que certains beug rencontrer ne le sont pas en <strong>rootfull</strong>.</p>
]]><![CDATA[Création d'un home chiffré avec VeraCrypt et pam_exec]]>https://catlife.drycat.fr/~/XataZ/création-d'un-home-chiffré-avec-vera-crypt/2020-01-15T14:07:42.646049+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-01-15T14:07:42.646049+00:00<![CDATA[<p>Je cherchais un moyen de chiffrer les homes des utilisateurs de mon PC, sous manjaro depuis peu.
Après avoir testé plusieurs solutions, mon choix c’est arrêté sur veracrypt, parce que pourquoi pas.</p>
<p>Pour ceci nous utiliserons donc <strong>veracrypt</strong> (à installer en fonction de votre distribution), couplé avec <strong>pam_exec</strong>.</p>
<p>Pour ce tutoriel, j’utilise manjaro avec xfce4 et lightdm, le comportement peut être différent avec d'autre environnement de bureau ou d'autre gestionnaire de connexion.<br>
De plus j'utilise LVM, avec un VG spécifique pour les homes nommés <em>vghome</em>, avec un LV par utilisateur, mon script sera à adapter en fonction de votre installation bien évidemment.</p>
<p>Ce mini tutoriel est plus un POC qu'autre chose, pour comprendre l'utilisation de pam_exec plus que le chiffrement réellement.</p>
<h1>Montage d'un volume veracrypt</h1>
<h2>Création du volume</h2>
<p>Il faut utiliser le même mot de passe que celui de votre session.</p>
<pre><code>$ veracrypt -t -c
Volume type:
1) Normal
2) Hidden
Select [1]: 1
Enter volume path: /dev/mapper/vghome-xataz
Encryption Algorithm:
1) AES
2) Serpent
3) Twofish
4) Camellia
5) Kuznyechik
6) AES(Twofish)
7) AES(Twofish(Serpent))
8) Camellia(Kuznyechik)
9) Camellia(Serpent)
10) Kuznyechik(AES)
11) Kuznyechik(Serpent(Camellia))
12) Kuznyechik(Twofish)
13) Serpent(AES)
14) Serpent(Twofish(AES))
15) Twofish(Serpent)
Select [1]: 1
Hash algorithm:
1) SHA-512
2) Whirlpool
3) SHA-256
4) Streebog
Select [1]: 1
Filesystem:
1) None
2) FAT
3) Linux Ext2
4) Linux Ext3
5) Linux Ext4
6) NTFS
7) exFAT
Select [2]: 5
Enter password: *************
Re-enter password: ************
Enter PIM: <a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> On laisse vide
Enter keyfile path [none]: <a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> On laisse vide
Please type at least 320 randomly chosen characters and then press Enter:
Characters remaining: 117
Done: 23,279% Speed: 12 MB/s Left: 8 minutes
The VeraCrypt volume has been successfully created.
</code></pre>
<p>Nous laissons <code>Enter PIM</code> et <code>Enter keyfile path</code> vide</p>
<p>Puis nous le montons temporairement dans <code>/mnt</code> par exemple, premièrement pour le tester, et deuxièmement pour copier notre home dessus :</p>
<pre><code>$ veracrypt -t /dev/mapper/vghome-xataz /mnt
$ chown -R xataz: /mnt
$ cp -rf --preserve=all /home/xataz/ /mnt/
</code></pre>
<p>Nous pouvons donc le démonter :</p>
<pre><code>$ veracrypt -d /mnt
</code></pre>
<h2>Modification du PAM</h2>
<p>Pour commencer, nous créons un script qui permettra le montage de notre partition, personnellement placer dans /opt, et nommé <code>pam_mountencrypt.sh</code> :</p>
<pre><code><a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>!/bin/bash
DEVICE_PATH="/dev/mapper/vghome-$PAM_USER "
HOME_PATH="/home/$PAM_USER "
if [ "$PAM_TYPE" == "auth" ] && ! mount | grep "$HOME_PATH" | grep veracrypt && [ -e $DEVICE_PATH ]; then
tr '\0' '\n' | veracrypt -t --non-interactive --stdin $DEVICE_PATH $HOME_PATH
elif [ "$PAM_TYPE" == "close_session" ] && mount | grep "$HOME_PATH" | grep veracrypt; then
if ! who | grep $PAM_USER | grep -v $PAM_TTY; then
pkill -KILL -u $PAM_USER && veracrypt -d $HOME_PATH
fi
fi
</code></pre>
<p>On oublie pas de le rendre exécutable.</p>
<p>Le script est relativement simple, mais en version littéraire ça donne :</p>
<ul>
<li>Si nous recevons une demande d'authentification, que le home n'est pas déjà monté et que la partition existe, on monte la partition. Donc si le home est déjà monté (utilisateur connecté sur un autre TTY par exemple), alors on ne fait rien.</li>
<li>Mais si on reçoit une demande de fermeture de session, que le home est bien monté, alors on vérifie que l'utilisateur n'est pas connecté sur une autre session, puis on kill tout les processus de l'utilisateur, et on démonte le home.</li>
<li>Les variables PAM_USER, PAM_TYPE et PAM_TTY sont injectés par pam_exec, et le mot de passe est injecté en stdin du script.</li>
</ul>
<p>Ce script sera exécuté par pam_exec à l'authentification, ainsi qu'à la fermeture de session.<br>
Pour ceci nous modifions le fichier <code>/etc/pam.d/system-login</code> :</p>
<pre><code><a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a># Après les autres lignes commençant par auth
auth optional pam_exec.so expose_authtok /opt/pam_mountencrypt.sh
<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a># Après les autres lignes commençant par session
session optional pam_exec.so /opt/pam_mountencrypt.sh
</code></pre>
<p>Puis nous allons faire une petite modification de systemd, qui sur certaine distribution ne ferme pas proprement tous les processus de l'utilisateur à la fermeture de la session.</p>
<p>Nous modifions donc le fichier <code>/etc/systemd/logind.conf</code> et on ajoute cette option :</p>
<pre><code>KillUserProcesses=yes
</code></pre>
<p>On redémarre la machine, et normalement tout fonctionne.</p>
<h1>D'autres cas d'utilisation</h1>
<p>Avec Veracrypt, nous pourrions imaginer un montage d'un volume caché si une certaine clé USB est connecté par exemple.<br>
J'utilise également pam_exec pour monter un répertoire réseau NFS. Si je suis sur mon réseau local, il monte le répertoire directement, mais si je suis sur un autre réseau, il me crée une connexion VPN vers chez moi, puis monte le répertoire. Je l'utilise aussi pour monter un répertoire cloud par rclone et chiffré.</p>
<p>Il y a vraiment beaucoup de cas d'utilisation, les possibilités sont quasiment illimitées, et pas forcément que pour monter un répertoire. Je suis tombé récemment sur un article, qui montrais comment mettre en place un profil itinérant sous GNU/Linux grâce notamment à pam_exec.</p>
]]><![CDATA[A la recherche d'une nouvelle distribution]]>https://catlife.drycat.fr/~/XataZ/a-la-recherche-d'une-nouvelle-distribution/2020-01-14T08:26:37.795074+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-01-14T08:26:37.795074+00:00<![CDATA[<p>Ayant récemment changé le PC portable de ma copine, j'ai donc décidé de réinstaller toute les machines de la famille (2 PCs portable, et 2 PC Bureautique), avec un OS unique pour simplifier la gestion derrière.</p>
<p>Le problème étant que je suis lasse de l'installation manuel d'archlinux, et surtout je n'ai plus le temps de passer des heures à configurer le tout.</p>
<p>J'ai alors commencé par aller sur distrowatch voir ce qu'il se faisait en ce moment, et après un premier filtre sur les distributions basé sur des distributions basé sur des distributions basé sur encore d'autres distributions, j'ai effectué cette énorme liste :</p>
<ul>
<li>CentOS</li>
<li>Manjaro</li>
<li>Linux Mint (petite exception)</li>
<li>Ubuntu (Et dérivé des DE)</li>
<li>Solus</li>
<li>Debian</li>
<li>openSuse</li>
<li>Fedora</li>
<li>Archlinux</li>
<li>Void Linux</li>
<li>Gentoo</li>
<li>Alpine</li>
<li>NixOS</li>
</ul>
<blockquote>
<p>Je comprends qu'il est difficile pour un débutant de ci retrouver dans ce merdier.</p>
</blockquote>
<p>Je me suis donc poser plusieurs questions pour filtrer la distribution qui correspondra le plus à nos besoin.</p>
<h1>Les questions</h1>
<h2>La base</h2>
<p>Je suis ouvert à tout, et n'ai aucun à priori sur telle ou telle distribution, donc que ce soit une base Debian, RedHat, Archlinux, Mandrake ou indépendant je m'en fou complètement. Je veux seulement quelques choses basé sur du binaire et non sur des sources.</p>
<p>Cette première question m'enlève simplement les distributions source-based, donc exit Gentoo et dérivés.<br>
J'exclus également NixOS, pour une raison simple, c'est une nouvelle façon de penser, et je n'ai actuellement pas envie et pas le temps d'apprendre quelques choses de nouveaux.</p>
<p>La liste se réduit donc :</p>
<ul>
<li>CentOS</li>
<li>Manjaro</li>
<li>Linux Mint (petite exception)</li>
<li>Ubuntu (Et dérivé des DE)</li>
<li>Solus</li>
<li>Debian</li>
<li>openSuse</li>
<li>Fedora</li>
<li>Archlinux</li>
<li>Void Linux</li>
<li>Alpine</li>
</ul>
<h2>Rolling Release ou fixed</h2>
<p>C'est une question compliqué et totalement subjectif, venant de ArchLinux, j'adore le rolling release, toujours les derniers logiciel, pas besoin de faire de migration, pas besoin de jouer avec des dépots tiers pour avoir des logiciels plus à jours etc ...</p>
<p>Donc on supprime ici pas mal de distributions de ma liste, comme Linux Mint, Ubuntu, Debian stable et testing, Fedora, et CentOs.</p>
<p>La liste se réduit de nouveau avec des critères de version pour la version RR :</p>
<ul>
<li>Manjaro</li>
<li>Solus</li>
<li>Debian <strong>SID</strong></li>
<li>openSuse <strong>tumbleweed</strong></li>
<li>Archlinux</li>
<li>Void Linux</li>
<li>Alpine <strong>edge</strong></li>
</ul>
<h2>Les logiciels</h2>
<p>Niveau logiciels, les habituels Navigateur web, Client mail, lecteur vidéo/audio, quelques jeux dont steam, du traitement de texte sont indispensable, et ayant de moins en moins de temps pour les gérer, je souhaite du Out-of-box, je lance l'installateur (graphique ou non), ça s'installe puis ça fonctionne. L'installation doit se faire en moins de 2h, et être 100% fonctionnel.</p>
<p>Par contre je souhaite un gestionnaire de paquet graphique, et même un gestionnaire de logiciel, un store, quelques choses de simple et efficace.</p>
<p>Niveau DE/WM, même si j'adore i3/sway qui est ultra léger, je ne peux malheureusement pas l'utiliser tout les jours, ce sont des PC familiaux, donc il faut un DE complet, un peu à la windows, donc je pars sur cinnamon voir MATE ou XFCE si pas trop de customisation à faire. Pas de gros DE comme Gnome ou KDE.</p>
<p>VoidLinux me tentait bien, mais à ma connaissance, il n'a pas de gestionnaire de paquet graphique, tout comme alpine.<br>
Archlinux on oublie pour le Out-Of-Box.</p>
<p>Donc là on peu en supprimer encore :</p>
<ul>
<li>Manjaro</li>
<li>Solus</li>
<li>Debian <strong>SID</strong></li>
<li>openSuse <strong>tumbleweed</strong></li>
</ul>
<h1>Test des distributions</h1>
<p>J'ai testé rapidement ces distributions sur une machine virtuel sous virtualBox, avec 2 coeurs et 2Go de ram, sur un DD de 20Go.<br>
Ce serons des tests rapides, rien de bien compliqué, j'installe, je check les logiciels installés, je regarde le taff que demandera la customisation du DE et la disponibilité des logiciels que j'utilise régulièrement. Je ne teste en aucun cas les performances de chacune.</p>
<p>Pour tester les logiciels supplémentaires, je rechercherais que 3 logiciels, vscodium ou vscode, spotify et bitwarden. Sachant que ces logiciels sont disponible en package full (snap, flatpack, appimage).</p>
<h2>Solus Budgie</h2>
<h3>Installation</h3>
<p>L'installation est simple et rapide, rien de spécial à dire sur le sujet, c'est fonctionnel rapidement.</p>
<h3>L'environnement</h3>
<p>L'environnement de bureau budgie est vraiment sympathique, simple, sobre et super efficace, j'aime beaucoup.</p>
<h3>Les logiciels pré-installés</h3>
<p>Nous avons le minimum vital, c'est parfait, suffisant.</p>
<h3>Les logiciels disponible</h3>
<p>Là nous avons un joli store d'application, qui fonctionne très bien. Le store est par contre assez pauvre, heureusement que le dépot tiers vient en ajouter un peu.<br>
Spotify est disponible dans le store, dans les applications tiers justement.<br>
Les deux autres sont indisponible nativement.<br>
Solus semble par contre compatible comme beaucoup avec flatpak et snap, donc c'est toujours possible de les installer.</p>
<h2>Manjaro XFCE</h2>
<h3>Installation</h3>
<p>L'installation est simple et rapide, tout s'installe depuis le liveCD.</p>
<h3>L'environnement</h3>
<p>XFCE me convient parfaitement avec leurs customisations, je ne pense pas avoir besoin de changer grand chose.</p>
<h3>Les logiciels pré-installés</h3>
<p>Tout ce qui faut est déjà installé, même steam (enfin le launcher) est présent.
Pamac c'est vraiment amélioré depuis mon dernière essais, même s'il n'est pas le plus jolie gestionnaire de logiciel, il est pas mal, plutôt clair, et simple d'utilisation. Nous avons possibilité d'y activer AUR et même snap (même si l'utilité est minime avec AUR), et c'est clair, c'est écris directement si c'est un paquet AUR ou snap.</p>
<h3>Les logiciels disponible</h3>
<p>Bon bas là pas de secret, nous avons vraiment tout de disponible, si pas disponible dans les dépots officiel, c'est peut être dans le dépot community, et au pire dans AUR.<br>
Mes 3 logiciels recherchés sont disponible sous AUR, donc semi-natif je dirais. VS code est même disponible dans les dépôts officiels.</p>
<p>Je ne suis surement pas objectif, car étant archlinuxien, j'aime AUR.</p>
<h2>Debian SID Cinnamon</h2>
<h3>Installation</h3>
<p>L'installation est un peu plus hardu, et un peu plus longue, car pour passer sur SID, il faut passer par une première installation sur stable ou testing, puis changer les dépots pour unstable, et mettre à jour. Rien d'insurmontable évidemment et relativement rapide.<br>
Sur VM pas de soucis de pilote, mais sur mes PCs, je sens bien en avoir quelques un. Je prendrais surement une ISO non-free pour ces installations si je choisi debian.<br>
Le partitionnement automatique avec LVM et la possibilité de séparer les partitions est top, je n'ai pas souvenir avoir vu ceci sur les autres distributions testé.</p>
<h3>L'environnement</h3>
<p>J'ai choisi cinnamon pour Debian, car XFCE en mode brut n'est pas du tout adapté à ce que je cherche, il faudra bien passé 1 ou 2h de plus pour le configurer au petit oignon.<br>
Cinnamon de base n'est pas moche, mais pas forcément à mon gout, mais l'application d'un thème sombre et d'un pack d’icône sera toujours plus rapide que la configuration de XFCE.</p>
<h3>Les logiciels pré-installés</h3>
<p>Bon là c'est particulier, car on peux vraiment choisir ce qu'on veut à l'installation si on passe par le net-install en passant par le mode expert, donc avoir son DE avec les logiciels de base, aucun soucis.<br>
Là on est dépendant de notre débit pour la durée de l'installation, avec la fibre, 45min suffise.<br>
Par contre, même si le gestionnaire de paquet synaptic c'est beaucoup amélioré, ce n'est pas le plus accueillant. Il reste cependant plus que fonctionnel.</p>
<h3>Les logiciels disponible</h3>
<p>Debian n'a que du logiciel libre dans ces dépots principaux. Il y a bien les dépots non-free, mais pas beaucoup de logiciel supplémentaire, plus des pilotes.<br>
Par contre debian étant une grande distribution, bien souvent des dépots tiers ou simplement des .deb sont disponible.<br>
Même avec la version unstable, il ne faut pas s'attendre à avoir la toute dernière version, firefox est par exemple en version ESR.<br>
Et comme toujours, on peux passer par les snap, flatpak et appImage au besoin.</p>
<h2>openSuse tumbleweed XFCE</h2>
<h3>Installation</h3>
<p>L'installation est simple, mais plutôt lente. Je n'aime pas spécialement la configuration des disques par défaut avec l'utilisation de btrfs, mais rien n'empêche un partitionnement manuel.</p>
<h3>L'environnement</h3>
<p>XFCE est plutôt jolie et corresponds à mes attentes, vraiment pas grand chose à modifier, voir même rien du tout.</p>
<h3>Les logiciels pré-installés</h3>
<p>Il ne manque quasi rien, à part VLC je dirais, tout est Out of box. Le gestionnaire de configuration YaST est vraiment puissant et permet de faire beaucoup de configuration, mais pas forcément utile à tout le monde.<br>
Un peu déçu par contre par YaST Software, il est puissant, mais pas très beau. Je ne demande pas un design de fou, mais une interface un peu plus simple et plus accueillante.</p>
<h3>Les logiciels disponible</h3>
<p>La dépot ne font pas partie des plus disponible, mais openSuse supporte flatpak et snap si vraiment il y a besoin. Aucun de mes logiciels dans les dépots.</p>
<h1>Le choix</h1>
<p>Pour finaliser mon choix, j'ai montré ces 4 distributions à ma copine, brut, sans customisation, voici ces conclusions :</p>
<ul>
<li>Manjaro, Solus et openSuse sont jolies, Debian fait trop vieillot.</li>
<li>Le gestionnaire de paquet de Debian et openSuse sont trop compliqué, Manjaro et Solus se rapproche plus de se qu'on trouve sur un(e) smartphone/tablette.</li>
<li>Pour le reste, c'est super fluide et facilement utilisable.</li>
</ul>
<p>Donc pour ma copine, les mieux sont Manjaro et Solus. C'est une conclusion d'une simple utilisatrice, elle utilise un PC que pour de la bureautique et regarder des vidéos de temps en temps.</p>
<p>Mon compte rendu personnel :</p>
<ul>
<li>Solus est un très joli OS, mais il manque encore de maturité, et surtout à un nombre de paquet limité.</li>
<li>Debian j'adore en version stable sur serveur, mais même en unstable, on n'a pas les toutes dernières version. De plus, je n'aime pas aller à l'encontre de la philosophie de debian, à savoir le full-libre. Cette philosophie en fait un OS de serveur parfait, mais un peu moins bon pour du desktop.</li>
<li>Manjaro je kiffe, même si certains choix politique sont discutable, cela reste une très bonne distribution, avec en plus l'accès à la communauté de Archlinux.</li>
<li>Opensuse, j'avoue que j'ai un peu craqué dessus, c'est clean, c'est stable, YaST est bien foutu. Mais comme pour Solus et Debian, il manque cruellement de paquet que j'utilise, libre ou non d'ailleurs.</li>
</ul>
<p>Comme vous l'aurez compris et de manière totalement subjective, mon choix se porte sur <strong>Manjaro</strong>, déjà parce que c'est basé sur Archlinux, donc nous avons accès à AUR, et cela permets de se passer de snap & co et surtout de dépôt tiers, dont la pérennité n'est pas certaines, mais aussi parce qu'il est 100% fonctionnel de base, je n'ai rien installé de plus sur le PC portable de ma copine, 100% out of box.</p>
<h1>Conclusion</h1>
<p>Je suis surement passé à coté de beaucoup de distribution très bien, mais je ne regrette pas ce choix.<br>
Cela fait maintenant 2 semaines que nos 2 PCs portable sont passés sur <strong>Manjaro</strong>, et ça tourne parfaitement. Je n'ai absolument pas touché au thème, simplement déplacé le panel en haut au lieu d'en bas, et c'est bon. Il ne me manque qu'à créer 2/3 raccourcis clavier et c'est good.<br>
Niveau logiciel, ba c'est du Arch, donc j'ai trouvé tout ce qu'il me faut.</p>
<p>Pour ma copine, elle adore, elle qui était très Windows par simple méconnaissance de ce qui pouvais exister d'autres, elle est totalement satisfaite. Elle a tout ce qu'il faut, rien ne lui manque pour le moment.</p>
<p>Pour moi cela ne change pas beaucoup, mais je pense sérieusement me réinstaller i3 pour plus de productivité quand je suis en mode boulot.</p>
]]><![CDATA[Je déteste le nouvel an]]>https://catlife.drycat.fr/~/XataZ/je-déteste-le-nouvel-an/2020-01-02T14:42:16.079661+00:00xatazhttps://catlife.drycat.fr/@/xataz/2020-01-02T14:42:16.079661+00:00<![CDATA[<p>Pendant les 2 prochaines semaines, je vais être <strong>exécrable</strong>, pourquoi ?! Hé bien je vais vous l'expliquer</p>
<p>Déjà, parce que ça va être le défilement des faux cul pour te souhaiter une <em>bonne et heureuse année</em>, alors qu'ils n'en ont rien à foutre de ta gueule.<br>
C'est le moment de recevoir plein de messages de gens dont les dernières nouvelles étaient pour la nouvelle année précédente, de recevoir des putains de messages groupés, sans aucune personnalisation, ou pire personnalité (<em>Bonne année à vous tous</em>).<br>
Avec les réseaux sociaux, ce phénomène agrave les choses, avec un simple <em>Bonne année 2020 !!!</em>, et qui veut prends, pourquoi se faire chier franchement ?!</p>
<p>Mais le pire, cela reste au taff, tu l'entends 100 fois par jour (<em>bonne année, bonne santé, meilleurs voeux</em>), sans aucune réelle envie, réelle sincérité, et toi comme un mouton, tu réponds pareil, car c'est simplement de la politesse. Ces mots finissent par remplacer les <em>bonjour</em> (qui est très faux cul également, bonjour étant pour souhaiter une bonne journée), pendant ce court moment. J'ai l'impression t'entendre un <em>ça va ?</em>, mais si tu sais, celui qui n'attend que la réponse <em>oui et toi ?</em>, car si tu réponds <em>non ça ne va pas</em>, il se casse.<br>
En plus de cette <em>répétition</em>, nous avons la perle, ceux qui ne te connaissent pas, qui ne te respectent pas, mais qui viennent, la bouche en cœur te souhaiter cette merveilleuse année, par exemple mon super DG, que j'ai vu 2 fois dans l'année, pour essayer de trouver un coupable, qui vient me caresser dans le sens du poil :</p>
<ul>
<li><em>Meilleurs vœux, en espérant que tu restes encore longtemps avec nous, on a besoin de gars comme toi ....</em></li>
<li><em>Ba non connard, je me casse dans 2 mois, mais si tu savais au moins qui je suis, tu serais au courant</em><br>
Au taff je propose qu'on se regroupe tous dans une pièce, et on cri <em>Meilleurs voeux</em>, et stop, c'est fini pour Janvier, tu en penses quoi ?!</li>
</ul>
<p>Ensuite il y a le sens des mots, dire <em>bonne année !!!</em> ou <em>bonne santé !!!</em> restent des affirmations, et non des souhaits, mais ces mots ne sont que des mots, ils ne sont pas magiques, il ne suffit pas d'avoir 500 <em>bonne santé</em> pour l'être.<br>
Puis une bonne année c'est quoi ?! Une année sans <em>couac</em>, sans <em>malheur</em> ?! Personnellement je n'ai jamais passé une année parfaite, il y a des hauts, mais surtout des bas, et c'est comme ça, c'est la vie.</p>
<p>Donc désolé si je suis mal poli, quand on me souhaite une <em>bonne année</em>, et que je sais que cette personne n'a pas une once de sincérité, je réponds simplement <em>merci</em>.</p>
<p>Tout cela ne veut pas dire que je n'aime pas le réveillons, être avec mes proches, c'est génial, leurs souhaiter le bonheur qu'ils méritent aussi, les embrasser, rouler un pelle à ma femme, etc ... J'aime tout ceci, j'aime mes proches, mais ils ne représentent que 5% des vœux que je reçois.<br>
J'aime également les petits messages qui sortent de l'ordinaire, j'en ai reçu un avec un petit <em>Passe une année 2020 rigolote</em>, c'est simple, mais putain que ça fait du bien, dommage que je ne sache pas qui est l'émetteur. </p>
]]><![CDATA[Créer sa propre distribution WSL]]>https://catlife.drycat.fr/~/XataZ/créer-sa-propre-distribution-wsl/2019-09-23T17:04:53.555109+00:00xatazhttps://catlife.drycat.fr/@/xataz/2019-09-23T17:04:53.555109+00:00<![CDATA[<p>Depuis quelques temps, mon PC du boulot est passé sous windows 10.</p>
<p>Sous Windows 7, j'avais donc des VMs Debian et des VMs CentOS (pour être au plus proche des serveurs) afin de faire mes tests sans risques.<br>
Mais au passage de Windows 10, je me suis dis que l'utilisation de wsl pourrait être pas mal, sachant que je bosse principalement sur du bash, du perl et du python, ça ne devrait poser aucun soucis. Je garde quand même quelques VMs pour faire des tests plus poussés évidemment, comme les tests de provisionning ou de clustering, mais sur hyper-v maintenant car j'utilise docker4windows.</p>
<p>Premier problème sur lequel je suis tombé, pas de distribution Archlinux (que j'aime énormément) et pas de distribution CentOs officiel. Nous allons donc voir ensemble comment les créer avec nos jolies mains.</p>
<h2>Création du WSL avec Docker</h2>
<h3>Création du tarball</h3>
<p>La méthode la plus simple que j'ai trouvé, est d'utiliser docker pour créer notre tarball d'installation.</p>
<p>Nous utiliserons cette méthode pour créer notre distribution CentOS.<br>
Nous commençons donc par télécharger l'image CentOS :</p>
<pre><code>PS C:\Users\xataz> docker image pull centos:7
7: Pulling from library/centos
d8d02d457314: Pull complete
Digest: sha256:307835c385f656ec2e2fec602cf093224173c51119bbebd602c53c3653a3d6eb
Status: Downloaded newer image for centos:7
docker.io/library/centos:7
</code></pre>
<p>Puis nous créons temporairement un conteneur :</p>
<pre><code>PS C:\Users\xataz> docker container create centos:7
f0d7d9392789d35af607cd1e6f88a6e14dcdfe21120c4ada55f180d532433d8b
</code></pre>
<p>Il nous suffit maintenant de créer une archive de ce conteneur :</p>
<pre><code>PS C:\Users\xataz> docker container export -o centos.tar.gz
f0d7d9392789d35af607cd1e6f88a6e14dcdfe21120c4ada55f180d532433d8b
</code></pre>
<p>Nous avons maintenant notre archive prête à l'emploi.</p>
<h3>Création de la distribution WSL</h3>
<p>Il ne nous reste plus qu'une seul étape, créer notre distribution.</p>
<p>Pour ceci nous ouvrons powershell, et nous utiliserons l'option import de wsl qui s'utilise ainsi :</p>
<pre><code>--import <Distribution> <EmplacementInstallation> <NomFichier> [Options]
Importe le fichier TAR spécifié en tant que nouvelle distribution.
Le nom de fichier peut être - pour l'entrée standard.
</code></pre>
<blockquote>
<p>Avec la version 2 de wsl, nous pouvons en plus spécifier la version à utiliser (1 ou 2), avec un --version N.</p>
</blockquote>
<p>Nous créons donc notre distribution :</p>
<pre><code>PS C:\Users\xataz> wsl --import Centos D:\WslDistro\Centos C:\users\xataz\centos.tar.gz
</code></pre>
<p>Puis nous pouvons enfin rentrer dedans :</p>
<pre><code>PS C:\Users\xataz> wsl --distribution Centos --user root
[root@DESKTOP-SHD40RK xataz]<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a> cat /etc/centos-release
CentOS Linux release 7.6.1810 (Core)
</code></pre>
<p>Nous nous retrouvons donc notre distribution CentOS, fonctionnel.</p>
<h2>Création du WSL avec le tarball</h2>
<h3>Récupération du tarball</h3>
<p>Nous allons maintenant créer une distribution ArchLinux, mais cette fois-ci directement avec le tarball fourni par archlinux.</p>
<p>Pour ceci nous aurons par contre besoin d'un shell unix, ça tombe bien, nous avons créer notre distribution CentOS.</p>
<p>Nous commençons par télécharger le bootstrap de archlinux, j'utilise personnellement le miroir de polymorf.</p>
<pre><code>$ curl http://archlinux.polymorf.fr/iso/2019.09.01/archlinux-bootstrap-2019.09.01-x86_64.tar.gz > archlinux.tar.gz
</code></pre>
<p>Le tarball de ArchLinux est part contre mal foutu (enfin pour WSL), car il y a un répertoire root.x86_64 dedans, il faudra donc le recréer :</p>
<pre><code>$ tar xzvf archlinux.tar.gz
$ tar czvf archlinux-wsl.tar.gz -C root.x86_64 .
</code></pre>
<h3>Création de la distribution WSL</h3>
<p>Puis il ne nous reste plus qu'à importer le tarball avec la même commande que précédemment :</p>
<pre><code>PS C:\Users\xataz> wsl --import Archlinux D:\WslDistro\Archlinux archlinux-wsl.tar.gz
PS C:\Users\xataz> wsl -d Archlinux
[root@DESKTOP-SHD40RK xataz]<a href="//catlife.drycat.fr/tag/" rel="noopener noreferrer">#</a>
</code></pre>
<h2>Conclusion</h2>
<p>Comme vous l'avez compris, il suffit simplement d'avoir une archive du rootfs de notre distribution, et nous pouvons les créer comme nous voulons, en illimité. </p>
]]><![CDATA[Multiroom parfait]]>https://catlife.drycat.fr/~/XataZ/multiroom-parfait-enfin-de-ma-vision/2019-05-09T08:05:52.526095+00:00xatazhttps://catlife.drycat.fr/@/xataz/2019-05-09T08:05:52.526095+00:00<![CDATA[<p>Cela fait un moment que je cherche une solution multiroom complète, depuis un moment, je tournais sur LMS (logitech media server) depuis quelques années, mais il me manquait quelques fonctionnalités. Et surtout il y en avait en trop, je n'utilise pas l'écoute local, mes deux sources sont spotify, et de temps en temps, youtube, jamendo ou autre depuis mon smartphone.</p>
<p>Après de nombreuse recherche, j'étais tombé sur snapcast, mais après quelques tests, je trouvais la qualité pas top, ça se désynchronisait assez souvant, sans revenir en synchro, donc pas forcément top top. En fin de compte, deux mois après mon essaie, une nouvelle version est sortie, mais je ne l'avais pas vu, je teste, et y'a du mieux, du beaucoup mieux. Toujours quelques désynchro minime, mais ça se re-synchronise très très vite, en moins d'une seconde généralement.</p>
<p>J'ai donc commencé à chercher la solution AllInOne parfaite, j'ai donc testé mopidy, basé sur mpd, facile de configuration avec snapcast, mais j'ai eu pas mal de petit bug, comme la perte de mon spotify connect par exemple, c'est embêtant, sachant que c'est ma principale utilisation.</p>
<p>J'ai ensuite testé volumio, qui propose des plugins pour snapcast, spotify et youtube. Bon le plugin youtube, je n'ai pas réussi à la faire fonctionner. Ensuite le plugin spotify fonctionnait parfaitement, jusqu'à l'activation du plugin snapcast, qui à fait perdre mon spotify connect, et impossible de le récupérer, sauf en supprimant le plugin snapcast, et en redémarrant la bête. Sans compter les bugs avec l'interface, qui lors de l'installation d'un plugin, se perds dans les noms, par exemple snapcast noté comme activé, alors que je viens de l'installer, et spotify désactivé, alors qu'il était activé avant, et en cliquant sur les paramètres de spotify, j'arrivais dans les paramètres de youtube. Pas très pratique.</p>
<h2>Ma solution</h2>
<p>La solution trouvé est relativement simple, et repose sur snapcast donc, avec librespot, mpd et la gestion du bluetooth. Pour la gestion du multiroom, j'utilise l'application android snapcast, qui permets de gérer les groupes, elle n'est pas top top pour le moment, j'ai donc installer une petite interface web permettant cette gestion.</p>
<h3>Snapcast</h3>
<p><a href="https://github.com/badaix/snapcast" rel="noopener noreferrer">Snapcast</a> est le coeur de notre solution, via un système client/serveur, il permets la diffusion d'un flux et une synchronisation de celui-ci sur plusieurs appareils. J'admets que je ne connais pas les détails techniques de son fonctionnement.</p>
<h3>Librespot</h3>
<p><a href="https://github.com/librespot-org/librespot" rel="noopener noreferrer">Librespot</a> permets la création d'un point spotify connect. Spotify connect n'est pas comme le bluetooth, si vous connecter votre smartphone dessus, c'est librespot qui va chercher le flux, le smartphone n'est donc qu'un controlleur.</p>
<h3>Bluetooth</h3>
<p>La partie la plus compliqué à mettre en place, j'ai beaucoup galéré, avec l'utilisation de multiple tuto sans succès (souvent obsolète). Pour finir que suis partie sur un script tout prêt nommé <a href="https://github.com/lukasjapan/bt-speaker" rel="noopener noreferrer">bt_speaker</a>, il fonctionne parfaitement, il y aura par contre quelques modifications à effectué au niveau de sa configuration.</p>
<h3>mpd</h3>
<p><a href="https://www.musicpd.org/" rel="noopener noreferrer">MPD</a> (Music Player Daemon) est un serveur de musique.</p>
<h2>Nous avons besoin</h2>
<p>Je passe les détails sur l'installation d'un raspberry-pi, et sa configuration, je pars du principe que vous avec un RPI3, avec debian 9 dessus, à jour, et correctement configuré.<br>
Donc ce qu'il faut :</p>
<ul>
<li>Un RPI3 pour le serveur + client</li>
<li>Autant de RPI que voulu pour les clients</li>
<li>Des SD ou clés USB avec debian 9 (j'ai pris la version lite perso)</li>
<li>Des enceintes</li>
<li>Et du temps (2 bonnes heures)</li>
</ul>
<p>Pour une meilleur qualité sonore, n'oubliez pas d'ajouter <code>audio_pwm_mode=2</code> dans le config.txt de la partition boot.</p>
<h2>Installation du serveur</h2>
<h3>Installation de snapcast</h3>
<p>J'ai décidé d'utiliser mon serveur également en client, donc j'installe snapserver et snapclient dessus. (Bon ce n'est pas vrai, mais c'est possible ^^)</p>
<pre><code>$ wget https://github.com/badaix/snapcast/releases/download/v0.15.0/snapclient_0.15.0_armhf.deb -O /tmp/snapclient.deb
$ wget https://github.com/badaix/snapcast/releases/download/v0.15.0/snapserver_0.15.0_armhf.deb -O /tmp/snapserver.deb
$ dpkg -i /tmp/snapclient.deb /tmp/snapserver.deb
$ apt install -f
</code></pre>
<h3>Installation de librespot</h3>
<p>La compilation de librespot plante avec la version de rust disponible sur raspbian, il faut donc compiler sa propre version :</p>
<pre><code>$ curl https://sh.rustup.rs -sSf | sh
</code></pre>
<p>Puis on installe librespot, comptez une bonne heure pour la compilation.</p>
<pre><code>$ source $HOME/.cargo/env
$ git clone https://github.com/librespot-org/librespot /tmp/librespot
$ apt install build-essential libasound2-dev pkg-config portaudio19-dev
$ cd /tmp/librespot
$ cargo build --release
$ cp /tmp/librespot/target/release/librespot /usr/bin/librespot
</code></pre>
<h3>Installation du bluetooth</h3>
<p>Pour le bluetooth, j'ai vraiment galéré, mais j'ai trouvé un petit script qui gère tout ça bien</p>
<pre><code>$ wget https://raw.githubusercontent.com/lukasjapan/bt-speaker/master/install.sh -O /tmp/bluetooth.sh
$ chmod u+x /tmp/bluetooth.sh
$ /tmp/bluetooth.sh
</code></pre>
<p>J'ai eu un petit soucis de permission en lançant le service, pour le corriger :</p>
<pre><code>$ chown -R btspeaker:btspeaker /home/btspeaker
$ chmod -R 775 /home/btspeaker
</code></pre>
<p>Lors de mes tests, je n'ai pas essayé d'affiner ces permissions, mais je pense qu'un 760 devrait fonctionner.</p>
<h3>Installation de mpd</h3>
<p>L'installation de mpd est très simple :</p>
<pre><code>$ apt install mpd
</code></pre>
<h2>Configuration</h2>
<h3>Configuration d'alsa</h3>
<p>Nous allons commencer par configurer alsa pour y créer une interface virtuelle, qui va tout rediriger vers un fichier, ce fichier sera utiliser par snapcast pour le bluetooth.</p>
<p>Il suffit de créer le fichier /etc/asound.conf :</p>
<pre><code>pcm.bluetooth {
type plug
slave.pcm ratebluetooth
}
pcm.ratebluetooth {
type rate
slave {
pcm bluewrite
format S16_LE
rate 44100
}
}
pcm.bluewrite {
type file
slave.pcm null
file "/tmp/bluetooth.snap"
format "raw"
}
pcm.mpd {
type plug
slave.pcm ratempd
}
pcm.ratempd {
type rate
slave {
pcm mpdwrite
format S16_LE
rate 48000
}
}
pcm.mpdwrite {
type file
slave.pcm null
file "/tmp/mpd.snap"
format "raw"
}
</code></pre>
<h3>Configuration de snapcast</h3>
<p>Nous allons modifier le fichier default de snapserver qui se trouve dans <code>/etc/default/snapserver</code>, afin d'y modifier SNAPSERVER_OPTS :</p>
<pre><code>SNAPSERVER_OPTS="--sampleformat 48000:16:2 -c flac -s pipe:///tmp/bluetooth.snap?name=bluetooth -s spotify:///usr/bin/librespot?name=spotify&username=XXXXXXXXXX&password=XXXXXXXXXX&devicename=snapspot -s pipe:///tmp/mpd.snap?name=mpd"
</code></pre>
<p>Nous pourrions également ajouter airplay, mais n'ayant pas d'appareil apple, je ne peux tester, je vous renvoie au github de snapcast pour la configuration.</p>
<p>Puis on relance snapcast :</p>
<pre><code>$ systemctl restart snapserver
$ systemctl restart snapclient
</code></pre>
<p>Puis nous allons modifier le client, pour lui donner un petit nom, pour ceci il suffit de modifier le fichier <code>/etc/hostname</code>, donc je le nomme simplement <code>bureau</code>, puisque se RPI est dans mon bureau. Pour prendre en compte ce changement, il suffit de reboot le RPI.</p>
<h3>Configuration du bluetooth</h3>
<p>Pour commencer, nous allons modifier le fichier <code>/etc/bluetooth/main.conf</code>, et y modifier la valeur de <code>class</code> (qui est normalement commenté) à <code>0x200414</code>. Ceci aura pour effet de rendre notre périphérique seulement en écoute, il sera donc détecté en tant qu'enceinte/casque.</p>
<p>Ensuite nous allons donner un petit nom à notre périphérique bluetooth, pour ceci créez le fichier <code>/etc/machine-info</code> et y mettre :</p>
<pre><code>PRETTY_HOSTNAME=snaptooth
</code></pre>
<p>Nous avons dernier fichier à modifier, il s'agit du fichier <code>/etc/bt_speaker/config.ini</code>, ou nous modifions la valeur de <code>play_command</code> par :</p>
<pre><code>play_command = aplay --device bluetooth -f cd -
</code></pre>
<p>Cette commande permets l'écoute de tout son arrivant du bluetooth, et de le retransmettre sur l'interface virtuelle nommé bluetooth, qui écrit dans le fichier bluetooth.snap, qui est lu par snapcast.</p>
<blockquote>
<p>Je n'avais pas un bon son en 48Mhz, je suis donc passé en 44.1Mhz (option <code>-f cd</code>). Si jamais vous voulez tester avec une fréquence de 48Mhz, vous pouvez tester avec <code>-f dat</code>, sans oublier de modifier la configuration de <code>asound.conf</code> et modifier <code>pcm.ratebluetooth</code>.</p>
</blockquote>
<p>Puis on relance le service btspeaker :</p>
<pre><code>$ systemctl restart bt_speaker
</code></pre>
<h3>Configuration de mpd</h3>
<p>Je passe la configuration de base de mpd (webradio, dossier de media etc ...), ici nous ne verrons que la connexion à snapcast.</p>
<p>Dans le fichier <code>/etc/mpd.conf</code>, commentez la partie <code>audio_output</code> présente, et ajoutez ceci :</p>
<pre><code>audio_output {
type "fifo"
name "my pipe"
path "/tmp/mpd.snap"
format "48000:16:2"
mixer_type "software"
}
</code></pre>
<h2>Installation et configuration des clients</h2>
<p>Pour les clients, c'est vraiment très simple :</p>
<pre><code>$ wget https://github.com/badaix/snapcast/releases/download/v0.15.0/snapclient_0.15.0_armhf.deb -O /tmp/snapclient.deb
$ dpkg -i /tmp/snapclient.deb
$ apt install -f
</code></pre>
<p>Nous modifions également le <code>/etc/hostname</code>, par exemple, là je l'appelle donc <code>salon</code>.</p>
<p>Et on modifie le fichier <code>/etc/default/snapclient</code> pour y ajouter l'IP du serveur snapcast :</p>
<pre><code>SNAPCLIENT_OPTS="-h 192.168.1.201"
</code></pre>
<p>et on reboot.</p>
<h2>Utilisation</h2>
<p>Pour l'instant j'utilise seulement depuis une vieille tablette, avec seulement 3 applications dessus, MALP pour la gestion des musiques MPD, Spotify pour gérer spotify, et snapcast pour gérer les clients. Mais je suis actuellement en train de travailler sur une interface qui permettra une gestion plus fine de snapcast, et pourquoi par la suite la gestion de mpd et spotify, mais là c'est vraiment pas pour demain.</p>
<p>Snapcast fonctionne par stream (avec ce tutoriel, nous en avons 3, spotify, bluetooth et mpd), avec l'application snapcast, nous pouvons donc associé tel ou tel client à un stream.
L'application ne permets pas une gestion fine, notamment la création de groupe (qui est gérer par snapcast via JSON-RPC), nous pourrions par exemple mettre 3 clients dans le salon, et en créer un groupe pour les liés ensembles tout le temps.</p>
<h2>Troubleshooting</h2>
<h3>Volume trop bas</h3>
<p>Nous pouvons régler le volume global du RPI :</p>
<pre><code>$ alsamixer
</code></pre>
<p>Mais au prochain reboot, on perd tout, pour sauvegarder :</p>
<pre><code>$ alsactl store
</code></pre>
<h2>Annexe</h2>
<p>Autre que les applications utilisées, j'ai également suivi quelques tutoriels, qui m'ont permis de comprendre un peu mieux ce que je faisais :</p>
<ul>
<li><a href="https://www.raspberrypi.org/forums/viewtopic.php?t=161944" rel="noopener noreferrer">Tuto bluetooth (forum raspberrypi)</a></li>
<li><a href="https://www.sigmdel.ca/michel/ha/rpi/bluetooth_02_fr.html" rel="noopener noreferrer">Tuto bluetooth (forum sigmdel)</a></li>
</ul>
<p>Les documentations officiel :</p>
<ul>
<li><a href="https://github.com/badaix/snapcast/blob/master/doc/player_setup.md" rel="noopener noreferrer">Docs snapcast</a></li>
<li><a href="https://github.com/librespot-org/librespot/wiki" rel="noopener noreferrer">Docs librespot</a></li>
</ul>
]]><![CDATA[DéGAFAMisation, easy or not ?]]>https://catlife.drycat.fr/~/XataZ/dé-gafa-misation-easy-or-not/2019-05-03T07:57:46.055042+00:00xatazhttps://catlife.drycat.fr/@/xataz/2019-05-03T07:57:46.055042+00:00<![CDATA[<p>Cela fait des années que j'essaie de ne plus utiliser les services proposés par les <strong>G</strong>oogle <strong>A</strong>pple <strong>F</strong>acebook <strong>A</strong>mazon <strong>M</strong>icrosoft, mais je me rends compte que ce n'est pas si simple.</p>
<p>Il faut différencier 2 types de services, les services de contenants (gmail, gdrive, outlook web, etc ...), et les services de contenus (youtube, facebook, netflix, etc ...).</p>
<h2>Les types de services</h2>
<h3>Les services de contenants</h3>
<p>Ces services sont assez simple à supprimer, un service mail reste un contenant, c'est nous qui créons le contenu, donc peu importe son interface, cela reste du mail. Pareil pour le drive, c'est notre contenu, que ce sois gdrive, ou nextcloud, c'est pareil, on stock simplement.</p>
<p>Il y a des services de contenants qui sont à la fois des services de contenus, par exemple youtube, qui est simplement un contenants de vidéos, mais c'est également son contenus qui en fait son succès. Nous pourrions aussi parler des OS, comme Windows qui reste la plateforme de jeux, et MacOS la plateforme de création.</p>
<h3>Les services de contenus</h3>
<p>Ces services sont selon moi, très difficile à supprimer. Les réseaux sociaux par exemple, c'est le fait que tout le monde soit dessus qui est intéressante, plus que les fonctionnalités. Youtube également, avec la quantité énorme de vidéos sur plein de sujet.</p>
<p>Sans contenu, ces plateformes n'existeraient pas, ou n'auraient pas autant de succès. Rien de mieux qu'un endroit central pour communiquer avec les amis.</p>
<p>Même dans les outils spécifique, comme github, il est difficile de s'en passer. Cela permets la centralisation de millions (surement même des milliards) de projets, pouvoir y contribuer sans devoir à chaque projets créer un compte. C'est un luxe non négligeable. Mais pour quelques choses orientés informatique, une vrai alternative fédéré pourrait remplacer facilement ceci, ce n'est malheureusement pas le cas pour les services plus générique.</p>
<h2>Mes services</h2>
<h3>Services en ligne</h3>
<p>Pour les mails, j'ai choisi protonmail en version payantes ($$), après avoir été quelques années en auto-hébergé.<br>
Pour la gestion de mes favoris j'utilise myFrama, j'utilise d'ailleurs de plus en plus les services de framasoft, avec framapiaf, framagit ou même framabag.<br>
J'utilise également quelques services de drycat, notamment le chat Riot, mais aussi Miaou en backup de mon compte framapiaf.<br>
Pour mes sauvegardes, j'utilise borgbase, qui pour un tarif raisonnable permets de stocker ces sauvegardes borg, mais également Hetzner Storage Box pour doublé celle-ci.<br>
Qwant et duckduckgo pour les recherches.<br>
Bitwarden pour la gestion des mots de passe.<br>
Pour la musique, il m'arrive d'utiliser Jamendo, qui contient que des musiques libre de droit.</p>
<h3>Services auto-hébergé</h3>
<p>Sur mon serveur j'ai une instance Nextcloud, qui gère beaucoup de choses :</p>
<ul>
<li>Stockage</li>
<li>Documents avec OnlyOffice</li>
<li>Notes</li>
<li>Contacts</li>
<li>Agenda</li>
<li>Favoris (Malgré que j'utilise de plus en plus myframa)</li>
</ul>
<p>J'ai également un petit gitea, un service de CI avec Jenkins, un éditeur de code en mode web avec code-server (Ms visual studio code), un serveur torrent pour les films de vacances. Et pour le moment c'est a peu prêt tout.</p>
<h2>Les GAFAM que j'utilise toujours</h2>
<h3>Google</h3>
<p>J'utilise google pour youtube, et de temps en temps pour les recherches, si dans les 2 premières pages je ne trouve pas ce que je cherche sur Qwant ou Duckduckgo. J'utilise également android sur mon smartphone, mais dégoogliser au maximum, avec microg, et je n'ai pas de googlePlay. Par contre j'ai du recréer un compte car j'utilise android TV, et yalp store est une vrai galère dessus.</p>
<h3>Apple</h3>
<p>Je n'ai plus utilisé Apple depuis l'Iphone premier du nom, que j'ai gardé 2 semaines.</p>
<h3>Facebook</h3>
<p>Je n'arrive pas à m'en séparer, non pas pour Facebook lui même où je ne poste rien, mais pour messenger avec principalement les conversations de groupe, et les événements. De plus j'ai depuis 4 mois un petit toutou (un magnifique husky), et j'ai trouvé un groupe Facebook qui organise des balades canines (des ballades avec 25 chiens en liberté dans une forêt, c'est génial), sans ce groupe, mon chien ne serait pas autant sociable et épanoui qu'il ne l'est aujourd'hui.</p>
<h3>Amazon</h3>
<p>J'utilise de plus en plus la boutique amazon, principalement pour de l’électronique, mais aussi du matériel de bricolage. J'ai depuis peu pris un compte prime, partagé à 3, qui est assez pratique. Après si je peux privilégier une autre boutique je le fais, et si possible local, mais bien souvent c'est moins cher sur Amazon, et c'est souvent le porte-feuille qui choisi. De plus ma ville n'est pas très fournis en magasins spécifique, donc faire 50km pour trouver quelques choses où le faire livrer dans mon point relais avec un mec qui serait quand même venu sans ma commande est selon moi plus écologique.</p>
<h3>Microsoft</h3>
<p>J'ai toujours une vieille adresse mail chez eux, il faut que je finisse de la transférer completement.<br>
Autrement même si je préfère largement GNU/Linux, j'utilise toujours Windows sur mon PC de bureau, juste pour les jeux, car malheureusement les jeux auquel je joue, utilisent bien souvent des anti-cheats qui sont impossible à émuler sous Nunux.</p>
<h3>Divers</h3>
<p>J'utilise beaucoup de service propriétaire, comme spotify, netflix ou même prime video. S'il existe des plateformes libre dans le même genre, c'est surtout le contenu qui est intéressant ici.</p>
<h2>Le coût</h2>
<p>Cette pseudo liberté à un coût, financier et/ou en temps. De plus, lorsque l'on s'héberge, il faut également faire ces propres sauvegardes, et bien souvent cela coûte assez cher, pour moi c'est la moitié de mon infra.</p>
<h3>Coût financier</h3>
<p>Au niveau des services en ligne que j'utilise :</p>
<ul>
<li>ProtonMail + protonVPN => 190,4€ pour 2 ans soit 7,94€ par mois</li>
<li>BorgBase => 150€ par an soit 12,5€ par mois</li>
<li>Hetzner storageBox => 11,88€ par mois soit 142,56€ par an</li>
<li>Bitwarden => 10€ par an soit 0,84€ par mois</li>
<li>Serveur scaleway => 2,40€ par mois soit 28,8 par an.</li>
</ul>
<p>A ceci s'ajoute mon serveur perso, un proliant Gen8 acheté 200€ y'a un moment, 8Go de ram ECC à 90€, et 8 disques de 4To à 120€ pièce en moyenne, les 4 premiers ayant cramés.</p>
<p>Donc le serveur + la ram, c'est rentabilisé depuis, même si ce n'est pas immortel, nous ignorerons ce coût. Mais les disques s'usent plus ou moins rapidement, mes premiers disques dessus on tenu 5/6 ans, et les derniers sont là depuis 4-5 mois. Donc si on estime le coût des disques à 120€ par disque (les capacités augmentant ainsi que le besoin) x 4 tout les 5 ans, on rajoute un coût moyen de 96€ par an, soit environ 8€ par mois.</p>
<p>A ceci s'ajoute l'électricité, mon serveur consomme en moyenne 60W, donc 24x365x60=525600Wh soit 525,6kWh. Si on ramène ceci au coût actuel du kWh, cela donne environ 80€ par an, soit 6,67€ par mois.</p>
<p>Tout ceci individuellement ne parait pas énorme, mais au global, nous avons un coût de 50,23€ par mois, soit 602,76€ par an, et ce n'est pas rien.<br>
J'ignore volontairement mes raspberry, je ne sais pas trop combien ils consomment, mais cela ne doit pas représenter plus de 20€ par an.<br>
J'ai également fait quelques dons au service que j'utilise, comme framasoft et drycat, bon après ça ne rentre pas en compte dans mes dépenses, c'est du bonus.</p>
<h3>Coût en temps</h3>
<p>En plus du coût financier, nous avons le coût en temps, que ce soit récurrent ou d'installation.</p>
<p>Pour de l'auto-héberger, il m'a fallu environ 1 weekend complet pour tout mettre en place (à hauteur de 10/12h par jour, soit environ 24h), tester, automatiser, prévoir un plan de reprise et les sauvegardes compris. Mais ensuite cela demande quelques heures toutes les semaines, je ne compte pas forcément, mais je dirais minimum 2h.</p>
<p>Pour ce qui est des services en ligne, ce n'est pas de tout repos au début, il faut migrer, trier et changer les mails.<br>
Par exemple, mon passage de gmail à auto-héberger avait pris facilement 1 mois, le temps de trier avant de transférer, de changer mon adresse mail sur certains sites, donc de refaire une passe sur une bonne partie des mails, mais aussi de recréer les filtres, les répertoires etc ... Ce fut chiant et très long.<br>
Ensuite ayant mon propre domaine, la migration vers protonmail fût beaucoup plus rapide, environ une soirée, le temps de transférer tout les mails ainsi que le domaine.<br>
C'est d'ailleurs pour cette raison que je n'ai toujours pas terminé mon transfert de ma boite outlook, mais j'arrive à la fin.</p>
<h2>Tout ceci pour dire quoi en faite ?</h2>
<p>Ba que c'est pas si simple, ces services sont maintenant très encrés dans la société, et même si tu veux en partir, c'est très difficile.<br>
D'une part pour l'auto-héberger, ce n'est pas à la porté de tous, que ce soit technique, financier, ou même de temps.</p>
<p>Il y a aussi un coût financier dans des alternatives, comme protonmail, ou autres, car les versions gratuites sont à des années lumières de ce que propose google de base, et même en payant d'ailleurs. Gratuit protonmail ne propose de 500Mo de stockage, 5Go pour la version à 5€ par mois, contre 25Go (de souvenir) gratuit avec google.</p>
<p>Ensuite il y a la simplicité, pour exemple mastodon, c'est simple à l'usage, mais faire comprendre à un néophite le principe d'instance qui communique avec d'autre, avec un choix monstrueux n'est pas évident. J'en ai parler à un pote récemment, il a voulu s'y intéresser et s'y inscrire, mais il ne savait pas où, et ne comprenais pas comment on pourrait converser dessus. Une fois inscrit, il a installé tusky sur son smartphone, et encore une fois, il ne comprenait pas ce qu'il devait mettre dans instance. Il n'y a pas besoin d'aide pour s'inscrire sur twitter par exemple, tu t'inscris, et pouf ça marche, tu installes l'appli, tu mets tes identifiants, et pouf ça marche.<br>
Pareil pour whatapps par exemple, tu l'installes, tu fais next-next-next, tu mets ton nom et c'est bon, ça fonctionne. Tu changes de tel, pas de soucis, ça fonctionne.</p>
<p>Depuis un certain temps, framasoft à mis en place les CHATONS, c'est une très bonne initiative, mais merde, certains n'ont pas les compétences pour héberger les données des autres, c'est comme prêter sa voiture à un mec qui perds toujours ces clés et qui est toujours bourré. Je ne suis pas un hacker, et n'est en aucun cas les compétences pour l'être, mais quand en 5 min, tu arrives à récupérer des identifiants de base de données sur 2 CHATONS sur 5 (pris totalement au hasard), ça fait réfléchir.</p>
<p>Malgré que beaucoup d'amis soient conscient de leurs vie privé, leur supprimer cette simplicité, et cette qualité est impossible. C'est tellement plus simple de créer un compte du google, et d'avoir accès à tout directement, que de devoir chercher des services à droites et à gauches. Et puis a qui faire confiance pour sécuriser mes données ?</p>
<h2>Conclusion</h2>
<p>Ma déGAFAMisation est loin d'être parfaite, il me reste encore du boulot. J'ai déjà réussi à me passer de beaucoup de service contenant (fichiers, mail, etc ...), mais le contenu, c'est plus compliqué. Les services de contenu opensource (peertube, gitea, jamendo, mastodon, diaspora, etc ...) ne sont en réalité pas des alternatives, mais des nouveaux services. Le contenu de peertube est différent du contenu de youtube, pareil entre diaspora et facebook etc ... (Je vais pas tous les faires).</p>
<h2>Annexe</h2>
<ul>
<li><a href="framasoft.org" rel="noopener noreferrer">framasoft</a></li>
<li><a href="https://degooglisons-internet.org" rel="noopener noreferrer">degooglisonsinternet</a></li>
<li><a href="https://disroot.org/en" rel="noopener noreferrer">disroot</a></li>
<li><a href="https://drycat.org" rel="noopener noreferrer">drycat</a></li>
<li><a href="https://www.privacytools.io/" rel="noopener noreferrer">privacytools</a></li>
</ul>
]]><![CDATA[Reverse port ssh forwarding]]>https://catlife.drycat.fr/~/XataZ/reverse-port-ssh-forwarding/2019-04-13T21:42:38.701740+00:00xatazhttps://catlife.drycat.fr/@/xataz/2019-04-13T21:42:38.701740+00:00<![CDATA[<p>Ayant récemment eu la fibre à 300mbps symétrique chez moi, j'ai décider de supprimer mon serveur dédié que j'avais depuis quelques années pour tout héberger chez moi.</p>
<p>Le problème étant que chez orange, je n'ai pas d'IP fixe. J'aurais bien évidemment pu utiliser un DNS dynamique, ou même créer un script pour utiliser mon nom de domaine chez mon registar, mais je ne me voyais pas exposer mon IP publique directement sur internet.</p>
<p>J'ai donc chercher une autre solution, ma première idée a été de créer un serveur VPN sur un petit VPS chez scaleway, mais les performances n'était pas au rendez-vous. Autant la vitesse de téléchargement du VPS vers mon serveur était correcte, mais dans l'autre sens c'était catastrophique, je dépassais pas les 50ko/s avec une perte de paquet assez importante.<br>
Malgré de nombreux essais, je n'ai pas réussi à améliorer ces performances.</p>
<p>Après beaucoup de recherche, j'ai donc trouvé un moyen via le ssh forwarding, mais de manière inverse.
De base nous utilisons ce système pour pouvoir monter un port externe en local, pour accéder à un service à distance, ou même outrepasser certaines restriction, comme Plex, qui demande un compte premium pour un accès à distance.<br>
Mais avec le reverse forwarding, nous montons un port local, vers un port externe.</p>
<p>Bon allez, on commence</p>
<h2>Préparation du VPS</h2>
<p>Nous avons un petit paramètre à ajouter sur le service ssh de notre VPS :</p>
<pre><code>GatewayPorts clientspecified
</code></pre>
<p>Ce paramètre permet justement l'utilisation du reverse port forwarding. Par défaut il est à <code>no</code>.<br>
Nous avons deux autres possibilités, <code>yes</code> ou <code>clientspecified</code>, le premier permets seulement de monté le port sur toute les interfaces, tandis que le deuxième permet de choisir sur quoi écouter, comme localhost par exemple.</p>
<p>Puis on relance le service :</p>
<pre><code>systemctl restart sshd
</code></pre>
<p>Et c'est tout</p>
<h2>Sur mon serveur</h2>
<p>J'ai par exemple mon jenkins qui tourne sur le port 9010, pour pouvoir le monté sur mon VPS, c'est relativement simple :</p>
<pre><code>ssh -fN -R 9010:localhost:9010 xataz@X.X.X.X
</code></pre>
<ul>
<li><code>-fN</code> permets de laisser ssh en arrière plan.</li>
<li><code>-R</code> permets le montage du port (à l'inverse de -L).</li>
<li><code>RemoteIP:RemotePort:LocalIP:LocalPort</code> ou <code>Destination:Source</code></li>
</ul>
<p>Et voilà, le port est monté sur le VPS.<br>
Si par exemple je veux le monter seulement en localhost :</p>
<pre><code>ssh -fN -R localhost:9010:localhost:9010 xataz@X.X.X.X
</code></pre>
<p>Pour faciliter la gestion, j'ai créer un petit service systemd nommé sshf (Oui j'ai été très inspiré) :</p>
<pre><code>[Unit]
Description=SSH forwarding for tunnel for %i
Wants=network-online.target
[Service]
User=xataz
Type=forking
ExecStart=/usr/bin/ssh -i /home/xataz/.ssh/id_rsa -fN -R localhost:%i:localhost:%i xataz@X.X.X.X
Restart=always
[Install]
WantedBy=multi-user.target
</code></pre>
<p>Et comme ça il me suffit de lancer le service, et de l'activer :</p>
<pre><code>systemctl start sshf@9010
systemctl enable sshf@9010
</code></pre>
<h2>Conclusion</h2>
<p>Grace à mon reverse proxy que j'ai mis sur le VPS, je peux maintenant accéder à mes services qui sont directement chez moi, et ceux sans exposer mon IP.</p>
]]><![CDATA[Mes machines]]>https://catlife.drycat.fr/~/XataZ/mes-machines/2019-04-12T19:01:44.185104+00:00xatazhttps://catlife.drycat.fr/@/xataz/2019-04-12T19:01:44.185104+00:00<![CDATA[<p>Pour commencer, je vais parler un peu de mes machines, histoire de me présenter un peu plus.</p>
<h2>Machines serveurs</h2>
<h3>Proliant gen8</h3>
<ul>
<li>CPU : Intel Celeron G1610T 2,3Ghz</li>
<li>RAM : 10Go</li>
<li>Disk :
<ul>
<li>HDD 4x4To</li>
<li>SSD 60Go (system)</li>
</ul>
</li>
<li>OS : Debian 9</li>
<li>Services :
<ul>
<li>nextcloud</li>
<li>rtorrent+rutorrent</li>
<li>jenkins</li>
<li>gitea</li>
<li>Quelques bases de données</li>
<li>Samba</li>
<li>Logitech Media Server</li>
</ul>
</li>
</ul>
<h3>VPS scaleway</h3>
<ul>
<li>CPU : ?? (1 core)</li>
<li>RAM : 1Go</li>
<li>SSD : 25Go</li>
<li>OS : Debian 9</li>
<li>Services :
<ul>
<li>Reverse Proxy Nginx</li>
</ul>
</li>
</ul>
<blockquote>
<p>Ce VPS fera l'objet d'un article, pour expliquer son utilité</p>
</blockquote>
<h3>RPI 3 (domotique)</h3>
<ul>
<li>CPU : Armv7</li>
<li>RAM : 1Go</li>
<li>Clé USB : 32Go</li>
<li>OS : Raspbian</li>
<li>Services :
<ul>
<li>Jeedom</li>
</ul>
</li>
</ul>
<h2>Machine bureautique</h2>
<h3>PC fixe</h3>
<ul>
<li>CPU : Intel i7 4770K</li>
<li>RAM : 24Go</li>
<li>GPU : Amd radeon 390X 8Go nitro</li>
<li>Disk :
<ul>
<li>SSD 256Go (système)</li>
<li>SSD 1To (application)</li>
<li>HDD 2To (données)</li>
</ul>
</li>
<li>OS : Windows 10 (Oui j'ai honte !!!)</li>
<li>Utilisation unique : Gaming</li>
</ul>
<blockquote>
<p>Je vais surement repasser sous Arch dessus (ça me manque trop), avec un VM windows 10 avec GPU passthrough pour le jeux. Cela fera surement l'objet d'un article.</p>
</blockquote>
<h3>PC Portable</h3>
<ul>
<li>CPU : Intel i5 7200U</li>
<li>RAM : 16Go</li>
<li>GPU ; Intel</li>
<li>Disk :
<ul>
<li>SSD m2 256Go</li>
<li>HDD 500Go</li>
</ul>
</li>
<li>OS : Archlinux avec i3</li>
</ul>
<h2>Diverses machines</h2>
<h3>RPI2</h3>
<ul>
<li>CPU : armv7</li>
<li>RAM : 1Go</li>
<li>Clé USB : 32Go</li>
<li>OS : Recalbox</li>
<li>Utilisation : Borne arcade</li>
</ul>
<h3>3 RPI1 B</h3>
<ul>
<li>CPU : armv5 (de souvenir)</li>
<li>RAM : 512Mo</li>
<li>SD : 2Go</li>
<li>OS : Raspbian</li>
<li>Utilisation : Squeezebox pour audio multiroom</li>
</ul>
<h3>3 RPI zero W</h3>
<p>Non utilisé pour le moment, surement pour d'autre squeeze box.</p>
<p>Voilà voilà </p>
]]>