Skip to main content

· 4 min read
TheBidouilleur

I recently went through an ~8 month formation during which I only had a keyboard to take notes. For me: no problem, I only ask for that: a support that I use personally and professionally. I type rather fast (about ~100 words/minutes), I use macros, and shortcuts to simplify my life, and if I ever need a diagram: I use draw.io.

But during team work, I understood the importance (and power) of a pencil and a sheet of paper. Without a representation method like schematics: you get lost quickly.


So I bought The Tablet. A toy for children that works like any magic board we had as children. The Tablet

And this 5€ toy saved my life several times during multiplayer projects. It was enough to avoid buying paper during those 8 months.

I still keep this tablet on my desk, but I would love a similar system, but keeping my writings/drawings in memory.

That's how I acquired the...

The Remarkable

Remarkable 2

Having a colleague with this same jewel, I was able to find out in advance (and even test) this reader. It's a Linux-based tablet that allows you to read PDFs, and take notes via a stylus, imitating as much as possible the feel of paper.

It takes a bit of practice to get the hang of it, but after a few hours, you can see how powerful the toy is in your hands.

You can upload pdf's from your computer to the tablet via USB or directly by dropping the files on the Remarkable cloud.

other methods

I think it is also possible to drop your files by WiFi directly... never tested

But if you use a remarkable tablet, don't forget that it will constantly sync with the brand's AWS servers by embedding your PDFs.

It's really annoying ... If only we had a solution!

Remarkable Fake Cloud

In its operation, remarkable is a Linux with a systemd daemon (named xochtl) that will manage the e-ink screen. And once the root password is obtained in the settings (after reading that remarkable loves open-source, it's nice that they let the full power on the tablet) you can have fun doing a lot of things...

The tablet can therefore acquire new features and also host some small applications (within reason). And what interested me in this is the possibility to have its own remarkable cloud so that its files stay at home!

If some are interested, here is the GitHub link with the link to the documentation.

RMFakeCloud

The UI allows me to upload PDFs which are synchronized as long as the tablet is on WiFi. And I can even send files from my own smtp (something impossible natively).

To find it, you have to search

A little parenthesis about the author (DDVK) of the project. He regularly publishes programs to make his tablet more powerful, more ergonomic but he is very little active on the forums / reddit, I invite you to leave him a star to be informed of his new projects.

So I can brag about my user being admin on the tablet.. :) General settings

Conclusion

