From 23d6e36028ab1ab334bf5bdf7d59ecc8201e975b Mon Sep 17 00:00:00 2001 From: Robert Rapp Date: Mon, 12 Oct 2026 19:39:25 +0200 Subject: [PATCH] gpu-vms: DHCP-Client-ID auf MAC, Docker-Runtime als Aufgabe, Zugang nach Neustart auffrischen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nach dem Treiber-Neustart hatten gpu-pve44 und gpu-pve46 ihre DHCP-Adressen getauscht; die strenge Hostschlüssel-Prüfung hat den Lauf gestoppt. netplan nutzt jetzt die MAC als Client-ID (Voraussetzung für Reservierungen, D5). Der Handler für nvidia-ctk ist eine idempotente Aufgabe, vor dem Neustart werden Handler ausgeführt. scripts/refresh-vm-access.sh holt Adressen aus dem Agenten, schreibt das Inventar und trägt die Hostschlüssel ein. Co-Authored-By: Claude Opus 5.5 --- platform/proxmox/ansible/playbooks/site.yml | 13 +++++++++ .../ansible/roles/gpu-node/handlers/main.yml | 4 --- .../ansible/roles/gpu-node/tasks/main.yml | 15 +++++++++-- platform/proxmox/scripts/refresh-vm-access.sh | 27 +++++++++++++++++++ platform/proxmox/scripts/trust-vm-hostkeys.sh | 19 ------------- 5 files changed, 53 insertions(+), 25 deletions(-) create mode 100755 platform/proxmox/scripts/refresh-vm-access.sh delete mode 100755 platform/proxmox/scripts/trust-vm-hostkeys.sh diff --git a/platform/proxmox/ansible/playbooks/site.yml b/platform/proxmox/ansible/playbooks/site.yml index 71d3c78..949f110 100644 --- a/platform/proxmox/ansible/playbooks/site.yml +++ b/platform/proxmox/ansible/playbooks/site.yml @@ -6,6 +6,19 @@ - name: GPU-VMs (Treiber gepinnt, Container-Toolkit, Docker, Xid-Exporter) hosts: gpu_vms + pre_tasks: + # DHCP-Client-ID = MAC statt DUID: sonst greifen Reservierungen über die MAC nicht und die + # Adressen wechseln beim Neustart (12.10. beobachtet). Wirkt ab dem nächsten Neustart der VM. + - name: DHCP-Client-ID auf MAC umstellen + ansible.builtin.copy: + dest: /etc/netplan/99-knaster-dhcp-id.yaml + content: | + network: + version: 2 + ethernets: + eth0: + dhcp-identifier: mac + mode: "0600" roles: [docker-host, gpu-node] - name: Infra-LXC (Docker) diff --git a/platform/proxmox/ansible/roles/gpu-node/handlers/main.yml b/platform/proxmox/ansible/roles/gpu-node/handlers/main.yml index ff61e93..55c2df1 100644 --- a/platform/proxmox/ansible/roles/gpu-node/handlers/main.yml +++ b/platform/proxmox/ansible/roles/gpu-node/handlers/main.yml @@ -1,7 +1,3 @@ -- name: configure nvidia runtime - ansible.builtin.command: nvidia-ctk runtime configure --runtime=docker - notify: restart docker - - name: restart docker ansible.builtin.service: name: docker diff --git a/platform/proxmox/ansible/roles/gpu-node/tasks/main.yml b/platform/proxmox/ansible/roles/gpu-node/tasks/main.yml index 3a454f5..2e4e6e9 100644 --- a/platform/proxmox/ansible/roles/gpu-node/tasks/main.yml +++ b/platform/proxmox/ansible/roles/gpu-node/tasks/main.yml @@ -30,12 +30,20 @@ creates: /etc/apt/sources.list.d/nvidia-container-toolkit.list executable: /bin/bash -- name: Container-Toolkit installieren und für Docker konfigurieren +- name: Container-Toolkit installieren ansible.builtin.apt: name: nvidia-container-toolkit state: present update_cache: true - notify: configure nvidia runtime + +# Als Aufgabe statt Handler: Ein Handler ging verloren, wenn der Lauf beim Neustart abbrach +- name: NVIDIA-Runtime in Docker eintragen + ansible.builtin.shell: | + grep -q '"nvidia"' /etc/docker/daemon.json 2>/dev/null && exit 0 + nvidia-ctk runtime configure --runtime=docker && echo geändert + register: nvidia_runtime + changed_when: "'geändert' in nvidia_runtime.stdout" + notify: restart docker - name: Modell-Disk (scsi1) formatieren, falls leer (formatiert nie eine vorhandene Partition um) community.general.filesystem: @@ -79,6 +87,9 @@ state: started daemon_reload: true +- name: Handler vor dem Neustart ausführen + ansible.builtin.meta: flush_handlers + - name: Neustart nach Treiberinstallation ansible.builtin.reboot: when: driver.changed diff --git a/platform/proxmox/scripts/refresh-vm-access.sh b/platform/proxmox/scripts/refresh-vm-access.sh new file mode 100755 index 0000000..4232e01 --- /dev/null +++ b/platform/proxmox/scripts/refresh-vm-access.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Zugang zu den GPU-VMs auffrischen (läuft auf ops, im Verzeichnis platform/proxmox/tofu, mit +# geladenem /root/.config/knaster/tofu.env). Nötig nach jedem VM-Neustart, solange die Gäste per +# DHCP ohne Reservierung laufen (D5): Adressen können wechseln (12.10. zwei VMs vertauscht). +# +# 1. aktuelle Adressen per qemu-guest-agent in den tofu-State holen (refresh-only) +# 2. ../ansible/inventory.generated.yml neu schreiben +# 3. Hostschlüssel über den Agenten lesen (Vertrauensweg Proxmox statt ssh-keyscan) und in +# ~/.ssh/known_hosts eintragen; vorher wartet das Skript, bis cloud-init fertig ist. +set -euo pipefail + +tofu apply -refresh-only -auto-approve -input=false -no-color >/dev/null +tofu output -raw ansible_inventory > ../ansible/inventory.generated.yml + +tofu output -json gpu_vms | python3 -c ' +import json, sys +for name, v in json.load(sys.stdin).items(): + if v["ipv4"]: + print(name, v["node"], v["vmid"], v["ipv4"]) +' | while read -r name node vmid ip; do + ssh -n "$node" "qm guest exec $vmid --timeout 900 -- cloud-init status --wait" >/dev/null || true + key=$(ssh -n "$node" "qm guest exec $vmid -- cat /etc/ssh/ssh_host_ed25519_key.pub" \ + | python3 -c 'import json, sys; print(json.load(sys.stdin)["out-data"].strip())') + ssh-keygen -R "$ip" >/dev/null 2>&1 || true + echo "$ip $key" >> ~/.ssh/known_hosts + echo "$name ($ip): $(ssh-keygen -lf <(echo "$ip $key") | awk '{print $2}')" +done diff --git a/platform/proxmox/scripts/trust-vm-hostkeys.sh b/platform/proxmox/scripts/trust-vm-hostkeys.sh deleted file mode 100755 index 0d40a01..0000000 --- a/platform/proxmox/scripts/trust-vm-hostkeys.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -# Hostschlüssel der GPU-VMs über den qemu-guest-agent lesen und in ~/.ssh/known_hosts eintragen -# (läuft auf ops, im Verzeichnis platform/proxmox/tofu). Vertrauensweg: Proxmox-API/Agent statt -# ssh-keyscan übers Netz. Wartet vorher, bis cloud-init in der VM fertig ist. -set -euo pipefail - -tofu output -json gpu_vms | python3 -c ' -import json, sys -for name, v in json.load(sys.stdin).items(): - if v["ipv4"]: - print(name, v["node"], v["vmid"], v["ipv4"]) -' | while read -r name node vmid ip; do - ssh -n "$node" "qm guest exec $vmid --timeout 900 -- cloud-init status --wait" >/dev/null || true - key=$(ssh -n "$node" "qm guest exec $vmid -- cat /etc/ssh/ssh_host_ed25519_key.pub" \ - | python3 -c 'import json, sys; print(json.load(sys.stdin)["out-data"].strip())') - ssh-keygen -R "$ip" >/dev/null 2>&1 || true - echo "$ip $key" >> ~/.ssh/known_hosts - echo "$name ($ip): $(ssh-keygen -lf <(echo "$ip $key") | awk '{print $2}')" -done