Exercise 1.5 - Namespaces

Return to Workshop

namespaces

Exercise 1.5 - Namespaces

Exercise Description

In this exercise, we will examine how to use namespaces to manage initialization processes, in multiple containers.

PID namespaces enable processes in different containers to have the same PID (process identifier). This means each container can have its own init (PID1) process that manages various system initialization tasks, as well as the container life cycle.

Also, each container has its unique /proc directory. Note that from within the container, you can only monitor those processes running inside this container. In other words, the container is only aware of its native processes and can not "see" the processes running in different parts of the system. It is the host operating system that is aware of processes running inside of the container, but assigns them different PID numbers.

Section 1: Launching a container

Launch a container in it’s own namespace and see what process it can see from inside the container.

sudo podman run -it redhatgov/alpine ps aux
Container processes
PID   USER     TIME   COMMAND
  1   root     0:00   ps aux   (1)
1 The only process we can see is just our last command ps aux.

Section 2: Enable namespace Sharing

Containers can share namespaces with other containers. This has to be explicitly set to enable sharing. To enable namespace sharing we will use the --pid flag to assign the namespace you want to share.

sudo podman run -it --pid=host redhatgov/alpine ps aux
Host processes
PID   USER     TIME  COMMAND
...
  624 root      0:00 /sbin/dhclient -d -q -sf /usr/libexec/nm-dhcp-helper -pf /var/run/dhclient-eth0.pid -lf /var/lib/NetworkManager/dhclient-5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03-eth0.lease -cf /var/lib/NetworkManager/dhclient-eth0.co
  837 root      0:01 {tuned} /usr/bin/python2 -Es /usr/sbin/tuned -l -P
  838 root      0:00 /usr/libexec/docker/rhel-push-plugin
 1108 root      0:00 /usr/libexec/postfix/master -w
 1114 vpopmail  0:00 qmgr -l -t unix -u
 1138 root      0:00 /usr/sbin/sshd -D
 1142 root      0:00 /usr/sbin/rsyslogd -n
 1147 root      0:00 /usr/sbin/crond -n
 1148 root      0:00 /sbin/agetty --noclear tty1 linux
 1149 root      0:00 /sbin/agetty --keep-baud 115200,38400,9600 ttyS0 vt220
 1203 root      0:00 rhnsd
 1276 root      0:08 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --authorization-plugin=rhel-push-plugin --exec-opt native.cgroupdriver=systemd --userland-pr
 1324 root      0:05 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containe
 6879 root      0:00 [kworker/0:0]
 8963 vpopmail  0:00 pickup -l -t unix -u
 8991 root      0:00 [kworker/0:1]
 9072 root      0:00 [kworker/0:3]
 9101 root      0:00 [kworker/u30:1]
 9257 996       0:22 /usr/libexec/cockpit-ws
 9271 root      0:00 /usr/libexec/cockpit-session localhost
 9276 1000      0:00 /usr/bin/ssh-agent
 9278 1000      5:40 cockpit-bridge
 9291 1000      0:00 dbus-daemon --print-address=9 --session
 9310 root      0:00 /usr/lib/systemd/systemd-timedated
 9320 root      0:01 {atomic_dbus.py} /usr/bin/python2 -Es /usr/share/atomic/atomic_dbus.py
 9343 root      0:00 /usr/bin/sudo -A cockpit-bridge --privileged
 9345 root      0:00 cockpit-bridge --privileged
 9448 root      0:00 udevadm monitor -u -s block
 9602 root      0:00 [kworker/u30:0]
 9679 root      0:00 [kworker/0:2]
 9927 root      0:00 sudo podman run -it --pid=host redhatgov/alpine ps aux
 9929 root      0:00 podman run -it --pid=host redhatgov/alpine ps aux
 9939 root      0:00 /usr/lib/systemd/systemd-udevd
 9987 root      0:00 /usr/bin/conmon --api-version 1 -s -c f3ee27c9798689f1e4b4597336163efbf2550513a80d404f31a6b8d0d7cd0370 -u f3ee27c9798689f1e4b4597336163efbf2550513a80d404f31a6b8d0d7cd0370 -r /usr/bin/runc -b /var/lib/containers/st
 9997 root      0:00 ps aux
