Docker之风席卷全球,但很多人觉得docker入门确实不太容易,其原因在于很多知识点上没准备好,在docker解决了什么问题、怎么解决的、用什么技术解决的都还没想清楚的时候就去探索docker组件原理,自然会犯迷糊,与其迷茫地寸步难行,不如先看看知识准备,入门了继续进行研究。 
Docker是一种在Linux容器里运行应用的开源工具,一种轻量级的虚拟机。除了运行应用,Docker还提供了一些工具,借助Docker Index或自己托管的Docker注册表对进行了集装箱化处理的应用进行分发,从而简化复杂应用的部署过程。 
本文将介绍如今在部署复杂系统时公司所面临的挑战,Docker怎样有效地解决这个问题,在宏观上对docker项目进行介绍,并发表一些自己理解的看法。之后的文章会慢慢深入,对docker模块逐个剖析。

0x01 什么是容器

容器指用来包装或装载物品的贮存器(如箱、罐、坛)或者成形或柔软不成形的包覆材料。在web环境中,容器是应用服务器中位于组件和平台之间的接口集合。在docker级别,容器可以理解为一个边界,边界里面是所想运行的各种程序,边界外面是基础环境,边界里外尽量少的耦合。 

0x02 容器的作用

服务器应用的部署已经越来越复杂了。把几个Perl脚本拷贝到正确目录就完成服务器应用的安装,这种时代已经一去不复返了。如今的软件有很多类型的需求: 
对已安装软件和库的依赖(“Python版本高于2.6.3,使用Django 1.2”) 
依赖于正在运行的服务(“需要一个MySQL 5.5数据库和一个RabbitMQ队列”) 
依赖于特定的操作系统(“在64位的Ubuntu Linux 12.04上构建、测试”) 
资源需求: 
最小的可用内存(“需要1GB的可用内存”) 
能绑定特定的端口(“绑定80和443端口”) 
我们来看一个相对简单的应用的部署:Wordpress。Wordpress的安装通常要求: 

在服务器上部署、运行这样一个系统,我们可能会遇到下面的问题和挑战: 
隔离性:如果我们已经在这个服务器上部署了不同的网站,已有的网站只能在nginx上 运行,而Wordpress依赖于Apache,这时我们就会有麻烦:它们都监听80端口。同时运行两个网站是可以的,但需要调整配置(修改监听端口), 设置反向代理等。库级别也会出现类似的冲突,如果还要运行一个仍然依赖PHP4的老应用就会出问题,因为Wordpress不再支持PHP4,同时运行 PHP4和PHP5则非常困难。运行在同一个服务器上的应用没有互相隔离(在文件系统级别和网络级别),所以它们可能会互相冲突。 
**安全性:**Wordpress的安全记录并不是非常好。所以还是给它创建个沙箱,至少黑客入侵时不会影响其他运行的应用。 
升级、降级:升级应用一般会覆盖现有文件。升级过程中会发生什么?系统要关闭么?如果升级失败,或者不对该怎么办?我们怎样快速回退到先前的版本? 
快照、备份:一旦所有的内容都设置好,就给系统创建一个“快照”,以便能备份快照,甚至能移到另一个服务器上再次启动,或者拷贝到多个服务器上以备不时之需。 
重复性:系统出新版本之后,比较好的做法是先在测试基础设施上自动部署并测试,然后再发布到生产系统。通常会利用诸如Chef、Puppet等 工具在服务器上自动安装一堆包,等一切内容都就绪后,再在生产系统上运行相同的部署脚本。这在百分之九十九的情况下都没有问题。但有百分之一的例外,在部 署到测试环境和生产环境之间的时间跨度里,你依赖的包在包仓库里有了更新,而新版本并不兼容。结果生产环境的设置和测试环境不同,还有可能破坏生产系统。 假如没有控制部署的每一个方面(例如托管自己的APT或YUM仓库),持续在多个阶段(比如测试、预演、生产环境)重复搭建出完全相同的系统就很困难。 
资源限制:如果我们的Wordpress耗费CPU资源,并占用了所有的CPU周期,导致其他应用无法做任何事情怎么办?如果它用尽了全部可用的内存呢?或者疯狂写日志阻塞磁盘呢?要是能限制应用的可用资源,比如CPU、内存和磁盘空间,就会非常方便。 
易于安装:也许有Debian或CentOS包,抑或是能自动执行所有复杂步骤并安装 Wordpress的Chef菜谱。但这些菜谱很难稳定下来,因为它们需要考虑目标系统上可能的系统配置。很多情况下,这些菜谱只能在干净的系统上运行。 因此,你不太可能更换成自己的包或Chef菜谱。这样的话,安装就是个复杂的系统工程,而不是午休期间就能搞定的事情。 
易于移除:软件应该能轻松、干净地移除,不留痕迹。但部署应用通常要调整已有的配置文件、设置状态(MySQL数据库的数据,日志),完全移除应用也变得不那么容易。 
那我们应该如何解决这些问题呢?

