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

[经验分享] Docker Architecture、Differences Between Virtual Machine(VM) And LXC Container Te

[复制链接]
YunVN网友  发表于 2015-4-17 10:36:27 |阅读模式
  目录



0. 引言 - 为什么要有Docker技术
1. Docker简介
2. Docker技术架构
3. Docker部署技术
4. 如何安装、部署Docker
5. Docker安全
6. 底层实现
  
  0. 引言 - 为什么要有Docker技术
  0x1: 虚拟机技术和LXC容器技术的差别



1. 虚拟机VM(Virtual Machine)技术
每个虚拟机都有自己独享的内核, 能运行完整的不作修改的操作系统
2. 容器技术LXC(Linux Container)技术
容器(container)是一种轻量级的虚拟化技术, 用于生成一个独立的标准运行环境而不需要多个内核实例,例如Docker就是一种典型的LXC容器技术的实现
  0x2: LXC容器技术的优势



1. 快速部署(秒级),启动一个容器只需要派生一个进程并完成OS启动的用户态部分
而启动一个虚拟机需要执行额外的 BIOS 和内核代码
2. 容器几乎没有额外的 IO 性能开销
如果没有完善的硬件虚拟化支持,虚拟机会引入显著的 IO 性能开销
3. 容器的内存开销较小: 启动一个没有任何负载的容器仅需要几十 MB 的内存
而虚拟机由于包含完整的内核,内存开销要大得多。另外如果使用 Union FS 来构造容器的文件系统,能减少 page cache 带来的内存开销
4. 较小的磁盘空间占用: 构造容器的文件系统时,静态文件可以使用 bind-mount 或者Union FS 方式从宿主机加载,可以节省大量磁盘空间
  0x3: LXC容器技术的优势



1. 资源隔离效果逊于虚拟机
对于虚拟机技术,由于有 Hypervisor 的存在,资源的隔离实现非常完整。
而容器技术还处于开发阶段,资源隔离的效果要逊于虚拟机
2. 内核的修改会影响所有的容器
虚拟机因为 Hypervisor 的存在,内核的更新只会影响一个应用
3. 缺少动态迁移的支持
目前 OpenVZ 的 CRIU 项目提供了初步的 checkpointing 和 restore支持,但完整的动态迁移仍需时日。虚拟机的动态迁移方案相对比较完整
  
  1. Docker简介
  Docker基于Go语言开发,代码托管在 Github上,并遵循Apache 2.0开源协议



Build, Ship and Run Any App, Anywhere
Docker - An open platform for distributed applications for developers and sysadmins.
  Docker项目的目标是实现轻量级的操作系统虚拟化解决方案。Docker的基础是Linux容器(LXC)等技术
在LXC的基础上Docker进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作Docker的容器就像操作一个快速轻量级的虚拟机一样简单

  0x1: Docker的特性



1. Build
Develop an app using Docker containers with any language and any toolchain.
2. Ship
Ship the "Dockerized" app and dependencies anywhere - to QA, teammates, or the cloud - without breaking anything.
3. Run
Scale to 1000s of nodes, move between data centers and clouds, update with zero downtime and more.
  0x2: Docker和Virtual Machines(VM)的区别
  下面的图片比较了Docker和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现
  1. Virtual Machines
   DSC0000.jpg
  Each virtualized application includes



1. the application: which may be only 10s of MB
2. the necessary binaries and libraries
3. an entire guest operating system - which may weigh 10s of GB
  2. Docker

   DSC0001.jpg
  The Docker Engine container



1. the application
2. its dependencies(Bins/Libs)
  It runs as an isolated process in userspace on the host operating system, sharing the kernel with other containers. Thus, it enjoys the resource isolation and allocation benefits of VMs but is much more portable and efficient.
DSC0002.png



