不吹牛,50行Go代码,编写一个简单的容器


不吹牛,50行Go代码,编写一个简单的容器

前面的十几篇文章分别介绍了各种namespace和pivot_root的使用,下面将通过一个简单例子将他们组合成一个容器。首先还是和RUNC一样构建一个rootfs(docker export $(docker create busybox) | tar -C rootfs -xvf -)。在ubuntu 14.04系统上,编译并运行下面程序:

package main
import (
	"fmt"
	"os"
	"os/exec"
	"syscall"
)
func main() {
	switch os.Args[1] {
	case "run":
		parent()
	case "child":
		child()
	default:
		panic("wat should I do")
	}
}

func parent() {
	cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		fmt.Println("ERROR", err)
		os.Exit(1)
	}
}
func child() {
	must(syscall.Mount("rootfs", "rootfs", "bind", syscall.MS_BIND|syscall.MS_REC, ""))
	must(os.MkdirAll("rootfs/.oldrootfs", 0700))
	must(syscall.PivotRoot("rootfs", "rootfs/.oldrootfs"))
	must(os.Chdir("/"))

	cmd := exec.Command(os.Args[2], os.Args[3:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("ERROR", err)
		os.Exit(1)
	}
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}

大部分代码之前文章分享的时候已经零散介绍了,这里只是组装了一下。但有个特殊的小细节:当执行run命令后,程序调用自己(/proc/self/exe指向程序本身)child命令重新执行并设置各种namespace,切换root目录,从而创建出一个新的容器。

展开阅读全文

页面更新:2024-05-17

标签:容器   代码   简单   组合   篇文章   零散   例子   细节   命令   目录   程序   系统   文章   科技

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top