4.Namespaces
Linux Container Namespaces
There are several types of namespaces in containers, including:
PID Namespaces:
Network Namespaces:
Mount Namespaces:
User Namespaces:
UTS Namespaces:
PID namespaces are a Linux kernel feature that allow processes to have their own unique process identifier (PID) space, separate from the global PID space. This allows for the creation of multiple, isolated process hierarchies within a single host.
For example, consider a scenario where you want to run multiple instances of a web server on a single host, each with its own set of processes. Without PID namespaces, you would have to manually manage the PIDs of each instance to ensure that there are no conflicts between them.
With PID namespaces, you can simply create a new namespace for each instance of the web server, and the processes within each namespace will have their own unique PIDs, separate from the other instances. This makes it much easier to manage and isolate the processes of each instance.
To create a new PID namespace, you can use the “unshare” command, followed by the -pid
flag. For example:
$ unshare --pid bash
This will create a new bash shell within a new PID namespace, and any processes that you start within this shell will have their own unique PIDs within that namespace. You can verify this by running the “ps” command and observing the PIDs of the processes.
Namespaces are a way for containers to share a single kernel, but have their own set of resources and processes. This allows for multiple containers to run on a single host without conflicting with each other.
For example, if we have two containers running on a host, each with their own namespace for network resources, they will be able to use the same network interface, but will not be able to see or interact with each other’s network connections.
To demonstrate this, we can use the following commands:
First, create a namespace for network resources using the “ip netns” command:
# ip netns add container1
Now, create a veth pair (virtual Ethernet pair) to connect the namespace to the host:
# ip link add veth0 type veth peer name veth1
Assign veth1 to the namespace:
# ip link set veth1 netns container1
Bring up the veth pair:
# ip link set veth0 up
# ip netns exec container1 ip link set veth1 up
Now, assign an IP address to veth0:
# ip addr add 192.168.0.1/24 dev veth0
And assign an IP address to veth1 in the namespace:
# ip netns exec container1 ip addr add 192.168.0.2/24 dev veth1
ow, we can test connectivity between the host and the namespace by pinging the IP address assigned to veth1:
# ping 192.168.0.2
In this example, we created a namespace for network resources and connected it to the host using a veth pair. We were then able to assign IP addresses to each end of the pair and ping the IP address in the namespace from the host, demonstrating that the namespace is isolated from the host’s network resources.
Mount namespaces in containers allow for the creation of isolated environments for file systems. This means that each container has its own unique file system, separate from the host operating system and other containers.
For example, let’s say we have a container running a web server. Within this container, we have the necessary files and directories for the web server to run, such as HTML files and images.
Now, let’s say we want to run a second container that also has a web server, but with different HTML files and images. If we didn’t have mount namespaces, both containers would be sharing the same file system and could potentially overwrite or interfere with each other’s files.
However, with mount namespaces, each container has its own isolated file system. This allows us to run both web servers with different files and directories, without them affecting each other.
To create a mount namespace in a container, we can use the --mount
flag when running the container. For example:
$ docker run -d --name mycontainer --mount type=bind,source=/path/to/files,
target=/var/www/html nginx
This command creates a new container named “mycontainer” and mounts the directory at /path/to/files
from the host operating system to the /var/www/html
directory within the container. This allows the web server within the container to access and serve the files from the host operating system.
User Namespaces in containers allow the container to have its own independent user and group IDs, separate from the host system. This can be useful for providing isolation and security within the container, as well as allowing the container to run processes with different user and group permissions than the host system.
For example, let’s say we have a container running as the user appuser
with a user ID of 1000 and a group ID of 1000. Without User Namespaces, this user would have the same permissions as the user appuser
on the host system. However, with User Namespaces enabled, we can map the user and group IDs within the container to different IDs on the host system. For example, we could map the user ID 1000 within the container to the user ID 2000 on the host system. This would allow the container to run processes as user 2000 on the host system, while still appearing as user 1000 within the container.
To enable User Namespaces in a container, we can use the --userns
flag when starting the container. For example:
docker run --userns=host -it ubuntu
This will start a new container running the Ubuntu image, with User Namespaces enabled and mapped to the host system’s user and group IDs.
UTS namespaces allow containers to have their own hostname and domain name system (DNS) domain, separate from the host machine. This means that each container can have its own hostname and DNS domain, without affecting the host machine or other containers.
To demonstrate this with a hands-on example, we can create a container using Docker and specify a hostname for the container.
First, let’s create a container using the following command:
docker run -it --name my_container ubuntu
This will create a container named my_container
using the Ubuntu image. Now, let’s specify a hostname for this container using the -h
flag:
docker run -it --name my_container -h my_container_host ubuntu
Now, if we check the hostname of the container using the hostname
command, it will return my_container_host
. This hostname is specific to the container and is not the same as the host machine’s hostname.
We can also specify a DNS domain for the container using the --dns-domain
flag:
docker run -it --name my_container -h my_container_host --dns-domain
my_container_domain ubuntu
Now, if we check the DNS domain of the container using the “hostname -d” command, it will return “my_container_domain”. This DNS domain is specific to the container and is not the same as the host machine’s DNS domain.
By using UTS namespaces, we can give each container its own unique hostname and DNS domain, allowing them to be isolated and operate independently from the host machine and other containers.