Aller au contenu principal

Construction d'une Machine de Rebonds

Mon homelab devops

Dans le cadre de mon projet Homelab DevOps, j'ai débuté le projet par la construction d'une machine de rebonds sous Debian, qui servira à la fois de poste de développement et de contrôleur pour Ansible et Terraform. Ce poste qui occupe donc une place centrale, me permet de gérer efficacement mon infrastructure as code (IaC) et de développer dans un environnement uniforme et contrôlé. L'objectif est de créer un système où la configuration, le déploiement, et la gestion de l'infrastructure sont automatisés et réplicables, réduisant ainsi les risques d'erreurs manuelles et augmentant la productivité.

Dans ce guide, je vais détailler les étapes de configuration de cette machine de rebonds, en partageant mes choix, mes configurations, et les scripts d'automatisation que j'ai utilisés. L'idée est de fournir un guide pratique pour ceux qui souhaitent mettre en place un système similaire, en mettant en avant les avantages d'une telle configuration pour un projet d'Homelab DevOps.

Choix de la Configuration Matérielle et de la Distribution Linux

Pour ce projet, j'ai opté pour un mini PC équipé d'un processeur Intel N95 à 4 cœurs, accompagné de 8 Go de RAM. Ce choix s'est avéré judicieux pour plusieurs raisons. Tout d'abord, la compacité du mini PC permet une intégration discrète dans mon espace de travail, tout en offrant suffisamment de puissance pour gérer les tâches de développement et d'automatisation sans encombre. Les 4 cœurs du processeur les 8Go de RAM garantissent une exécution fluide des run de configuration avec Ansible. La machine est équipée d'un SSD de 256 Go dédié au système d'exploitation. L'utilisation de LVM (Logical Volume Manager) sur le disque système offre une flexibilité appréciable pour gérer les partitions et optimiser l'utilisation de l'espace disque selon les besoins. Cela permet notamment de redimensionner les volumes à la volée ou d'en ajouter de nouveaux sans interruption de service, une fonctionnalité précieuse pour un système en constante évolution.

En ce qui concerne la distribution Linux, j'ai préféré opter pour une Debian. Ce choix repose sur plusieurs critères. Debian est reconnue pour sa stabilité et sa sécurité, des atouts indispensables pour un système qui se veut à la fois fiable et performant. Sa large communauté d'utilisateurs et de développeurs assure un support étendu et une documentation riche, facilitant la résolution de problèmes et l'implémentation de nouvelles fonctionnalités.

Lors de l'installation, j'ai attribué une IP fixe à la machine sur la première interface réseau. Cette configuration statique simplifie l'accès à la machine, tant pour la gestion à distance que pour l'exposition de services, en garantissant que l'adresse ne change pas au redémarrage ou en cas de coupure de courant. Cela facilite également la configuration des règles de pare-feu et la mise d'un VPN pour un accès sécurisé.

Pour une gestion sécurisée, j'ai créé un utilisateur administrateur spécifique (bob). Cet utilisateur dispose des droits nécessaires pour effectuer des tâches d'administration système sans recourir à l'utilisation directe de l'utilisateur root, renforçant ainsi la sécurité de la machine. Enfin, l'installation d'OpenSSH a été choisie dans les tâches de sélection pour permettre l'accès à distance.

Première Connexion et Installation d'Ansible

Après avoir installé le système d'exploitation, ainsi qu'automatisé l'étape suivante consistait à installer Ansible. Ansible joue un rôle crucial dans l'automatisation et la gestion de configurations au sein de mon projet Homelab DevOps, permettant de déployer et de gérer l'infrastructure de manière efficace et reproductible. Pour cette installation, j'ai opté pour la dernière version disponible à ce moment, soit la version 9.2 ce qui correspond à la version 2.16.2 d'ansible-core. Pour me connecter, j'ai utilisé le mot de passe défini lors de l'installation.

Installation d'Ansible via pip