0x03 虚拟机VS容器-虚拟机解决方案

我们决定在单独的虚拟机上运行独立的应用,例如Amazon的EC2,大部分问题这时会迎刃而解: 
隔离性:在一个VM上安装一个应用,应用是完全独立的,除非它们攻入了对方的防火墙。 
重复性:用你喜欢的方式准备系统,然后创建一个AMI。你可以随意实例化多个AMI实例。完全是可重现的。 
安全性:由于我们完全隔离,如果Wordpress遭到攻击,其余的基础设施并不会受到影响——除非你没有保管好SSH密钥或者在哪里都使用同一个密码,但你应该不会这么做吧? 
**资源限制:**VM会分配特定的CPU周期、可用内存和磁盘空间,没有加价的话就不能超额。 
易于安装:越来越多的应用能够在EC2上运行,只要在AWS marketplace上点击一个按钮就能实例化应用。启动只需要几分钟,就是这样。 
易于移除:不需要某个应用了?销毁VM。干净又方便。 
**升级、降级:**Netflix如何部署代码里提到,只需要在新VM上部署新版本,然后让负载均衡器指向部署了新版本的VM。不过应用如果需要在本地保存状态,这种方法就不是很好用了。 
快照、备份:点击一个按钮(或者调用一下API)就能获得EBS磁盘的快照,快照会备份到S3中。 
完美! 
不过……我们有个新问题:虚拟机在两个方面比较昂贵: 
金钱:你真的有那么多钱为每个应用启动一个EC2实例?另外你能预测到需要多少个实例么?如果你以后需要更多的资源,你需要停止VM进行升级——否则就要为闲置资源白白付钱,直到真正用起来(除非你用能动态调整大小的Solaris Zones,比如Joyent上的)。 
时间:虚拟机相关的操作大多都很慢:启动要几分钟,捕捉快照要几分钟,创建镜像也需要几分钟。世界不停转动,我们可没有这种时间! 
我们能做得更好吗?

0x04 虚拟机VS容器-容器解决方案

Docker是由公共PaaS提供商dotCloud的人发起的开源项目,于去年初发起。从技术角度来说,Docker(主要用Go语言编写)试图简化两种已有技术的使用: 
**LXC:**Linux容器,允许独立进程在比普通Unix进程更高的隔离级别上运行。使用的技术术语是集装箱化:一个容器里运行一个进程。容器支持的隔离级别有: 
文件系统:容器只能访问自己的沙箱文件系统(类似于chroot),否则要专门挂载到容器的文件系统中才能访问。 
用户名字空间:容器有自己的用户数据库(也就是容器的root不等于主机的root账户)。 
进程名字空间:只有容器里的进程才是可见的(ps aux的输出会非常简洁)。 
网络名字空间:每个容器都有自己的虚拟网络设备和虚拟IP(因此它可以绑定任意端口,不用占用主机端口)。 
AUFS:高级多层的统一文件系统,可用来创建联合、写时拷贝的文件系统。 
Docker可以安装在任何支持AUFS和内核版本大于等于3.8的Linux系统上。但从概念上来说它并不依赖于这些技术,以后也可以和类似的技术一起运行,例如Solaris的Zones或BSD jails,并将ZFS作为文件系统。不过目前只能选择Linux 3.8+和AUFS。

0x05 为什么是Docker

