Create Your Own Container Using Linux Namespaces Part-1.

Devesh Sharma
Opstree
Published in
3 min readApr 14, 2020

In this lock-down, everyone has to maintain a social distance and in this trying time, we can learn from docker to isolate ourselves. So before that, we need to learn how docker does it?
The best approach to learn is to simulate it. For that, we’ll be creating our own container tool for the application to isolate itself.

Technology docker uses

Linux Namespaces:-

The namespace is technology is behind most of the modern-day container’s tools like docker, rkt, LXC. For providing isolation for the process.

7 namespace we use to create container.:-

  • Mount — isolate filesystem mount points
  • UTS — isolate hostname and domainname
  • IPC — isolate interprocess communication (IPC) resources
  • PID — isolate the PID number space
  • Network — isolate network interfaces
  • User — isolate UID/GID number spaces
  • Cgroup — limit a resource usage (CPU, memory, disk I/O, network, etc.).

Above namespace is to provide a high level of Isolation.

This blog, I’m trying to cover namespace to create a container in golang.

Why Golang?

I pick golang because of the fact that Docker has written in golang and it provides low-level interface. Why docker go with Golang? Check there.

Namespace System calls.

So we will use 3 system call: -

1. Clone:- creates a new process

2. Setns:- allows the calling process to join an existing namespace

3. Unshare:- moves the calling process to a new namespace

Golang code for creating container.

</p>package mainimport ("path/filepath""fmt""os""os/exec""syscall""github.com/docker/docker/pkg/reexec")func main() {type SysProcIDMap struct {ContainerID intHostID      intSize        int}var rootfsPath string
cmd := reexec.Command("nsInitialisation", rootfsPath)
cmd = exec.Command("/bin/bash")cmd.Stdout = os.Stdoutcmd.Stdin = os.Stdincmd.Stderr = os.Stderr
cmd.Env = []string{"PS1=-[ns-process]- # "}
cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWUTS |syscall.CLONE_NEWNS |syscall.CLONE_NEWIPC |syscall.CLONE_NEWNET |syscall.CLONE_NEWPID |syscall.CLONE_NEWUSER,UidMappings: []syscall.SysProcIDMap{{ContainerID: 0,HostID: os.Getuid(),Size: 1,},},GidMappings: []syscall.SysProcIDMap{{ContainerID: 0,HostID: os.Getgid(),Size: 1,},},}if err := cmd.Run(); err != nil {fmt.Printf("Error running the /bin/bash command %s\n", err)os.Exit(1)}}<p>

CLONE_NEWUTS syscall:-

CLONE_NEWUTS is set, then create the process in a new UTS namespace. it creates new hostname UTS namespaces only has Only a privileged process (CAP_SYS_ADMIN).

CLONE_NEWNS syscall:-

CLONE_NEWNS is started in a new mount namespace. we have to mount file system. For that we will use pivot_root I.e. it allows you to change what /.

</p>func pivotRoot(newroot string) error {putold := filepath.Join(newroot, "/.pivot_root")if err := syscall.Mount(newroot,newroot,"",syscall.MS_BIND|syscall.MS_REC,"",); err != nil {return err}// Create old put Directoryif err := os.MkdirAll(putold, 0700); err != nil {return err}if err := syscall.PivotRoot(newroot, putold); err != nil {return err}if err := os.Chdir("/"); err != nil {return err}putold = "/.pivot_root"if err := syscall.Unmount(putold,syscall.MNT_DETACH,); err != nil {return err}if err := os.RemoveAll(putold); err != nil {return err}return nil}<p>

CLONE_NEWUSER syscall:-

CLONE_NEWUSER is set, then create the process in a new user namespace. The User namespace provides isolation of UIDs and GIDs.

CLONE_NEWIPC syscall:-

CLONE_NEWIPC is set, then create the process in a new IPC namespace.

CLONE_NEWPID syscall:-

Mounting new /proc, running process inside the namespace. This is because ps relies on /proc to detect running processes and we were still referencing the host’s /proc.

</p>func mountProc(newroot string) error {source := "proc"target := filepath.Join(newroot, "/proc")fstype := "proc"flag := 0data := ""os.MkdirAll(target, 0755)if err := syscall.Mount(source,target,fstype,uintptr(flag),data,); err != nil {return err}return nil}<p>

You can go with code: https://github.com/Deveshs23/mycontainer/

In the Next part, We will focus on the Namespace network and create some basic functions of docker and also talk about reexec.

Summary:-

In this blog, we have some basic containerize tools.

Reference Links:-

https://knowyourmeme.com/photos/1789334-spongebob-squarepants https://dribbble.com/shots/5823662-Isolation medium.com/@teddyking/linux-namespaces-850489d3ccf

Originally published at http://blog.opstree.com on April 14, 2020.

--

--