Systemd nspawn - machinectl cannot open shell
Mit machinectl shell <container> lässt sich auf einfache Weise eine shell innerhalb eines Containers starten. Das funktioniert allerdings nur wenn systemd als Init-Manager verwendet wird und die Version aktuell genug ist. Andernfalls wird folgender Fehler zurückgeliefert:
[root@c8-nspawn1 ~]# machinectl list MACHINE CLASS SERVICE OS VERSION ADDRESSES ve123 container systemd-nspawn - - 192.168.4.2… [root@c8-nspawn1 ~]# machinectl shell ve123 Failed to get shell PTY: Protocol error
Um die Abschottung zu realisieren verwendet systemd Namespaces, die vom Linuxkernel bereitgestellt werden. Dadurch ist es alternativ möglich mit nsenter in den Namespace des Containers zu wechseln. Benötigt wird dazu die Prozess-ID (PID) des Init-Prozesses innerhalb des Containers:
[root@c8-nspawn1 ~]# systemctl status systemd-nspawn@ve123 ● systemd-nspawn@ve123.service - Container ve123 Loaded: loaded (/usr/lib/systemd/system/systemd-nspawn@.service; disabled; vendor preset: disabled) Active: active (running) since Sun 2021-01-24 00:22:39 CET; 6 days ago Docs: man:systemd-nspawn(1) Main PID: 1533 (systemd-nspawn) Status: "Container running." Tasks: 4 (limit: 16384) Memory: 2.4M CGroup: /machine.slice/systemd-nspawn@ve123.service ├─payload │ ├─1535 /sbin/init │ ├─1734 /sbin/syslogd -t │ └─1850 /sbin/getty 38400 console └─supervisor └─1533 /usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth -U --settings=override --machine=ve123
Die PID von init im Container ve123 ist 1535. Diese kann man auch wie folgt auslesen:
[root@c8-nspawn1 ~]# cat /sys/fs/cgroup/pids/machine.slice/systemd-nspawn@ve123.service/tasks 1533 1535 1734 1850 [root@c8-nspawn1 ~]# head -2 /sys/fs/cgroup/pids/machine.slice/systemd-nspawn@ve123.service/cgroup.procs | tail -1 1535
Eine Loginshell lässt sich folgendermaßen öffnen:
[root@c8-nspawn1 ~]# nsenter -t 1535 -a /bin/sh -l ve123:/#
Dabei versucht -a alle Namespaces einzubinden, sie können mit -{m,u,i,n,p,U,C} aber auch individuell genannt werden.
Bash Funktion mshell
Um die ganzen Schritte abzukürzen kann man der Shell (hier am Beispiel bashrc) eine kleine Funktion hinzufügen:
function mshell () { [ -z "$1" ] && { echo "Usage: mshell <veid>" >&2; return 1; } pid=$(head -q -n 2 "/sys/fs/cgroup/pids/machine.slice/systemd-nspawn@$1.service/cgroup.procs" 2>/dev/null | tail -1) [ -z "$pid" ] && { echo "Container not found" >&2; return 1; } nsenter -t $pid -a /bin/sh -l }
Nach dem nächsten Login oder manuellem Laden der .bashrc kann man einfach in den Container wechseln:
[root@c8-nspawn1 ~]# mshell ve122 Container not found [root@c8-nspawn1 ~]# mshell ve123 ve123:/#