1. 一个Container通常包含应用及应用依赖项,Container用来隔离进程,这些进程主要运行在主机操作系统上的隔离区和用户空间。
这个是明显不同于传统的VMs
2. 传统的硬件虚拟化(例如VMWare、KVM、Xen、EC2)旨在创造一个完整虚拟机。每个虚拟化应用不仅包含应用的二进制文件,还需运行该应用程序所需的库、一个完整的Guest操作系统
3. 由于所有的容器共享同一个操作系统(以及二进制文件和库),所以,他们明显要比VM小的多,这样,就完全可以在一个物理主机上托管100个VMs(一般VM数量会受到严格限制)。此外,因为它们使用主机操作系统,重启一个VM并不意味着要重启操作系统,因此,容器更加轻便、高效
4. Docker中的容器效率会更高。因为一个传统的VM、应用、每个应用副本以及每个应用微小的变更都需要重新创建一个完整的VM  
一个新的应用在主机上仅仅包含应用及其二进制文件/库,这样就无需创建一个新的客户机操作系统。
5. 如果想在主机上运行该应用的几个副本,你甚至无需复制共享的二进制文件,即使你对应用进行了变更,你也无需拷贝变更内容
  0x3: Docker技术的核心竞争优势



1. Docker简单来说就是一个Container的管理工具。而Container就是一个更轻量级的虚拟机,但是这个虚拟机没有操作系统和设备(操作系统是共享的),container技术目前解决了软件行业的最大的几个问题
1) 应用的共享
2) 配置管理和维护(还有应用的隔离,效率等等)
3) 不管是在物理机环境还是云环境和虚拟机相比,container不仅更轻量,而且配置简化了很多(不用考虑操作系统和设备的配置)
2. 写应用的人不用考虑操作系统的配置,应用都在container里面
3. Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
4. Docker容器的运行不需要额外的hypervisor支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。事实上,Linux的内核已经在很多方面(例如命名空间)对虚拟化进行了支持
  Relevant Link:



http://blog.iyunv.com/u012601664/article/details/39547319
http://special.csdncms.iyunv.com/BeDocker/
http://www.iyunv.com/article/2014-02-01/2818306-Docker-Story
http://www.iyunv.com/article/2014-06-20/2820325-cloud-Docker
http://www.iyunv.com/article/2014-07-02/2820497-what's-docker
http://dockerpool.com/static/books/docker_practice/introduction/why.html
  0x4: Docker在线入门教程



https://www.docker.com/tryit
  
  2. Docker技术架构
  0x1: the open-source application container engine



https://github.com/docker/docker
  0x2: Docker的架构

  Docker架构下的三种运行方式



1. 作为守护进程,在Linux主机上管理LXC容器
1) 使用namespaces来做权限的控制和隔离
2) 使用cgroups来进行资源的配置
3) 通过aufs来提高文件系统的资源利用率
aufs是UnionFS的一种,它可以把对文件系统的改动当成一次commit一层层的叠加。这样的话多个容器之间就可以共享他们的文件系统层次。这样的话极大的节省了对存储的需求,并且也能加速容器的启动
2. 作为一个CLI,与守护进程的REST API进行对话(docker run ...)
3. 作为仓库的客户端,分享你所构建的内容(docker pull, docker commit)  
  0x3: Docker源码学习



http://www.infoq.com/cn/articles/docker-source-code-analysis-part1
http://www.infoq.com/cn/articles/docker-source-code-analysis-part2
http://www.infoq.com/cn/articles/docker-source-code-analysis-part3
  Relevant Link:



http://www.iyunv.com/article/2014-06-20/2820325-cloud-Docker
http://www.infoq.com/cn/dockers/
http://yeasy.gitbooks.io/docker_practice/
https://docker.cn/p/
http://www.iyunv.com/article/a/2014-06-18/15819053
  
  3. Docker部署技术

  0x1: Docker镜像



1. Docker镜像就是一个只读的模板
2. 一个镜像可以包含一个完整的ubuntu操作系统环境,里面仅安装了Apache或用户需要的其它应用程序
3. 镜像可以用来创建Docker容器
4. Docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用
  镜像的实现原理
Docker镜像是怎么实现增量的修改和维护的呢?每个镜像都由很多层次构成,Docker使用Union FS将这些不同的"层"结合到一个镜像中去 ,通常Union FS有两个用途



1. 一方面可以实现不借助LVM、RAID将多个disk挂到同一个目录下
2. 另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起,Live CD 正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作。Docker在AUFS上构建的容器也是利用了类似的原理
  0x2: Docker容器



