预备知识: 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预备知识

准备工作

  1. 阿里云抢占式实例:centos7.4
  2. 每次实例释放后都要重新安装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就没有了

问题的原理

解决: 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)
}
}

参考

  1. nano在CentOS上的安装和使用
  2. 如何在 CentOS 8 上安装 Go
  3. 用go写一个docker#

【协作式原创】自己动手写docker之run代码解析的更多相关文章

  1. 《自己动手写docker》之namespace部门实验

    动手写一遍,印象不一样! package main import ( "log" "os" "os/exec" "syscall& ...

  2. 【协作式原创】查漏补缺之Go并发问题(单核多核)

    主要回答一下几个问题 1.单核并发问题 2.多核并发问题 2.几个不正确的同步案例 1.单核并发问题 先看一段go(1.11)代码: 单核CPU,1万个携程,每个携程执行100次+1操作, 思考n最终 ...

  3. 【协作式原创】查漏补缺之Go的slice基础和几个难点

    [转载]队友博客 Q: 为啥要字节对齐的 https://www.nowcoder.com/discuss/57978 TODO: Q: go反汇编指令 go tool compile -S plan ...

  4. 【协作式原创】查漏补缺之乐观锁与悲观锁TODO

    面试官:你了解乐观锁和悲观锁吗? 乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题. 悲观锁的实现方式是加锁,加锁既可以是对代码块加锁(如Java的synchronized关键字),也可以是 ...

  5. 【协作式原创】查漏补缺之Golang中mutex源码实现(预备知识)

    预备知识 CAS机制 1. 是什么 参考附录3 CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是 ...

  6. 【协作式原创】查漏补缺之Golang中mutex源码实现

    概览最简单版的mutex(go1.3版本) 预备知识 主要结构体 type Mutex struct { state int32 // 指代mutex锁当前的状态 sema uint32 // 信号量 ...

  7. 自己动手写一个编译器Tiny语言解析器实现

    然后,上一篇文章简介Tiny词法分析,实现语言.本文将介绍Tiny的语法分析器的实现. 1 Tiny语言的语法 下图是Tiny在BNF中的文法. 文法的定义能够看出.INNY语言有以下特点: 1 程序 ...

  8. 【原创】自己动手写工具----XSmartNote [Beta 3.0]

    一.前面的话 在动笔之前,一直很纠结到底要不要继续完成这个工具,因为上次给它码代码还是一年多之前的事情,参考自己动手写工具----XSmartNote [Beta 2.0],这篇博文里,很多园友提出了 ...

  9. 【原创】自己动手写控件----XSmartNote控件

    一.前面的话 在上一篇博文自己动手写工具----XSmartNote [Beta 3.0]中,用到了若干个自定义控件,其中包含用于显示Note内容的简单的Label扩展控件,用于展示标签内容的labe ...

随机推荐

  1. 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 ...

  2. 减轻集群负载、三种k8s 替代openstack的解决方案

    减轻集群负载.三种k8s 替代openstack的解决方案 待办 https://news.ycombinator.com/item?id=17013779 kubevirt https://host ...

  3. curl模拟提交

    function curl_post($url, $post){ $options = array( CURLOPT_RETURNTRANSFER =>true, CURLOPT_HEADER ...

  4. 数据库程序接口——JDBC——API解读第二篇——执行SQL的核心对象

    结构图 核心对象 Statement Statement主要用来执行SQL语句.它执行SQL语句的步骤为: 第一步:创建statement对象. 第二步:配置statement对象,此步骤可以忽略. ...

  5. Go字符串

    1. 字符串的声明是使用 package main import "fmt" func main() { /* Go中的字符串是一个字节的切片. 可以通过将其内容封装在“”中来创建 ...

  6. kafka集群搭建记录

    本文记录搭建kafka搭建过程. 一.硬件机器介绍 192.168.183.195 master-node 192.168.183.194 data-node1 192.168.183.196 dat ...

  7. <好きになるなら> 歌詞

    あー生意気なこと言ったあと 何故かしらぽつんとしてしまう あー偶然のふり待ちぶせた ゴメンネと素直に言えるかな 帰る道はいつもカナリア 変ねこのごろ自分の気持ちがよめない もうじき風の向きが変わりそう ...

  8. django template 模板

    九.Template模板 Template 模板是根据view传过来数据在html展示的功能,典型python 模板jinjia2库提供丰富的上下文展示func 创建template位置在项目下与ap ...

  9. Foreach报错

    List<String> a = new ArrayList<String>(); 2 a.add("1"); 3 a.add("2") ...

  10. Chrome无法从该网站添加应用,扩展程序和用户脚本

    #开始 更新谷歌浏览器之后发现不能通过本地 crx文件安装离线插件了 网上找到的方法有两种 一个就是通过添加浏览器参数解决 但是这个方法我尝试之后失败了 第二个方法就是用工具安装 具体如何太麻烦了就没 ...