Docker非常轻量。启动VM是个大动作,需要占用大量内存;而启动Docker容器只耗费很少的CPU和内存,并且非常快。几乎和启动一个常规进程没什么区别。不仅运行容器快,构建镜像、捕获文件系统的快照也很快。 
它运行在已经虚拟化过的环境中。也就是说,你可以在EC2实例、Rackspace VM或VirtualBox里运行Docker。事实上,在Mac和Windows上使用Docker的首选方式是使用Vagrant。 
Docker容器能移植到任何运行Docker的操作系统上。无论是Ubuntu还是CentOS,只要Docker运行着,你的容器就能运行。 
让我们回到前面的部署、操作问题列表,看看Docker是怎么解决的: 
隔离性:Docker在文件系统和网络级别隔离了应用。从这个意义上来讲很像在运行”真正的“虚拟机。 
重复性:用你喜欢的方式准备系统(登录并在所有软件里执行apt-get命令,或者使用Dockerfile),然后把修改提交到镜像中。你可以随意实例化若干个实例,或者把镜像传输到另一台机器,完全重现同样的设置。 
**安全性:**Docker容器比普通的进程隔离更为安全。Docker团队已经确定了一些安全问题,正在着手解决。 
**资源约束:**Docker现在能限制CPU的使用率和内存用量。目前还不能直接限制磁盘的使用情况。 
**易于安装:**Docker有一个Docker Index,这个仓库存储了现成的Docker镜像,你用一条命令就可以完成实例化。比如说,要使用Clojure REPL镜像,只要运行docker run -t -i zefhemel/clojure-repl命令就能自动获取并运行该镜像。 
易于移除:不需要应用了?销毁容器就行。 
升级、降级:和EC2 VM一样:先启动应用的新版本,然后把负载均衡器切换到新的端口。 
**快照、备份:**Docker能提交镜像并给镜像打标签,和EC2上的快照不同,Docker是立即处理的。

0x06 Docker入门知识准备

Namespace定义与概念 
每个用户实例之间相互隔离, 互不影响。 一般的硬件虚拟化方法给出的方法是VM,而LXC给出的方法是container,更细一点讲就是kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace将container的进程、网络、消息、文件系统、UTS(“UNIX Time-sharing System”)和用户空间隔离开。 
Cgroups定义与概念 
cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对该进程的资源控制。 groups可以限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系 统的资源 
AUFS定义与概念 
AUFS (AnotherUnionFS) 是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统, 更进一步的理解, AUFS支持为每一个成员目录(类似Git Branch)设定readonly、readwrite 和 whiteout-able 权限, 同时 AUFS 里有一个类似分层的概念, 对 readonly 权限的 branch 可以逻辑上进行修改(增量地, 不影响 readonly 部分的)。通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个disk挂到同一个目录下, 另一个更常用的就是将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起,Live CD正是基于此方法可以允许在 OS image 不变的基础上允许用户在其上进行一些写操作

0x07 Docker有哪些缺点

尽管Docker有助于系统的可靠部署,但它本身并不是个完全成熟的部署系统。它操作的是容器里运行的应用。哪个容器安装在哪个服务器上,以及如何启动它们,则超出了Docker的范围。 
同样的,Docker也不处理跨多个容器(可能在多个物理服务器上,也可能在多个VM上)运行的应用。要让容器互相通信,需要某些发现机制,来找出哪些IP和端口上的其他应用可用。这和跨常规虚拟机的服务发现非常相似。etcd等工具,或者其他的服务发现机制都能用来解决这个问题。

0x08 Docker未来发展

虽然Docker目前默认使用LXC和AUFS,但是Docker的核心思想本身,并不强制绑定这两者,0.8版本已经可以使用BTRFS,而整个Docker框架也改成了插件式的架构,便于添加替换各个功能模块 

例如更多的Storage方案的支持,规避AUFS当前的问题,除了LXC以外更多的虚拟化方案等

0x09 总结

容器实质上是一个职责划分的工具。Docker与容器不是等价的,docker是容器,但容器不仅仅指的是docker,docker为容器的一个代表,个人理解的docker主要解决的问题为如下两方面 
1、不同层之间的依赖关系解耦;例如:安装、移除、重复利用。如下图中,container与Host OS和Server之间的解耦。 
2、同层之间资源隔离与资源限制;例如:端口、cpu抢占,同服站点互不影响。下图中App A与APP B之间的隔离,和APP各自的资源利用限制。 
 
容器解决的问题虚拟机已全部解决,为什么还需要容器docker呢?原因是虚拟机在架构上太重,在资源上有很多不必要的花费,在时间上启动、创建镜像、快照等消耗较长,在层次结构上虚拟机只具有一层封装,将操作系统、服务、应用全部封装,并不能灵活的拆卸与组装,职责划分并不明确。 
Docker略带积木化色彩,将杂糅的运行环境积木化,用于更快更好的搭建和复用。

参考文档

Docker容器http://www.infoq.com/cn/articles/docker-containers 
http://blog.csdn.net/colorant/article/details/20608157 
LXC 入门文章http://www.cnblogs.com/lisperl/archive/2012/04/15/2450183.html 
Docker核心技术预览:http://www.infoq.com/cn/articles/docker-core-technology-preview