1. Docker 利用容器来运行应用
2. 容器是从镜像创建的"运行实例"。它可以被启动、开始、停止、删除。每个容器都是相互隔离的(isolation)、保证安全的平台
3. 可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序
4. 镜像是只读的,容器在启动的时候创建一层可写层作为最上层
  0x3: Docker仓库



1. 仓库是集中存放镜像文件的场所。有时候会把"仓库"和"仓库注册服务器"(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)
2. 仓库分为
1) 公开仓库(Public): 最大的公开仓库是Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括Docker Pool等,可以提供大陆用户更稳定快速的访问
2) 私有仓库(Private): 用户也可以在本地网络内创建一个私有仓库
当用户创建了自己的镜像之后就可以使用push命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上pull下来就可以了
3. Docker仓库的概念跟Git类似,"仓库注册服务器"可以理解为GitHub这样的托管服务
  0x4: 成功使用案例



1. Gilt: Distributed applications to scale
Gilt Groupe, Inc., a leading online shopping company, operates an online flash sale site for men, women, girls, boys, and unisex in the United States.
2. Yelp: Continuous Integration
Yelp (NYSE: YELP) connects people with great local businesses. Yelp had a monthly average of 120 million unique visitors in Q4 2013
3. Spotify: Continuous Delivery
Spotify streams music to more than 40 million users in 57 countries around the world.
4. Baidu: Platform-as-a-Service (PaaS)
Baidu, Inc. is the number one Chinese-language Internet search provider that has a broad portfolio of products including social-networking products, music products, mobile related products and other products and services.
5. New Relic: Distributed Applications Composition
New Relic is a Software Analytics company that makes sense of billions of metrics across millions of apps.
6. Rackspace: Continuous Integration
Rackspace's email service (MailGun) that allows you to send, receive and track emails effortlessly. Mailgun has made significant investments in building a Docker-centric continuous integration system for this service where high-availability is a requirement.
7. Yandex: Platform-as-a-Service (PaaS)
Yandex is an European Internet company and the largest search provider in Russia.
Yandex’s Platform-as-a-Service (PaaS) is using Docker for infrastructure virtualization and application isolation.
8. Cambridge: Continuous Delivery
Cambridge Healthcare provides online access to health records and analytics for both patients and clinicians. They replaced several AWS AMIs with a single bare metal host running Docker to speed up their Jenkins-based continuous delivery pipeline.
9. eBay: Easy Application Deployment
eBay Now is eBay's local, same day delivery service. In this use case, Senior Architect Ted Dziuba discusses his use of Docker in a continuous integration process. He uses Docker to implement an efficient, automated path from the developer's laptop through test and QA.
  Relevant Link:



https://www.docker.com/resources/usecases/
https://www.docker.com/
  
  4. 安装、部署、使用Docker
  0x1: Docker Installation Based On Red Hat (64 bit)



https://docs.docker.com/installation/rhel/
https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F
https://code.iyunv.com/u010702509/docker_redhat
  对于CentOS6,可以使用EPEL库安装Docker,命令如下



//1. 安装Docker支持
sudo yum install http://mirrors.yun-idc.com/epel/6/i386/epel-release-6-8.noarch.rpm
sudo yum install docker-io
//2. 登录Docker镜像仓库
docker login
//3. 下载最新镜像
sudo docker pull centos:latest
  0x2: Docker Installation Based On ubntu 12.04 (64 bit)



1. 安装、升级内核
//Docker的运行需要Linux内核提供相应的支持
sudo apt-get update
sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring
sudo reboot
2. 第一次添加Docker的repository到你的本地秘钥库
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sudo apt-get update
sudo apt-get install lxc-docker
//期间会遇到一个警告,说这个包不可靠,你只需要回复yes然后继续安装就可以了
3. 官方也提供了一个简单脚本帮助你安装,你可以用curl来获取这个脚本然后执行安装
curl -s https://get.docker.io/ubuntu/ | sudo sh
4. 下载安装ubuntu的镜像封装到一个沙箱中
sudo docker run -i -t ubuntu /bin/bash
  0x3: Docker Installation Based On ubntu 13.04 (64 bit)




