【协作式原创】自己动手写docker之run代码解析
预备知识: Linux命令
预备知识:namespace和cgroup(CentOS7.7)
一,exec替换进程映像
函数功能: 用exec函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID
例如:在shell命令行执行ps命令,实际上是shell进程调用fork复制一个新的子进程,在利用exec系统调用将新产生的子进程完全替换成ps进程。
- MNT namespace的go代码实现
启动一个bash进程,并且单独给予和父进程不同的mount namespace.
func main() {
cmd := exec.Command("/bin/sh") // 加载可执行文件/bin/sh到内存中并运行。
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWNS,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Printf("Run error:%v\n", err)
log.Fatal(err)
}
}
- 对应如下代码
构造一个命令,用于启动init进程。
func NewParentProcess(command string, tty bool) *exec.Cmd {
args := []string{"init", command}
cmd := exec.Command("/proc/self/exe", args...) // 指向同一个可执行文件。
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS |
syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC,
}
if tty {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
return cmd
}
urfave cli预备知识
准备工作
- 阿里云抢占式实例:centos7.4
- 每次实例释放后都要重新安装go
wget https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xf go1.13.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
source ~/.bash_profile
yum -y install nano
yum install git
git clone https://github.com/yudidi/go-docker.git
git branch -all
git checkout remotes/origin/ns
demo
理解为什么增加init命令和为什么挂载proc
1_no_proc
2_add_proc
3_add_proc_and_not_affect_host


demo-init源码
syscall.Exec启动进程和os/exec.Command启动进程的区别
Q: run和init到底启动了几个进程
A: 2个进程,一个运行go-docker run,一个运行go-docker init。

这些进程的ns
13864和父进程3911,1号进程均一致
13868和父进程13864不同