11174 1000      0:00 /bin/bash
11579 root      0:00 /usr/libexec/cockpit-session localhost
11584 1000      0:00 /usr/bin/ssh-agent
11586 1000      5:43 cockpit-bridge
11600 1000      0:00 dbus-daemon --print-address=9 --session
11608 root      0:00 /usr/bin/cockpit-bridge --privileged
20803 root      0:03 /usr/bin/registry serve /etc/docker-distribution/registry/config.yml
21132 1000      0:00 /bin/bash
22868 root      0:00 udevadm monitor -u -s block
23107 root      0:00 udevadm monitor -u -s block
23310 root      0:00 udevadm monitor -u -s block
23461 root      0:00 udevadm monitor -u -s block
23580 root      0:00 udevadm monitor -u -s block
23601 root      0:00 sudo -i
23603 root      0:00 -bash
23762 root      0:00 udevadm monitor -u -s block
23818 root      0:00 [kworker/u30:2]
24212 root      0:00 udevadm monitor -u -s block

As you can see we now have access to all of the processes running on host system by using the --pid flag.

Section 3: Network Namespace

Network namespaces provide isolation of network controllers, system resources associated with networking, firewall and routing tables. This allows container to use separate virtual network stack, loopback device and process space. You can add virtual or real devices to the container, assign them their own IP Addresses and even full iptables rules.

Network namespaces allow containers to be created with unique IP address and interfaces. Let’s run a container and examine the default container network interface.

sudo podman run -it redhatgov/alpine ip addr show
Container network
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1               (1)
    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
50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP  (2)
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link tentative
       valid_lft forever preferred_lft forever
1 Loopback
2 eth0

By default a container’s network is isolated with it’s own IP and interface. By changing the namespace to host by using the --net flag, the process will have access to the host machines network interface.

sudo podman run -it --net=host redhatgov/alpine ip addr show
Host network
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1                (1)
    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 9001 qdisc pfifo_fast state UP qlen 1000   (2)
    link/ether 0e:d1:08:25:e2:78 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.246/24 brd 10.0.2.255 scope global dynamic eth0
       valid_lft 3076sec preferred_lft 3076sec
    inet6 fe80::cd1:8ff:fe25:e278/64 scope link
       valid_lft forever preferred_lft forever
3: cni-podman0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN         (3)
    link/ether 02:42:c7:e8:36:fb brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global cni-podman0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c7ff:fee8:36fb/64 scope link
       valid_lft forever preferred_lft forever
1 Loopback
2 eth0
3 cni-podman0

--net=container:NAME_or_ID: This puts the container’s processes inside of the network stack that has already been created inside of another container. The new container’s processes will be confined to their own filesystem and process list and resource limits, but will share the same IP address and port numbers as the first container, and processes on the two containers will be able to connect to each other over the loopback interface.

Note: --net="host" gives the container full access to local system services such as D-bus and is therefore considered insecure.

Section 4: Sharing Network Namespaces

Containers have a default security model that enforces isolation at the kernel level for process separation as well as network separation between containers. Sometimes you may need to debug a application or container and need to attach or share a containers namespace. Sharing namespaces should only be done in certain situations that require it, but for development it may be appropriate for debugging.

Let’s examine how we can share the networking namespace between containers. We will launch a nginx container that will bind to port 80 inside it’s container network interface.

sudo podman run -d --name http nginx:alpine

Now that we have the Nginx container running in the background as a daemon (-d) we will launch a second container and see if we can use curl to connect to the Nginx container.

sudo podman run --rm redhatgov/fedora curl -s localhost
$

Should return nothing. Because the namespace is not shared.

Now let’s use the --net=container: flag to attach to the http containers network interface and try the curl command again.

sudo podman run --rm --net=container:http redhatgov/fedora curl -s localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>                               (1)
<p>If you see this page, the nginx web server is
successfully installed and working. Further
configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
1 Welcome to nginx! This is the default Nginx message and shows that we were able to share a namespace to connect to this container.

It can also see and interface with the processes in the shared container.

sudo podman run --pid=container:http alpine ps aux
PID   USER     TIME   COMMAND
  1   root     0:00   nginx: master process nginx -g daemon off;  (1)
  5   100      0:00   nginx: worker process                       (2)
  6   root     0:00   ps aux
1 Nginx master process
2 Nginx worker process

This is useful for debugging tools, such as strace. This allows you to give more permissions to certain containers without changing or restarting the application.


Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop