Exercise 1.5 - Namespaces

Return to Workshop

namespaces

Namespaces

Pid Namespace

PID namespaces allow processes in different containers to have the same PID, so each container can have its own init (PID1) process that manages various system initialization tasks as well as containers life cycle. Also, each container has its unique /proc directory. Note that from within the container you can monitor only 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. On the other hand, the host operating system is aware of processes running inside of the container, but assigns them different PID numbers.

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

sudo docker 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.

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 docker run -it --pid=host redhatgov/alpine ps aux
Host processes
1136 root       0:00 /sbin/agetty --keep-baud 115200 38400 9600 ttyS0 vt220
1137 root       0:00 /sbin/agetty --noclear tty1 linux
1320 root       0:00 rhnsd
2993 root       0:00 [kworker/0:1]
3067 root       0:00 [kworker/0:3]
3211 root       0:00 [kworker/u30:0]
3645 vpopmail   0:00 pickup -l -t unix -u
3849 root       0:00 [kworker/0:2]
4056 root       0:00 [kworker/u30:1]
4529 root       0:00 /usr/lib/systemd/systemd-machined
4559 root       0:00 sudo docker run -it --pid=host redhatgov/alpine ps aux
4560 root       0:00 /usr/bin/docker-current run -it --pid=host redhatgov/alpi
4564 root       0:00 /usr/lib/systemd/systemd-udevd
4593 root       0:00 [kdmflush]
4594 root       0:00 [bioset]
4597 root       0:00 [xfs-buf/dm-1]
4598 root       0:00 [xfs-data/dm-1]
4599 root       0:00 [xfs-conv/dm-1]
4600 root       0:00 [xfs-cil/dm-1]
4601 root       0:00 [xfs-reclaim/dm-]
4602 root       0:00 [xfs-log/dm-1]
4603 root       0:00 [xfs-eofblocks/d]
4604 root       0:00 [xfsaild/dm-1]
4605 root       0:00 /usr/lib/systemd/systemd-udevd
4608 root       0:00 /usr/lib/systemd/systemd-udevd
4609 root       0:00 ps aux
10538 root       0:00 /usr/sbin/lvmetad -f
10711 root       0:00 [dm_bufio_cache]
10874 root       1:04 /usr/bin/docker-current daemon --authorization-plugin=rhe
10880 root       0:04 [loop0]
10882 root       0:00 [loop1]
10884 root       0:00 [kdmflush]
10885 root       0:00 [bioset]
10886 root       0:00 [kcopyd]
10887 root       0:00 [bioset]
10888 root       0:00 [dm-thin]
10889 root       0:00 [bioset]
11527 root       0:00 /usr/libexec/docker/rhel-push-plugin
12622 root       0:00 /usr/sbin/crond -n
13170 root       0:03 node /usr/lib/node_modules/wetty/bin/wetty.js --sslkey /h
13193 root       0:00 /usr/sbin/sshd -D
24142 root       0:00 login -- ec2-user
24147 1000       0:00 -zsh
24725 root       0:00 udevadm monitor -u -s block
25323 root       0:00 udevadm monitor -u -s block
25513 root       0:00 udevadm monitor -u -s block
25948 root       0:00 udevadm monitor -u -s block
26095 root       0:00 udevadm monitor -u -s block
26250 root       0:00 udevadm monitor -u -s block
26825 root       0:00 udevadm monitor -u -s block
26915 root       0:00 udevadm monitor -u -s block
27422 root       0:00 udevadm monitor -u -s block
32327 root       0:00 [kworker/0:0]
32644 root       0:00 [kworker/u30:2]

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

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 docker 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 docker 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: docker0: <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 docker0
       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 docker0

--net=container:NAME_or_ID: Tells Docker to put this 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.

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 docker 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 docker 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 docker 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 docker 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