pip est le gestionnaire de paquets pour Python permettant d'installer et de gérer des bibliothèques et des outils supplémentaires. L'utilisation de pip pour installer Ansible permet une flexibilité maximale, notamment en termes de versionnage et de gestion des dépendances. Voici les étapes suivies lors de la première connexion à la machine pour installer Ansible :

  1. Désactivation de la protection des packages systèmes python : Debian a pour éviter les compromissions des packages systèmes mis en place une protection qu'il faut temporairement désactivé :

    su - # Entrez le mdp root défini lors de l'installation
    apt update && apt install git python3-pip curl
    export PIP_BREAK_SYSTEM_PACKAGES=1
  2. Mise à jour de pip : Avant d'installer Ansible, il est recommandé de mettre à jour pip lui-même pour s'assurer de l'utilisation de la dernière version. Ceci peut être accompli avec la commande suivante :

    pip install --upgrade pip
  3. Installation d'Ansible : Avec pip à jour, l'installation d'Ansible est directe. La commande suivante installe Ansible dans l'espace utilisateur, une pratique recommandée pour éviter les conflits avec les versions des paquets systèmes :

    pip install --user ansible==9.2 --user

    Pour finir, il faut ajouter le répertoire $HOME/.local/bin au PATH de l'utilisateur :

    echo 'export PATH=${HOME}/.local/bin:${PATH}' >> ~/.bashrc

    Fermer la session.

Automatisation de la Configuration avec un Playbook Ansible

Suite à l'installation d'Ansible, l'étape suivante a été de développer un playbook Ansible pour automatiser la configuration et l'installation de tous les outils nécessaires à mon projet Homelab DevOps. Grâce à Ansible, j'ai pu créer un processus reproductible et efficace, assurant une configuration uniforme de l'environnement à chaque déploiement. J'ai créé un fichier de configuration déposé dans un dossier où se trouvera tout le code pour monter ce homelab :

[defaults]
inventory = ./inventory/hosts.yml
remote_user = bob
callbacks_enabled = timer, profile_tasks, profile_roles

Utilisation d'asdf pour la Gestion des Versions

L'un des aspects clés de ce playbook est l'installation d'asdf-vm, un gestionnaire de versions polyvalent permettant de gérer plusieurs versions d'un grand nombre d'outils de développement. L'utilisation d'asdf m'a permis de simplifier la gestion des dépendances et d'assurer que les versions des outils comme Terraform et Ansible soient facilement modifiables et alignées avec les besoins spécifiques de mes projets.

---
- name: Configure Rebond
hosts: localhost
connection: local
gather_facts: true
become: true
vars:
user: bob
devops_tools:
- { name: direnv, version: 2.33.0 }
- { name: helm, version: 3.14.0 }
- { name: kubectl, version: 1.25.0 }
- { name: glab, version: 1.36.0 }
- { name: hadolint, version: 2.10.0 }
- { name: jq, version: 1.7.1 }
- { name: k9s, version: 0.31.7 }
- { name: krew, version: 0.4.4 }
- { name: kubectl, version: 1.29.1 }
- { name: rclone, version: 1.65.2 }
- { name: terraform, version: 1.7.2 }
- { name: opentofu, version: 1.6.1 }
- { name: trivy, version: 0.32.0 }
- { name: yq, version: 4.40.5 }
- { name: packer, version: 1.10.1 }
roles:
- role: stephrobert.bootstrap
- role: stephrobert.motd
vars:
motd_banner: "{{ ansible_hostname}}"
- role: rebond
- role: stephrobert.sshd
vars:
sshd_allowagentforwarding: "yes"
sshd_allowtcpforwarding: "yes"
sshd_allowusers: bob

Le code du role rebond :

