nsenter
root@pc-01:~# docker ps | grep busybox 807e1730775a busybox "sh" 5 hours ago Up 5 hours optimistic_hermann root@pcl-01:~# docker inspect 807e1730775a -f '{{.State.Pid}}' 2781180 root@pc-01:~# nsenter --target 2781180 --mount --uts --ipc --net --pid root@pc-01:/# ls bin boot dev etc home lib lost+found media mnt opt proc root run sbin snap srv sys tmp usr var root@pcl-01:/# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: tap0_kata: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UNKNOWN group default qlen 1000 link/ether c2:03:51:46:a8:8b brd ff:ff:ff:ff:ff:ff 136: eth0@if137: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever root@pc-01:/# exit logout root@pc-01:~# docker exec -it 807e1730775a sh / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel qlen 1000 link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever / #
Linux containers and namespaces
To demonstrate the namespaces managing a container, I'll use Podman to create a container from the UBI8:8.2 image from Red Hat Container Catalog. The container resides on a Red Hat Enterprise Linux (RHEL) 8.2 host. For the purpose of this article, the procps-ng
package is installed inside the container, which provides top
and ps
commands.
[root@workshop ~]# podman run --name namespace-demo -it registry.access.redhat.com/ubi8/ubi /bin/bash
In another terminal, use the runc
command to determine the process id associated with the new container.
[root@workshop ~]# runc list
ID PID STATUS BUNDLE CREATED OWNER
92585ccfd2d20c4bc7f03863d9b0a999eea18c91fb76f6333ef21171138beb83 7172 running /var/lib/containers/storage/overlay-containers/92585ccfd2d20c4bc7f03863d9b0a999eea18c91fb76f6333ef21171138beb83/userdata 2020-06-24T14:56:37.895046979Z root
The process id is 7172.
Use the lsns
command to list the namespaces associated with a given process.
[root@workshop ~]# lsns -p 7172
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 137 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 16
4026531837 user 137 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 16
4026532438 net 1 7172 root /bin/bash
4026532516 mnt 1 7172 root /bin/bash
4026532517 uts 1 7172 root /bin/bash
4026532518 ipc 1 7172 root /bin/bash
4026532519 pid 1 7172 root /bin/bash
Inspect the namespaces with nsenter
The nsenter
command expands to namespace enter
. It accepts different options to only enter the specified namespace.
Let's enter the network namespace to check the IP address and route table.
[root@workshop ~]# nsenter -t 7172 -n ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether ea:95:99:52:13:56 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.88.0.6/16 brd 10.88.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::e895:99ff:fe52:1356/64 scope link
valid_lft forever preferred_lft forever
Here, -t
is the target process id, and -n
refers to the network namespace.
[root@workshop ~]# nsenter -t 7172 -n ip route
default via 10.88.0.1 dev eth0
10.88.0.0/16 dev eth0 proto kernel scope link src 10.88.0.6
Next, I enter the process namespace to check the process details.
[root@workshop ~]# nsenter -t 7172 -p -r ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:56 pts/0 00:00:00 /bin/bash
root 135 0 0 16:55 ? 00:00:00 ps -ef
The -r
option sets the root directory to the top-level directory within the namespace so that the commands run in the context of the namespace.
[root@workshop ~]# nsenter -t 7172 -p -r top
The bash
command, which executes during podman run
, is the first process inside the namespace.
Enter the UTC namespace to check the hostname.
[root@workshop ~]# nsenter -t 7172 -u hostname
92585ccfd2d2
Modify the hostname within the namespace and verify the new name.
[root@workshop ~]# nsenter -t 7172 -u hostname namespace.enable.sysadmin
[root@workshop ~]# nsenter -t 7172 -u hostname
namespace.enable.sysadmin
Finally, enter all namespaces by using the -a
option.
[root@workshop ~]# nsenter -t 7172 -a
[root@namespace /]# df -h
Filesystem Size Used Avail Use% Mounted on
overlay 7.9G 6.3G 1.6G 80% /
tmpfs 64M 0 64M 0% /dev
tmpfs 1.9G 1.4M 1.9G 1% /etc/hosts
shm 63M 0 63M 0% /dev/shm
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
tmpfs 1.9G 0 1.9G 0% /proc/acpi
tmpfs 1.9G 0 1.9G 0% /proc/scsi
tmpfs 1.9G 0 1.9G 0% /sys/firmware
tmpfs 1.9G 0 1.9G 0% /sys/fs/selinux
Summary
Linux containers help with rapid application delivery and the use of DevOps practices. It is essential to make sure that those applications are secure, isolated, and resource-restricted. The nsenter
tool helps you understand the low-level details of a container. It also helps with troubleshooting issues with container orchestration and deployment.