

Linux namespace in Go - Part 1, UTS and PID
source link: https://songrgg.github.io/programming/linux-namespace-part01-uts-pid/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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
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.
// folder v1
package main
import (
"fmt"
"os"
"os/exec"
"syscall"
)
func main() {
exec.Command("/bin/bash")
cmd := exec.Cmd{
Path: "/bin/bash",
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
SysProcAttr: &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS,
},
}
if err := cmd.Run(); err != nil {
fmt.Println(err)
}
}
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.
[sojiang@ namespace-demo]$ hostname
sojiang.local
[sojiang@ namespace-demo]$ sudo go run exercise01/main.go
[root@ namespace-demo]# hostname
sojiang.local
[root@ namespace-demo]# hostname test.local
[root@ namespace-demo]# hostname
test.local
[root@ namespace-demo]# exit
exit
[sojiang@ namespace-demo]$ hostname
sojiang.local
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:
SysProcAttr: &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID,
},
Run the process again,
[sojiang@ namespace-demo]$ sudo go run exercise02/main.go
[root@ namespace-demo]$ ps -ef
sojiang 6820 4062 0 06:44 ? /bin/zsh -i
root 7561 ... sudo go run exercise02/main.go
[root@ namespace-demo]$ kill -9 6820
bash: kill: (6820) - No such process
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.
Reference
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK