自己动手写Docker
2020-11-06 15:35:05 19 举报
AI智能生成
自己动手写docker
作者其他创作
大纲/内容
0、GitHub地址
https://github.com/xianlubird/mydocker
1、Docker基础技术
1、namespace, cgroup,ufs 详解
2、额外技术-内核升级
2、Docker技术实现
1、构造容器
1、Linux proc 文件系统介绍
/proc/N PID 的进程信息
/proc/N/cmdline 进程启动命令
/proc/N/cwd 链接到进程当前工作目录
/proc/N/environ 进程环境变量列表
/proc/N/exe 链接到进程的执行命令文件
/proc/N/fd 包含进程相关的所有文件描述符
/proc/N/maps 与进程相关的内存映射信息
/proc/N/mem 指代进程持有的内存,不可读
/proc/N/root 链接到进程的根目录
/proc/N/stat 进程的状态
/proc/N/statm 进程使用的内存状态
/proc/N/status 进程状态信息,比 stat/statm 更具可读性
/proc/self/ 链接到当前正在运行的进程
/proc/N/cmdline 进程启动命令
/proc/N/cwd 链接到进程当前工作目录
/proc/N/environ 进程环境变量列表
/proc/N/exe 链接到进程的执行命令文件
/proc/N/fd 包含进程相关的所有文件描述符
/proc/N/maps 与进程相关的内存映射信息
/proc/N/mem 指代进程持有的内存,不可读
/proc/N/root 链接到进程的根目录
/proc/N/stat 进程的状态
/proc/N/statm 进程使用的内存状态
/proc/N/status 进程状态信息,比 stat/statm 更具可读性
/proc/self/ 链接到当前正在运行的进程
2、实现Run命令, 类似 docker run -it busybox [command]
1、使用 /proc/self/exe 调用自身进初始化行命名空间clone,挂载必要的proc 等
2、使用linux exec技术, 它的作用是执行filename对应的程序。它
会覆盖当前进程的镜像、数据、堆械等信息;相当于替代当其父进程的内容
会覆盖当前进程的镜像、数据、堆械等信息;相当于替代当其父进程的内容
3、资源限制 cgroups
已知知识点
1、cgroup hierarchy 中的节点,用于管理进程和 subsystem 的控制关系。
2、subsystem 作用于 hierarchy 上的 cgroup节点,并控制节点中进程的资源占用。
3、hierarchy 将 cgroup 通过树状结构串起来,并通过虚拟文件系统的方式暴露给用户。
2、subsystem 作用于 hierarchy 上的 cgroup节点,并控制节点中进程的资源占用。
3、hierarchy 将 cgroup 通过树状结构串起来,并通过虚拟文件系统的方式暴露给用户。
大致实现,如memory
1、 找到memory系统的 hierarchy /sys/fs/cgroup/memory/ ,建立自己进程名字的目录, 如 /sys/fs/cgroup/memory/mydocker
2、设置memory.limit_in_bytes 数值
3、将自己的pid 加入到目录下的tasks 文件中,即可生效限制memory
4、管道技术
1、为什么需要使用管道技术?
主要是为了command 参数的传输,如果用户输入一个很长的参数(超过4K)或者特殊字符则可能传参失败;
2、如何使用管道技术?
1、一个进程默认会有三个文件描述符,分别是标准输入、标准输出、标准错误。这
是子进程创建的时候就会默认带着的,其实还有一个外带的文件描述符第四个文件描述符;一般用于传送本进程的参数;
是子进程创建的时候就会默认带着的,其实还有一个外带的文件描述符第四个文件描述符;一般用于传送本进程的参数;
2、原理:本进程会拥有该文件描述符的写管道,其启动的子进程会拥有该描述符的读管道,那么子进程只需打开自己的第3索引文件描述符(即第四个文件描述符号,索引从0开始计算)就可以获取到读管道,从而读取其参数;
3、部分源码
1、父进程
2、子进程
2、构建镜像
1、获取完整镜像
1、docker run -it -d busybox top -b
2、docker export -o busybox.tar [contianerID]
3、mkdir busybox; tar xvf busybox.tar -C busybox
2、构造镜像基本要素
1、当前进程拥有完整的文件系统
2、需要挂载proc,以保证应用程序可以调用/访问系统内核
3、建立虚拟内存文件系统 tmpfs,供系统使用
3、进程如何拥有完整的文件系统 ?
1、使用pivot_root
* pivot_root和chroot的主要区别是,pivot_root主要是把整个系统切换到一个新的root目录,而移除对之前root文件系统的依赖,这样你就能够umount原先的root文件系统。而chroot是针对某个进程,而系统的其它部分依旧运行于老的root目录
* pivot_root和chroot的主要区别是,pivot_root主要是把整个系统切换到一个新的root目录,而移除对之前root文件系统的依赖,这样你就能够umount原先的root文件系统。而chroot是针对某个进程,而系统的其它部分依旧运行于老的root目录
4、使用aufs 挂载目录
大致挂载方式和之前的详解是一样的
代码实现参考 git checkout code-4.4
5、打包镜像
使用tar命令,把aufs 的读写挂载层内容进行打包
3、构建容器进阶
1、实现容器后台允许
在执行init进程后,调用需执行的命令立刻退出即可,从而产生孤儿进程系统会接手这种孤儿进程;这样就实现容器挂在后台
2、实现查看运行中的容器(需记录容器)
3、实现查看容器日志
把标准输出打到对应的记录文件即可
4、实现进入容器namespacce
setns
cgo
5、实现停止容器
6、实现删除容器
7、实现通过容器制作镜像
通过打包挂载层,即容器内可读写的层内容
详解:前面说过ufs,是分读层和写层,镜像层都为readonly, 然后建立一个临时的写层,并将其挂载到容器(即进程)内
8、实现容器指定环境变量运行
需记录容器init 进程号,通过/proc/{PID}/environ 获取到容器进程的环境变量,然后复制给即将运行的 exec 进程,从而达到指定环境变量运行
4、容器网络
1、Linux 虚拟网络设备
Linux Veth 是成对出现的虚拟网络设备,发送到veth 一端虚拟设备请求会从另一端的虚拟设备中发出。
创建两个网络namepsace
设置网络路由
2、Linux Bridge
Bridge 虚拟设备是用来桥接的网络设备,它相当于现实世界中的交换机 可以连接不同的
网络设备,当请求到达 Bridge 设备时,可以通过报文中的 Mac 地址进行广播或转发。
网络设备,当请求到达 Bridge 设备时,可以通过报文中的 Mac 地址进行广播或转发。
创建网桥
3、Linux Iptables
1、MASQUERADE
iptables 中的 MASQUERADE 策略可以将请求包中的源地址转换成一个网络设备的地址,
比如上面介绍的那个 Namespace 中网络设备的地址是 172.18.0.2 ,这个地址虽然在宿主机
上可以路由到 brO 的网桥,但是到达宿主机外部之后,是不知道如何路由到这个 IP 地址的,
所以如果请求外部地址的话,需要先通过 MASQUERADE 策略将这个 IP 转换成宿主机出口网
卡的 IP
比如上面介绍的那个 Namespace 中网络设备的地址是 172.18.0.2 ,这个地址虽然在宿主机
上可以路由到 brO 的网桥,但是到达宿主机外部之后,是不知道如何路由到这个 IP 地址的,
所以如果请求外部地址的话,需要先通过 MASQUERADE 策略将这个 IP 转换成宿主机出口网
卡的 IP
操作:
2、DNAT
iptables 中的 DNAT 策略也是做网络地址的转换,不过它是要更换目标地址,经常用于将
内部网络地址的端口映射到外部去 比如,上面那个例子中的 Namespace 如果需要提供服务给
宿主机之外的应用去请求要怎么办呢?外部应用没办法直接路由到 172.18.0.2 这个地址,这时
候就可以用到 DNAT 策略。
内部网络地址的端口映射到外部去 比如,上面那个例子中的 Namespace 如果需要提供服务给
宿主机之外的应用去请求要怎么办呢?外部应用没办法直接路由到 172.18.0.2 这个地址,这时
候就可以用到 DNAT 策略。
操作:
4、Go 语言网络库介绍
1、net库
net 库是 Go 语言内置的库,提供了跨平台支持的网络地址处理,以及各种常见协议的 IO
支持,比如 TC UDP, DNS Unix Socket 等。
支持,比如 TC UDP, DNS Unix Socket 等。
2、github.com/vishvananda/netlink
Go 语言版本的操作网络接口、路由表等配置的库 ,使用 它的
调用相 当于我们通过 IP 命令去管理网络接口。
调用相 当于我们通过 IP 命令去管理网络接口。
3、github.com/vishvananda/netns
Go 语言版本进出 Net Namespace 库,通过这个库,可以让 netlink
库中配置网络接口的代码在某个容器的 Net Namespace 中执行
库中配置网络接口的代码在某个容器的 Net Namespace 中执行
参考代码
git checkout code-6.5
5、下一阶段
RunC
用于创建容器的工具集
Containerd
规范调用容器的使用方式,根据OCI 规范统一使用容器的接口
Docker
containerd 的诞生地,及推广最成功的容器实现服务
Kubernetes
容器编排工具
Containerd/cri
专门提供给k8s 的api
istio
service mesh 服务网格,做流量控制
收藏
收藏
0 条评论
下一页