Docker

Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器完全是使用沙箱机制,相互之间不会有任何接口。

Docker  PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github , 基于go语言并遵从Apache2.0协议开源。

Docker2013年以来非常火热,无论是从 github 上的代码活跃度,还是RedhatRHEL6.5中集成对Docker的支持, 就连 Google Compute Engine也支持 docker 在其之上运行。

一款开源软件能否在商业上成功,很大程度上依赖三件事 - 成功的 user case(用例), 活跃的社区和一个好故事。 dotCloud 自家的 PaaS 产品建立在docker之上,长期维护且有大量的用户,社区也十分活跃,接下来我们看看docker的故事。

面对上述几个问题,docker设想是交付运行环境如同海运,OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员制造。这样,交付一个软件,就是一系列标准化组件的集合的交付,如同乐高积木,用户只需要选择合适的积木组合,并且在最顶端署上自己的名字(最后个标准化组件是用户的app)。这也就是基于dockerPaaS产品的原型。

Docker架构

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来创建。容器与镜像的关系类似于面向对象编程中的对象与类。

典型场景

docker的网站上提到了docker的典型场景:

·            Automating the packaging and deployment of applications

·            Creation of lightweight, private PAAS environments

·            Automated testing and continuous integration/deployment

·            Deploying and scaling web apps, databases and backendservices

由于其基于LXC的轻量级虚拟化的特点,docker相比KVM之类最明显的特点就是启动快,资源占用小。因此对于构建隔离的标准化的运行环境,轻量级的PaaS(dokku), 构建自动化测试和持续集成环境,以及一切可以横向扩展的应用(尤其是需要快速启停来应对峰谷的web应用)

构建标准化的运行环境,现有的方案大多是在一个baseOS上运行一套puppet/chef,或者一个image文件,其缺点是前者需要base OS许多前提条件,后者几乎不可以修改(因为copy on write 的文件格式在运行时rootfsread only)。并且后者文件体积大,环境管理和版本控制本身也是一个问题。

PaaS环境是不言而喻的,其设计之初和dotcloud的案例都是将其作为PaaS产品的环境基础。

因为其标准化构建方法(buildfile)和良好的REST API,自动测试和持续集成/部署能够很好的集成进来。

因为LXC轻量级的特点,其启动快,而且docker能够只加载每个container变化的部分,这样资源占用小,能够在单机环境下与KVM之类的虚拟化方案相比能够更加快速和占用更少资源。

局限

Docker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,简单总结几点:

1.     Docker是基于Linux 64bit的,无法在32bitlinux/Windows/unix环境下使用

2.     LXC是基于cgrouplinux kernel功能的,因此containerguest系统只能是linux base

3.     隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库

4.     网络管理相对简单,主要是基于namespace隔离

5.     cgroupcpucpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费)

6.     dockerdisk的管理比较有限

7.     container随着用户进程的停止而销毁,container中的log等用户数据不便收集

针对1-2,有windows base应用的需求的基本可以pass; 3-5主要是看用户的需求,到底是需要一个container还是一个VM, 同时也决定了docker作为 IaaS 不太可行。

针对6,7虽然是docker本身不支持的功能,但是可以通过其他手段解决(disk quota, mount --bind)。总之,选用container还是vm, 就是在隔离性和资源复用性上做权衡。

Docker并非适合所有应用场景,Docker只能虚拟基于Linux的服务。Windows Azure 服务能够运行Docker实例,但到目前为止Windows服务还不能被虚拟化。

原理

Docker核心解决的问题是利用LXC来实现类似VM的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源。同VM的方式不同LXC 其并不是一套硬件虚拟化方法 - 无法归属到全虚拟化、部分虚拟化和半虚拟化中的任意一个,而是一个操作系统级虚拟化方法, 理解起来可能并不像VM那样直观。所以我们从虚拟化到docker要解决的问题出发,看看他是怎么满足用户虚拟化需求的。

用户需要考虑虚拟化方法,尤其是硬件虚拟化方法,需要借助其解决的主要是以下4个问题:

·            隔离性 - 每个用户实例之间相互隔离, 互不影响。硬件虚拟化方法给出的方法是VM, LXC给出的方法是container,更细一点是kernel namespace

·            可配额/可度量 - 每个用户实例可以按需提供其计算资源,所使用的资源可以被计量。硬件虚拟化方法因为虚拟了CPU, memory可以方便实现, LXC则主要是利用cgroups来控制资源

