Linux namespace in Go - Part 1, UTS and PID
This article starts some Golang experiments on Linux namespace and provides context for Container technology. Linux namespace is an important foundation of container technology, it provides lightweight isolation between processes with Linux kernel support, therefore, different services can share the same machine with better resource utilization, great security.
The series of Linux namespace in Go:
- Linux namespace in Go - Part 1, UTS and PID
- Linux namespace in Go - Part 2, UID and Mount
- Linux namespace in Go - Part 3, Cgroups resource limit
Linux namespace
There’s a definition from Linux manual introducing Linux namespace:
A namespace wraps a global system resource in an abstraction that makes it appear to the processes within the namespace that they have their own isolated instance of the global resource. Changes to the global resource are visible to other processes that are members of the namespace, but are invisible to other processes.
So, Linux namespace is the key that we can control the resources the processes can access.
Namespace types
What kind of isolation could we control is decided by the namespace types.
- UTS
Hostname and NIS domain name - Cgroup
Controls the system resources (like CPU, Memory…) the process can use. - IPC
POSIX message queues - Network
Network devices, stacks, ports, etc. - Mount
Mount points - PID
Process IDs - Time
Boot and monotonic clocks - User
User and group IDs
“Go” through these types
Note that Linux namespace is only available in Linux distributions, I use Ubuntu 20.04 and Golang 1.14.2 here to run the experiments. If you’re using other OS, you might find the Linux namespace libraries missing, go and find a Linux machine and Ubuntu is recommended.
Note: The experiments code can be found in https://github.com/songrgg/namespace-demo
UTS Namespace
UTS will isolate the hostname for the forked process from its caller.
1 | // folder v1 |
This script needs sudo
permission, run sudo go run main.go
and it will create a new bash process with a new UTS namespace, you could modify hostname within this namespace and it won’t change the outside’s hostname.
1 | [sojiang@ namespace-demo]$ hostname |
PID namespace
PID namespace would create a new namespace for the process where the process ID is the same as the parent process, but note that you can only operate the processes under your namespace and can’t operate the processes in the parent namespace, in the opposite, the parent namespace has permission to operate the processes under the child namespaces.
Create a PID namespace simply by adding a CLONE_NEWPID
flag:
1 | SysProcAttr: &syscall.SysProcAttr{ |
Run the process again,
1 | [sojiang@ namespace-demo]$ sudo go run exercise02/main.go |
In the ps -ef
output, we could see zsh
which runs in the parent namespace and go run exercise02/main.go
is running in the process’s namespace. We call the parent namespace P
and the child namespace C
, if we run sleep 100
in P
, use ps -ef
to get the process id and run kill -9 <process-id>
in C
, it will output “process not exist”. In the opposite, we could kill the process in C
, that’s because the process visibility is in a single direction, only parent namespace could see all the processes in both P
and C
.
Like the following picture, pid 1 is in the parent namespace of pid Namespace x, so pid 1 could see all the processes, pid 3 could only see pid 3, pid 5 and pid 5.
What’s next?
Here I did experiments on Linux UTS and PID namespaces, we know the isolation mechanism of them. I still have several questions,
- How to run the program as other user instead of root?
- I can still see the process list by
ps -ef
in the child namespace, however, most of the processes are in the parent namespace, there’s no need for me to see them, how to hide them or have my own process list?
The answer is in the Linux namespace in Go - Part 2, UID and Mount.