1. 确认是否安装了AUFS
sudo apt-get update
sudo apt-get install linux-image-extra-`uname -r`
2. 之后的步骤同ubntu 12.04 (64 bit)
  Relevant Link:



https://code.iyunv.com/u010702509/docker_ubntu
  0x4: Docker简单命令使用
  关于Docker的使用,最好的方法还是去官方提供的在线模拟运行网站,看再多的理论都不如亲自动手搭建部署实践



https://www.docker.com/tryit
  Relevant Link:



https://code.iyunv.com/u010702509/docker_puppet
https://code.iyunv.com/u010702509/docker_shareimage
https://code.iyunv.com/u010702509/docker_buildimage
https://code.iyunv.com/u010702509/docker_basic
https://code.iyunv.com/u010702509/docker/file/Docker.md
  0x5: Hello word Docker使用
  使用docker images显示本地已有的镜像



sudo docker images

  启动容器有以下几种方式



1. 基于镜像新建一个容器并启动
1) 输出一个"Hello World",之后终止容器
sudo docker run centos:latest /bin/echo 'Hello world'
2) 启动一个 bash 终端,允许用户进行交互,用户可以通过所创建的终端来输入命令
sudo docker run -t -i centos:latest /bin/bash
//-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开
2. 将在终止状态(stopped)的容器重新启动
可以利用docker start -a containerID命令,直接将一个已经终止的容器启动运行,容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源
3. 让Docker容器在后台以守护态(Daemonized)形式运行
sudo docker run -d centos:latest /bin/sh -c "while true; do echo hello world; sleep 1; done"
0e5719fb43aecf87f27d18089aac5034532d08a764ee5bce794192ca5b134404
容器启动后会返回一个唯一的id,也可以通过docker ps命令来查看容器信息
要获取容器的输出信息,可以通过docker logs命令
docker logs 0e5719fb43ae
  终止一个容器有2种方法



1. 使用docker stop来终止一个运行中的容器
2. 当Docker容器中指定的应用终结时,容器也自动终止
//终止状态的容器可以用docker ps -a命令看到,处于终止状态的容器,可以通过docker start命令来重新启动
  在使用 -d 参数时,容器启动后会进入后台。 某些时候需要进入容器进行操作



docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                      PORTS               NAMES
0e5719fb43ae        centos:latest       "/bin/sh -c 'while t   6 minutes ago       Up 6 minutes                                    loving_wright
docker attach loving_wright
//可以使用docker kill loving_wright来杀死后台运行中的容器
  可以使用docker rm来删除一个处于终止状态的容器



docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                      PORTS               NAMES
0e5719fb43ae        centos:latest       "/bin/sh -c 'while t   6 minutes ago       Exited (-1) 2 seconds ago                                    loving_wright
docker rm  loving_wright
//要注意的是,只有处于停止状态的容器才能删除
  当利用docker run来创建容器时,Docker在后台运行的标准操作包括



1. 检查本地是否存在指定的镜像,不存在就从公有仓库下载
2. 利用镜像创建并启动一个容器
3. 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
4. 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
5. 从地址池配置一个ip地址给容器
6. 执行用户指定的应用程序
7. 执行完毕后容器被终止
  我们在使用Docker的使用,离程序员最近的就是Image,也就是一个个封装好的应用环境



