设为首页 收藏本站
查看: 995|回复: 0

[经验分享] [原][Docker]特性与原理解析

[复制链接]

尚未签到

发表于 2015-4-17 09:55:59 | 显示全部楼层 |阅读模式
Docker特性与原理解析

  文章假设你已经熟悉了Docker的基本命令和基本知识


首先看看Docker提供了哪些特性:


  • 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上,例如运行一个一次性交互shell  

  • 文件系统隔离:每个进程容器运行在完全独立的根文件系统里  

  • 写时复制:采用写时复制方式创建根文件系统,这让部署变得极其快捷,并且节省内存和硬盘空间  

  • 资源隔离:可以使用cgroup为每个进程容器分配不同的系统资源  

  • 网络隔离:每个进程容器运行在自己的网络命名空间里,拥有自己的虚拟接口和IP地址  

  • 日志记录:Docker将会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索  

  • 变更管理:容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器。无需使用模板或手动配置
从以上特性分别看实现原理

1. 交互式Shell
  首先我们允许一个交互式的容器
  

$docker run -i -t  /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//rootfs
  这个配置是怎么来的呢,其实所有容器的管理都是通过lxc来管理的,lxc的配置文件放在
  /var/lib/docker/containers//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/
  看做是一个容器的配置目录的话,可以看到在配置目录下面有一个 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>  

  
------ 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管理.
  默认情况下是使用了所有CPU和内存的,但是可以在config.lxc增加如下配置设置CPU等,具体可以参考lxc的文档
  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 &
  从ghost访问 telnet 172.17.0.2 80
  在容器中看到如下:
  

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/.log 下

7.变更管理
  Docker的变更管理看做是git的版本管理好了。
  生成镜像的时候,未做改动的部分就是上一个版本的镜像的引用,如果做了改动,就是一个新的文件。
  将刚才操作的容器做成镜像
  docker commit  
  此时的镜像多出来的部分,比如我在这个镜像中安装了Python,那么多出来的部分作为新文件,其他部分任然是上一个版本的引用。
  你可以搭建自己的镜像服务器,push到自己的镜像服务器,从其他机器拉下来后直接可以运行。

  以上,一点愚见,希望指正.


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58027-1-1.html 上篇帖子: Docker学习总结之docker入门 下篇帖子: docker 创建私有仓库(仅在内网环境使用)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表