Donnerstag, 16. Mai 2024

Containern - Praxis

Im ersten Teil habe ich die Installation einer LXD Umgebung beschrieben. Im zweiten Teil soll es um die weitere Konfiguration und den Umgang mit LXD Containern gehen: 

  • Zugriff auf die Container mittels Port Mapping, 
  • Hardware anbinden durch USB Port Mapping und Verwaltung, 
  • Backup und Zugriff auf den Speicher.

Es gibt eine gute grundlegende Doku, ich will nur ein paar praktische Versuche dokumentieren.

LXC Container sind System Container und es gibt deshalb keine oder kaum Images mit fertigen Applikationen. Aber welche Images kann man eigentlich laden? (siehe auch) So zeigen wir uns die verfügbaren Repositories an: 

lxc remote list

Ich denke zwei sind wichtig

lxc image list ubuntu:
lxc image list images:

Bei ubuntu referenziert man ein Image durch ubuntu:xx.yy für images: kann man sich die verfügbare Liste in Form der Referenzen so ausgeben lassen

lxc image list images: |\
awk -F'|' '{ print $2}' |\
sed '/^[[:space:]]*$/d' |\
awk -F'/' '{ print $1"/"$2 }' | sort | uniq | egrep -v 'more|ALIAS'

Mir fällt auf: es gibt ein fertiges openwrt Image.

Praxis mit Ports, USB Geräten und Speicher

Das sehr kleine Image 'openwrt' ist schnell getestet

lxc launch images:openwrt/23.05

Für den Zugriff auf die Web Oberfläche brauche ich ein Portweiterleitung für Port 80, der launch Befehl war ohne Angabe eines Namens, deswegen hat lxc einen zufälligen Namen erzeugt und ausgegeben. In meinem Beispiel 'closing-toucan'. Mit einer Zeile Code erzeugt man ein Device 'tcp80' für eine Portweiterleitung vom Host (listen) zum Container (connect):

CONTAINER=closing-toucan
port=80
lxc config device add ${CONTAINER} tcp${port} proxy listen=tcp:0.0.0.0:${port} connect=tcp:127.0.0.1:${port}

Damit ist die Weboberfläche von OpenWrt mit http://container-vm:80 erreichbar.

Wartungsfreundlicher: Profile 

Wir erzeugen analog zu oben ein Profile 'proxy-8083' mit einem Device hostport8083.

port=8083
lxc profile create proxy-${port}
lxc profile device add proxy-${port} hostport${port} proxy listen=tcp:0.0.0.0:${port} connect=tcp:127.0.0.1:${port}

Ich installiere FHEM in einem neuen Container entsprechend debian.fhem.de mit einem Script auf meinem GitHub.

CONTAINER=fhem
lxc launch ubuntu:22.04 ${CONTAINER}
lxc exec ${CONTAINER} -- sh -c "wget -O - https://raw.githubusercontent.com/heinz-otto/scripts/master/Bash/setupFhemEasy.sh | bash"

Das Profile dem Container hinzufügen

lxc profile add ${CONTAINER} proxy-8083

und der FHEM Container ist erreichbar http://container-vm:8083/

Tipp: Die Angabe listen=tcp:0.0.0.0:80 kann anstatt mit allen Interfaces 0.0.0.0 auch mit einer IP eines Interfaces erfolgen, falls der Host mehrere Netzwerkverbindungen hat. 

USB Gerät im Container fhem verwenden

Zwischenspiel

Da ich für diesen Artikel eine VM als LXD Host verwende, muss ich zunächst die Schnittstelle vom Host zur container-vm verbinden!

Am Host ist eine UART Bridge CP210x angeschlossen an deren seriellen Schnittstelle ein HM-MOD-RPI-PCB Modul für die Steuerung von Homematic Geräten verbunden ist. Host -> VM -> LXC -> (Docker).

