Raspberry Pi Administration mit Ansible
Updates lassen sich auf deinen vielen Raspberry Pis sehr einfach un zentral mit einem Ansible Playbook einspielen.
Du brauchst dich dafür nicht mehr per SSH bei jedem deiner Raspberry Pis einzeln anmelden und den Update- und Upgrade-Befehl ausführen.
Mit Ansible startest du das Playbook bequem auf deinem Laptop bzw. PC mit einem Befehl und der Rest wird von Ansible automatisch erledigt.
Updates einspielen und die Server auf dem aktuellsten Stand zu halten ist eine unverzichtbare Aufgabe, die regelmäßig durchgeführt werden muss.
Mit Ansible lässt sich die eigene Raspberry Pi Serverfarm sehr schön orchestrieren.
Wenn man viele Server hat, dann kann diese Aufgabe einige Zeit in Anspruch nehmen.
Mit Ansible lassen sich die Raspberry Pis im eigenen Netzwerk sehr schnell und unkompliziert updaten.
Wie sieht der ganze Prozess mit Ansible aus?
Bisher sieht der Prozess so aus:
ssh benutzername@ip-adresse-rpi1 screen sudo apt update && sudo apt dist-upgrade && sudo apt-get clean exit (Strg+D) exit (Strg+D)
ssh benutzername@ip-adresse-rpi2 screen sudo apt update && sudo apt dist-upgrade && sudo apt-get clean exit (Strg+D) exit (Strg+D) ...
ssh benutzername@ip-adresse-rpin screen sudo apt update && sudo apt dist-upgrade && sudo apt-get clean exit (Strg+D) exit (Strg+D)
Mit Ansible vereinfacht sich der Update-Prozess erheblich.
Neuer Prozess
ansible-playbook -i inventory.ini update_upgrade.yml -v
Was wird benötigt?
Damit du mit Ansible deine Raspberry Pis aktualisieren und auf dem aktuellsten Stand halten kannst, sind ein paar Dinge vorzubereiten.
SSH-Zugriff auf RPis einrichten
Für die Verwendung von Ansible benötigen wir einen funktionierenden SSH-Zugriff auf unsere Raspberry Pis.
In meinem Fall verwende ich dafür einen YubiKey, den ich nach diesen Anleitungen konfiguriert habe.
Wenn du keinen YubiKey oder anderen Hardwaretoken hast, kannst du den ganzen Prozess auch mit "normalen" SSH-Schlüsseln umsetzen.
YubiKey vorbereiten
Bevor der YubiKey zur Authentifizierung verwendet werden kann, sind die GPG-Schlüssel zu erstellen und auf den Hardwaretoken zu übertragen.
Für die einzelnen Schritte findest du Anleitungen in meinem Blog.
Raspberry Pi anpassen
Die Raspberry Pis sind ebenfalls vorzubereiten, dass eine Anmeldung per SSH und dem YubiKey möglich ist.
Die Raspberry Pis sind nach dieser Anleitung konfiguriert:
Client für YubiKey konfigurieren
Zum Abschluss ist dein Client noch für die Verwendung mit dem YubiKey zu konfigurieren.
Abhängig von deinem Betriebssystem findest du in meinem Blog die entsprechende Anleitung für die Einrichtung.
YubiKey Themenseite
Hier geht es zur 👉 YubiKey Themenseite, dort findest du noch mehr Beiträge rund um den YubiKey.
Ansible auf Client installieren
Ansible muss dann noch auf deinem Client installiert werden. Bei Linux und MacOS ist das sehr einfach
Für MaxOS kann Ansible mithilfe von Homebrew installiert werden:
brew install ansible
Bei Linux kommt Ansible mithilfe der Repositories auf den Client
sudo apt-get install ansible
Damit ist die Konfiguration des Clients und des bzw. der Server abgeschlossen und das Ansible Playbook kann erstellt werden.
Gib mir gerne einen Kaffee ☕ aus ❗️
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
ansible.cfg
[defaults]
inventory = {{ lookup('env','PWD') }}/inventory.ini
[ssh_connection]
# Control the mechanism for transferring files (new)
# If set, this will override the scp_if_ssh option
# * sftp = use sftp to transfer files
# * scp = use scp to transfer files
# * piped = use 'dd' over SSH to transfer files
# * smart = try sftp, scp, and piped, in that order [default]
transfer_method = smart
# ansible.cfg
# For more details and options please refer to
# https://github.com/ansible/ansible/blob/devel/examples/ansible.cfg
inventory.ini
In den inventory.ini
werden alle Server aufgelistet. Für eine bessere Übersicht können die Server in unterschiedliche Kategorien zusammengefasst werden.
Diese Funktion ist bei großen Infrastrukturen und umfangreichen Playbooks hilfreich. Bei diesem kleinen Beispiel aber nicht wirklich wichtig.
Die Gruppierung dient dazu aufzuzeigen, wie eine inventory.ini
aufgebaut werden kann.
In der inventory.ini
verwende ich host names und keine IP-Adressen.
Auf meinem Laptop habe ich die /etc/hosts
Datei gepflegt und die hosts names werden automatisch den richtigen IP-Adressen zugeordnet.
Die Verwendung von IP-Adressen ist einfacher, wenn keine host names aktiv gepflegt werden.
Ich habe auch eine kleine Besonderheit bei mir, der Server share
ist nur über einen Jump Host per SSH erreichbar.
Der Jump Host ermöglicht es von einem Netzwerksegment in ein anderes zu gelangen, ohne das der Client dem anderen Segment angehört.
Die Konfiguration dafür ist in der ~/.ssh/config
definiert.
Wie das Ganz eingerichtet wird, beschreibe ich in diesem Beitrag:
# ini file is in use to update & upgrade the Raspberry Pi servers.
[raspberry_server]
radiopi-wlan ansible_host=radiopi-wlan
pihole-lan ansible_host=pihole
nextcloud2 ansible_host=nextcloud
nextcloud-share ansible_host=share
[radio]
#radiopi-lan
radiopi-wlan
[pihole]
pihole-lan
[nextcloud]
nextcloud2 ansible_host=nextcloud
[share]
nextcloud-share ansible_host=share
[raspberry_server:vars]
ansible_user=benutzer
ansible_become=yes
ansible_become_method=sudo
ansible_python_interpreter='/usr/bin/env python3'
###############
## General Playbook Variables
###############
# You can define if a backup of files should be created automatically when
# a new file overwrites it
# 'yes' or 'no'
- backup_of_scripts='no'
Ansible Playbook update_upgrade.yml
In dieser Datei wird festgelegt, welche Schritte Ansible durchführen soll.
Die Namen ping
, update_upgrade
und clean_server
sind dabei die Namen der Ordner im Hauptordner roles
- ansible.cfg
- inventory.ini
- update_upgrade.yml
- roles/
- ping/
- defaults/
- files/
- handlers/
- meta/
- tasks/
- templates/
- tests/
- vars/
- update_upgrade/
- defaults/
- files/
- handlers/
- meta/
- tasks/
- templates/
- tests/
- vars/
- clean_server/
- defaults/
- files/
- handlers/
- meta/
- tasks/
- templates/
- tests/
- vars/
Die Datei update_upgrade.yml
ist das Ansible Playbook, dass alle Schritte enthält, die von Ansible für die definierten Server in der inventory.ini
durchlaufen werden sollen.
#
# Playbook - Update And Upgrade
#
# -------------------------------------------
#
# Description:
# Update and upgrade all hosts in group raspberry_server
#
# -------------------------------------------
# Dry Run:
# ansible-playbook -i inventory.ini update_upgrade.yml --check
#
# Run:
# ansible-playbook -i inventory.ini update_upgrade.yml -v
#
---
- hosts: raspberry_server
gather_facts: false
roles:
- ping
- update_upgrade
- clean_server
#- gather_facts
tasks:
# - name: Ping all server
# include: roles/ping/tasks/ping.yml
Gib mir gerne einen Kaffee ☕ aus ❗️
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
Ordnerstruktur für die Rollen
Für jede Rolle wird ein neuer Ordner mit einem aussagekräftigen Namen im Hauptordner roles
angelegt.
In diesem Beispiel heißen die Ordner:
ping
update_upgrade
clean_server
Diese Ordner sind damit die Hauptordner für die neuen Rollen und enthalten immer die gleichen Unterordner mit der hier aufgezeigten Benennung.
Für das einfache Beispiel, dass wir hier verwenden, ist die Ordnerstruktur eigentlich viel zu umfangreich. Wenn aber mehr mit Ansible gearbeitet wird, dann wirst du an einer solchen Ordnerstruktur nicht vorbeikommen. Also warum nicht gleich damit anfangen?
Ich habe mit an den Best Practices orientiert und den Vorschlag aus der offiziellen Dokumentation entnommen:
roles/
README.md # Role Information
- name-of-role/ # unique role name
- defaults/ #
-- main.yml # <-- default lower priority variables for this
- files/ #
-- bar.txt # <-- files for use with the copy resource
-- foo.sh # <-- script files for use with the script resource
- handlers/ #
-- main.yml # <-- handlers file
- meta/ #
-- main.yml # <-- role dependencies
- tasks/ #
-- main.yml # <-- tasks file can include smaller files if warranted
- templates/ # <- files for use with the template resource
-- ntp.conf.j2 # <-- templates end in .j2
- tests/ #
-- test.yml # <-- test playbook script
-- inventory.ini # <-- test inventory file
- vars/ #
-- main.yml # <-- variables associated with this role
Die Aufgaben (= tasks) liegen im Ordner tasks
und dort in der Datei main.yml
.
Hier nicht verwirren lassen, egal welche Rolle verwendet wird, die Datei im Ordner tasks
ist immer mit main.yml
zu benennen.
Die Zuordnung macht Ansible mit dem Namen des übergeordneten Rollen-Ordners. Also in unserem Beispiel
ping
update_upgrade
clean_server
Rolle Ping
Name des Hauptordners ping
.
Die gesamte Ordnerstruktur für ping
sieht wie folgt aus:
- ping/
- defaults/
- files/
- handlers/
- meta/
- tasks/
- templates/
- tests/
- vars/
Die Datei main.yml
im Ordner tasks
hat den folgenden Inhalt.
#
# Tasks: Ping
#
# -------------------------------------------
#
# Description:
# Send ping to remote servers
#
# -------------------------------------------
#
#
---
# Send a ping and check if the server is available
- name: "{{ ping1 }}"
ping:
Die Datei main.yml
im Ordner vars
hat den folgenden Inhalt.
---
# vars file for ping
ping_test: "test"
ping1: "Name"
Alle anderen Unterordner enthalten für diese Rolle keine weiteren Dateien.
Rolle update_upgrade
Name des Hauptordners update_upgrade
.
Die gesamte Ordnerstruktur für update_upgrade
sieht wie folgt aus:
- update_upgrade/
- defaults/
- files/
- handlers/
- meta/
- tasks/
- templates/
- tests/
- vars/
Die Datei main.yml
im Ordner tasks
hat den folgenden Inhalt.
#
# Task:
# Update And Upgrade
#
# -------------------------------------------
#
# Description:
# Update and upgrade all Debian based OS
#
# -------------------------------------------
#
#
---
# Update process
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html
- name: Update apt repo and cache on all Debian/Ubuntu boxes
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
upgrade: full
register: apt
- debug: msg={{ apt.stdout.split('\n')[:-1] }}
# https://www.jeffgeerling.com/blog/2022/ansible-playbook-upgrade-ubuntudebian-servers-and-reboot-if-needed
- name: Check if a reboot is needed on all servers
ansible.builtin.stat:
path: /var/run/reboot-required
get_md5: no
register: reboot_required_file
- name: Reboot the server (if required).
ansible.builtin.reboot:
when: reboot_required_file.stat.exists == true
Gib mir gerne einen Kaffee ☕ aus ❗️
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
Rolle clean-server
Name des Hauptordners clean-server
.
Die gesamte Ordnerstruktur für clean-server
sieht wie folgt aus:
- clean-server/
- defaults/
- files/
- handlers/
- meta/
- tasks/
- templates/
- tests/
- vars/
Die Datei main.yml
im Ordner tasks
hat den folgenden Inhalt.
#
# Task: Clean Server
#
# -------------------------------------------
#
# Description:
# The playbook removes all useless and unused packages
#
#
#
# -------------------------------------------
#
#
---
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html
- name: Remove useless packages from the cache
apt:
autoclean: yes
- name: Remove dependencies that are no longer required
apt:
autoremove: yes
Rolle gather-facts
Es lassen sich auch sämtlichen Informationen der Pis ausgegeben. Dafür gibt es umfangreichen Funktionen in Ansible.
Für dieses Beispiel wird das nicht verwendet, aber es zeigt ganz gut die Möglichkeiten von gather-facts
.
Die Datei main.yml
im Ordner tasks
hat den folgenden Inhalt.
#
#
# Task:
# Gather Facts
#
# -------------------------------------------
#
# Description:
# Gather Facts
# In Playbook gather facts must be set on "true"
# gather_facts: true
#
# -------------------------------------------
#
#
---
###########################
# List facts for information/debugging only
###########################
# https://www.middlewareinventory.com/blog/ansible-facts-list-how-to-use-ansible-facts/
# List all available facts for hosts.
# - debug:
# msg: "{{vars}}"
# list ansible_default_ipv4
# - debug:
# msg: "{{ansible_default_ipv4}}"
# list only IP address of ansible_default_ipv4
# - debug:
# msg: "{{ansible_default_ipv4.address}}"
###########################
# Load facts into variables
###########################
- debug: var=hostvars[inventory_hostname]['ansible_distribution']
- debug: var=hostvars[inventory_hostname]['ansible_distribution_file_variety']
- debug: var=hostvars[inventory_hostname]['ansible_distribution_version']
- debug: var=hostvars[inventory_hostname]['ansible_dns']['nameservers']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['address']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['alias']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['broadcast']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['gateway']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['interface']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['macaddress']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['mtu']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['netmask']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['network']
- debug: var=hostvars[inventory_hostname]['ansible_default_ipv4']['type']
# Links:
# https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html
Weitere Tweaks
McFly
Wenn du einen Mac verwendest, dann kannst du dir das kleine Tool McFly installieren und sehr einfach dein Playbook in der Shell Historie heraussuchen und aufrufen.
Das wiederholte Eingeben des Ansible-Befehls ist damit unnötig. Mit dem Shortcut Strg + R
kannst du durch die Historie surfen.
Versionsverwaltung mit Git
Alle Dateien des Ansible Playbooks lassen sich hervorragend über Git versionieren und managen.
Für das eigene Hosting bietet sich hier besonders Gitea an, dass keine großen Anforderungen an die Hardware stellt.
Möchtest du keinen eigenen Gitea-Server, betreiben, dann kannst du
- 👉 codeberg.org verwenden.
Gib mir gerne einen Kaffee ☕ aus ❗️
Wenn dir meine Beiträge gefallen und geholfen haben, dann kannst du mir gerne einen Kaffee ☕️ ausgeben.
Follow Me❗️
Source
Photo by Arindam Mahanta on Unsplash