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