·            移动性 - 用户的实例可以很方便地复制、移动和重建。硬件虚拟化方法提供snapshotimage来实现,docker(主要)利用AUFS实现

·            安全性 - 这个话题比较大,这里强调是host主机的角度尽量保护container。硬件虚拟化的方法因为虚拟化的水平比较高,用户进程都是在KVM等虚拟机容器中翻译运行的, 然而对于LXC, 用户的进程是lxc-start进程的子进程, 只是在Kernelnamespace中隔离的, 因此需要一些kernelpatch来保证用户的运行环境不会受到来自host主机的恶意入侵, dotcloud(主要是)利用kernel grsecpatch解决的.

Linux Namespace(NS)

         LXC所实现的隔离性主要是来自Kernel的namespace,其中pid,net,ipc,mnt,uts等namespace将container的进程,网络,消息,文件系统和hostname隔离开。

pid namespace

之前提到用户的进程是lxc-start进程的子进程, 不同用户的进程就是通过pidnamespace隔离开的,且不同 namespace 中可以有相同PID。具有以下特征:

1.     每个namespace中的pid是有自己的pid=1的进程(类似/sbin/init进程)

2.     每个namespace中的进程只能影响自己的同一个namespace或子namespace中的进程

3.     因为/proc包含正在运行的进程,因此在container中的pseudo-filesystem/proc目录只能看到自己namespace中的进程

4.     因为namespace允许嵌套,父namespace可以影响子namespace的进程,所以子namespace的进程可以在父namespace中看到,但是具有不同的pid

正是因为以上的特征,所有的LXC进程在docker中的父进程为docker进程,每个lxc进程具有不同的namespace。同时由于允许嵌套,因此可以很方便的实现 LXC in LXC

net namespace

有了 pid namespace, 每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过netnamespace实现的,

每个net namespace有独立的 networkdevices, IP addresses, IP routing tables, /proc/net 目录。这样每个container的网络就能隔离开来。

LXC在此基础上有5种网络类型,docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge连接在一起。

ipc namespace

container中进程交互还是采用linux常见的进程间交互方法(interprocesscommunication - IPC), 包括常见的信号量、消息队列和共享内存。然而同VM不同,container 的进程间交互实际上还是host上具有相同pid namespace中的进程间交互,因此需要在IPC资源申请时加入namespace信息 - 每个IPC资源有一个唯一的 32bit ID

mnt namespace

类似chroot,将一个进程放到一个特定的目录执行。mnt namespace允许不同namespace的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。同chroot不同,每个namespace中的container/proc/mounts的信息只包含所在namespacemount point

uts namespace

UTS(“UNIXTime-sharing System”) namespace允许每个container拥有独立的hostnamedomainname, 
  使其在网络上可以被视作一个独立的节点而非Host上的一个进程。

user namespace

每个container可以有不同的 user group id, 也就是说可以以container内部的用户在container内部执行程序而非Host上的用户。

有了以上6namespace从进程、网络、IPC、文件系统、UTS和用户角度的隔离,一个container就可以对外展现出一个独立计算机的能力,并且不同containerOS层面实现了隔离。 
  然而不同namespace之间资源还是相互竞争的,仍然需要类似ulimit来管理每个container所能使用的资源 - LXC 采用的是cgroup

Control Groups (cgroups)

cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对该进程的资源控制。具体的资源配置选项可以在该文件夹中新建子 subsystem {子系统前缀}.{资源项} 是典型的配置方法,

memory.usage_in_bytes 就定义了该group subsystem memory中的一个内存限制选项。

另外,cgroups中的 subsystem可以随意组合,一个subsystem可以在不同的group中,也可以一个group包含多个subsystem - 也就是说一个 subsystem

Linux 容器 (LXC)

LXC 旨在提供一个共享kernel OS 级虚拟化方法,在执行时不用重复加载Kernel, containerkernelhost共享,因此可以大大加快container启动过程,并显著减少内存消耗。在实际测试中,基于LXC的虚拟化方法的IOCPU性能几乎接近 baremetal 的性能[6]  , 大多数数据有相比 Xen具有优势。当然对于KVM这种也是通过Kernel进行隔离的方式, 性能优势或许不是那么明显, 主要还是内存消耗和启动时间上的差异。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值