1. 准备工作
本文会实现容器和宿主机之间文件的相互复制.
1.1 准备环境
root@nicktming:~/go/src/github.com/nicktming/mydocker# git clone https://github.com/nicktming/mydocker.git
root@nicktming:~/go/src/github.com/nicktming/mydocker# git checkout code-5.7.1
root@nicktming:~/go/src/github.com/nicktming/mydocker# git checkout -b dev-5.7.2
1.2 准备busybox.tar
// 前提条件
root@nicktming:/nicktming# pwd
/nicktming
root@nicktming:/nicktming# ls
busybox.tar
2. 方法
主要是测试一下
copy
, 很简单的操作. 在test/copy/test-1.go
func main() {
test01()
}
func test01() {
copy("/root/filecopy/busybox", "/root/filecopy/tmp")
copy("/root/filecopy/busybox/bin/top", "/root/filecopy/tmp")
}
func copy(src, dst string) {
exist, _ := command.PathExists(src)
if !exist {
log.Printf("src:%s not exists!\n", src)
return
}
exist, _ = command.PathExists(dst)
if !exist {
log.Printf("dst:%s not exists!\n", src)
return
}
if _, err := exec.Command("cp", "-r", src, dst).CombinedOutput(); err != nil {
log.Printf("cp -r %s %s, err:%v\n", src, dst, err)
return
}
}
测试
root@nicktming:~/go/src/github.com/nicktming/mydocker/test/copy# pwd
/root/go/src/github.com/nicktming/mydocker/test/copy
root@nicktming:~/go/src/github.com/nicktming/mydocker/test/copy# ls -l /root/filecopy
total 8
drwxr-xr-x 12 root root 4096 Apr 19 06:53 busybox
drwxr-xr-x 2 root root 4096 Apr 19 06:55 tmp
root@nicktming:~/go/src/github.com/nicktming/mydocker/test/copy# ls -l /root/filecopy/tmp/
total 0
root@nicktming:~/go/src/github.com/nicktming/mydocker/test/copy# go run test-1.go
root@nicktming:~/go/src/github.com/nicktming/mydocker/test/copy# ls -l /root/filecopy/tmp/
total 1100
drwxr-xr-x 12 root root 4096 Apr 19 07:10 busybox
-rwxr-xr-x 1 root root 1120520 Apr 19 07:10 top
root@nicktming:~/go/src/github.com/nicktming/mydocker/test/copy#
3.实现
在理解了
Aufs
的原理后, 实现这些操作基本上就是文件复制的问题, 只需要找到容器在宿主机上的挂载点就可以操作了, 如果是从容器内复制内容到宿主机, 则将找到要复制的文件在宿主机的某个位置即可, 然后该位置的文件复制到宿主机的另外一个位置即可. 反之也是一样.
那如何找到容器的挂载点呢?因为知道容器名, 所以可以直接从
/var/run/mydocker
中读该容器的metadata
即可.
3.1 增加CopyCommand
// main.go
func main() {
...
app.Commands = []cli.Command{
...
command.CopyCommand,
}
...
}
// command/command.go
var CopyCommand = cli.Command{
Name: "cp",
Usage: "copy files",
Action: func(c *cli.Context) error {
source := c.Args().Get(0)
destination := c.Args().Get(1)
log.Printf("source:%s, destination:%s\n", source, destination)
Copy(source, destination)
return nil
},
}
3.2 增加command/copy.go
最终找到容器要操作的文件在宿主机的位置为
containerMntPath
, 而本身宿主机要操作的文件路径为hostPath
.
func Copy(source, destination string) {
f1 := strings.Contains(source, ":")
f2 := strings.Contains(destination, ":")
if (f1 && f2) || (!f1 && !f2) {
log.Printf("f1:%v, f2:%v, not correct format\n", f1, f2)
return
}
var from_container_to_host bool = true
containerUrl := source
hostUrl := destination
if f2 {
from_container_to_host = false
containerUrl = destination
hostUrl = source
}
containerName := strings.Split(containerUrl, ":")[0]
containerPath := strings.Split(containerUrl, ":")[1]
log.Printf("containerUrl:%s, hostUrl:%s, conatinerName:%s, containerPath:%s\n", containerUrl, hostUrl, containerName, containerPath)
containerInfo, err := GetContainerInfo(containerName)
if err != nil {
log.Printf("GetContainerInfo error:%v\n", err)
return
}
containerMntPath := containerInfo.RootPath + "/mnt/" + containerName + containerPath
hostPath := hostUrl
log.Printf("containerPath:%s, hostPath:%s\n", containerMntPath, hostPath)
log.Printf("from_container_to_host:%v\n", from_container_to_host)
if from_container_to_host {
log.Printf("from %s to %s\n", containerMntPath, hostPath)
FileCopy(containerMntPath, hostPath)
} else {
log.Printf("from %s to %s\n", hostPath, containerMntPath)
FileCopy(hostPath, containerMntPath)
}
}
func FileCopy(src, dst string) {
exist, _ := PathExists(src)
if !exist {
log.Printf("src:%s not exists!\n", src)
return
}
exist, _ = PathExists(dst)
if !exist {
log.Printf("dst:%s not exists!\n", src)
return
}
if _, err := exec.Command("cp", "-r", src, dst).CombinedOutput(); err != nil {
log.Printf("cp -r %s %s, err:%v\n", src, dst, err)
return
}
}
3.2 测试
启动一个容器, 然后测试两个操作:
1. 容器往宿主机复制内容.
2. 宿主机往容器复制内容.
-------------------------------terminal 01----------------------------
root@nicktming:~/go/src/github.com/nicktming/mydocker# ./mydocker run -d -name container01 busybox /bin/top
2019/04/19 15:19:56 rootPath is empaty, set rootPath: /nicktming
root@nicktming:~/go/src/github.com/nicktming/mydocker# ./mydocker ps
ID NAME PID STATUS COMMAND CREATED
15556583962876437411 container01 18416 running /bin/top 2019-04-19 15:19:56
root@nicktming:~/go/src/github.com/nicktming/mydocker# ./mydocker exec container01 /bin/sh
2019/04/19 15:20:21 containerName:container01,command:/bin/sh
/ # ls -l
total 44
drwxr-xr-x 2 root root 12288 Feb 14 18:58 bin
drwxr-xr-x 4 root root 4096 Mar 17 16:05 dev
drwxr-xr-x 3 root root 4096 Mar 17 16:05 etc
drwxr-xr-x 2 nobody nogroup 4096 Feb 14 18:58 home
dr-xr-xr-x 103 root root 0 Apr 19 07:19 proc
drwx------ 2 root root 4096 Apr 19 07:20 root
drwxr-xr-x 2 root root 4096 Mar 17 16:05 sys
drwxrwxrwt 2 root root 4096 Feb 14 18:58 tmp
drwxr-xr-x 3 root root 4096 Feb 14 18:58 usr
drwxr-xr-x 4 root root 4096 Feb 14 18:58 var
-------------------------------terminal 02----------------------------
root@nicktming:/nicktming# mkdir copy && echo "copy files" > copy/test01.txt
// 从宿主机copy文件到容器中
root@nicktming:~/go/src/github.com/nicktming/mydocker# ./mydocker cp /nicktming/copy/test01.txt container01:/
2019/04/19 15:49:50 source:/nicktming/copy/test01.txt, destination:container01:/
2019/04/19 15:49:50 containerUrl:container01:/, hostUrl:/nicktming/copy/test01.txt, conatinerName:container01, containerPath:/
2019/04/19 15:49:50 containerPath:/nicktming/mnt/container01/, hostPath:/nicktming/copy/test01.txt
2019/04/19 15:49:50 from_container_to_host:false
2019/04/19 15:49:50 from /nicktming/copy/test01.txt to /nicktming/mnt/container01/
root@nicktming:~/go/src/github.com/nicktming/mydocker#
// 从容器中copy文件到宿主机
root@nicktming:~/go/src/github.com/nicktming/mydocker# ./mydocker cp container01:/bin/top /root/go/src/github.com/nicktming/mydocker
2019/04/19 15:51:00 source:container01:/bin/top, destination:/root/go/src/github.com/nicktming/mydocker
2019/04/19 15:51:00 containerUrl:container01:/bin/top, hostUrl:/root/go/src/github.com/nicktming/mydocker, conatinerName:container01, containerPath:/bin/top
2019/04/19 15:51:00 containerPath:/nicktming/mnt/container01/bin/top, hostPath:/root/go/src/github.com/nicktming/mydocker
2019/04/19 15:51:00 from_container_to_host:true
2019/04/19 15:51:00 from /nicktming/mnt/container01/bin/top to /root/go/src/github.com/nicktming/mydocker
// 验证top命令是否copy到当前位置
root@nicktming:~/go/src/github.com/nicktming/mydocker# ls
cgroups command main.go memory mydocker nsenter pictures README.md test top urfave-cli-examples
root@nicktming:~/go/src/github.com/nicktming/mydocker#
// 查看容器中是否有test1.txt文件
-------------------------------terminal 01----------------------------
/ # ls -l
total 48
drwxr-xr-x 2 root root 12288 Feb 14 18:58 bin
drwxr-xr-x 4 root root 4096 Mar 17 16:05 dev
drwxr-xr-x 3 root root 4096 Mar 17 16:05 etc
drwxr-xr-x 2 nobody nogroup 4096 Feb 14 18:58 home
dr-xr-xr-x 102 root root 0 Apr 19 07:19 proc
drwx------ 2 root root 4096 Apr 19 07:20 root
drwxr-xr-x 2 root root 4096 Mar 17 16:05 sys
-rw-r--r-- 1 root root 11 Apr 19 07:49 test01.txt
drwxrwxrwt 2 root root 4096 Feb 14 18:58 tmp
drwxr-xr-x 3 root root 4096 Feb 14 18:58 usr
drwxr-xr-x 4 root root 4096 Feb 14 18:58 var
/ # cat test01.txt
copy files
/ # exit
root@nicktming:~/go/src/github.com/nicktming/mydocker#
- 时序图
copy.png
5. 参考
1. 自己动手写docker.(基本参考此书,加入一些自己的理解,加深对
docker
的理解)
6. 全部内容
mydocker.png
1. [mydocker]---环境说明
2. [mydocker]---urfave cli 理解
3. [mydocker]---Linux Namespace
4. [mydocker]---Linux Cgroup
5. [mydocker]---构造容器01-实现run命令
6. [mydocker]---构造容器02-实现资源限制01
7. [mydocker]---构造容器02-实现资源限制02
8. [mydocker]---构造容器03-实现增加管道
9. [mydocker]---通过例子理解存储驱动AUFS
10. [mydocker]---通过例子理解chroot 和 pivot_root
11. [mydocker]---一步步实现使用busybox创建容器
12. [mydocker]---一步步实现使用AUFS包装busybox
13. [mydocker]---一步步实现volume操作
14. [mydocker]---实现保存镜像
15. [mydocker]---实现容器的后台运行
16. [mydocker]---实现查看运行中容器
17. [mydocker]---实现查看容器日志
18. [mydocker]---实现进入容器Namespace
19. [mydocker]---实现停止容器
20. [mydocker]---实现删除容器
21. [mydocker]---实现容器层隔离
22. [mydocker]---实现通过容器制作镜像
23. [mydocker]---实现cp操作
24. [mydocker]---实现容器指定环境变量
25. [mydocker]---网际协议IP
26. [mydocker]---网络虚拟设备veth bridge iptables
27. [mydocker]---docker的四种网络模型与原理实现(1)
28. [mydocker]---docker的四种网络模型与原理实现(2)
29. [mydocker]---容器地址分配
30. [mydocker]---网络net/netlink api 使用解析
31. [mydocker]---网络实现
32. [mydocker]---网络实现测试
网友评论