• systemd-nspawn / machinectl

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
ve123   container systemd-nspawn -  -…

[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
           │ ├─1535 /sbin/init
           │ ├─1734 /sbin/syslogd -t
           │ └─1850 /sbin/getty 38400 console
             └─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

[root@c8-nspawn1 ~]# head -2 /sys/fs/cgroup/pids/machine.slice/systemd-nspawn@ve123.service/cgroup.procs | tail -1

Now you can create a login shell inside that container's namespace:

[root@c8-nspawn1 ~]# nsenter -t 1535 -a /bin/sh -l

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
Data protection info | Help us to optimize this site and allow cookies please - insights will not be passed on to third parties.
Decline Accept