---
- name: Check swap State
ansible.builtin.stat:
path: /swapfile
register: swap_file_check
when: ansible_virtualization_type != "docker"
- name: Umount swap | {{ inventory_hostname }}
ansible.posix.mount:
name: swap
fstype: swap
state: absent
when: ansible_virtualization_type != "docker" and swap_file_check.stat.exists
- name: Swap Off | {{ inventory_hostname }}
ansible.builtin.shell:
cmd: swapoff -a
when: ansible_virtualization_type != "docker" and ansible_swaptotal_mb > 0
- name: Configure keyboard
ansible.builtin.copy:
src: "files/{{ item }}"
dest: "/etc/default/{{ item }}"
force: true
owner: root
group: root
mode: "0640"
loop:
- keyboard
- locale
- name: Import tasks to install package for {{ ansible_os_family | lower }}
ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml"
- name: Set timezone
community.general.timezone:
name: "Europe/Paris"
tags: keyboard
- name: Check zsh install
ansible.builtin.stat:
path: "/home/{{ user }}/.oh-my-zsh"
register: ohmyzsh_file_check
become: false
- name: Get Oh my zsh
become: false
ansible.builtin.shell: curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | sh
when: not ohmyzsh_file_check.stat.exists
- name: Uncomment PATH
ansible.builtin.lineinfile:
path: "/home/{{ user }}/.zshrc"
regexp: "^# export PATH.*$"
line: "export PATH=$HOME/.local/bin:$PATH"
become: false
- name: Install oh_my_zsh theme
ansible.builtin.git:
repo: "https://github.com/romkatv/powerlevel10k.git"
dest: "/home/{{ user }}/.oh-my-zsh/custom/themes/powerlevel10k"
version: HEAD
become: false
- name: Install oh_my_zsh plugin zsh-syntax-highlighting
ansible.builtin.git:
repo: "https://github.com/zsh-users/zsh-syntax-highlighting.git"
dest: "/home/{{ user }}/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting"
force: true
version: HEAD
become: false
- name: Install oh_my_zsh plugin zsh-autosuggestions
ansible.builtin.git:
repo: "https://github.com/zsh-users/zsh-autosuggestions.git"
dest: "/home/{{ user }}/.oh-my-zsh/custom/plugins/zsh-autosuggestions"
force: true
become: false
- name: Add plugin to .zshrc
ansible.builtin.lineinfile:
path: "/home/{{ user }}/.zshrc"
regexp: "^plugins=.*$"
line: "plugins=(git gcloud docker kubectl colored-man-pages ansible asdf aws ubuntu direnv fzf docker-compose zsh-syntax-highlighting zsh-autosuggestions helm pip poetry python ripgrep sudo terraform vagrant vault zsh-interactive-cd)"
become: false
- name: change theme zshrc
ansible.builtin.lineinfile:
path: "/home/{{ user }}/.zshrc"
regexp: "^ZSH_THEME=.*$"
line: 'ZSH_THEME="powerlevel10k/powerlevel10k"'
become: false
- name: Add PATH
ansible.builtin.lineinfile:
path: "/home/{{ user }}/.zshrc"
state: present
regexp: '^# export (PATH=\")({{ item }}:)?((?(2).*?(?!(?:.\"))|.*?(?!(?:{{ item }}))))(:{{ item }})?((?(4).*|\"))'
line: '\1\3:{{ item }}\5'
backrefs: true
loop:
- "$HOME/.local/bin"
- "$HOME/.asdf/bin"
become: false
- name: Install asdf
ansible.builtin.git:
repo: "https://github.com/asdf-vm/asdf.git"
dest: "/home/{{ user }}/.asdf"
version: v0.10.2
become: false
- name: Add asdf to .zshrc
ansible.builtin.lineinfile:
path: "/home/{{ user }}/.zshrc"
regexp: "{{ item }}"
line: "{{ item }}"
with_items:
- ". $HOME/.asdf/asdf.sh"
- "fpath=(${ASDF_DIR}/completions $fpath)"
- "autoload -Uz compinit && compinit"
become: false
- name: Add plugin asdf
ansible.builtin.shell: "zsh -lc 'source /home/{{ user }}/.asdf/asdf.sh && /home/{{ user }}/.asdf/bin/asdf plugin add {{ item.name }}' || true"
with_items: "{{ devops_tools }}"
become: false
- name: Install Tools with asdf
ansible.builtin.shell: "zsh -lc 'source /home/{{ user }}/.asdf/asdf.sh && /home/{{ user }}/.asdf/bin/asdf install {{ item.name }} {{ item.version }}'"
with_items: "{{ devops_tools }}"
become: false
- name: Define global version asdf
ansible.builtin.shell: "zsh -lc 'source /home/{{ user }}/.asdf/asdf.sh && /home/{{ user }}/.asdf/bin/asdf global {{ item.name }} {{ item.version }}'"
with_items: "{{ devops_tools }}"
become: false

J'ai ajouté ma config zsh que vous pouvez utiliser ou pas. Pour le désactiver, commentez le !

Vous remarquerez que ce playbook déclare une connexion local et non ssh. J'utilise aussi deux de mes rôles ansible, le premier nommé bootstrap et le second sshd. Pour les installer :

ansible-galaxy install stephrobert.bootstrap
ansible-galaxy install stephrobert.sshd
ansible-galaxy install stephrobert.motd

Ces rôles ont été écrits exprès pour ce projet et ne sont pas parfaits, il manque par exemple l'installation et la configuration de Fail2Ban.

Appliquons le playbook:

ansible-playbook rebond.yml

Durcissement de la Configuration SSH