1. 所有的实例你都需要在你的机器中运行docker进程,后台运行docker进程,简单演示
sudo docker -d &
2. 现在你可以运行Docker客户端,默认情况下所有的命令都会经过一个受保护的Unix socket转发给docker进程,所以我们必须运行root或者通过sudo授权
sudo docker help
3. 下载ubuntu base镜像
# Download an ubuntu image
sudo docker pull ubuntu
4. 执行一个进程
CONTAINER_ID=$(sudo docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done")
sudo docker logs $CONTAINER_ID
5. 查看日志文件来确认它是否正常工作
sudo docker attach -sig-proxy=false $CONTAINER_ID
6. 连接到容器实时查看结果
sudo docker ps
7. 查看正在运行的进程
sudo docker stop $CONTAINER_ID
8. 当我们不需要时停止容器
sudo docker ps
  Relevant Link:



https://code.iyunv.com/u010702509/docker_helloword
  0x6: JAVA Tomcat Running Environment Installation




http://blog.iyunv.com/junjun16818/article/details/34845613#comments
  
  5. Docker安全
  评估Docker的安全性时,主要考虑三个方面



1. 由内核的"名字空间(namespace)"和"控制组机制"提供的容器内在安全
2. Docker程序(特别是服务端)本身的抗攻击性
3. 内核安全性的加强机制对容器安全性的影响
  0x1: 内核名字空间(namespace)
  Docker容器和LXC容器很相似,所提供的安全特性也是类似的。当用docker run启动一个容器时,在后台Docker为容器创建了一个独立的名字空间和控制组集合



1. 名字空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用
1) 父命名空间的进程"不能"被子命名空间看到
2) 子命名空间的进程"可以"被父命名空间看到
3) 同级之间的命名空间之间的进程"不可见"
1. 每个容器都有自己独有的网络栈,意味着它们不能访问其他容器的sockets或接口。但是,如果主机系统上做了相应的设置,容器可以像跟主机交互一样的和其他容器交互。当指定公共端口或使用links来连接2个容器时,容器就可以相互通信了(可以根据配置来限制通信的策略)
从网络架构的角度来看,所有的容器通过本地主机的网桥接口相互通信,就像物理机器通过物理交换机通信一样
  Docker的名字空间是基于Linux内核的命名空间架构实现的,关于Linux内核命名空间的相关知识,请参阅另一篇文章



http://www.iyunv.com/LittleHann/p/4026781.html
//搜索:2. Linux命名空间
  0x2: 控制组

  控制组是Linux容器机制的另外一个关键组件,负责实现资源的审计和限制
它提供了很多有用的特性;以及确保各个容器可以公平地分享主机的内存、CPU、磁盘 IO 等资源。更重要的是,控制组确保了当容器内的资源使用产生压力时不会连累主机系统
尽管控制组不负责隔离容器之间相互访问、处理数据和进程,它在防止拒绝服务(DDOS)攻击方面是必不可少的。尤其是在多用户的平台(比如公有或私有的PaaS)上,控制组十分重要。例如,当某些应用程序表现异常的时候,可以保证一致地正常运行和性能
  0x3: 内核能力机制

  能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。Linux内核自2.2版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上(DAC、MAC模型)
例如,一个Web服务进程只需要绑定一个低于1024的端口的权限,并不需要root权限。那么它只需要被授权net_bind_service能力即可
使用能力机制对加强 Docker 容器的安全有很多好处。通常,在服务器上会运行一堆需要特权权限的进程,包括有 ssh、cron、syslogd、硬件管理工具模块(例如负载模块)、网络配置工具等等。容器跟这些进程是不同的,因为几乎所有的特权进程都由容器以外的支持系统来进行管理



1. ssh: 访问被主机上ssh服务来管理
2. cron: 通常应该作为用户进程执行,权限交给使用它服务的应用来处理
3. 日志系统: 由Docker或第三方服务管理  
4. 网络管理: 在主机上设置,除非特殊需求,容器不需要对网络进行配置
  从上面的例子可以看出,大部分情况下,容器并不需要"真正的"root权限,容器只需要少数的能力即可。为了加强安全,容器可以禁用一些没必要的权限



1. 完全禁止任何mount操作
2. 禁止直接访问本地主机的套接字
3. 禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等
4. 禁止模块加载
  默认情况下,Docker启动的容器被严格限制只允许使用内核的一部分能力,这样,就算攻击者在容器中取得了root权限,也不能获得本地主机的较高权限,能进行的破坏也有限
默认情况下,Docker采用白名单机制,禁用必需功能之外的其它权限。 当然,用户也可以根据自身需求来为Docker容器启用额外的权限
  0x4: 系统原生提供的底层安全机制

  除了"能力机制"之外,还可以利用一些现有的安全机制来增强使用Docker的安全性



1. LSM(Linux Security Module)
1) TOMOYO
2) AppArmor
3) SELinux
2. 编译和运行时的安全检查
1) GRSEC
2) PAX
3) 通过地址随机化(ASLR Address space layout randomization)避免恶意探测
3. 使用一些有增强安全特性的容器模板
1) 带AppArmor的模板
2) 带SELinux策略的模板
4. 用户可以自定义访问控制机制来定制安全策略
  跟其它添加到Docker容器的第三方工具一样(比如网络拓扑和文件系统共享),有很多类似的机制,在不改变Docker内核情况下就可以加固现有的容器
  Relevant Link:



