在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
Docker 特性与原理 首先看看Docker提供了哪些特性:
从以上特性分别看实现原理 1. 交互式Shell 首先我们允许一个交互式的容器 $docker run -i -t <image name> /bin/bash 这样就建立了一个到容器内的交互式连接,看到的是如下的命令行: root@df3880b17407:/# 这里我们启动了一个容器,以bash作为其根进程. root@df3880b17407:/# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 18164 2020 ? S 06:06 0:00 /bin/bash 可以看到,在这个容器中,bash 的 PID为 1,而实体机平常情况下,是这样的: root@ubuntu:~# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 24716 2612 ? Ss Sep04 0:01 /sbin/init 大家都知道,所有进程的共同祖先都是 PID=1的进程 所以在容器中,所有以后创建的进程都是通过/bin/bash 创建的,PID=1的 bash是容器中所有进程的祖先理解了这点后,对容器的理解就很简单了. 2. 文件系统隔离 对于一个正在运行的容器,其文件系统都是一个从根目录开始的虚拟文件系统,在容器中看到的是这样的: root@df3880b17407:/# ll / total 68 drwxr-xr-x 2 root root 4096 Jul 22 22:51 bin drwxr-xr-x 2 root root 4096 Apr 10 22:12 boot drwxr-xr-x 3 root root 4096 Jul 22 22:49 dev drwxr-xr-x 85 root root 4096 Sep 5 06:49 etc drwxr-xr-x 2 root root 4096 Apr 10 22:12 home drwxr-xr-x 16 root root 4096 Jul 22 22:50 lib drwxr-xr-x 2 root root 4096 Aug 12 03:30 lib64 drwxr-xr-x 2 root root 4096 Jul 22 22:48 media drwxr-xr-x 2 root root 4096 Apr 10 22:12 mnt drwxr-xr-x 2 root root 4096 Jul 22 22:48 opt dr-xr-xr-x 356 root root 0 Sep 5 06:06 proc drwx------ 2 root root 4096 Jul 22 22:51 root drwxr-xr-x 7 root root 4096 Sep 5 07:23 run drwxr-xr-x 2 root root 4096 Aug 12 03:30 sbin drwxr-xr-x 2 root root 4096 Jul 22 22:48 srv dr-xr-xr-x 13 root root 0 Sep 5 06:06 sys drwxrwxrwt 2 root root 4096 Sep 5 06:55 tmp drwxr-xr-x 20 root root 4096 Sep 5 06:11 usr drwxr-xr-x 19 root root 4096 Sep 5 06:11 var 其实真是情况是这样的,容器中的文件系统都是挂载到了真是系统中的一个目录下面. /var/lib/docker/containers/<image-long-id>/rootfs 这个配置是怎么来的呢,其实所有容器的管理都是通过lxc来管理的,lxc的配置文件放在 /var/lib/docker/containers/<image-long-id>/config.lxc 文件中有字段表示容器挂载到哪个文件目录, 比如我的是这样的: lxc.rootfs = /var/lib/docker/containers/df3880b17407575cd642a6b7da3c7e417a55fad5bbd63152f89921925626d2b6/rootfs 打开看一下,一目了然: root@ubuntu:/var/lib/docker/containers/df3880b17407575cd642a6b7da3c7e417a55fad5bbd63152f89921925626d2b6/rootfs# ll total 84 drwxr-xr-x 53 root root 4096 Sep 5 00:23 ./ drwx------ 4 root root 4096 Sep 5 00:53 ../ drwxr-xr-x 2 root root 4096 Jul 22 15:51 bin/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 boot/ drwxr-xr-x 3 root root 4096 Jul 22 15:49 dev/ drwxr-xr-x 85 root root 4096 Sep 4 23:49 etc/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 home/ drwxr-xr-x 16 root root 4096 Jul 22 15:50 lib/ drwxr-xr-x 2 root root 4096 Aug 11 20:30 lib64/ drwxr-xr-x 2 root root 4096 Jul 22 15:48 media/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 mnt/ drwxr-xr-x 2 root root 4096 Jul 22 15:48 opt/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 proc/ drwx------ 2 root root 4096 Jul 22 15:51 root/ drwxr-xr-x 7 root root 4096 Sep 5 00:23 run/ drwxr-xr-x 2 root root 4096 Aug 11 20:30 sbin/ drwxr-xr-x 2 root root 4096 Jul 22 15:48 srv/ drwxr-xr-x 2 root root 4096 Mar 12 18:41 sys/ drwxrwxrwt 2 root root 4096 Sep 4 23:55 tmp/ drwxr-xr-x 20 root root 4096 Sep 4 23:11 usr/ drwxr-xr-x 19 root root 4096 Sep 4 23:11 var/ 这些就是容器中的真实目录了,容器中对于目录的操作都是操作了这个host机器的真实目录。 3. 写时复制 我们把每一个 /var/lib/docker/containers/<image-long-id> 看做是一个容器的配置目录的话,可以看到在配置目录下面有一个 rw/目录,打开看有些什么 total 36 drwxr-xr-x 9 root root 4096 Sep 5 00:23 ./ drwx------ 4 root root 4096 Sep 5 00:53 ../ drwxr-xr-x 6 root root 4096 Sep 4 23:49 etc/ drwxr-xr-x 2 root root 4096 Sep 5 00:23 run/ drwxrwxrwt 2 root root 4096 Sep 4 23:55 tmp/ drwxr-xr-x 7 root root 4096 Sep 4 23:11 usr/ drwxr-xr-x 5 root root 4096 Sep 4 23:11 var/ -r--r--r-- 1 root root 0 Sep 4 23:06 .wh..wh.aufs drwx------ 2 root root 4096 Sep 4 23:06 .wh..wh.orph/ drwx------ 2 root root 4096 Sep 4 23:11 .wh..wh.plnk/ 里面是一些不完整的根目录,这不能说明什么,但是我们在container中写入文件后,看看其中的变化 在容器中执行以下命令 root@df3880b17407:/# touch /opt/x 在 /opt 下我们生成了一个文件 再看看 root@ubuntu:/var/lib/docker/containers/df3880b17407575cd642a6b7da3c7e417a55fad5bbd63152f89921925626d2b6/rw# ll total 40 drwxr-xr-x 10 root root 4096 Sep 5 01:00 ./ drwx------ 4 root root 4096 Sep 5 00:53 ../ drwxr-xr-x 6 root root 4096 Sep 4 23:49 etc/ drwxr-xr-x 2 root root 4096 Sep 5 01:00 opt/ drwxr-xr-x 2 root root 4096 Sep 5 00:23 run/ drwxrwxrwt 2 root root 4096 Sep 4 23:55 tmp/ drwxr-xr-x 7 root root 4096 Sep 4 23:11 usr/ drwxr-xr-x 5 root root 4096 Sep 4 23:11 var/ -r--r--r-- 1 root root 0 Sep 4 23:06 .wh..wh.aufs drwx------ 2 root root 4096 Sep 4 23:06 .wh..wh.orph/ drwx------ 2 root root 4096 Sep 4 23:11 .wh..wh.plnk/ 是的,在host机器上新生成了 opt/目录,这里做到了容器的写时复制 4. 资源隔离 以系统的三大进程间通信的消息队列来看 初始状态在 ghost, ipcs -q 查看消息队列 root@ubuntu:~/codes/msq# ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 在ghost 创建一个, 这里楼主自己写的代码创建的消息队列: root@ubuntu:~/codes/msq# ./main 1 Create msq with key id 65536root@ubuntu:~/codes/msq# ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 65536 root 666 0 0 然后在容器中查看 ipcs -q root@df3880b17407:/# ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 可以看到系统资源是隔离的,这里只是说了一部分,其实还包括了可以通过cgoup对其做CPU和Memory的Quota管理. lxc.cgroup.cpu.shares=512 lxc.cgroup.cpuset.cpus=1.2 资源隔离的原理就在于利用cgroup,将不同进程的使用隔离开,假设每个容器都是以bash启动的,那么在容器内部,每个子进程都只能使用当前bash下面的资源,对于其他的系统资源是隔离的.子进程的访问权限由父进程决定 5.网络隔离 在安装好docker后,会默认初始化一个 docker0的网桥 docker0 Link encap:Ethernet HWaddr ee:8c:1f:8b:d7:59 inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0 ... 在host机器上,会为每一个容器生成一个默认的网卡类似这样的 vethdBVa1H veth* 这个网卡的一端连接在容器的eth0,一端连接到docker0.这样就实现了每个容器有一个单独的IP. 这里如果需要容器访问外网,需要将eth0设置为混杂模式: $ifconfig eth0 promisc 这样看来,容器会从172.17.0.0/24 这个网段选择一个IP作为eth0的IP,这样,容器就可以和外部通过 docker0网桥通信了. 在容器内部监听一个端口 python -m SimpleHTTPServer 80 >> /tmp/log.log & Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 2823/python tcp 0 0 172.17.0.2:80 172.17.42.1:46142 TIME_WAIT - 在host上看到 Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 172.17.42.1:46142 172.17.0.2:80 ESTABLISHED 10244/telnet 如果需要外部能够访问容器,需要做端口映射规则,和配置虚拟机一样的道理, 只不过这里可以看到的是,80端口并没有占用了本地端口,而是在容器内部做了监听,外部是通过docker0 桥接过去的,每个容器间也做到了端口和网络隔离. 6.日志记录 不多说,在 /var/lib/docker/containers/<image-long-id>.log 下 7.变更管理 Docker的变更管理看做是git的版本管理好了。 生成镜像的时候,未做改动的部分就是上一个版本的镜像的引用,如果做了改动,就是一个新的文件。 将刚才操作的容器做成镜像 docker commit <image-id> <REPOSITORY> 此时的镜像多出来的部分,比如我在这个镜像中安装了Python,那么多出来的部分作为新文件,其他部分任然是上一个版本的引用。 你可以搭建自己的镜像服务器,push到自己的镜像服务器,从其他机器拉下来后直接可以运行。 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持! |
请发表评论