We started to approach note taking in a different way when the iPads came out, offering a cross between a PC and a smartphone experience. Remarkable has created an incredible product by offering a complete rethink of this functionality: no keyboard, no mouse... just a pen and a "paper " screen. And since the tablet is under Linux, I'm sure we're not done exploiting its potential by tinkering with it. (I didn't specify, but we have root access on the RM2) Dat root access

:::security deposit (Edit on 24/10) Be careful not to store anything confidential, the tablet is not encrypted! Although the accesses are not obvious (You would have to dismount and dump the eMMC card), it is possible to find your files quite easily. If you are interested in this subject, here is an article that talks about it and even proposes a solution: https://blog.redteam-pentesting.de/2021/remarkable-encryption/ :::

note

(Be careful, I didn't talk about the price... hang on if you want to buy it)

· 5 min read
TheBidouilleur

Introduction à Nix et NixOS

NixOS est une distribution Linux sortie initialement en 2003 et créée par (Eelco Dolstra, un chercheur travaillant sur la création d'un système immuable. Celle-ci se base sur le gestionnaire de paquet Nix qui permet de gérer la configuration du système à l'aide de fichiers Nix (un langage de programmation similaire au Haskell).

Ainsi si je souhaite créer un utilisateur kiko sur mon système, je peux écrire ceci dans mon fichier configuration.nix (qui est le fichier de configuration de l'OS initial)

  users.users.kiko = {
isNormalUser = true;
description = "kiko";
extraGroups = [ "networkmanager" "wheel" "sudo" ];
packages = with pkgs; [
firefox
vim
neovim
kubectl
terraform
];
};

Ou si je veux installer des programmes dans le système, je peux écrire ça :

  environment.systemPackages = with pkgs; [
vim
wget
htop
];

Et là, si vous êtes habitués aux gestionnaires de paquets normaux : vous avez remarqué que mon utilisateur peut installer des librairies de manière autonome.

C'est l'un des points forts de Nix ! Des environnements éphémères, des librairies contradictoires qui peuvent cohabiter, et des utilisateurs entièrements indépendants.

Nix (nous parlons du gestionnaire de paquets) autorise chaque utilisateur à avoir son propre PATH (ex: /run/wrappers/bin:/home/kiko/.nix-profile/bin:/etc/profiles/per-user/kiko/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin). Mais il ne se limite pas qu'à ça : on peut créer des environnements temporaires assez rapidement pour ne pas avoir à installer un programme et pouvoir s'en servir ponctuellement.

❯ cowsay
The program 'cowsay' is not in your PATH. It is provided by several packages.
You can make it available in an ephemeral shell by typing one of the following:
nix-shell -p cowsay
nix-shell -p neo-cowsay

~
❯ nix-shell -p cowsay
this path will be fetched (0.01 MiB download, 0.05 MiB unpacked):
/nix/store/9647mfqndy0aa8qkniqa05qc9yi575ny-cowsay-3.04
copying path '/nix/store/9647mfqndy0aa8qkniqa05qc9yi575ny-cowsay-3.04' from 'https://cache.nixos.org'...

~ via ❄️ impure (shell)
❯ cowsay "J aime la bidouille"
_____________________
< J aime la bidouille >
---------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||

~ via ❄️ impure (shell)
exit
exit

~ took 44s
❯ cowsay
The program 'cowsay' is not in your PATH. It is provided by several packages.
You can make it available in an ephemeral shell by typing one of the following:
nix-shell -p cowsay
nix-shell -p neo-cowsay

Nous avons créé un environnement similaire au notre.. mais avec le binaire cowsay.

Mais nous avons parlé d'environnement, alors créons un réel nix-shell plus complet...

Nix-Shell

Créons 2 fichiers.

# default.nix
with (import <nixpkgs> {});
let
my-python-packages = python-packages: with python-packages; [
requests
];
python-with-my-packages = python3.withPackages my-python-packages;
in
mkShell {
buildInputs = [
python-with-my-packages
];
}
# app.py
import requests
response = requests.get('http://perdu.com')
print(response.content)

Le fichier app.py est notre très complèxe application tandis que le fichier default.nix décrit l'environnement requis. Si je lance directement l'application python3 app.py je me retrouve avec une erreur car je n'ai pas installé python3 dans mon environnement.. Je peux créer un nix-shell avec python et lancer mon app.py :

❯ nix-shell -p python38 # création d'un env avec python3.8

/tmp/python via 🐍 v3.8.13 via ❄️ impure (shell)
❯ python3 app.py
Traceback (most recent call last):
File "app.py", line 1, in <module>
import requests
ModuleNotFoundError: No module named 'requests'

Mais nous nous retrouvons avec un autre problème de dépendance.. Il est donc possible de créer notre environnement à l'aide du fichier default.nix qui contiendra Python et la librairie requests (indispensable pour notre application.

Par défaut, nix-shell va chercher les fichiers nommés default.nix dans notre répertoire courant.

/tmp/python via 🐍 took 5m28s 
❯ nix-shell

/tmp/python via 🐍 v3.9.13 via ❄️ impure (nix-shell)
❯ python3 app.py
b"<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1><h2>Pas de panique, on va vous aider</h2><strong><pre> * <----- vous &ecirc;tes ici</pre></strong></body></html>\n"

Avec cette méthode, il est possible d'avoir plusieurs environnements pour lancer des applications différentes sans se soucier des effets de bords sur nos autres programmes.

Home-Manager

Si jamais je résume ce que nous avons vu :

  • Comment NixOS peut automatiser une configuration d'OS (On pourrait voir comment l'installer de la même manière)
  • Comment créer des environnements indépendants Il reste un aspect essentiel au passage sur Nix: le déploiement d'une configuration utilisateur !

Nix permet de déployer bien plus que quelques programmes, il existe une librairie d'instruction pour faciliter la configuration/déploiement d'un logiciel. Par exemple, à la création de mon utilisateur quotidien, je dois parametrer Git avec mon nom, et mon mail avant chaque commit..

git config --global user.name "Toto"
git config --global user.email "toto@toto.com"

Avec Nix, je peux créer un fichier dans mon home et garder cette configuration en dur :

  programs = {
git = {
enable = true;
userName = "Toto";
userEmail = "toto@toto.com";
ignores = [
"*~"
"*.swp"
];
};
};

J'ai donc plusieurs fichiers Nix me permettant d'installer mes programmes, de configurer Git, d'installer mon EMacs-Doom avec mes paramètres, de déposer mes dotfiles aux bons endroits. Pour l'instant.. ma configuration est publique et disponible ici, à voir ce que j'en ferai à l'avenir.. :)

Conclusion

Nix est vaste, très vaste, et il peut être compliqué d'en apprendre les bases. La communauté est au courant du manque de documentation et fait beaucoup d'effort pour donner une image agréable à Nix pour les débutants. Je pense que Nix a un potentiel non-négligeable pour les workstations/serveurs et pourrait même remplacer des outils de déploiement d'OS comme Packer.

On peut trouver les instructions / packages sur l'incroyable site search.nix.org. Je pense continuer à apprendre Nix jusqu'à pouvoir moi-même contribuer à la communauté et maintenir mes propres packages.

Seule complexité reste d'apprendre le langage Nix ! Mais avez-vous entendu parler de Guix.. ?

· 5 min read
TheBidouilleur

J'ai eu l'occasion de tester de nombreux moyens de transport alternatifs pour des déplacements quotidiens en ville (Trottinettes, Vélo électrique) mais aucun ne m'a jamais autant tenté que la gyroroue ! Depuis que j'ai découvert ce véhicule via les vidéos de Thomas(Mr.Flex sur YouTube), je fantasme sur l'idée de pouvoir m'en servir pour mes déplacements en plus de pouvoir prendre le train, bus ou tram.

Jusque-là, je me déplaçais exclusivement en vélo électrique (avec environ ~10 km pour arriver au travail), seuls les deux-roues m'intéressaient. Puis, pendant mes vacances d'étés de 2022, et étant donné que j'avais beaucoup de temps libre : je me suis dit "Pourquoi pas ?". Je me suis donc procuré un appareil d'occasion nommé le Kingsong ks-16b. Image montrant la gyroroue

Utiliser un appareil d'occasion me rassure pas mal en sachant que je ne veux pas abîmer du neuf, je récupère cette roue avec un kilométrage de 265 km et une batterie de 680Wh (me suffisant pour faire 40km). J'ai essayé de faire au moins 20 minutes d'apprentissages par jour pour me familiariser avec la bête et espérer la maîtriser en moins d'une semaine. (Ce que les gens promettent parfois sur les réseaux.)

Je vais donc résumer dans la prochaine partie mes avancées dans l'apprentissage de la gyroroue.

La longue route

Lundi 08/08

Première séance de 30min. Je comprends à quel point on sous-estime le simple fait de monter sur la roue sans s'appuyer sur un mur. J'arrive à monter avec peine mais je suis surpris de pouvoir y arriver en si peu de temps. Je peux démarrer et faire 1-2m sans tomber.

Mardi 09/08

Je m'accroche pendant une belle heure, objectif : aller d'un point A à un point B. (En l'occurrence : traverser mon garage) Je prends une ceinture (à mettre dans le trolley, ça aide à ce que la roue ne tombe pas alors que je descends de la roue) et je démarre pour faire une simple ligne droite. Aucun succès, pas moyen de faire quelques mètres sans devoir mettre pied à terre. Je ne désespère pas en réussissant à faire le pendule contre un mur mais je suis un peu déçu de ne pas pouvoir faire mieux.

Mercredi 10/08

Mercredi se décompose en 2 séances d'une heure chacune : matin, et après-midi. Le matin, aucune avancée. Des pendules, j'avance contre un mur à droite, j'avance (un peu) contre un mur à gauche mais insatisfait de ma progression. Je me motive à faire une nouvelle séance qui commence de la même manière. (Je traverse un peu mon garage en long mais incapable de me tenir droit) Je suis conscient que je dois aller vite et projeter mon regard, mais comment faire des dizaines de mètres si je n'arrive pas à tenir droit sur 2-3m ? Et en décidant de prendre une grande ligne droite et d'appuyer sur le champignon : j'arrive à me stabiliser pendant les 2-3 premiers mètres avant de continuer sur ma lancée. La solution à comprendre : C'est normal que je sois déséquilibré au début, c'est justement pour trouver ma stabilité ! Je m'amuse à faire 20… 30 et 50 mètres, je n'arrive pas à rouler droit, mais j'avance, et c'est ce qui compte.

Jeudi 11/08

Plein de confiance, je reprends là où je me suis arrêté. Je file plus ou moins droit mais je n'ai aucune difficulté à avancer. Je m'arrête après 20min à cause d'une douleur du pied droit, en sachant que je suis encore très crispé : ça ne m'étonnerait pas que ça soit à cause de mon manque de confiance. J'arrive à faire un virage parfait (pas saccadé), hâte de m'entraîner à faire de belles courbes.

Samedi 13/08

J'arrive à tourner à 90° ! J'ai quelques douleurs musculaires, je prend quelques pauses entre chaque séance pour éviter de conserver ces douleurs.

Samedi 20/08

Après la bonne pause d'une semaine, je profite d'une sortie en famille pour faire de la gyroroue en parc. J'ai roulé ~30min pour une distance d'environ 4km (!). J'arrivais à esquiver les groupes de personnes sans soucis et à atteindre une vitesse de 23km/h. Il me manque surement de la précision, mais je me sens vraiment en confiance.

J'ai bien pensé à enregistrer le trajet via l'application Euc World mais aucun moyen de le partager via le site officiel. Voici une capture d'écran prise le jour-même. Trajet

Equipement

J'envisage de me servir de la roue au quotidien. Et tout comme le vélo, je souhaite m'imposer un certain équipement. Casque intégral (moto, moto-cross ou VTT) et protection au dos seront mon minimum. J'envisage aussi de mettre des genouillères et des protections aux coudes.

Casque

J'ai beaucoup réfléchi à un casque intégral qui pourrait être confortable, pratique et sécurisant. Ma première suggestion était un casque de VTT/BMX qui recouvrirait le menton (pour protéger la machoire) mais je me suis finalement orienté vers un casque moto classique. Lien ici

casque1 casque2 casque3

N'ayant jamais été sur la moindre moto, je trouve ce casque un peu lourd mais j'imagine que c'est un poids correct pour un réel casque intégral. (1.6kg)

Assurance

Pour rouler sur route, je souhaite avoir une assurance pour protéger les gens et me protéger. Comme de nombreux Wheelers, je pense me tourner vers Wizza mes tarifs

En contactant la MAIF (avec laquelle je possède un contrat), j'ai remarqué qu'ils avaient également une offre pour les EDPMs, et donc les gyroroues. Le prix est d'environ 5€/mois.

· 4 min read
TheBidouilleur

I'm in the middle of learning Kubernetes and solutions to manage a cluster, I'm practicing on a test cluster that has small containers on it like the one running thebidouilleur.xyz.

Longhorn is a must-have in the Kubernetes universe (and in particular k3s), I couldn't continue learning without dwelling on Longhorn. But first things first.

What is Longhorn?

Longhorn is presented in this simple sentence:

Longhorn is a lightweight, reliable and easy-to-use distributed block storage system for Kubernetes.

But we can go a little further than this simple sentence... Longhorn is a centralized storage system between cluster nodes. This means that instead of using an external storage like an NFS (or other, here is the list of possibilities we will be able to keep the data internally by using the disks of our machines present in the cluster.

And if you ask yourself the same question as me before knowing : Longhorn will make the equivalent of a RAID 0 by replicating the data on several nodes to avoid that the loss of a machine leads to the loss of data.

Concrete values

For example, counting the disks of my nodes I have 4x32Gio and 1x16Gio, that is 144Gio ( or 132Go because Rancher uses this value ). Of these 132GB, I currently occupy 36, I can use 56 on Longhorn, and I have 40 reserved for replicas. (by default, Rancher generates 3 replicas)

Dashboard longhorn

Comment déployer Longhorn ?

How to deploy Longhorn ?

link to official documentation

You can deploy Longhorn using Helm, the Rancher catalog or just through Kubectl

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.3.0/deploy/longhorn.yaml

Version !

Be careful, this command will only deploy version 1.3.0 of longhorn, remember to get the last link in the documentation (or edit the link I put)

As a security measure, you should always check the contents in the applied yaml. Remember to take a look!

You'll have to wait until the pods deploy to start using Longhorn. To check the real time status, the documentation suggests the following command:

kubectl get pods \
--namespace longhorn-system \
--watch

But you can use k9s as well.

Once OK, we can deploy our first pod linked to longhorn.

Putting Longhorn into practice

Here is the manifest that we will deploy to use a volume in longhorn:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: longhorn-nginx-thebidouilleur-demo
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
name: longhorn-thebidouilleur-demo
namespace: default
spec:
containers:
- name: block-volume-test
image: nginx:stable-alpine
imagePullPolicy: IfNotPresent
volumeMounts:
- name: volume-longhorn
mountPath: "/usr/share/nginx/html"
ports:
- containerPort: 80
volumes:
- name: volume-longhorn
persistentVolumeClaim:
claimName: longhorn-nginx-thebidouilleur-demo

Volume OK

We ask for 1Gio to be allocated to this volume (it will influence the storage allocated for replicas) and we deploy a classic nginx. Once deployed, we will open a tunnel to this pod:

kubectl port-forward longhorn-thebidouilleur-demo 8080:80
tip

Knowing that the tunnel must open on your local machine (and not on one of the cluster nodes). I invite you to consult this page put kubectl on your machine.

and if we query the nginx, we obviously get a 403 error because the longhorn folder is empty. So we will create our index.html file directly from the pod.

kubectl exec longhorn-thebidouilleur-demo -i -t -- /bin/sh
echo "Hello World" > /usr/share/nginx/html/index.html

And by re-interrogating our pod: we find our Hello World.

[thebidouilleur@bertha ~]$ curl localhost:8080
Hello World

Now... it's very nice but do we keep our page in case of deletion of the pod?

kubectl delete pod longhorn-thebidouilleur-demo

We can see that on the longhorn dashboard: the volume has been switched to deattach. *(which means that the data are still present but not used on a pod)

We will re-apply the same manifest to recreate our pod and redo the same tunnel to access the nginx

[thebidouilleur@bertha ~]$ curl localhost:8080
Hello World

We have our "Hello World" page back!

Conclusion

Longhorn is an extremely easy to use tool that allows you to avoid creating an external solution to the cluster that would be less practical to manage. I didn't go very far in its features either and I let you make your own opinion for longhorn in production (and for that, go see the article of the site easyadmin.tech) Longhorn is welcome in my test Homelab and will be in the center of it !

· 4 min read
TheBidouilleur

Introduction

Mon premier cluster Kubernetes est actuellement en ligne. C'est encore un banc de test mais je l'ai pris prématurement en prod pour me forcer à l'administrer de manière sérieuse. Aujourd'hui (et en espérant que ça ait déjà évolué lorsque vous lirez l'article), mes pods utilisent un backend storage en NFS (accessible sur mon NAS).

Je veux que Kubernetes devienne mon manager de conteneur principal, je pense donc essentiel de découvrir les particularités générales de Kubernetes avant de commencer à y déployer des applications un peu plus complexes. Le stockage S3 est souvent référencé comme pratique et utile avec Kubernetes.

remarque

J'ai déjà utilisé Minio dans un autre contexte. Mais je ne compte pas utiliser Minio pour débuter S3, je veux une solution déjà prête et générique (apprendre la normalité avant de se spécialiser). Inutile de préciser qu'à l'avenir : Minio sera ma solution principale en Object Storage.

Je me suis donc orienté vers AWS Contabo qui propose une solution bien moins chère que notre amis américain. je paye 2,39€ mensuels pour 250Go à la place des 5,75€ demandés par Amazon.

Qu'est ce que le S3 ?

Pas besoin de faire une définition bancale, voici directement l'explication d'Amazon :

Amazon Simple Storage Service (Amazon S3) est un service de stockage d'objets qui offre une capacité de mise à l'échelle, une disponibilité des données, une sécurité et des performances de pointe. Les clients de toutes les tailles et de tous les secteurs peuvent stocker et protéger n'importe quelle quantité de données pour la quasi-totalité des cas d'utilisation, par exemple les lacs de données ainsi que les applications natives cloud et mobiles. Grâce à des classes de stockage économiques et à des fonctions de gestion faciles à utiliser, vous pouvez optimiser les coûts, organiser les données et configurer des contrôles d'accès affinés pour répondre à des exigences opérationnelles, organisationnelles et de conformité spécifiques.

Traduction : C'est une méthode performante et rapide de transférer des masses de données.

Et comment utiliser un stockage S3 ?

Il convient avant tout de rappeler une notion importante dans l'utilisation d'un Cloud : Un cloud n'est que l'ordinateur de quelqu'un d'autre

Si vous ne stockez pas chez vous : considerez que vos données peuvent être visionnées sans votre concentement. (Gouv, NSA, Mamie, Hacker etc...) Alors il convient de chiffrer vos données. Nous parlerons de Minio dans sur une autre page, une solution libre et open-source à héberger à la maison.

On peut dialoguer avec un serveur S3 via de nombreux outils :

Pour chiffrer mes données, je peux très bien passer par un simple script Bash chiffrant via GPG, puis envoyant les objets vers mon s3. Mais je n'apprécie pas cette solution bancale, et autant utiliser une solution all-in-one comme rclone ou restic. Et c'est effectivement avec restic que l'on va chiffrer et push les données.

Chiffrer puis envoyer ses objets

Comme dit précédemment : restic va être notre outil principal. Celui-ci fonctionne avec un système de "dépot"

Création du dépot restic

Restic permet de créer un dépot (qui peut être distant ou local), ce dépot chiffré sera le lieu où nous enverrons nos objets. Pour une première utilisation, on doit initialiser le dépot avec un restic init qui va créer la structure de fichier, et décider de la clé de chiffrement. Une fois le dépot créer, nous pourrons envoyer nos snapshots.

Restic autorise l'utilisation de variables d'environnement. On peut les définir avant d'utiliser restic.

export AWS_ACCESS_KEY_ID=ab5u8coxxpvjxwq4zu74jifmvfvxfu2y
export AWS_SECRET_ACCESS_KEY=3hs9sopqqto9sf8hhet8i92di987qcs6
bucketName="thebidouilleur" # variable séparée pour pouvoir la réutiliser ailleurs
export RESTIC_PASSWORD=Smudge9476 # Mot de passe de chiffrement
export RESTIC_REPOSITORY="s3:https://eu2.contabostorage.com/${bucketName}"

Ce ne sont pas mes vrais tokens, ne tentez pas d'utiliser les mêmes variables.

On peut enfin laisser restic créer notre dépot :

restic init

Si aucune erreur n'apparait ... félicitation ! On peut faire un restic backup pour créer notre première snapshot !

L'usage d'un S3 me permettra également de sauvegarder mes conteneurs utilisant des volumes sur Longhorn. Je pourrai ainsi sauvegarder mes données et les restaurer sur un autre cluster.

· 5 min read
TheBidouilleur

[ This article is from my old-blog, it will also be available in the "Documentation" section of the site ]

Introduction

Soon 7 years since my main infrastructure is on Proxmox. It's the hypervisor I trust most, which is also free and open-source. As soon as I have to deploy more than 2 virtual machines and can choose the environment: Proxmox will be my first choice. It offers a complete and efficient webui, without forgetting the advantage of command line tools. I don't rule out that someday, I may change my environment. And today, I have new needs in my hypervisor: Automate a complete deployment of my infrastructure, and since I will not reinstall each machine individually, I must start from a "base" that will serve as a template for the machine system to be pre-configured as I wish. And this famous template, I can make by hand.... or I can deploy it automatically with Packer!

What is Packer?

Packer is a tool developed by hashicorp (a company that provides open-source programs in the world of devops) allowing to deploy a template virtual machine automatically. In a practical case, Packer will connect to your public-cloud(aws, oracle, scaleway) / hypervisor(proxmox, qemu, esxi) to send instructions to install the virtual machine. (Like resources needed. RAM, CPU cores, type of bios)

How does Packer work?

Packer has few dependencies, it needs a public hypervisor/cloud, access to the "screen"* of the virtual machine, and ssh access for Packer to verify that the installation has completed (and also to launch a config management tool such as ansible).

*virtual machine screen will be used to send keystrokes.

A little vocabulary

The place where Packer deploys the VM is called Builder, in my case: It's Proxmox! And the term "provisioning" refers to the tool that will finish configuring the VM (Ex: Ansible).

Create our first template

Before we tackle a big fish like debian, we'll start with a simpler system to install: Alpine. The alpine installer will ask about ten questions, one by one. There is an answer file system that will automatically answer questions, but I could not run this file under alpine. (Only on Alpine, the answer file works on debian).

As I cannot use an answer file: we will answer questions manually (by sending keystrokes).

/!\ In the rest of this article, I will base myself on this deposit that is hosted on my gitea: packer-alpine-proxmox.

{
"description": "Build Alpine Linux 3 x86_64 Proxmox template",
"variables": {

"proxmox_url": "{{env `proxmox_url`}}",
"proxmox_username":"{{env `proxmox_user`}}",
"proxmox_password": "{{env `proxmox_password`}}",
"proxmox_host": "{{env `proxmox_node`}}",

"storage_name": "{{env `storage_name`}}",
"bridge": "{{env `bridge`}}",
"vm_id": "9001",
"vm_name": "alpine3-tf",
"template_description": "Alpine Linux 3.11 x86_64 template built with packer",
"vm_memory": "1024",

"ssh_username": "root",
"ssh_password": "{{env `ssh_password`}}"
},
"sensitive-variables": ["proxmox_password", "ssh_password" ],
"provisioners": [
{
"type": "ansible",
"playbook_file": "./playbook/provisioning.yml",
"ansible_env_vars": ["ANSIBLE_FORCE_COLOR=True" ]
}
],
"builders": [
{
"type": "proxmox",
"proxmox_url": "{{user `proxmox_url`}}",
"insecure_skip_tls_verify": true,
"username": "{{user `proxmox_username`}}",
"password": "{{user `proxmox_password`}}",
"vm_id": "{{user `vm_id`}}",
"vm_name": "{{user `vm_name`}}",
"template_description":"{{user `template_description`}}",
"memory": "{{user `vm_memory`}}",
"cores": "2",
"os": "l26",
"http_directory": "http",

"node": "{{user `proxmox_host`}}",
"network_adapters": [
{
"model": "virtio",
"bridge": "{{user `bridge`}}"
}
],
"disks": [
{
"type": "virtio",
"disk_size": "16G",
"storage_pool": "{{user `storage_name`}}",
"storage_pool_type": "directory",
"format": "qcow2"
}
],
"ssh_username": "{{user `ssh_username`}}",
"ssh_password": "{{user `ssh_password`}}",
"ssh_timeout": "15m",
"ssh_certificate_file": "/root/id_rsa",
"iso_file": "{{user `storage_name`}}:iso/alpine-virt-3.15.0-x86_64.iso",
"unmount_iso": true,
"boot_wait": "15s",
"boot_command": [
"<wait25>root<enter><wait4>",
"setup-alpine<enter><wait8>",
"<enter><wait4>",
"alpine-tf<enter><wait4><enter><wait4>",
"dhcp<enter>",
"<wait5>n<enter><wait5>",
"{{user `ssh_password`}}<enter><wait5>",
"{{user `ssh_password`}}<enter><wait>",
"<wait5>",
"Europe/Paris <enter><wait2><enter><wait5>",
"n<enter>",
"<wait1>1<enter><wait3>",
"<enter><wait2>",
"vda<enter>",
"lvm<enter>",
"sys<enter>",
"<wait2>",
"y<enter><wait35>",


"reboot <enter>",
"<wait65>",

"root<enter><wait8>",
"{{user `ssh_password`}}<enter><wait5> ",
"<wait10>",

"apk update && apk add curl<enter>",
"mkdir -p ~/.ssh<enter>",
"touch ~/.ssh/authorized_keys<enter><wait5>chmod 600 ~/.ssh/authorized_keys<enter><wait5>",
"curl http://{{ .HTTPIP }}:{{ .HTTPPort }}/authorized_keys >> ~/.ssh/authorized_keys<enter>",
"echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config <enter>",
"<wait2>service sshd restart <enter> <wait2>",
"curl http://{{ .HTTPIP }}:{{ .HTTPPort }}/repositories > /etc/apk/repositories<enter>",
"<wait>apk update <enter>",

"apk add python3<enter><wait1>",
"curl https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py<enter> <wait2>",
"python3 /tmp/get-pip.py <enter> <wait2>",

"apk add qemu-guest-agent<enter><wait3>",
"rc-update add qemu-guest-agent<enter>",
"service qemu-guest-agent start<enter>"

]
}
]
}

We'll quickly go through the structure of this Packer file:

  • the part "Variable" relates to static variables and/or environment variables (We'll see later)
  • Provision designates the command to be launched after the creation of the template
  • and what concerns the template itself (parameters, hypervisors...) is in the builder part

and the boot_command part in Builder is the list of all keyboard entries that Packer will type, It often places the download of Packer's Preseed to the VM.

small explanation about file transfer from packer to template: Packer, at start, will create a web server with the contents of the http/ folder, if you place files inside it, you can tell packer to type the following command to recover files. (Ex: Preseed, ssh keys etc.)

curl  http://{{ .HTTPIP }}:{{ .HTTPPort }}/fichier

So, in this Alpine installation, I will answer questions one by one, with pre-configured timers (which count in seconds). And at the end of the installation, we launch the playbook provisioning.yml which allows me to install the dependencies useful to my VMs. There is no need to go further in the playbook: it's still a template.

Why running packer through shell script?

If you went to my repository (linked above), you probably saw the file buid.sh.

#!/bin/bash
#export ssh_password=$(vault kv get -field root_password secrets/password)
export proxmox_password=$(vault kv get -field proxmox_password kv/wysux)
export proxmox_user=$(vault kv get -field proxmox_user kv/wysux)
export proxmox_node=$(vault kv get -field proxmox_node kv/wysux)
export proxmox_url=$(vault kv get -field proxmox_url kv/wysux)

export ssh_password="toto13"

export bridge="vmbr0"
export storage_name="local"

rm http/authorized_keys || true
for f in ssh/*.pub; do
name_of_key=$(echo $f | cut -d "/" -f2 )
echo -e "#$name_of_key" >> http/authorized_keys
key=$(cat $f)
echo -e "$key" >> http/authorized_keys
done
packer build alpine-3-amd64-proxmox.json

This file will provide some parameters to Packer such as variables containing passwords. I use Vault to retrieve sensitive information from a remote server. You can choose to not use Vault by placing passwords directly in clear text.

· 10 min read
TheBidouilleur

L'année dernière, j'ai dit que j'appréciais particulièrement Caddy qui était simple, pratique, rapide et efficace. Caddy permet, à partir d'une ligne aussi simple que :

domain.tld {
reverse_proxy 127.0.0.1:80
}

En plus de ça, Caddy va constamment vérifier l'expiration de vos certificats letsencrypt et de les renouveler automatiquement sans aucune interaction nécéssaire. Caddy est également facile à déployer via Docker.

Que demander de plus ?

De l'automatisation ?

Parfaitement, cher lecteur ! Vous m'étonnez toujours ! J'ai donc créé un Rôle Ansible générant ma configuration automatiquement à partir d'un dépôt Git avec les IP correspondant aux domaines que je souhaite utiliser. Maintenant, à partir de ça, je peux faire un script Bash récupérant les ports de mes conteneurs, puis push sur mon Git les nouvelles redire….

C'est une usine à gaz…

Et vous avez raison ! Ce système est obsolète en quelques secondes lorsqu'on utilise un système de service discovery permettant de récupérer mes services et automatiser l'ajout de ces services sur mon g…. Bon d'accord, toujours "usine à gaz" !

Pas le choix, je vais devoir en conséquence remplacer Caddy par quelque chose d'autre. Et justement : je sais exactement le soft à utiliser.

Place à Traefik, le RP (Reverse proxy) multi-provider avec du service discovery.

Cet article sur Traefik est en cours de rédaction, vous pouvez me suivre sur twitter pour être au courant des prochaines écritures ainsi que mon avancement dans mes projets !

Qu'est-ce que Traefik ?

logo de traefik

Comme expliqué juste au-dessus, Traefik est un reverse-proxy qui se démarque des autres par son systeme de provider et de middleware. Il ne réinvente pas la roue, mais il est particulièrement efficace lorsque l'on a un grand nombre de redirections à paramétrer ou que nous avons des règles qui changent régulièrement.

si vous ignorez ce qu'est un reverse-proxy, je vous invite à consulter cet article de Ionos

Traefik n'est pas fait pour vous si :

  • Vous n'utilisez pas Docker, Kubernetes ou Consul
  • Si vous avez peu de règles (et surtout si elles sont statiques)
  • Vous ne vous souciez pas d'automatiser votre RP

et en revanche : Traefik est fait pour vous si :

  • Vos services sont répartis sur de nombreuses machines
  • Vous avez un Swarm / Kubernetes

Traefik, ce n'est pas pour tout le monde. Mais il y a de nombreux cas, et de nombreux domaines où Traefik n'est pas employé alors qu'il le devrait.

Comment fonctionne Traefik ?

Traefik se base sur un système de Provider. Un Provider est un moyen de récupérer les fameuses règles "domaine -> IP" de manière automatique (ou presque). Par exemple, sur Caddy, notre provider (la manière dont on récupère notre configuration) est un simple fichier. Notre seule manière d'automatiser Caddy se repose donc sur notre gestion de ce fichier. (le Caddyfile)

Et c'est justement cet unique provider qui va me faire pencher vers Traefik, qui possède une grande liste de provider. Parmis ces providers, nous avons :

  • Docker
  • Kubernetes / Rancher
  • Redis
  • des Fichiers classiques
  • Une API Json

et en fonction des providers que l'on accorde à Traefik(et du contenu), celui-ci va s'adapter pour créer les redirections de manière automatique.

Nous allons tester ça directement dans notre premier Traefik de test ! On va avant-tout créer le réseau Docker qui permettra à notre reverse-proxy d'accéder aux conteneurs.

docker network create --driver=overlay traefik-net

et on va créer notre docker-compose contenant Traefik:

version: "3.7"

services:
traefik:
image: "traefik:v2.5"
container_name: "traefik"
hostname: "traefik"
networks:
- traefik-net
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./config:/etc/traefik"
networks:
traefik-net:
external: true
driver: overlay
name: traefik-net

Puis, dans un dossier ./config, nous allons créer le fichier traefik.yml qui va contenir notre configuration, et nos providers.

# fichier traefik.yml, à mettre dans un dossier ./config
---
log:
level: "INFO"
format: "common"

providers:
docker:
endpoint: "unix:///var/run/docker.sock" # Provider Docker sur la machine locale
exposedByDefault: false # Par défaut, les conteneurs ne possèdent pas de redirection
network: "traefik-net" # Le réseau docker dans lequel il y aura.
watch: true
file:
filename: "/etc/traefik/dynamic.yml" # Fichier contenant les règles statiques
watch: true # Va actualiser son contenu régulièrement pour mettre les règles à jour
providersThrottleDuration: 10 # Va actualiser les règles chaque 10s

api: # Va rendre le Dashboard de Traefik accessible en http
dashboard: true
debug: false
insecure: true

entryPoints: # Notre entrée, nous acceptons les requetes via https sur le port 80
insecure:
address: ":80"

Et notre fichier dynamic.yml qui contiendra nos règles statiques :

http:
routers:
helloworld-http:
rule: "Host(`hello-world.tld`)"
service: hello-world
entryPoints:
- insecure

services:
hello-world:
loadBalancer:
servers:
- url: "http://192.168.128.1:80"

En démarrant Traefik, on on remarque qu'il va se mettre à jour chaque 10s en interrogeant le daemon Docker ainsi que le fichier.

On peut maintenant créer notre premier conteneur à rajouter de cette manière:

version: "3.7"

services:
whoami:
image: "containous/whoami"
container_name: "whoami"
hostname: "whoami"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.entrypoints=insecure"
- "traefik.http.routers.whoami.rule=Host(`whoami-tf.thebidouilleur.xyz`)"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"

networks:
default:
external:
name: traefik_net

Nous avons alors créé la règle "whoami-tf.thebidouilleur.xyz" vers notre conteneur. On remarque que nous n'avons pas exposé de port, Traefik va passer par le réseau interne traefik_net pour accéder au service. C'est une couche de sécurité à ne pas négliger, vos services seront accessibles entre eux, et via le reverse-proxy.

Gestion des certificats https

Maintenant, si vous passez par internet pour accéder à vos services.. C'est peut-être pratique d'avoir du https, et justement : Traefik gèrera vos certificats de manière automatique. Traefik utilise l'api gratuite de LetsEncrypt pour obtenir ses certificats, nous devons donc créer une entrée dédiée au https sur le port 443

On va donc mettre à jour notre configuration comme ceci :

entryPoints:
insecure:
address: ":80"
http:
redirections:
entryPoint:
to: secure
secure:
address: ":443"

certificatesResolvers:
letsencrypt:
acme:
email: "contact@thoughtless.eu"
storage: "/etc/traefik/acme.json"
# caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
keyType: "EC256"
httpChallenge:
entryPoint: "insecure"

Redémarrez Traefik, et celui-ci tentera de générer les certificats pour les domaines configurés ! En accédant à la page suivante : http://traefik:8080 ,vous aurez un dashboard sur lequel vous verrez les routeurs "domaines d'entrés", les "services" (redirections), et si ce symbole apparait : Traefik a bien appliqué un certificat à ce router.

Il est également possible, avec un peu plus de configuration, d'obtenir un certificat Wildcard (certificat valide pour un domaine entier) avec Traefik. Pour le moment : je n'ai pas besoin d'un wildcard pour mes domaines. Si le sujet vous intéresse, voici un lien pour approfondir ça : Certificat Wildcard Traefik

Et si on allait plus loin ?

Traefik et Swarm

Depuis maintenant un peu plus d'un an, mes conteneurs tournent sur un cluster swarm (Si vous ne savez pas ce qu'est un Swarm, je vous renvoie vers cet article), et ça peut complexifier les choses lorsque les labels (permettant à traefik de comprendre quel docker correspond à quel domaine) fonctionnent un peu différemment.

Les labels classiquent ne fonctionnent que sur la machine hote (par exemple: Worker01) mais si Traefik est sur la machine Worker02, les labels des conteneurs ne seront pas visibles. Pour palier à ce problème, nous devons utiliser les mêmes labels … dans la section deploy d'un docker-compose.

Voici le docker-compose whoami adapté pour Swarm:

version: "3.7"

services:
whoami:
image: "containous/whoami"
container_name: "whoami"
hostname: "whoami"
deploy:
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.entrypoints=insecure"
- "traefik.http.routers.whoami.rule=Host(`whoami-tf.thebidouilleur.xyz`)"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"

networks:
default:
external:
name: traefik_net

danger

à noter que cette structure ne fonctionne qu'avec les docker-compose de version >3.7

Et pour que le conteneur traefik puisse lire ces labels.. Il doit être sûr un manager du swarm. Nous devons donc également mettre à jour notre docker-compose de Traefik :

version: "3.7"

services:
traefik:
image: "traefik:v2.5"
container_name: "traefik"
hostname: "traefik"
networks:
- traefik-net
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./config:/etc/traefik"
deploy:
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=secure"
- "traefik.http.routers.traefik.rule=Host(`traefik.forky.ovh`)"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"


networks:
traefik-net:
external: true
driver: overlay
name: traefik-net

et nous pouvons le déployer dans le swarm avec la commande

docker stack deploy -c docker-compose.yml traefik

Autre spécificité du Swarm : Si le port d'écoute du service n'est pas 80, il faudra préciser à Traefik le port à utiliser. C'est ce qu'on peut voir sur le docker-compose ci-dessus avec traefik.http.services.traefik.loadbalancer.server.port, ça sera la dernière différence entre Traefik sur une machine standalone et un cluster.

Maintenant, comment faire si nous voulons créer une règle automatique avec une machine qui n'est pas dans notre swarm ?

Astuce pour machines isolées du cluster

Jusque-là, nous avons 2 providers : le provider Docker (pour le cluster) et le provider file qui concerne les règles statiques (comme mon pfsense). Traefik n'accepte pas qu'on ait 2 providers du même type, ce qui veut dire que je ne peux pas surveiller le daemon docker de ma machine, ainsi que celui d'une machine distante.

Par exemple, mon Gitea est un conteneur qui n'est pas dans mon swarm, et comme c'est une machine que je redeploie régulièrement (et donc IP différente), j'aimerai beaucoup laisser traefik faire son travail, mais en le laissant en même temps s'occuper du swarm !

C'est là que j'ai découvert un projet Github répondant à ce besoin : Traefik-pop

Le schéma ASCII du dépôt parle de lui-même :

                        +---------------------+          +---------------------+
| | | |
+---------+ :443 | +---------+ | :3000| +------------+ |
| WAN |--------------->| traefik |--------------------->| gitea | |
+---------+ | +---------+ | | +------------+ |
| | | | |
| +---------+ | | +-------------+ |
| | redis |<---------------------| traefik-kop | |
| +---------+ | | +-------------+ |
| swarm | | gitea |
+---------------------+ +---------------------+

J'ai un peu modifié le dessin pour qu'il colle à mon exemple.

Si le dessin est un peu compliqué : Nous allons créer une base de donnée Redis (C'est plus facile pour moi de le mettre sur le swamr, mais théoriquement, vous pouvez la mettre où vous voulez). Cette bdd, sera utilisée en tant que provider Traefik pour mettre à jour les règles automatiquements ! Le docker-compose de mon gitea devient donc :

version: "3"
networks:
gitea:
external: false
services:
server:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GIT_DISCOVERY_ACROSS_FILESYSTEM=1
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2200:22"
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.entrypoints=secure"
- "traefik.http.routers.gitea.rule=Host(`git.thoughtless.eu`)"
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"

En redémarrant Traefik, et en accédant au panel, on remarque un nouvel provider : Redis.

et en visualisant les règles : nous avons bien notre règle concernant Gitea !

Conclusion

Traefik est un des meilleurs reverses-proxy pour les infrastructures grandissantes. Celui-ci s'adapte à de nombreux besoins en proposant une couche d'automatisation sans négliger la gestion statique et manuelle. Celui-ci demande un temps d'adaptation qui sera vite rentabilisé.

J'espère que ce reverse-proxy vous inspirera pour une infrastructure scalable simple et fiable.

Merci de m'avoir lu !

· 8 min read
TheBidouilleur

[ Cet article provient de mon ancien-blog, celui-ci sera également disponible dans la partie "Documentation" du site ]

Introduction

Depuis que jai commencé l'informatique (depuis un peu moins d'une dizaine d'année), je ne me suis jamais préoccupé de comment je visualisais mes logs. Un petit view par ci, un gros grep par là.. mais aucune gestion avancée.

J'ai basé ma supervision sur Zabbix et Grafana qui m'affichent les metriques de chaque machine virtuelle individuellement. Et même si c'est bien pratique, je n'ai presque aucun visuel sur l'état de mes applications ! J'ai donc décidé de me renseigner sur Graylog et Elastic Search proposant une stack assez fiable et facile à mettre en place. Puis en voyant les ressources demandées, j'ai remis ce besoin à "plus tard", et j'ai remis "plus tard" à l'année prochaine.. Et ainsi de suite !

2 ans plus tard…

Aujourd'hui (Decembre 2021), une grosse faille 0day est dévoilée concernant Log4J, et on ne parle pas d'une "petite" faille, c'est une bonne grosse RCE comme on les aime !

Je ne suis pas concerné par Log4J, ce n'est pas utilisé dans Jenkins, et je n'ai aucune autre application basée sur Java ouverte sur internet. Mais j'aurai bien aimé savoir si mon serveur a été scanné par les mêmes IP que l'on retrouve sur les listes à bannir. Et c'est avec cet évenement que j'ai décidé de me renseigner sur "Comment centraliser et visualiser ses logs?".

Le choix de la stack

une stack est un groupement de logiciel permettant de répondre à une fonction. Un exemple classique est celui de la stack "G.I.T." (et non pas comme l'outil de versioning!) :

  • Grafana
  • Influxdb
  • Telegraf

C'est une stack qui permet de visualiser les mectriques de différentes machines, InfluxDB est la base de donnée stockant les informations, Telegraf est l'agent qui permet aux machines d'envoyer les métriques, et Grafana est le service web permettant de les visualiser.

Comme dit dans l'introduction, j'utilise Zabbix qui me permet de monitorer et collecter les metriques, et j'y ai couplé Grafana pour les afficher avec beaucoup de paramètrages.

Dans la centralisation de logs (et la visualisation), on parle souvent de la stack suivant:

**ELK**:

  • ElasticSearch
  • Logstash
  • Kibana

Mais cette stack n'est pas à déployer dans n'importe quel environnement, il est efficace, mais très lourd.

Dans ma quête pour trouver une stack permettant la centralisation de logs, j'apprécierai utiliser des services que je dispose déjà.
Et voici le miracle à la mode de 2021 ! La stack GLP : Grafana, Loki, Promtail.

Stack GLP

Là où j'apprécie particulièrement cette stack, c'est qu'il est léger. Beaucoup plus léger que ELK qui, même si très efficace, demande beaucoup.

Extrait doc ELK

De même que Graylog2 + Elastic Search (une très bonne alternative) qui demande presque un serveur baremetal low-cost à lui seul. Extrait doc graylog

Alors que Grafana / Loki ne demanderont que 2Go pour fonctionner efficacement et sans contraintes. (Grand maximum, à mon échelle : j'utiliserai beaucoup moins que 2Go)

Installer notre stack

Je pars du principe que tout le monde sait installer un Grafana, c'est souvent vers ce service que les gens commencent l'auto-hebergement (en même temps, les graphiques de grafana sont super sexy !).

Mais si vous n'avez pas encore installé votre Grafana (dans ce cas, quittez la salle et revenez plus tard), voici un lien qui vous permettra de le faire assez rapidement

Par simplicité, je ne vais pas utiliser Docker dans cette installation.

Partie Loki

J'ai installé Loki sur un conteneur LXC en suivant le guide sur le site officiel ici. Je passe par systemd pour lancer l'executable, et je créé à l'avance un fichier avec le minimum syndical (qui est disponible sur le github de Grafana)

auth_enabled: false

server:
http_listen_port: 3100
grpc_listen_port: 9096

common:
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory

schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h

Je n'ai pas pris la peine d'activer l'authentification en sachant que je suis dans un LAN avec uniquement mes machines virtuelles. Je considère pas que mon Loki comme un point sensible de mon infra.

Après seulement 2-3 minutes de configuration, notre Loki est déjà disponible !

On peut dès maintenant l'ajouter en tant que datasource sur notre Grafana : Configuration de Loki sur Grafana

Contexte
  • J'utilise localhost car la machine possédant le grafana héberge également le Loki.*
  • Il se peut que Grafana rale un peu car notre base de donnée Loki est vide.

Partie Promtail

Promtail est l'agent qui va nous permettre d'envoyer nos logs à Loki, j'ai écris un role Ansible assez simple me permettant d'installer notre agent sur de nombreuses machines en surveillant les logs provenant de Docker, varlog et syslog.

Voici ma template Jinja2 à propos de ma configuration :

server:
http_listen_port: 9080
grpc_listen_port: 0

positions:
filename: /tmp/positions.yaml

clients:
{% if loki_url is defined %}
- url: {{ loki_url }}
{% endif %}


scrape_configs:


- job_name: authlog
static_configs:
- targets:
- localhost
labels:
{% if ansible_hostname is defined %}
host: {{ ansible_hostname }}
{% endif %}
job: authlog
__path__: /var/log/auth.log


- job_name: syslog
static_configs:
- targets:
- localhost
labels:
{% if ansible_hostname is defined %}
host: {{ ansible_hostname }}
{% endif %}
job: syslog
__path__: /var/log/syslog

- job_name: Containers
static_configs:
- targets:
- localhost
labels:
{% if ansible_hostname is defined %}
host: {{ ansible_hostname }}
{% endif %}
job: containerslogs
__path__: /var/lib/docker/containers/*/*-json.log

- job_name: DaemonLog
static_configs:
- targets:
- localhost
labels:
{% if ansible_hostname is defined %}
host: {{ ansible_hostname }}
{% endif %}
job: daemon
__path__: /var/log/daemon.log

Si vous n'êtes pas à l'aise avec des templates Jinja2, vous trouverez une version "pure" de la config ici

Vous pouvez bien evidemment adapter cette template à vos besoins. Mon idée première est d'avoir une "base" que je peux mettre sur chaque machine (en sachant aussi que si aucun log n'est disponible, comme pour Docker, Promtail ne causera pas une erreur en ne trouvant pas les fichiers)

Une fois Promtail configuré, on peut le démarrer : via l'executable directement :

/opt/promtail/promtail -config.file /opt/promtail/promtail-local-config.yaml

ou via systemd (automatique si vous passez par mon playbook) :
systemctl start promtail

Une fois cet agent un peu partout, on va directement aller s'amuser sur Grafana !

Faire des requetes à Loki depuis Grafana

On va faire quelque chose d'assez contre-intuitif : nous n'allons pas commencer par faire un Dashboard : on va d'abord tester nos requetes ! Scrollez pas, je vous jure que c'est la partie la plus fun !

Sur Grafana, nous avons un onglet "Explore". Celui-ci va nous donner accès à Loki en écrivant des requetes, celles-ci sont assez simple, et surtout en utilisant l'outil "click-o-drome" en dépliant le Log Browser Metric browser Pardon j'ai un chouïa avancé sans vous...

Avec la template que je vous ai donné, vous aurez 4 jobs :

  • daemon
  • authlog
  • syslog
  • containersjobs

Ces jobs permettent de trier les logs, on va tester ça ensemble. Nous allons donc selectionner la machine "Ansible", puis demander le job "authlog". Je commence par cliquer sur Ansible, puis Authlog. Grafana me proposera exactement si je souhaite choisir un fichier spécifique. Si on ne précise pas de fichier(filename) Grafana prendra tous les fichiers (donc aucune importance si nous n'avons qu'un seul fichier)

vous remarquerez plus tard que dès notre 1ere selection, grafana va cacher les jobs/hôte/fichier qui ne concernent pas notre début de requete.

Selections de paramètres

En validant notre requete (*bouton show logs*)

Visualisation des logs de la machine 'Ansible'

Nous avons donc le résultat de la requete vers Loki dans le lapse de temps configuré dans Grafana (1h pour moi). Mon authlog n'est pas très interessant, et mon syslog est pollué par beaucoup de message pas très pertinents.

Nous allons donc commencer à trier nos logs !

En cliquant sur le petit "?" au dessus de notre requete, nous avons une "cheatsheet" résumant les fonctions basiques de Loki. Nous découvrons comment faire une recherche exacte avec |=, comment ignorer les lignes avec != et comment utiliser une expression regulière avec |~

Je vous partage également une cheatsheet un peu plus complète que j'ai trouvé sur un blog : ici

Ainsi, on peut directement obtenir des logs un peu plus colorés qui nous permettrons de cibler l'essentiel !

Log de la machine 'Drone-Runner'

(L'idée est de cibler les logs sympas avec les couleurs qui vont avec)

Conclusion

Si on entend souvent parler de la suite ELK, ça n'est pas non-plus une raison pour s'en servir à tout prix ! Loki est une bonne alternative proposant des fonctionnalitées basiques qui suffiront pour la plupart.

danger

Ce projet est obsolète, il peut être risqué de s'en servir dans un environnement sensible.

· 3 min read
TheBidouilleur

[ This article is from my old-blog, it will also be available in the "Documentation" section of the site ]

Changelog (Jan 2022) - Today I replaced Caddy with Traefik, to be seen in a future article.

In my short life as a computer scientist, I've always had only one public IP. The one on my OVH server where you are currently viewing the site. And knowing that I have many web services, it was quickly necessary for me to look for different solutions to install an efficient Reverse Proxy that would be used to redirect my users to the desired application according to the domain.

In my long quest (which is certainly not complete), I had the opportunity to test many solutions like Haproxy, Apache2, Nginx and now.. Caddy

Haproxy has been for me the easiest and most convenient to start, good documentation, incorporates many tools to check configuration, or add authentications. I was satisfied for a few years.

(I don't count on Apache2, which was handy to get started without installing a service dedicated to my need for redirection)

Then I used aaPanel (which you will find an article on this site) allowing me to have a whole web panel for my sites and my redirects! I gave up knowing that it was a well-crafted system in which I had little freedom in terms of editing config

Then my unnecessary need for a web interface led me to NPM (Nginx Proxy Manager) for more information here. Which was very convenient for me knowing that it was in the form of a Docker container, and offering an interface managing the creation of redirection as well as the SSL, still at let's encrypt. But every time the certificate expired, NPM required me to manually select one-by-one each certificate to be updated: and that was unthinkable when you knew how many domains i had created.

Today, my attention is focused on Caddy which, for the moment, corresponds exactly to what I want, and with incredible simplicity.

Caddy

Caddy is, as you will have understood, a fairly versatile reverse proxy and very used in some Docker containers! It automatically generates your certificates (and configures redirects automatically) without any problems with Let's Encrypt. Caddy is quite lightweight and will avoid slow configurations, here is a dumb example:

thoughtless.eu {
reverse_proxy 192.168.5.125:8062
log {
output file /var/log/caddy/thoughtless.eu_access.log
}
}

This line will create a reverse-proxy redirection with the default configuration:

  • Caddy updatera / will generate certificates whenever necessary
  • It will automatically redirect requests to http:// to https://
  • It will write access logs in a file

In Apache2 / Haproxy, it would have taken a lot of lines.

But let's wait and see, Caddy is still very new for me, and I'm sure my next need will point me towards another solution such as Traefik for example!

Good luck in your long quest around reverse proxies

· 6 min read
TheBidouilleur

[ This article is from my old-blog, it will also be available in the "Documentation" section of the site ]

Introduction

The world of containerization has brought many things into system administration, and has updated the concept of DevOps. But one of the main things that containers (and especially Docker) bring us is automation.

And although Docker is already complete with service deployment, we can go a little further by automating container management! And to answer that: Docker Inc. offers a tool suitable for automatic instance orchestration: Docker Swarm.

What is Docker Swarm?

As previously stated: Docker Swarm is an orchestration tool. With this tool, we can automatically manage our containers with rules favoring High-availability, and Scalability of your services. We can therefore imagine two scenarios that are entirely compatible:

  • Your site has a peak load and requires several containers: Docker Swarm manages replication and load balancing
  • A machine hosting your Dockers is down: Docker Swarm replicates your containers on other machines.

So we'll see how to configure that, and take a little look at the state of play of the features on offer.

Create Swarm Cluster

For testing, I will use PWD (Play With Docker) to avoid mounting this on my infra:)

So I have 4 machines under Alpine on which I will start a Swarm cluster. 4 terminals, one per node

The first step is to define a Manager, this will be the head of the cluster, as well as the access points to the different machines. In our case, we will make it very simple, the manager will be Node1.

To start the Swarm on the manager, simply use the 'docker swarm init' command. But, if your system has a network card count greater than 1 (Fairly easy on a server), you must give the listening IP. In my case, the LAN interface IP (where VMs communicate) is 192.168.0.8. So the command I'm going to run is

docker swarm init èèadvertise-addr 192.168.0.8

Docker says:

Swarm initialized: current node (cdbgbq3q4jp1e6espusj48qm3) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join —token SWMTKN-1-5od5zuquln0kgkxpjybvcd45pctp4cp0l12srhdqe178ly8s2m-046hmuczuim8oddmk08gjd1fp 192.168.0.8:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.`

In summary: The cluster is well started, and it gives us the exact command to join the cluster from other machines! Since Node1 is the manager, I just need to run the docker swarm join command on Node2-4.

docker swarm join --token SWMTKN-1-5od5zuquln0kgkxpjybvcd45pctp4cp0l12srhdqe178ly8s2m-046hmuczuim8oddmk08gjd1fp 192.168.0.8:2377

Once completed, you can view the result on the manager with the command 'docker node ls' All node in terminal

Deploy a simple service

If you are a docker run user and you refuse docker-compose, you should know one thing: i don't like you. As you are nice to me, here is a piece of information that won't help: the equivalent of 'docker run' in Swarm is 'docker service'. But we're not going to get into that in this article.

Instead, we will use the docker-composed equivalent, which is the docker stack. So first of all, here's the .yml file

version: "3"
services:
viz:
image: dockersamples/visualizer
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
ports:
- "8080:8080"
deploy:
replicas: 1
placement:
constraints:
- node.role == manager

Before you start it, you'll probably notice the deploy part that lets you give directions to Swarm. So we can add constraints to deploy this on the manager(s), ask the host to limit the use of resources, or manage replicas for load balancing.

This first container will be used to have a simple dashboard to see where the Dashboards are positioned, and avoid going to CLI only for this function.

We will deploy this compose with the following command:

docker stack deploy —compose-file docker-compose.yml swarm-visualize

Once the command is complete, you simply open the manager's web server at port 8080. WEBUI Swarm

So we now have a web panel to track container updates.

Simplified management of replicas

When you access a container, you must go through the manager. But there is nothing to prevent being redirected to the 3-4 node via the manager. This is why it is possible to distribute the load balancing with a system similar to HAProxy, i.e. by redirecting users to a different container each time a page is loaded.

Here is a docker-compose automatically creating replicas:

version: '3.3'
services:
hello-world:
container_name: web-test
ports:
- '80:8000'
image: crccheck/hello-world
deploy:
replicas: 4

And the result is surprising: Scaling hello-world with 4

We can also adjust the number of replica. By decreasing it:

docker service scale hello-world_hello-world=2

Scaling hello-world with 2

Or by increasing it:

docker service scale hello-world_hello-world=20

Scaling hello-world with 20

What about High Availability?

I focused this article on the functions of Swarm, and how to use them. And if I did not address this item first, it is because every container created in this post is managed in HA! For example, I will forcibly stop the 10th replica of the "Hello world" container, which is on Node1. And this one will be directly revived, Kill hello-world

Okay, But docker could already automatically restart containers in case of problem, how is swarm different?

And to answer that, I'm going to stop the node4 Kill Node4

It is noted that the other nodes distribute automatically (and without any intervention) the stopped containers. And since we only access services through managers, they will only redirect to the containers that are started. One of the servers can therefore catch fire, the service will always be redundant, balanced, and accessible.

Conclusion

Docker-Swarm is a gateway to application clusters that are incredibly complex without a suitable tool. Swarm is easy to meet special needs without any technical expertise. In a production environment, it is advisable to switch to Kubernetes or Nomad which are much more complete and powerful alternatives.

I encourage you to try this kind of technology that will govern our world of tomorrow!

Thanks for reading