Ansible ist eine leistungsstarke Open-Source-Plattform für die automatisierte Serveradministration. Mit der in den Konfigurationsdateien verwendeten, einfachen YAML-Syntax und agentlosen Architektur macht Ansible es möglich, komplexe IT-Aufgaben effizient zu automatisieren. Neben Ansible gibt es zwei weitere bekannte Tools für die Konfigurationsverwaltung: Puppet und Salt. Jedes dieser Tools hat seinen eigenen Ansatz zur Automatisierung.
Ein Vorteil von Ansible ist das Prinzip der Idempotenz, welches durch den deklarativen Ansatz von Ansible umgesetzt wird. Das bedeutet, dass Tasks nur dann Änderungen vornehmen, wenn sie tatsächlich nötig sind. Die in YAML definierten tasks beschreiben, so wie zum Beispiel ein Docker Compose File, den gewollten Zustand einer Aktion. Ist dieser Vorhanden werden Aktionen automatisch übersprungen. Dies ermöglicht es, Playbooks mehrfach auszuführen, ohne dass unnötige Änderungen vorgenommen werden. Letztendlich lassen sich so manche Ansibletasks ohne Bedenken regelmäßig per Cronjob ausführen.
In diesem Ansible Task lasse ich in meinem Homelab automatisch Updates durchführen und führe anstehende Upgrades durch. Anschließend wird eine Variable gefüllt und somit geprüft, ob im Fall eines Kernelupdates oder veralteter Bibliotheken ein reboot nötig ist. Je ob es sich um einen Hypervisor oder die darauf laufenden Gastmaschinen handelt, wird der Neustart auf eine andere Zeit verlegt.
Mein bisheriger Stand sieht so aus:
---
- name: Update and Upgrade Debian Servers
hosts: all
gather_facts: yes
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 86400
- name: Upgrade packages
apt:
upgrade: yes
- name: Remove dependencies that are no longer required.
ansible.builtin.apt:
autoremove: yes
- name: Check if a reboot is required.
ansible.builtin.stat:
path: /var/run/reboot-required
get_checksum: no
register: reboot_required_file
- name: Schedule reboot at 02:00 if not a host machine
ansible.builtin.command: sudo shutdown -r 02:00
when:
(reboot_required_file.stat.exists) and
(inventory_hostname not in groups[pve_hosts])
- name: Schedule reboot at 04:00 if not a guest machine
ansible.builtin.command: sudo shutdown -r 04:00
when:
(reboot_required_file.stat.exists) and
(inventory_hostname in groups[pve_hosts])
Ein weiteres und deutlicheres Beispiel für die Grundidee von Ansible ist der folgende task mit dem wir Konfigurationsabweichungen in der SSHD Config in regelmäßigen Abständen überschreiben können. Es mag sein, dass ich einmal auf eine Passwortanmeldung ausweichen muss und dafür die config ändere oder ein künftiges Upgrade der SSHD Config die bisherigen Anpassungen verwirft. Es mag sogar sein, dass ich vergesse die Änderung rückgängig zu machen. Wioe auch immer!
Im Grunde stellt Ansible dann aber den durch mich eigentlich gewollten Zustand (zb. nur ssh key, keine root anmeldung etc) in regelmäßigen Zeitabständen und durch das Einfügen eines Blocks am Anfang der Config (“first come first serve” Prinzip!) wieder her.
---
- hosts: all
tasks:
- name: sshd configuration file update
blockinfile:
path: /etc/ssh/sshd_config
insertbefore: BOF # Beginning of the file
marker: "# {mark} ANSIBLE MANAGED BLOCK BY LINUX-ADMIN"
block: |
PermitRootLogin no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
backup: yes
validate: /usr/sbin/sshd -T -f %s
- name: Restart SSHD
service:
name: sshd
state: restarted
Das sind also zwei erste Beispiele für eine auf Ansible basierende und grundlegende Serveradministration. Durch die Verwendung von Playbooks, Roles und anderen fortgeschrittenen Funktionen lassen sich sebstverständlich auch noch komplexe Aufgaben automatisieren und wiederholen. Dazu in einem späteren Beitrag mehr.