kill掉13864,不会影响13864的运行(这就是容器内的第一个进程)
[root@192 go-docker]# kill 13864
//
[root@192 go-docker]# ps -ef|grep 138
root 13868 1 0 10:27 pts/0 00:00:00 /proc/self/exe init /bin/sh
root 13962 1323 0 10:50 pts/1 00:00:00 grep --color=auto 138
// 13868进程仍在继续打印时间
所以13864进程不表示容器(杀死了他,子进程仍在打印时间,说明这两个进程没有依赖关系),容器本身就不是一个进程,容器只是描述一种边界,而ns就是实现这个边界的方法。
ns这个空间中,13864是第一个在该空间运行的进程。踩坑
[root@192 go-docker]# ./go-docker run --ti /bin/sh
{"level":"fatal","msg":"fork/exec /proc/self/exe: no such file or directory","time":"2020-03-06T08:24:23-05:00"}
原因: // TODO
运行之后关闭之后,centos的/proc就没有了
问题的原理
- Shared subtrees
https://segmentfault.com/a/1190000006912742
https://www.cnblogs.com/sparkdev/p/9424649.html
解决: mount -t proc proc /proc
demo-ns源码
main.go
package main
import (
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"os"
)
const usage = `go-docker`
func main() {
app := cli.NewApp()
app.Name = "go-docker"
app.Usage = usage
app.Commands = []cli.Command{
runCommand,
initCommand,
}
app.Before = func(context *cli.Context) error {
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.SetOutput(os.Stdout)
return nil
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
参考
【协作式原创】自己动手写docker之run代码解析的更多相关文章
- 《自己动手写docker》之namespace部门实验
动手写一遍,印象不一样! package main import ( "log" "os" "os/exec" "syscall& ...
- 【协作式原创】查漏补缺之Go并发问题(单核多核)
主要回答一下几个问题 1.单核并发问题 2.多核并发问题 2.几个不正确的同步案例 1.单核并发问题 先看一段go(1.11)代码: 单核CPU,1万个携程,每个携程执行100次+1操作, 思考n最终 ...
- 【协作式原创】查漏补缺之Go的slice基础和几个难点
[转载]队友博客 Q: 为啥要字节对齐的 https://www.nowcoder.com/discuss/57978 TODO: Q: go反汇编指令 go tool compile -S plan ...
- 【协作式原创】查漏补缺之乐观锁与悲观锁TODO
面试官:你了解乐观锁和悲观锁吗? 乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题. 悲观锁的实现方式是加锁,加锁既可以是对代码块加锁(如Java的synchronized关键字),也可以是 ...
- 【协作式原创】查漏补缺之Golang中mutex源码实现(预备知识)
预备知识 CAS机制 1. 是什么 参考附录3 CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是 ...
- 【协作式原创】查漏补缺之Golang中mutex源码实现
概览最简单版的mutex(go1.3版本) 预备知识 主要结构体 type Mutex struct { state int32 // 指代mutex锁当前的状态 sema uint32 // 信号量 ...
- 自己动手写一个编译器Tiny语言解析器实现
然后,上一篇文章简介Tiny词法分析,实现语言.本文将介绍Tiny的语法分析器的实现. 1 Tiny语言的语法 下图是Tiny在BNF中的文法. 文法的定义能够看出.INNY语言有以下特点: 1 程序 ...
- 【原创】自己动手写工具----XSmartNote [Beta 3.0]
一.前面的话 在动笔之前,一直很纠结到底要不要继续完成这个工具,因为上次给它码代码还是一年多之前的事情,参考自己动手写工具----XSmartNote [Beta 2.0],这篇博文里,很多园友提出了 ...
- 【原创】自己动手写控件----XSmartNote控件
一.前面的话 在上一篇博文自己动手写工具----XSmartNote [Beta 3.0]中,用到了若干个自定义控件,其中包含用于显示Note内容的简单的Label扩展控件,用于展示标签内容的labe ...
随机推荐
- The Reason Why Cosmetic Airless Bottles Are Widely Used
The contents of the Cosmetic Airless Bottles can be isolated from the air, to prevent the product ...
- 减轻集群负载、三种k8s 替代openstack的解决方案
减轻集群负载.三种k8s 替代openstack的解决方案 待办 https://news.ycombinator.com/item?id=17013779 kubevirt https://host ...
- curl模拟提交
function curl_post($url, $post){ $options = array( CURLOPT_RETURNTRANSFER =>true, CURLOPT_HEADER ...
- 数据库程序接口——JDBC——API解读第二篇——执行SQL的核心对象
结构图 核心对象 Statement Statement主要用来执行SQL语句.它执行SQL语句的步骤为: 第一步:创建statement对象. 第二步:配置statement对象,此步骤可以忽略. ...
- Go字符串
1. 字符串的声明是使用 package main import "fmt" func main() { /* Go中的字符串是一个字节的切片. 可以通过将其内容封装在“”中来创建 ...
- kafka集群搭建记录
本文记录搭建kafka搭建过程. 一.硬件机器介绍 192.168.183.195 master-node 192.168.183.194 data-node1 192.168.183.196 dat ...
- <好きになるなら> 歌詞
あー生意気なこと言ったあと 何故かしらぽつんとしてしまう あー偶然のふり待ちぶせた ゴメンネと素直に言えるかな 帰る道はいつもカナリア 変ねこのごろ自分の気持ちがよめない もうじき風の向きが変わりそう ...
- django template 模板
九.Template模板 Template 模板是根据view传过来数据在html展示的功能,典型python 模板jinjia2库提供丰富的上下文展示func 创建template位置在项目下与ap ...
- Foreach报错
List<String> a = new ArrayList<String>(); 2 a.add("1"); 3 a.add("2") ...
- Chrome无法从该网站添加应用,扩展程序和用户脚本
#开始 更新谷歌浏览器之后发现不能通过本地 crx文件安装离线插件了 网上找到的方法有两种 一个就是通过添加浏览器参数解决 但是这个方法我尝试之后失败了 第二个方法就是用工具安装 具体如何太麻烦了就没 ...