Skip to content
/ mydocker Public

参考《自己动手写 docker》从零开始实现一个简易的 docker 以及相关教程。Build a simple Docker from scratch along with related tutorials.

License

Notifications You must be signed in to change notification settings

lixd/mydocker

 
 

Repository files navigation

mydocker

《自己动手写 docker》笔记和源码

建议先了解一下 Docker 的核心原理大致分析,可以看这几篇文章:

通过上述文章,大家对 Docker 的实现原理已经有了初步的认知,接下来我们就用 Golang 手动实现一下自己的 docker(mydocker)。

微信公众号:探索云原生

鸽了很久之后,终于开通了,欢迎关注。

一个云原生打工人的探索之路,专注云原生,Go,坚持分享最佳实践、经验干货。

扫描下面的二维码关注我的微信公众帐号,一起探索云原生吧~

实现 mydocker run 命令

搭配 从零开始写 Docker:实现 run 命令 食用更加~。


开发环境如下:

root@mydocker:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.2 LTS
Release:	20.04
Codename:	focal
root@mydocker:~# uname -r
5.4.0-74-generic

测试脚本如下:

# 克隆代码
git clone -b feat-run https://github.com/lixd/mydocker.git
cd mydocker
# 拉取依赖并编译
go mod tidy
go build .
# 测试
./mydocker run -it /bin/ls # 需要 root 权限

正常结果

root@mydocker:~/mydocker# ./mydocker run -it /bin/ls
{"level":"info","msg":"init come on","time":"2024-01-08T09:32:52+08:00"}
{"level":"info","msg":"command: /bin/ls","time":"2024-01-08T09:32:52+08:00"}
{"level":"info","msg":"command:/bin/ls","time":"2024-01-08T09:32:52+08:00"}
LICENSE  Makefile  README.md  container  example  go.mod  go.sum  main.go  main_command.go  mydocker  run.go
root@mydocker:~/mydocker# ./mydocker run -it /bin/sh
{"level":"info","msg":"init come on","time":"2024-01-08T09:32:54+08:00"}
{"level":"info","msg":"command: /bin/sh","time":"2024-01-08T09:32:54+08:00"}
{"level":"info","msg":"command:/bin/sh","time":"2024-01-08T09:32:54+08:00"}
# ps -e
    PID TTY          TIME CMD
      1 pts/1    00:00:00 sh
      5 pts/1    00:00:00 ps

代码分析

mydocker 的代码分为以下几个部分:

.
├── container
│   ├── container_process.go # 构建容器进程运行参数
│   └── init.go # 初始化容器进程,并执行容器进程
├── example
│   └── main.go # 单独的文件,可编译成独立的可执行文件, 一个 Go 中调用 namespace 和 Cgroups 的例子,不牵涉其他 go 文件
├── go.mod
├── go.sum
├── LICENSE
├── main_command.go # 命令行解析,包含两个部分 run 和 init
├── main.go # main 函数入口
├── Makefile
├── README.md
└── run.go # 启动子进程

下面介绍基本的执行流程:

当执行./mydocker run -it /bin/ls时,会先执行到 main_command.go::cli.Command::Action,在里面会提取出/bin/ls命令(被保存在cmd变量中),tty变量则是用于确定是否需要打开新终端。

之后会调用run.go::Run函数,该函数会调用container/container_process.go::NewParentProcess函数,构建子进程运行参数。在构建参数时,会指示创建新的namespaces. 之后run.go::Run函数启动子进程。在container/container_process.go::NewParentProcess中构建的子进程参数如下:/proc/self/exe init /bin/ls,表示要创建的子进程就是自身,只不过要执行的命令是init,参数是/bin/ls

在新创建的子进程中,mydocker会执行到main_command.go::cli.Command::Action,这里会调用container/init.go::RunContainerInitProcess函数。在该运行函数中,会挂在相应的目录,最后会执行/bin/ls命令。

About

参考《自己动手写 docker》从零开始实现一个简易的 docker 以及相关教程。Build a simple Docker from scratch along with related tutorials.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published