Compare commits
3 Commits
9cd471d66e
...
78b8e68f9f
| Author | SHA1 | Date | |
|---|---|---|---|
| 78b8e68f9f | |||
| d349595aec | |||
| 22bb3ccec9 |
178
README.md
178
README.md
@@ -1,144 +1,78 @@
|
|||||||
# Ansible Setup - Schul-Laptops
|
# schul-laptops
|
||||||
|
|
||||||
12 Linux Mint Laptops verwalten mit Ansible + Clonezilla Backup.
|
12–16 Linux-Mint-Laptops verwalten: **ansible-pull** (laufende Updates) +
|
||||||
|
**Clonezilla** (Komplett-Image ~1×/Jahr). Ueberblick: `COCKPIT.md` · Status:
|
||||||
|
`CLAUDE.md` · Architektur: `docs/architektur.md`.
|
||||||
|
|
||||||
## Erstes Setup (einmalig auf diesem Rechner)
|
## So funktioniert es (Normalfall)
|
||||||
|
|
||||||
### 1. Passwordless Sudo einrichten
|
Jeder Laptop zieht sich alle 30 Minuten (und bei jedem Boot) selbst dieses Repo
|
||||||
|
von `https://git.lehrstun.de/admin/schul-laptops.git` und fuehrt `local.yml` aus.
|
||||||
|
Es gibt keinen Push mehr — das Schul-WLAN laesst das nicht zu.
|
||||||
|
|
||||||
Damit Ansible ohne Passwort arbeiten kann:
|
**Aenderung ausrollen:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo visudo
|
cd ~/projekte/schul-laptops
|
||||||
|
# z.B. Paket ergaenzen in group_vars/all.yml oder Task in local.yml
|
||||||
|
git add -A && git commit -m "..." && git push
|
||||||
|
# fertig — die Laptops holen es sich beim naechsten Timer-Lauf
|
||||||
```
|
```
|
||||||
|
|
||||||
Am Ende hinzufuegen:
|
**Auf einem Laptop nachsehen:**
|
||||||
```
|
|
||||||
puettmann ALL=(ALL) NOPASSWD: ALL
|
|
||||||
```
|
|
||||||
|
|
||||||
Speichern mit `Ctrl+X`, dann `Y`, dann `Enter`.
|
|
||||||
|
|
||||||
### 2. Inventory anpassen
|
|
||||||
|
|
||||||
Bearbeite `inventory.yml` und trage die richtigen IP-Adressen ein:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nano ~/ansible-schule/inventory.yml
|
systemctl list-timers ansible-pull* # laeuft der Timer?
|
||||||
|
journalctl -u ansible-pull -n 50 # letztes Pull-Log
|
||||||
|
sudo systemctl start ansible-pull.service # sofort ziehen statt warten
|
||||||
```
|
```
|
||||||
|
|
||||||
## Workflow: Image auf andere Rechner spielen
|
## Komplett-Image (~1×/Jahr, nach den Ferien)
|
||||||
|
|
||||||
### Schritt 1: Image erstellen (Clonezilla)
|
Details in `CLONEZILLA_AUTOMATISCH.md`. Kurzfassung:
|
||||||
|
|
||||||
1. Clonezilla Live USB-Stick erstellen
|
- **Erstinstallation:** Clonezilla-USB-Stick + externe Platte `DEZNTRSICHERUNG`,
|
||||||
2. Von USB booten
|
danach einmalig `sudo files/first-boot-setup.sh laptopXX` (vergibt den Namen).
|
||||||
3. "device-image" → "savedisk" waehlen
|
- **Danach ohne Stick:** Platte anstecken, Laptop einschalten. Ist das neueste
|
||||||
4. Image auf externen Datentraeger speichern
|
Image auf der Platte neuer als das installierte, bespielt sich der Laptop
|
||||||
|
selbst neu — der Hostname bleibt erhalten.
|
||||||
### Schritt 2: Image auf Clients aufspielen
|
- **Neues Master-Image:** auf laptop03 im GRUB-Menue „Schul-Neuinstallation“
|
||||||
|
waehlen → „IMAGE ERSTELLEN“.
|
||||||
1. Von Clonezilla USB booten
|
|
||||||
2. "device-image" → "restoredisk" waehlen
|
|
||||||
3. Image auswaehlen, auf Festplatte spielen
|
|
||||||
|
|
||||||
### Schritt 3: First-Boot Setup (auf jedem geklonten Rechner)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
|
|
||||||
```
|
|
||||||
|
|
||||||
(Ersetze `laptop05` durch den jeweiligen Hostnamen)
|
|
||||||
|
|
||||||
## Ansible Befehle
|
|
||||||
|
|
||||||
Alle Befehle aus dem Verzeichnis `~/ansible-schule` ausfuehren:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/ansible-schule
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alle Rechner pingen
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/ping.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### System-Update auf allen Clients
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/update.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Software installieren
|
|
||||||
```bash
|
|
||||||
# Standard-Pakete (in der Datei definiert)
|
|
||||||
ansible-playbook playbooks/install-software.yml
|
|
||||||
|
|
||||||
# Bestimmte Pakete
|
|
||||||
ansible-playbook playbooks/install-software.yml -e "packages=['firefox','vlc','gimp']"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nur bestimmte Rechner
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/update.yml --limit laptop05,laptop06
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alle Clients neustarten
|
|
||||||
```bash
|
|
||||||
ansible-playbook playbooks/reboot.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schnelle Befehle ohne Playbook
|
|
||||||
```bash
|
|
||||||
# Shell-Befehl auf allen Clients
|
|
||||||
ansible clients -m shell -a "df -h"
|
|
||||||
|
|
||||||
# Paket installieren
|
|
||||||
ansible clients -m apt -a "name=htop state=present" --become
|
|
||||||
|
|
||||||
# Datei kopieren
|
|
||||||
ansible clients -m copy -a "src=./files/test.txt dest=/tmp/"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verzeichnisstruktur
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
```
|
```
|
||||||
~/ansible-schule/
|
~/projekte/schul-laptops/
|
||||||
├── ansible.cfg # Ansible-Konfiguration
|
├── local.yml # DAS Playbook (laeuft per ansible-pull auf jedem Laptop)
|
||||||
├── inventory.yml # Liste aller Laptops mit IPs
|
├── group_vars/all.yml # Paketliste u.a. Variablen
|
||||||
├── README.md # Diese Datei
|
├── files/
|
||||||
├── playbooks/
|
│ ├── schul-pull.sh # Pull-Wrapper (HTTPS, SSH-Fallback)
|
||||||
│ ├── ping.yml # Erreichbarkeit testen
|
│ ├── ansible-pull.service # systemd-Units
|
||||||
│ ├── update.yml # System-Updates
|
│ ├── ansible-pull.timer
|
||||||
│ ├── install-software.yml
|
│ └── first-boot-setup.sh # einmalig nach Erstinstallation
|
||||||
│ ├── reboot.yml
|
├── docs/ # Architektur, Entscheidungslog
|
||||||
│ └── set-hostname.yml
|
└── playbooks/, inventory.yml, update-ips.sh, ansible.cfg # LEGACY, s.u.
|
||||||
└── files/
|
|
||||||
└── first-boot-setup.sh # Nach Klonen ausfuehren
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Legacy: Push-Betrieb (nur Heimnetz)
|
||||||
|
|
||||||
|
Das alte Push-Setup funktioniert weiterhin, aber **nur wenn die Laptops im
|
||||||
|
eigenen WLAN haengen** (Schul-WLAN blockiert SSH/mDNS zwischen Geraeten):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./update-ips.sh # IPs per mDNS einsammeln
|
||||||
|
ansible-playbook playbooks/ping.yml # Erreichbarkeit
|
||||||
|
ansible-playbook playbooks/update.yml # Updates pushen
|
||||||
|
ansible clients -m shell -a "df -h" # Ad-hoc-Befehl
|
||||||
|
```
|
||||||
|
|
||||||
|
Voraussetzung auf neuen Controllern: passwordless sudo fuer `puettmann`
|
||||||
|
(`sudo visudo` → `puettmann ALL=(ALL) NOPASSWD: ALL`).
|
||||||
|
|
||||||
## Problemloesungen
|
## Problemloesungen
|
||||||
|
|
||||||
### "Permission denied" bei SSH
|
- **Laptop zieht nichts:** `journalctl -u ansible-pull` — HTTPS blockiert? Dann
|
||||||
```bash
|
greift automatisch der SSH-Fallback (Port 2222, Deploy-Key unter /root/.ssh).
|
||||||
# SSH-Key manuell kopieren
|
- **Pull sofort ausloesen:** `sudo systemctl start ansible-pull.service`
|
||||||
ssh-copy-id puettmann@192.168.1.105
|
- **Push: Permission denied:** `ssh-copy-id puettmann@<IP>`;
|
||||||
```
|
Host-Key-Warnung: `ssh-keygen -R <IP>`
|
||||||
|
|
||||||
### Rechner nicht erreichbar
|
|
||||||
```bash
|
|
||||||
# Einzelnen Rechner testen
|
|
||||||
ansible laptop05 -m ping -vvv
|
|
||||||
```
|
|
||||||
|
|
||||||
### Host-Key Warnung
|
|
||||||
Ist in ansible.cfg deaktiviert. Falls es trotzdem auftritt:
|
|
||||||
```bash
|
|
||||||
ssh-keygen -R 192.168.1.105
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tipps
|
|
||||||
|
|
||||||
1. **Bandbreite sparen:** Updates nachts oder gestaffelt ausfuehren
|
|
||||||
2. **Grosse Aenderungen:** Besser per Clonezilla-Image
|
|
||||||
3. **Kleine Aenderungen:** Ansible (schneller, kein Neustart)
|
|
||||||
4. **Testen:** Erst mit `--limit laptop05` auf einem Rechner testen
|
|
||||||
|
|||||||
8
files/ansible-pull.service
Normal file
8
files/ansible-pull.service
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Schul-Laptops: Konfiguration per ansible-pull aktualisieren
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/schul-pull.sh
|
||||||
11
files/ansible-pull.timer
Normal file
11
files/ansible-pull.timer
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Schul-Laptops: regelmaessiger ansible-pull (Boot + alle 30 min)
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=2min
|
||||||
|
OnUnitActiveSec=30min
|
||||||
|
RandomizedDelaySec=5min
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
@@ -3,12 +3,19 @@
|
|||||||
# First-Boot Setup fuer geklonte Rechner
|
# First-Boot Setup fuer geklonte Rechner
|
||||||
#
|
#
|
||||||
# Dieses Script nach dem Klonen EINMAL ausfuehren auf jedem Rechner:
|
# Dieses Script nach dem Klonen EINMAL ausfuehren auf jedem Rechner:
|
||||||
# sudo ~/ansible-schule/files/first-boot-setup.sh laptop05
|
# sudo ~/projekte/schul-laptops/files/first-boot-setup.sh laptop05
|
||||||
#
|
#
|
||||||
# Es macht:
|
# Es macht:
|
||||||
# 1. Neuen Hostnamen setzen
|
# 1. Neuen Hostnamen setzen
|
||||||
# 2. Neue SSH-Host-Keys generieren (wichtig!)
|
# 2. Neue SSH-Host-Keys generieren (wichtig!)
|
||||||
# 3. Neue Machine-ID generieren
|
# 3. Neue Machine-ID generieren
|
||||||
|
# 4. Privaten Admin-Key entfernen (ausser auf laptop03, siehe docs/decisions.md E-005)
|
||||||
|
# 5. Image-Versionsdatei setzen (falls nicht vorhanden)
|
||||||
|
# 6. ansible-pull-Timer aktivieren und ersten Lauf anstossen
|
||||||
|
#
|
||||||
|
# Beim automatischen Reimage von der externen Platte uebernimmt das
|
||||||
|
# Clonezilla-Restore-Skript diese Schritte — dieses Script ist nur fuer
|
||||||
|
# die Erstinstallation per USB-Stick gedacht.
|
||||||
#
|
#
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -53,9 +60,30 @@ cp /etc/machine-id /var/lib/dbus/machine-id
|
|||||||
# 4. SSH-Dienst neustarten
|
# 4. SSH-Dienst neustarten
|
||||||
systemctl restart ssh
|
systemctl restart ssh
|
||||||
|
|
||||||
|
# 5. Privaten Admin-Key entfernen — der Gitea-Admin-Key gehoert nur auf laptop03.
|
||||||
|
# Der Read-only-Deploy-Key unter /root/.ssh bleibt (wird fuer den Pull-Fallback gebraucht).
|
||||||
|
if [ "$NEW_HOSTNAME" != "laptop03" ]; then
|
||||||
|
echo -e "${YELLOW}Entferne privaten Admin-Key...${NC}"
|
||||||
|
rm -f /home/puettmann/.ssh/id_ed25519 /home/puettmann/.ssh/id_ed25519.pub
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. Image-Versionsdatei: "0" ist aelter als jeder Image-Name, d.h. das naechste
|
||||||
|
# angesteckte Image wuerde ein Reimage ausloesen — das Restore-Skript schreibt
|
||||||
|
# hier den echten Image-Namen hinein.
|
||||||
|
if [ ! -f /etc/schul-image-version ]; then
|
||||||
|
echo "0" > /etc/schul-image-version
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. ansible-pull aktivieren: ab jetzt holt sich der Laptop alles selbst.
|
||||||
|
echo -e "${YELLOW}Aktiviere ansible-pull-Timer...${NC}"
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now ansible-pull.timer
|
||||||
|
systemctl start --no-block ansible-pull.service
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}=== Setup abgeschlossen ===${NC}"
|
echo -e "${GREEN}=== Setup abgeschlossen ===${NC}"
|
||||||
echo -e "Hostname: ${GREEN}$NEW_HOSTNAME${NC}"
|
echo -e "Hostname: ${GREEN}$NEW_HOSTNAME${NC}"
|
||||||
|
echo "Der erste ansible-pull-Lauf wurde gestartet (Log: journalctl -u ansible-pull)."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Optional: Rechner neustarten mit 'sudo reboot'"
|
echo "Optional: Rechner neustarten mit 'sudo reboot'"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
24
files/schul-pull.sh
Normal file
24
files/schul-pull.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Zieht das schul-laptops-Repo und fuehrt local.yml aus.
|
||||||
|
# HTTPS zuerst (funktioniert auch im Schulnetz), SSH mit Deploy-Key als Fallback.
|
||||||
|
# Wird vom systemd-Timer (ansible-pull.timer) als root aufgerufen.
|
||||||
|
#
|
||||||
|
set -u
|
||||||
|
|
||||||
|
HTTPS_URL="https://git.lehrstun.de/admin/schul-laptops.git"
|
||||||
|
SSH_URL="ssh://git@46.225.114.15:2222/admin/schul-laptops.git"
|
||||||
|
DEPLOY_KEY="/root/.ssh/ansible-pull-deploy"
|
||||||
|
CHECKOUT="/var/lib/schul-laptops"
|
||||||
|
|
||||||
|
run_pull() {
|
||||||
|
ansible-pull -U "$1" -d "$CHECKOUT" -c local -i localhost, local.yml
|
||||||
|
}
|
||||||
|
|
||||||
|
if run_pull "$HTTPS_URL"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "HTTPS fehlgeschlagen, versuche SSH-Fallback (Port 2222) ..." >&2
|
||||||
|
export GIT_SSH_COMMAND="ssh -i $DEPLOY_KEY -p 2222 -o BatchMode=yes"
|
||||||
|
run_pull "$SSH_URL"
|
||||||
9
group_vars/all.yml
Normal file
9
group_vars/all.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
# Software, die auf allen Schul-Laptops installiert sein soll.
|
||||||
|
# Paket hier ergaenzen + pushen = wird auf allen Laptops installiert.
|
||||||
|
schul_pakete:
|
||||||
|
- htop
|
||||||
|
- git
|
||||||
|
- curl
|
||||||
|
- vim
|
||||||
|
- ansible
|
||||||
63
local.yml
Normal file
63
local.yml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
# Wird per ansible-pull auf jedem Laptop lokal ausgefuehrt (via schul-pull.sh).
|
||||||
|
# Aenderungen hier verteilen sich beim naechsten Timer-Lauf auf alle Laptops.
|
||||||
|
- name: Schul-Laptop konfigurieren
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
become: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: APT-Cache aktualisieren
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
|
||||||
|
- name: System-Updates installieren (safe upgrade)
|
||||||
|
apt:
|
||||||
|
upgrade: safe
|
||||||
|
|
||||||
|
- name: Standard-Software installieren
|
||||||
|
apt:
|
||||||
|
name: "{{ schul_pakete }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
# --- Selbstverwaltung: haelt die Pull-Mechanik auf allen Laptops aktuell ---
|
||||||
|
|
||||||
|
- name: Pull-Script installieren
|
||||||
|
copy:
|
||||||
|
src: files/schul-pull.sh
|
||||||
|
dest: /usr/local/bin/schul-pull.sh
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: systemd-Units fuer ansible-pull installieren
|
||||||
|
copy:
|
||||||
|
src: "files/{{ item }}"
|
||||||
|
dest: "/etc/systemd/system/{{ item }}"
|
||||||
|
mode: "0644"
|
||||||
|
loop:
|
||||||
|
- ansible-pull.service
|
||||||
|
- ansible-pull.timer
|
||||||
|
register: units
|
||||||
|
|
||||||
|
- name: systemd neu laden, falls Units geaendert
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
when: units.changed
|
||||||
|
|
||||||
|
- name: ansible-pull.timer aktivieren
|
||||||
|
systemd:
|
||||||
|
name: ansible-pull.timer
|
||||||
|
enabled: yes
|
||||||
|
state: started
|
||||||
|
|
||||||
|
# --- Status melden ---
|
||||||
|
|
||||||
|
- name: Pruefen ob ein Neustart noetig ist
|
||||||
|
stat:
|
||||||
|
path: /var/run/reboot-required
|
||||||
|
register: reboot_required
|
||||||
|
|
||||||
|
- name: Neustart-Hinweis ins Log schreiben
|
||||||
|
debug:
|
||||||
|
msg: "ACHTUNG: Neustart erforderlich (wird nicht automatisch ausgefuehrt)."
|
||||||
|
when: reboot_required.stat.exists
|
||||||
Reference in New Issue
Block a user