Skip to main content

· 6 min read
TheBidouilleur

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

Introduction

Bientot 7 ans que mon infra principale est sous Proxmox. C'est l'hyperviseur dans lequel j'ai le plus confiance, et qui est également gratuit. Dès que je dois déployer plus de 2 machines virtuelles et qu eje peux choisir l'environnement : Proxmox sera mon premier choix. Il propose une webui complète et efficace, sans oublier l'avantage des outils en cli. Je n'exclue pas qu'un jour, je puisse changer d'environnement. Et aujourd'hui, j'ai de nouveaux besoins dans mon hyperviseur : Automatiser un déploiement complet de mon infrastructure, et comme je vais pas réinstaller chaque machine individuellement, je dois partir d'une "base" qui servira de template pour que le système des machines soit pré-configuré comme je le souhaite. Et cette fameuse template, je peux la faire à la main.... ou je peux la déployer automatiquement via Packer !

Qu'est ce que Packer?

Packer est un outil développé par hashicorp (une entreprise qui fourni des programmes open-sources dans l'univers du devops) promettant de déployer une machine virtuelle de template de manière automatique.

Dans un cas pratique, Packer va se connecter à votre cloud-publique(aws, oracle, scaleway) / hyperviseur(proxmox, qemu, esxi) pour envoyer les instructions permettant d'installer la machine virtuelle

Dans mon cas, je me suis amusé à déployer des templates Alpine et debian sous Qemu et Proxmox.

Comment fonctionne Packer ?

Packer possède peu de dépendances, il a besoin d'un hyperviseur/cloud publique, d'un accès à "l'écran" de la machine virtuelle, et d'un accès ssh pour que Packer vérifie que l'installation s'est bien terminée (et également pour lancer un outil de gestion de config comme ansible.

Un peu de vocabulaire#

On appelle Builder l'endroit o√Ļ Packer d√©ploie la VM, dans mon cas : c'est Proxmox ! Et le terme provisionner d√©signe l'outil qui va finir la configuration de la VM apr√®s Packer (Ex: Ansible).

Créer notre première template

Avant de s'attaquer à un gros poisson comme debian, on va commencer par un système plus simple à installer : Alpine. L'installateur de Alpine va poser une dizaine de questions, une à une. Il existe un système de fichier-réponse qui va répondre automatiquement aux questions mais je n'ai pas réussi à executer ce fichier sous alpine. (Uniquement sous Alpine, le fichier réponse fonctionne sous debian).

Si le sujet vous interesse, je vous renvoie vers ce lien: Wiki Alpine Answer-file.

Comme je ne peux pas utiliser de fichier réponse : nous allons répondre aux questions manuellement.

Retrouvez le code source

Dans la suite de cet article, je vais présenter le fonction de ce dépot : packer-alpine-proxmox.

Voici mon fichier Packer répondant aux questions:

{    "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>"

            ]        }    ]}

Nous allons rapidement décortiquer la structure de ce Packer :

  • la partie "Variable" concerne les variables statiques et/ou variables d'environnements (On va voir √ßa un peu plus tard)
  • Provisionner designe la commande que l'on va lancer apr√®s la cr√©ation de la template
  • et ce qui concerne la template elle-m√™me (param√®tres, hyperviseurs...) est dans la partie builder

et la partie boot_command dans Builder est la liste de toutes les entrées au clavier que Packer va taper, On y place souvent le téléchargement du Preseed de Packer vers la VM.

petite explication sur le transfert de fichier de packer vers la template : Packer, à son lancement, va créer un serveur web avec le contenu du dossier http/, si on y place des fichiers à l'interieur, on peut dire à packer de taper la commande suivante pour récupérer des fichiers. (Ex: Preseed, clés ssh etc..)

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

Ainsi, dans cette installation d'Alpine, je vais répondre une à une aux questions, avec des timer pré-configurés (qui se comptent en seconde). Et à la fin de l'installation, nous lançons le playbook provisionning qui me permet d'installer les dépendances utiles à mes VMs. Il n'est pas necessaire d'aller très loin dans le playbook : ça reste une template.

Build.sh, Vault, et la création de authorized_keys#

Si vous êtes allé voir mon dépot (dont le lien est plus haut), vous avez surement vu le fichier 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 || truefor 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_keysdone
packer build alpine-3-amd64-proxmox.json

ce fichier va donner les paramètres essentiels à Packer. Les premières variables sont les identifiants pour se connecter à proxmox

si vous n'utilisez pas vault, n'hésitez pas à remplacer les commandes le concernant par le contenu des variables.

· 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 || truefor 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_keysdonepacker 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.

· 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 un 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 du stack

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

  • Grafana
  • Influxdb
  • Telegraf

C'est un 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 du stack suivant:

ELK:

  • ElasticSearch
  • Logstash
  • Kibana

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

Dans ma quête pour trouver un 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 ! Le Stack GLP : Grafana, Loki, Promtail.

Stack GLP#

L√† o√Ļ j'appr√©cie particuli√®rement ce stack, c'est qu'il est l√©ger. Beaucoup plus l√©ger que ELK qui, m√™me si tr√®s efficace, demande beaucoup.

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

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 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 : !()[https://i.imgur.com/G3tWx1r.png]

(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

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)

En validant notre requete (bouton show logs)

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 !

(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.

· 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:8062log {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

· 5 min read
TheBidouilleur

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

Docker Swarm

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.

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:2377To 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'

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.

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:

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

docker service scale hello-world_hello-world=2

Or by increasing it:

docker service scale hello-world_hello-world=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,

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

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