Achtung: Linux inkrementiert die Device Nummer bei jedem Hot Plug! Das hier gezeigte Verfahren ist nur restart fest, wenn man die Device Nummer nach einem Neustart ermittelt und die USB Schnittstelle nicht im laufenden Betrieb neu steckt! 

Am Host kann man die USB Schnittstelle entweder in der GUI (virt-manager) oder in der Kommandozeile verbinden. (virt-xml --add-device --host-device, virsh attach-device)

Die Abfrage mit der Kommandozeile liefert mehr Informationen

lsusb

zeigt eine Liste. Interessant sind zwei Zahlenpärchen (im Beispiel rot und grün markiert):

Bus 001 Device 010: ID 0403:6001 Future Tech..., Ltd FT232 Serial (UART) IC
Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Bus 001 Device 003: ID 10c4:ea60 Silicon Labs CP210x UART Bridge

Aus dem rot markiertem Pärchen kann man die Device ID bilden. Die grün markierten Pärchen liefern die Vendor:Product ID.

Will man mehr über den Stick wissen, weil z.B. zwei Sticks mit einem CP210x angesteckt sind fragt serial/by-id ab (lsusb -s 001:004 -v funktioniert auch): 

ls -l /dev/serial/by-id/
lrwxrwxrwx 1 root root 13 Mai  5 13:17 usb-FTDI_FT232R_USB_UART_00000000-if00-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root 13 Mai  5 13:31 usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_cc35fc0cd4dbed119f0fed2d62c613ac-if00-port0 -> ../../ttyUSB2
lrwxrwxrwx 1 root root 13 Mai  4 23:35 usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0 -> ../../ttyUSB0

Ich möchte den Stick an USB2 eindeutig zuordnen, die Informationen liefert mir serial/by-path

ls -l /dev/serial/by-path/|grep USB

pci-0000:00:14.0-usb-0:1.2:1.0-port0 -> ../../ttyUSB1
pci-0000:00:14.0-usb-0:3:1.0-port0 -> ../../ttyUSB0
pci-0000:00:14.0-usb-0:4:1.0-port0 -> ../../ttyUSB2

Aus den rot und grün markierten Zahlen kann man die Nodedev ID bilden. 

Damit hat man für die drei Geräte jeweils drei mögliche hostdev Parameter (Device, Vendor:Product, Nodedev - ID), alle führen zum gleichen Ergebnis (--update bei laufender VM):

hostdev=<001.010|001.004|001.003>
hostdev=<0403:6001|10c4:ea60>
hostdev=<usb_1_1_2|usb_1_3|usb_1_4>
name=container-vm
virt-xml ${name} --add-device --host-device ${hostdev} --update

In der VM sollte jetzt die Schnittstelle als USB0 zu sehen sein: 

ls -lha /dev/ttyUSB?

Jede Variante hat ihre Eigenheit, keine Variante ist dauerhaft zuverlässig, da nicht alle notwendigen Informationen gespeichert werden!

  1. Die Device ID hängt von Zeit und Raum ab, Linux erhöht sie bei jedem Stecken und setzt sie zurück beim reboot.
  2. Die Vendor:Product ID ist nicht eindeutig genug wenn z.B. mehrere CP210x stecken.
  3. Die Nodedev ID ist eindeutig vom Steckplatz, sie liefert bei der Ausführung ein eindeutiges Ergebnis.

Stabile Verhältnisse hätte man bei der Konfiguration nach einem Neustart und ohne jede weitere Änderung. Eine Abhilfe kann hier eventuell die Arbeit mit udev-rules sein, bzw. bei jedem Start der VM müsste die Anbindung der USB Schnittstelle per Nodedev ID erfolgen. Vielleicht hilft dieses Script?

Welches Gerät zu einer VM verbunden ist, kann man so anzeigen

virsh dumpxml ${name} | xpath -e /domain/devices/hostdev

Oder auch so:

