简介
在上篇中我们实现了rm命令,删除存在的容器,本篇中,将完善之前的文件系统隔离,实现容器与容器之间的文件系统隔离
源码说明
同时放到了Gitee和Github上,都可进行获取
本章节对应的版本标签是:5.7,防止后面代码过多,不好查看,可切换到标签版本进行查看
代码实现
实现该功能的主要思路如下:
在以前的文章:自己动手写Docker系列 – 4.2使用AUFS包装busybox
实现了容器文件系统与宿主机文件的隔离,但目前为止,所有的容器都是使用的同一个目录,容器与容器之间存在相互影响
本篇文章目的就是为了消除这边影响,实现容器与容器之间的文件系统也进行隔离
实现思路:
以前的文件系统如下:
- 只读层:busybox系统,这个只能读,是系统的基础
- 可写层:writerLayer,这个是容器内部的可写层,能进行对应的修改
- 挂载层:mnt,挂载外部的文件系统,类似于虚拟机的文件共享
要实现容器间的文件系统隔离,就是在可写层和挂载层再加一层,以容器名称进行隔离,也就是:
- 只读层:不变
- 可写层:再加容器名为名的目录,进行隔离,也就是 writeLayer/{容器名称}
- 挂载层:再加容器名为名的目录,进行隔离,也就是 mnt/{容器名称}
文件系统进行隔离后,我们commit的时候,对应的对容器可写层进程打包即可
根据思路,代码实现也比较简单,自己理清思路后,很快便能进行改造实现
修改容器启动时可写层和挂载层,以容器名进行隔离
在容器启动的时候,获取当前的容器名,用于构建相关的隔离目录
func Run(tty, detach bool, cmdArray []string, config *subsystem.ResourceConfig, volume, containerName string) {
// 容器容器名
id, containerName := getContainerName(containerName)
pwd, err := os.Getwd()
if err != nil {
log.Errorf("Run get pwd err: %v", err)
return
}
mntUrl := pwd + "/mnt/"
rootUrl := pwd + "/"
// 传入初始化进程,初始化工作空间
parent, writePipe := container.NewParentProcess(tty, containerName, rootUrl, mntUrl, volume)
if err := parent.Start(); err != nil {
log.Error(err)
// 如果fork进程出现异常,但有相关的文件已经进行了挂载,需要进行清理,避免后面运行报错时,需要手工清理
// 删除容器工作空间进行改造
deleteWorkSpace(rootUrl, mntUrl, volume, containerName)
return
}
// 记录容器信息进行改造
containerName, err = recordContainerInfo(parent.Process.Pid, cmdArray, id, containerName)
if err != nil {
log.Errorf("record contariner info err: %v", err)
return
}
......
log.Infof("parent process run")
if !detach {
_ = parent.Wait()
// 删除容器工作空间进行改造
deleteWorkSpace(rootUrl, mntUrl, volume, containerName)
// 删除容器信息进行改造
deleteContainerInfo(containerName)
}
os.Exit(-1)
}
获取容器名
func getContainerName(containerName string) (string, string) {
id := randStringBytes(10)
if containerName == "" {
containerName = id
}
return id, containerName
}
生成容器信息
func recordContainerInfo(pid int, cmdArray []string, id, containerName string) (string, error) {
createTime := time.Now().Format("2000-01-01 00:00:00")
command := strings.Join(cmdArray, " ")
containerInfo := &container.ContainerInfo{
ID: id,
Pid: strconv.Itoa(pid),
Command: command,