http://dockerpool.com/static/books/docker_practice/security/README.html
  
  6. 底层实现
  Docker底层的核心技术包括



1. Linux上的名字空间(Namespaces)
2. 控制组(Control groups)
3. Union文件系统(Union file systems)
4. 容器格式(Container format)
  我们知道,传统的虚拟机通过在宿主主机中运行hypervisor来模拟一整套完整的硬件环境提供给虚拟机的操作系统。虚拟机系统看到的环境是可限制的,也是彼此隔离的。这种直接的做法实现了对资源最完整的封装,但很多时候往往意味着系统资源的浪费。例如,以宿主机和虚拟机系统都为Linux系统为例,虚拟机中运行的应用其实可以利用宿主机系统中的运行环境
我们知道,在操作系统中,包括



1. 内核
2. 文件系统
3. 网络
4. PID
5. UID
6. IPC
7. 内存
8. 硬盘
9. CPU等等
  所有的资源都是应用进程直接共享的。 要想实现虚拟化,需要实现对这些资源的虚拟隔离
随着Linux系统对于"名字空间(name space)"功能的完善实现,Linux内核已经可以实现上面的所有需求,让某些进程在彼此隔离的名字空间中运行。大家虽然都共用一个内核和某些运行时环境(例如一些系统命令和系统库),但是彼此却看不到,都以为系统中只有自己的存在。这种机制就是容器(Container),利用名字空间来做权限的隔离控制,利用cgroups来做资源分配
  Docker采用了C/S架构,包括客户端和服务端。Docker daemon作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。客户端和服务端既可以运行在一个机器上,也可通过 socket或者RESTful API来进行通信

  Docker daemon一般在宿主主机后台运行,等待接收来自客户端的消息。Docker客户端则为用户提供一系列可执行命令,用户用这些命令实现跟Docker daemon交互
  0x1: 名字空间
  名字空间是Linux内核一个强大的特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响



1. pid名字空间
不同用户的进程就是通过pid名字空间隔离开的,且不同名字空间中可以有相同pid。所有的LXC进程在Docker中的父进程为Docker进程,每个LXC进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的Docker容器
2. net名字空间
有了pid名字空间,每个名字空间中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过net名字空间实现的,每个net名字空间有独立的网络设备、IP 地址、路由表、/proc/net目录。这样每个容器的网络就能隔离开来。Docker默认采用veth的方式,将容器中的虚拟网卡同host上的一个Docker网桥docker0连接在一起
3. ipc名字空间
容器中进程交互还是采用了Linux常见的进程间交互方法(interprocess communication - IPC),包括信号量、消息队列和共享内存等。然而同VM不同的是,容器的进程间交互实际上还是host上具有相同pid名字空间中的进程间交互,因此需要在IPC资源申请时加入名字空间信息,每个IPC资源有一个唯一的32位id
4. mnt名字空间
类似chroot,将一个进程放到一个特定的目录执行。mnt名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间中的进程所看到的文件目录就被隔离开了。同chroot不同,每个名字空间中的容器在/proc/mounts的信息只包含所在名字空间的mount point,即mnt名字空间是真正意义上的"chroot"
5. uts名字空间
UTS("UNIX Time-sharing System") 名字空间允许每个容器拥有独立的hostname和domain name,使其在网络上可以被视作一个独立的节点而非主机上的一个进程
6. user名字空间
每个容器可以有不同的用户和组id,也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户
  0x2: 控制组(cgroups)

  Cgroups是control groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu、memory、IO等等)的机制。最初由google的工程师提出,后来被整合进Linux内核。Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有cgroups就没有LXC
Cgroups最初的目标是为资源管理提供的一个统一的框架,既整合现有的cpuset等子系统,也为未来开发新的子系统提供接口。现在的cgroups适用于多种应用场景,从单个进程的资源控制,到实现操作系统层次的虚拟化(OS Level Virtualization)。Cgroups提供了一下功能



