1. docker exec 如何是怎么做到进入一个容器的?
容器是一个特殊的进程。Namespace是起到对进程的隔离作用,这种隔离作用虽然对进程来说是无法感知的,但是确实以文件的形式存在宿主机中。
首先通过docker命令查看目标容器的进程ID。
docker inspect --format '{{ .State.Pid }}' <容器ID>
然后通过得到的进程号,去宿主机的proc文件中找到对应进程的Namespace文件。
ls -l /proc/<进程ID>/ns
所以想要进入一个容器,其实只需要使得一个进程加入到目标进程的Namespace就可以实现进入到目标容器的目的,这就是docker exec的实现原理。
在Linux系统中有一个setns()的系统调用可以实现这个目的,即:设置当前进程的Namespace。
在Docker中则有其他的参数可以做到设置容器的Namespace,例如 --net可以设置一个容器的Network Namespace。
## 新建容器,并加入到ID=4ddf4638572d的容器Network Namespace中。docker run -it --net container:4ddf4638572d busybox ifconfig
2. Volume(数据卷)的作用是什么?
容器技术使用了 rootfs 机制和 Mount Namespace,使得容器可以在一个完全隔离的文件系统环境中运行。但是如果容器又想要访问到宿主机的文件要怎么做呢?这就是Volume存在的原因。
Docker Volume可以允许你将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作。
3. Docker Volume有几种声明方式?
docker run -v /test ...docker run -v /home:/test ...
两种方式都是把宿主机的目录挂载到容器的 /test目录下。
区别是:
- 第一种方式会先在宿主机创建临时目录
/var/lib/docker/volumes/[VOLUME_ID]/_data,再把临时目录挂载到容器的/test目录上。 - 第二种方式会把宿主机中的
/home目录挂载到容器的/test目录上。4. Volume(数据卷)的原理是什么?
容器的启动过程是需要经过 rootfs 准备和chroot 执行,只有在chroot执行后,容器所看的到文件环境才是完全隔离的文件系统环境。所以Volume,只需要选择在 rootfs准备好之后,并且在chroot执行之前的时机去完成挂载即可。
并且由于Mount Namespace存在,宿主机也无法感知到这个挂载点的存在。5. 挂载的数据卷能否被docker commit 提交?
不会被提交。
原因:
挂载的目录虽然在可读写层(/var/lib/docker/aufs/mnt/[可读写层 ID]/)中,但是实际操作的目录是在宿主机中,可读写层中的挂载目录实际是一个只有目录名的空目录。
只有进入到容器中,得知这个Volume的挂载信息,才能找到对应的挂载目录。
docker commit是在容器进程外执行,由于 Mount Namespace 的隔离作用,宿主机不能得知这个Volume的存在,所以即使挂载的数据卷在可读写层,也不会被提交,即:提交的是一个空的目录。
那为什么会有一个空的目录呢?因为容器需要先创建一个目录才能完成数据卷的挂载,而这个目录是在可读写层真实存在的。