for vm in $(virsh list --name)
   do 
      echo "USB Devices connected to VM ${vm}"
      virsh qemu-monitor-command ${vm} --hmp 'info usb'
   done

ToDo: Man kann alle Informationen auch mit udevadm info -r -q all "/dev/ttyUSB0" abrufen.

USB Gerät zum LXD Container verbinden

Ich mache es gleich wieder mit einem Profil

lxc profile create forwardUSB0
lxc profile device add forwardUSB0 ttyUSB0 unix-char mode=0660 gid=20 path=/dev/ttyUSB0

Das Profil mit dem Container verbinden.

lxc profile add ${CONTAINER} forwardUSB0

Im LXC Container sollten wir jetzt die Schnittstelle als USB0 sehen:

lxc exec ${CONTAINER} -- ls -lha /dev/ttyUSB0

Damit konnte ich das HM-MOD-RPI-PCB Modul in FHEM einwandfrei in Betrieb nehmen.

define myHMUART HMUARTLGW /dev/ttyUSB0

Anmerkung: Der Device Name ttyUSB0 ist frei wählbar. Der Key path= setzt den Zielpfad, d.h. das Gerät wird als /dev/ttyUSB0 angelegt. Wird nur path= (oder nur source=) angegeben, wird source= und path= intern gleich gesetzt, d.h. /dev/ttyUSB0 auf dem Host wird mit /dev/ttyUSB0 im Container verbunden. Will man das anders verbinden, muss source= und path= angegeben werden. Will man einen Wert im Profile später ändern, kann man entweder alles editieren oder den Wert direkt setzen. 

lxc profile edit forwardUSB0
lxc profile device set forwardUSB0 ttyUSB0 source=/dev/ttyUSB0

Die Änderung wird geprüft und sofort wirksam.

Das nächste Beispiel wird durch die Definition der Profile vereinfacht.

Port und USB im docker Container verwenden

Dazu trenne ich die Weiterleitung zum Container fhem:

CONTAINER=fhem
lxc profile remove ${CONTAINER} proxy-8083
lxc profile remove ${CONTAINER} forwardUSB0

und verbinde die Profile mit dem 'docker' Container

CONTAINER=docker
lxc profile add  ${CONTAINER} proxy-8083
lxc profile add  ${CONTAINER} forwardUSB0

Den offiziellen Docker Container für fhem starten

CONTAINER=docker
lxc exec ${CONTAINER} -- sh -c "docker run -d --name fhem \
    -p 8083:8083 --device /dev/ttyUSB0 ghcr.io/fhem/fhem-minimal-docker"

Damit funktioniert der Zugriff auf fhem im docker Container und die USB Schnittstelle sollte ebenfalls funktionieren.

Speicher verwalten

Bei der Einrichtung der LXD Umgebung im ersten Teil haben wir einen Storagepool "pool_b" erzeugt. Aber wie groß und wo ist der eigentlich?

lxc storage show pool_b

Die Werte size und source beantwortet diese Frage. 1GiB ist reichlich wenig, da könnte man nicht einmal ein normales fhem docker image laden. Die Größe ist schnell geändert:

lxc storage set pool_b size=5GiB

Die folgenden Punkte habe ich noch nicht genau untersucht, die Dokumentation liest sich relativ einfach.

Analyse

Was ist jetzt alles "dran" an  einem Container?

lxc config show --expanded ${CONTAINER}

Ich glaube da fehlt noch einiges...

ToDo? 

Ein Volume kann man zwischen storage Pools kopieren oder verschieben.

Bei der Anlage des Pools kann durch die Option source= die Lage angegeben werden. Es können verschiedene Dateisysteme angelegt werden. Dokumentation

Ein Backup scheint auch relativ einfach.

Codebox zum kopieren

Code

Leerzeile

Linkliste

https://doc.opensuse.org/documentation/leap/virtualization/html/book-virtualization/cha-libvirt-config-virsh.html


Keine Kommentare:

Kommentar veröffentlichen