1. 限制进程组可以使用的资源数量(Resource limiting)
1) memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)
2. 进程组的优先级控制(Prioritization)
1) 使用cpu子系统为某个进程组分配特定cpu share
3. 记录进程组使用的资源数量(Accounting)
1) 使用cpuacct子系统记录某个进程组使用的cpu时间
4. 进程组隔离(Isolation)
1) 使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间
5. 进程组控制(Control)
1) 使用freezer子系统可以将进程组挂起和恢复
  Relevant Link:



https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/ch01.html
http://www.iyunv.com/lisperl/archive/2012/04/17/2453838.html
  0x3: 联合文件系统(UnionFS)

  联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)
联合文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像,另外,不同Docker容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
Docker中使用的AUFS(AnotherUnionFS)就是一种联合文件系统。AUFS支持为每一个成员目录(类似Git的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 AUFS 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)
Docker 目前支持的联合文件系统种类包括



1. AUFS
2. btrfs
3. vfs
4. DeviceMapper
  Unionfs是一个堆栈式的联合文件系统,它可以把多个目录(也叫分支)内容合并在一起, 而目录的物理位置是分开的。Unionfs允许只读和可读写目录并存,就是说可同时删除和增加内容. Unionfs应用的地方很多



1. 在多个磁盘分区上合并不同文件系统的主目录
2. 把几张CD光盘合并成一个统一的光盘目录(归档)
3. 具有写时复制(copy-on-write)功能Unionfs可以把只读和可读写文件系统合并在一起,虚拟上允许只读文件系统的修改可以保存到可写文件系统当中
  Linux上unionfs的实现依托了VFS设计的灵活性,从架构上看,它在VFS的下层,在具体文件系统(如ext3, ext4等)的上层。系统调用read()/write()落在VFS上,VFS找到待操作文件的inode(unionfs inode),经过unionfs的路由后找到真实文件的inode,执行操作。这是一个kernel hook的过程
  Relevant Link:



http://www.kissthink.com/archive/9120.html
http://fengchj.com/?tag=%E8%81%94%E5%90%88%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F
http://en.wikipedia.org/wiki/Union_mount
http://en.wikipedia.org/wiki/UnionFS
http://lwn.net/Articles/325369/
http://lwn.net/Articles/327738/
  0x4: overlayfs

  overlayfs能将两个目录"合并"(借助了Linux内核提供的命名空间的基础数据结构、以及位于VFS和底层具体文件系统之间的UnionFS实现的逻辑上虚拟的合并),例如



1. dir1/目录
./fire
./water
2. dir2/目录
./apple
./banana
  mount -t overlayfs overlayfs -olowerdir=/dir1,upperdi=/dir2 /test1/
合并以后,test1/目录里将会有



./fire
./water
./apple
./banana
  其中/test1/fire、/dir1/fire其实是"同一个文件",用的是一台page cache
  基于overlayfs实现"文件目录共享"



1. 准备一个base目录,将常用的可共用的系统文件放置进去,例如/etc、/bin、/lib、/usr等
2. 列出每个虚拟机容器需要独立使用的目录,例如/store1、/store2、/store3、/store4
3. 为每个虚拟机准备一个空目录,例如/container1、/container2、/container3、/container4
4. mount
mount -t overlayfs overlayfs -olowerdir=/base,upperdir=/store1 /container1
mount -t overlayfs overlayfs -olowerdir=/base,upperdir=/store2 /container2
mount -t overlayfs overlayfs -olowerdir=/base,upperdir=/store3 /container3
mount -t overlayfs overlayfs -olowerdir=/base,upperdir=/store4 /container4
5. 运维人员执行
cd /container1/
chroot
这样,每个虚拟机就在拥有自己"独立"的目录的前提下,并共享了系统的一些库文件
  overlayfs从概念上有点类似视图的概念,对lowerdir的文件目录进行了一层抽象,对外提供了一层虚拟的视图
  VFS的高度灵活性为overlayfs的实现提供了坚实的架构基础,既然对一个文件的操作是可以任意实现的,那就完全可以把文件A的read直接转为对另一个文件B的read
这就是overlayfs的根本,把对overlayfs文件系统系统里一个文件的操作,转为对lowerdir里对应文件的操作



