Systemd nspawn - machinectl cannot open shell
With machinectl shell <container> you can open a login shell within a container very easily, but you must use systemd as init manager inside the container and you need a sufficiently modern version of systemd. Otherwise you run into the following error:
[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
Systemd uses namespaces for separation that are provided by recent linux kernel versions. It is possible to enter a namespace directly by using nsenter, you just need the process id (pid) of the container's init process:
[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
The container ve123's init pid is 1535 and it can be retrieved like this:
[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
Now you can create a login shell inside that container's namespace:
[root@c8-nspawn1 ~]# nsenter -t 1535 -a /bin/sh -l ve123:/#
With -a nsenter tries to use all namespaces. They can be listed individually as well using -{m,u,i,n,p,U,C}.
mshell bash function
In order to speed it up you can add a little function to your shell (bash in this example):
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 }
After your next shell login or manual reload of .bashrc you can enter a container very easily:
[root@c8-nspawn1 ~]# mshell ve122 Container not found [root@c8-nspawn1 ~]# mshell ve123 ve123:/#