Docker与容器快速入门的更多相关文章

  1. 【云计算】Dockerfile、镜像、容器快速入门

    Dockerfile.镜像.容器快速入门 1.1.Dockerfile书写示例 Dockerfile可以用来生成Docker镜像,它明确的定义了Image的生成过程.虽然直接修改容器也可以提交生成镜像 ...

  2. Castle IOC容器快速入门

    主要内容 1.为什么要IOC 2.什么是Castle IOC容器 3.快速入门示例 4.几个重要的概念 一,为什么要IOC IOC(控制反转或者叫依赖注入)Martin Fowler大师在他的文章中已 ...

  3. docker安装kafka快速入门

    docker安装kafka快速入门 1.安装zookeeper docker search zookeeperdocker pull zookeeperdocker run -d -v /home/s ...

  4. Docker三十分钟快速入门(上)

    一.背景 ​ 最近,Docker技术真是一片火热,它的出现也弥补了虚拟机资源消耗过高的问题,直接让虚拟化技术有了质的飞跃.那么本文我们来聊一聊Docker,和大家一起认识Docker,简单入门Dock ...

  5. Docker三十分钟快速入门(下)

    一.背景 上篇文章我们进行了Docker的快速入门,基本命令的讲解,以及简单的实战,那么本篇我们就来实战一个真实的项目,看看怎么在产线上来通过容器技术来运行我们的项目,来达到学会容器间通信以及dock ...

  6. Docker学习系列(二):Docker三十分钟快速入门(上)

    一.背景 ​ 最近,Docker技术真是一片火热,它的出现也弥补了虚拟机资源消耗过高的问题,直接让虚拟化技术有了质的飞跃.那么本文我们来聊一聊Docker,和大家一起认识Docker,简单入门Dock ...

  7. 几张图帮你理解 docker 基本原理及快速入门

    写的非常好的一篇文章,不知道为什么被删除了.  利用Google快照,做个存档. 快照地址:地址 作者地址:青牛 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 do ...

  8. [转]docker 基本原理及快速入门

    版权声明:原创作品, 来自海牛部落-青牛,http://hainiubl.com/topics/13 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud ...

  9. docker 基本原理及快速入门

    作者地址:青牛 什么是docker Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目.它基于 Google 公司推出的 Go 语言实现. 项目后来 ...

随机推荐

  1. EF工作中踩过的坑.

    1.EF同一个linq里边不支持两个或两个以上不同dbcontext的使用,必须拆解开才能使用; ef也不支持自定义集合和dbcontext属性的混合使用. 2.如果要用用统一域账号连接databas ...

  2. (旧)子数涵数·C语言——让C帮你做计算

    之前,我们学过了我们的第一个C程序--hello World.现在开始进一步学习,想一想如何让C帮你做计算. 我们先来看代码(我没有新建,还是用之前的hello world.cpp): 好,因为之前在 ...

  3. 窗体==>>初始Windows程序

    初识Windows程序 01.创建Windows程序(VS) 01.打开Visual Studio开发工具 02.选择"文件"→"新建"→"项目&qu ...

  4. redis配置注意事项

    最近在看redis方面的官方文档,redis-server的相关配置建议如下: 1.vm.overcommit_memory = 1 2.禁用linux内核特性transparent huge pag ...

  5. spring bean加载顺序指定方式之一

    在某些情况下,我们在容器启动的时候做一些事情,举个例子,加载缓存等.. 此时我们会希望某个bean先被加载并执行其中的afterpropertiesset方法. 因为spring默认是通过contex ...

  6. atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener

    atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener 1. 自定义web服务器的实现方案,基于原始socket vs   ...

  7. java中判断字符串是否为数字的方法

    一: //1.用JAVA自带的函数 public static boolean isNumeric(String str){ for (int i = 0; i < str.length(); ...

  8. ExtJs中xtype与组件类的对应表

    from:http://blog.163.com/jx_dream/blog/static/117056627201223091021410/ 核心提示:我们在使用 ExtJs 创建组件时最容易理解的 ...

  9. PL/SQL基础1(笔记)

    --基本结构DECLARE--变量声明部分:在此声明PL/SQL用到的变量,类型,游标,以及局部的存储过程和函数BEGIN --执行部分:过程及SQL语句,即程序的主要部分 EXCEPTION --执 ...

  10. ARC-数据类型需要释放的情况

    // Foundation :  OC// Core Foundation : C语言// Foundation和Core Foundation框架的数据类型可以互相转换的 //NSString *s ...