J'ai également inclus dans le playbook des tâches dédiées au durcissement de la configuration SSH. Cette étape est importante pour sécuriser l'accès à la machine, notamment en désactivant l'authentification par mot de passe et en limitant les tentatives de connexion. Ces mesures réduisent le risque d'accès non autorisé et renforcent la sécurité générale du système.

    - role: stephrobert.sshd
vars:
sshd_allowagentforwarding: "yes"
sshd_allowtcpforwarding: "yes"
sshd_allowusers: bob

Ajout de Rôles Futurs

Ce playbook est conçu pour être évolutif. Dans le futur, j'envisage d'ajouter d'autres rôles pour prendre en charge des aspects supplémentaires de la configuration et de la gestion de l'environnement, tels que la mise en place de Docker, ou encore l'intégration de systèmes de surveillance et d'alerte. Cette approche modulaire permet une adaptation et une expansion faciles du système en fonction de l'évolution de mes besoins.

En conclusion, le développement de ce playbook Ansible représente un pas important vers l'automatisation et la standardisation de mon environnement Homelab DevOps. Non seulement il simplifie le déploiement initial et les mises à jour, mais il assure également que la configuration de la machine reste sécurisée et conforme aux bonnes pratiques. Cet effort d'automatisation est essentiel pour maintenir une infrastructure agile, sécurisée et facilement reproductible.

Gestion des Versions avec asdf-vm

asdf-vm est un outil de gestion de versions polyvalent qui permet de gérer plusieurs langages de programmation et applications, offrant une flexibilité et une uniformité sans précédent pour la gestion des dépendances dans les projets de développement. Dans mon projet Homelab DevOps, l'utilisation d'asdf est centrale pour garantir que tous les outils, comme Ansible et Terraform, sont à la bonne version, essentielle pour la compatibilité et la sécurité des déploiements.

Installation d'asdf-vm

L'installation d'asdf-vm a été automatisée via le playbook Ansible mentionné précédemment. Une fois asdf installé, il est nécessaire de l'initialiser dans le shell de l'utilisateur pour qu'il soit disponible directement dans la session de commande. Cette étape se fait en ajoutant des lignes spécifiques dans le fichier de profil de l'utilisateur, comme .bashrc ou .zshrc.

Ajout de Plugins

asdf fonctionne avec un système de plugins, chaque plugin permettant de gérer les versions d'un outil ou d'un langage spécifique. Pour ajouter un plugin, on utilise la commande asdf plugin add suivie du nom de l'outil. Par exemple, pour gérer les versions de Terraform, on exécutera :

asdf plugin add mkcert

Cette approche modulaire permet d'installer facilement n'importe quel outil de développement, en s'appuyant sur une vaste bibliothèque de plugins maintenue par la communauté.

Installation de Versions Spécifiques

Après avoir ajouté les plugins nécessaires, le pas suivant est d'installer des versions spécifiques des outils. asdf permet d'installer plusieurs versions et de basculer entre elles selon les besoins. Pour installer une version spécifique, on utilise la commande asdf install suivi du nom de l'outil et de la version désirée. Par exemple, pour installer mkcert version 1.4.3 :

asdf list all mkcert
0.9.0
0.9.1
1.0.0
1.0.1
1.1.0
1.1.1
1.1.2
1.2.0
1.3.0
1.4.0
1.4.1
1.4.2
1.4.3
1.4.4
asdf install mkcert 1.4.3

Sélection de la Version à Utiliser

Une fois les versions installées, on peut choisir quelle version utiliser globalement ou localement (par projet) grâce à la commande asdf global ou asdf local, respectivement. Par exemple, pour définir mkcert 1.4.3 comme version globale :

asdf global mkcert 1.4.3

Cela rend la version 0.14.5 de Terraform la version par défaut pour tout le système. Pour un projet spécifique, on pourrait vouloir utiliser une version différente. Dans ce cas, on se place dans le répertoire du projet et on exécute :

asdf local terraform 0.13.5

Cela configure la version 0.13.5 de Terraform comme la version utilisée dans ce répertoire de projet, permettant une granularité et une flexibilité maximales pour la gestion des dépendances.

Utilisation de Visual Studio Code avec Remote SSH

L'un des aspects les plus importants de mon environnement de développement Homelab DevOps est l'utilisation de ://blog.stephane-robert.info/post/visual-code-remote/). Cette fonctionnalité transforme la manière dont je développe et interagit avec le code stocké sur ma machine de rebonds DevOps, en me permettant de travailler directement sur les fichiers situés sur la machine distante, comme si j'étais localement connecté à celle-ci.

Configuration de VS Code pour Remote SSH