static struct file *ovl_open(struct dentry *dentry, int flags, const struct cred *cred)
{
int err;
struct path realpath;
enum ovl_path_type type;
/*
overlayfs在dentry的d_fsdata成员里放了文件对应的lowerdir和upperdir的信息,此处便可以找到该文件对应的lowerdirdir的文件
*/
type = ovl_path_real(dentry, &realpath);
if (ovl_open_need_copy_up(flags, type, realpath.dentry))
{
if (flags & O_TRUNC)
err = ovl_copy_up_truncate(dentry, 0);
else
err = ovl_copy_up(dentry);
if (err)
return ERR_PTR(err);
ovl_path_upper(dentry, &realpath);
}
/*
将这个lowerdir对应的文件path传给vfs_open,这样,被真正open的就是lowerdir对应的"下层文件"了,之后的read/mmap都是调用该文件的file_operation
*/
return vfs_open(&realpath, flags, cred);
}
  而overlayfs提供的"虚拟共享目录"也是通过VFS层实现的



static int ovl_readdir(struct file *file, void *buf, filldir_t filler)
{
struct ovl_dir_file *od = file->private_data;
int res;
if (!file->f_pos)
ovl_dir_reset(file);
if (od->is_real)
{
res = vfs_readdir(od->realfile, filler, buf);
file->f_pos = od->realfile->f_pos;
return res;
}
if (!od->is_cached)
{
struct path lowerpath;
struct path upperpath;
struct ovl_readdir_data rdd = { .list = &od->cache };
ovl_path_lower(file->f_path.dentry, &lowerpath);
ovl_path_upper(file->f_path.dentry, &upperpath);
//将上下两层目录的内容都读出来,合并,放入rdd这个数据结构
res = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd);
if (res)
return res;
od->cache_version = ovl_dentry_version_get(file->f_path.dentry);
od->is_cached = true;
/*
将od->curser指向od-cache里对应偏移的dentry,这个dentry可以理解为类似该目录下面文件的dentry
*/
ovl_seek_cursor(od, file->f_pos);
}
/*
rdd数据结构里的list成员,实际上是指向od->cache的,所以移动od->cursor就是在沿着rdd->list找到所有dentry
*/
while (od->cursor.next != &od->cache)
{
int over;
loff_t off;
struct ovl_cache_entry *p;
p = list_entry(od->cursor.next, struct ovl_cache_entry, l_node);
off = file->f_pos;
file->f_pos++;
list_move(&od->cursor, &p->l_node);
if (p->is_whiteout)
continue;
over = filler(buf, p->name, p->len, off, p->ino, p->type);
if (over)
break;
}
//两层目录下的文件的文件名都读出来放到一起了
return 0;
}
  overlayfs的特性是将上下层目录合并为一个文件系统,"下层"目录是只读的,所以修改都是对"上层"的修改,在这个"新"的文件系统中



1. 新创建的文件实际是创建在"上层"目录的
2. 删除文件时
1) 如果文件来自"下层"目录,则隐藏它(从虚拟机容器用户的角度来看就像删除了一样)
2) 如果文件来自"上层"目录,则直接删除即可
3. 写一个文件时
1) 如果文件来自"下层"目录,则拷贝其到上层目录,然后写这个"上层"的新文件
2) 如果文件来自"上层"目录,则直接写即可

  有VFS的高度灵活性,才有overlayfs的简洁实现



1. 上下合并
2. 同名覆盖
3. 写时拷贝
  Relevant Link:



http://en.wikipedia.org/wiki/OverlayFS
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/overlayfs.txt
https://github.com/torvalds/linux/commit/e9be9d5e76e34872f0c37d72e25bc27fe9e2c54c
http://www.phoronix.com/scan.php?page=news_item&px=MTc5OTc
http://wenku.baidu.com/view/2c82473ca32d7375a41780ab.html
https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-2.6.38/209-overlayfs.patch?rev=26213
http://issuu.com/byjgli/docs/overlayfs_procfs_____________/3
  
  Copyright (c) 2014 LittleHann All rights reserved
  

运维网声明 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-58077-1-1.html 上篇帖子: docker解决数据存储问题的方案 下篇帖子: docker level1
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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