La première étape consiste à installer l'extension Remote - SSH disponible dans le marketplace de VS Code. Cette extension permet à VS Code de se connecter à un serveur distant, d'ouvrir des dossiers et de modifier des fichiers à distance via SSH.

Après l'installation de l'extension, la configuration est relativement simple :

  1. Editer le fichier de configuration SSH de votre machine , généralement situé à ~/.ssh/config sur votre machine locale.

    Host rebond.robert.local
    User bob
    MACs hmac-sha2-512-etm@openssh.com

Une fois la configuration SSH ajoutée, vous pouvez vous connecter à votre machine distante en sélectionnant Remote-SSH: Connect to Host... dans la Command Palette et en choisissant l'hôte configuré.

Avantages de l'Approche Remote SSH

L'utilisation de VS Code en mode Remote SSH offre plusieurs avantages significatifs pour le développement et la gestion de l'infrastructure :

  • Environnement Unifié : Je peux travailler dans mon environnement local de VS Code tout en exécutant et déboguant le code directement sur la machine distante. Cela élimine les différences entre les environnements de développement et de production, réduisant ainsi les erreurs de configuration.
  • Accès Direct aux Ressources : Le mode Remote SSH me donne un accès direct aux fichiers, bases de données, et autres ressources stockées sur la machine de rebonds, facilitant la gestion et le développement de l'infrastructure.
  • Performance : En travaillant directement sur le serveur, je minimise les latences liées au transfert de fichiers ou à l'utilisation de ressources distantes, optimisant ainsi ma productivité.
  • Sécurité : La connexion sécurisée via SSH assure que toutes les modifications et le transfert de données se font de manière sécurisée, ce qui est essentiel dans la gestion d'une infrastructure DevOps.

Partage et Contribution sur GitHub

Dans l'esprit de collaboration et d'ouverture caractéristique de la communauté DevOps, j'ai décidé de rendre le code développé pour mon projet Homelab DevOps disponible sur GitHub. Cette démarche vise non seulement à partager mes réalisations avec la communauté, mais aussi à encourager les contributions externes qui pourraient enrichir le projet.

Le code de mon projet, incluant les playbooks Ansible et les configurations, a été déposé dans ce dépôt GitHub.

Je crois fermement en l'amélioration continue et en la collaboration ouverte. C'est pourquoi j'encourage toute personne intéressée par le projet à contribuer. Que ce soit par la correction de bugs, l'ajout de nouvelles fonctionnalités, ou même la proposition d'améliorations de documentation, toutes les contributions sont les bienvenues. Voici comment vous pouvez contribuer :

  • Forker le projet : Créez une copie du projet sur votre compte GitHub pour commencer à travailler sur vos modifications.
  • Soumettre des Pull Requests : Après avoir apporté vos modifications ou améliorations, soumettez une pull request pour que je puisse examiner vos propositions et les intégrer au projet principal.
  • Ouvrir des Issues : Si vous rencontrez des problèmes ou si vous avez des suggestions qui ne nécessitent pas de modification directe du code, n'hésitez pas à ouvrir une issue sur le dépôt GitHub.

J'ai à cœur de maintenir le projet accessible et compréhensible pour tous. Cela signifie que, même si je suis ouvert aux contributions, j'aspire à ce que le code reste simple et éloigné de toute complexité inutile. L'objectif est de fournir une base solide et flexible, permettant à chacun d'adapter le projet à ses propres besoins sans se perdre dans une "usine à gaz".

Conclusion et Perspectives

Alors que cette étape de mon projet Homelab DevOps s'achève, je suis déjà tourné vers l'avenir. La prochaine étape consistera à configurer la seconde carte réseau avec une IP fixe pour un réseau privé. J'installerai aussi tout ce qu'il faut pour fournir des IP via DHCP et connecté ce réseau à internet.

Sur ce réseau privé on trouvera un serveur Proxmox VE comme solution de virtualisation et de conteneurisation sur une autre machine du Lab. L'intégration de Proxmox ouvrira de nouvelles possibilités, notamment en favorisant l'expérimentation de nouvelles technologies et configurations sans affecter l'infrastructure principale.

En partageant mon expérience et mon code, j'espère inspirer d'autres passionnés de DevOps à entreprendre leurs propres projets Homelab, en explorant les possibilités infinies offertes par l'automatisation, la virtualisation, et la collaboration ouverte. La route vers l'excellence en DevOps est un voyage continu d'apprentissage et d'adaptation...