Docker Architecture、Docker Usage

目录php

0. 引言 - 为何要有Docker技术
1. Docker简介
2. Docker安装、部署、使用
3. Docker安全
4. Docker底层实现
5. Docker网络配置
6. Dockerfile详解
7. Docker Volume

 

0. 引言 - 为何要有Docker技术html

0x1: 虚拟机技术和LXC容器技术的差异node

1. 虚拟机VM(Virtual Machine)技术
每一个虚拟机都有本身独享的内核, 能运行完整的不做修改的操做系统 

2. 容器技术LXC(Linux Container)技术
容器(container)是一种轻量级的虚拟化技术, 用于生成一个独立的标准运行环境而不须要多个内核实例,例如Docker就是一种典型的LXC容器技术的实现

0x2: LXC容器技术的优点linux

1. 快速部署(秒级),启动一个容器只须要派生一个进程并完成OS启动的用户态部分
而启动一个虚拟机须要执行额外的 BIOS 和内核代码

2. 容器几乎没有额外的 IO 性能开销
若是没有完善的硬件虚拟化支持,虚拟机会引入显著的 IO 性能开销

3. 容器的内存开销较小: 启动一个没有任何负载的容器仅须要几十 MB 的内存
而虚拟机因为包含完整的内核,内存开销要大得多。另外若是使用 Union FS 来构造容器的文件系统,能减小 page cache 带来的内存开销

4. 较小的磁盘空间占用: 构造容器的文件系统时,静态文件可使用 bind-mount 或者Union FS 方式从宿主机加载,能够节省大量磁盘空间

0x3: LXC容器技术的优点git

1. 资源隔离效果逊于虚拟机
对于虚拟机技术,因为有 Hypervisor 的存在,资源的隔离实现很是完整。
而容器技术还处于开发阶段,资源隔离的效果要逊于虚拟机

2. 内核的修改会影响全部的容器
虚拟机由于 Hypervisor 的存在,内核的更新只会影响一个应用

3. 缺乏动态迁移的支持
目前 OpenVZ 的 CRIU 项目提供了初步的 checkpointing 和 restore支持,但完整的动态迁移仍需时日。虚拟机的动态迁移方案相对比较完整

 

1. Docker简介github

Docker基于Go语言开发,代码托管在 Github上,并遵循Apache 2.0开源协议web

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的容器就像操做一个快速轻量级的虚拟机同样简单
docker

0x1: Docker的特性shell

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)的区别ubuntu

下面的图片比较了Docker和传统虚拟化方式的不一样之处,可见容器是在操做系统层面上实现虚拟化,直接复用本地主机的操做系统,而传统方式则是在硬件层面实现

1. Virtual Machines

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

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.

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的内核已经在不少方面(例如命名空间)对虚拟化进行了支持

0x4: 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)  

0x5: 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上构建的容器也是利用了相似的原理 

0x6: Docker容器

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

0x7: Docker仓库

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

0x8: 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.csdn.net/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.csdn.net/article/a/2014-06-18/15819053
https://www.docker.com/resources/usecases/
https://www.docker.com/
http://blog.csdn.net/u012601664/article/details/39547319
http://special.csdncms.csdn.net/BeDocker/
http://www.csdn.net/article/2014-02-01/2818306-Docker-Story
http://www.csdn.net/article/2014-06-20/2820325-cloud-Docker
http://www.csdn.net/article/2014-07-02/2820497-what's-docker
http://dockerpool.com/static/books/docker_practice/introduction/why.html
https://github.com/docker/docker

 

2. 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.csdn.net/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.csdn.net/u010702509/docker_ubntu 

0x4: Install Docker on Ubuntu 14.04 LTS

apt-get update
apt-get -y install docker.io

0x5: Docker简单命令使用

1. 列出机器上的镜像(images)

docker images 

咱们能够根据REPOSITORY来判断这个镜像是来自哪一个服务器,若是没有 / 则表示官方镜像,相似于username/repos_name表示Github的我的公共库,相似于regsistory.example.com:5000/repos_name则表示的是私服

2. 在docker index中搜索image(search)

docker search remnux
//搜索的范围是官方镜像和全部我的公共镜像。NAME列的 / 后面是仓库的名字

3. 从docker registry server 中下拉image或repository(pull)

docker pull centos
//默认拉取最新镜像: centos:latest

也能够明确指定具体的镜像
docker pull centos:centos6

也能够从某我的的公共仓库(包括本身是私人仓库)拉取
docker pull remnux/thug

若是你没有网络,或者从其余私服获取镜像,形如 
docker pull dl.dockerpool.com:5000/mongo:latest

4. 推送一个image或repository到registry(push)

与上面的pull对应,能够推送到Docker Hub的Public、Private以及私服,但不能推送到Top Level Repository

docker push seanlook/mongo
docker push registry.tp-link.net:5000/mongo:2014-10-27

5. 使用image建立container并执行相应命令,而后中止

docker run命令首先会从特定的image创之上create一层可写的container,而后经过start命令来启动它。中止的container能够从新启动并保留原来的修改。run命令启动参数有不少

docker run --rm=true ubuntu echo "hello world"
hello word
//--rm=true参数,即完成操做后中止容器并从文件系统移除
当利用docker run来建立容器时,Docker在后台运行的标准操做包括
    1) 检查本地是否存在指定的镜像,不存在就从公有仓库下载
    2) 利用镜像建立并启动一个容器
    3) 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
    4) 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
    5) 从地址池配置一个ip地址给容器
    6) 执行用户指定的应用程序
    7) 执行完毕后容器被终止

6. 使用image建立container并进入交互模式, login shell是/bin/bash

docker run -i -t --name mytest centos:centos6 /bin/bash
bash-4.1#
//--name参数能够指定启动后的容器名字,若是不指定则docker会帮咱们取一个名字
//-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开 

7. 运行出一个container放到后台运行

docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 2; done"
ae60c4b642058fefcc61ada85a610914bed9f5df0e2aa147100eab85cea785dc
//它将直接把启动的container挂起放在后台运行(saas),而且会输出一个CONTAINER ID,经过docker ps能够看到这个容器的信息,可在container外面查看它的输出docker logs ae60c4b64205,也能够经过docker attach ae60c4b64205链接到这个正在运行的终端

8. 映射host到container的端口和目录

映射主机到容器的端口是颇有用的,好比在container中运行memcached,端口为11211,运行容器的host能够链接container的 internel_ip:11211 访问,若是有从其余主机访问memcached需求那就能够经过-p选项,形如-p <host_port:contain_port>,存在如下几种写法 
-p 11211:11211 这个便是默认状况下,绑定主机全部网卡(0.0.0.0)的11211端口到容器的11211端口上
-p 127.0.0.1:11211:11211 只绑定localhost这个接口的11211端口
-p 127.0.0.1::5000
-p 127.0.0.1:80:8080

9. 终止容器

终止一个容器有2种方法
    1) 使用docker stop来终止一个运行中的容器 
    2) 当Docker容器中指定的应用终结时,容器也自动终止
//终止状态的容器能够用docker ps -a命令看到,处于终止状态的容器,能够经过docker start命令来从新启动  
在使用 -d 参数时,容器启动后会进入后台。 某些时候须要进入容器进行操做,可使用docker rm来删除一个处于终止状态的容器,要注意的是,只有处于中止状态的容器才能删除

10. 查看日志文件来确认它是否正常工做

sudo docker attach -sig-proxy=false $CONTAINER_ID

11. 将在终止状态(stopped)的容器从新启动

能够利用docker start -a containerID命令,直接将一个已经终止的容器启动运行,容器的核心为所执行的应用程序,所须要的资源都是应用程序运行所必需的。除此以外,并无其它的资源 

12. 将一个container固化为一个新的image(commit)

当咱们在制做本身的镜像的时候,会在container中安装一些工具、修改配置,若是不作commit保存起来,那么container中止之后再启动,这些更改就消失了。
docker commit <container> [repo:tag]
只能提交正在运行的container,即经过docker ps能够看见的容器

13. 默认状况下全部的命令都会通过一个受保护的Unix socket转发给docker进程,因此咱们必须运行root或者经过sudo受权

sudo docker help

Relevant Link:

https://code.csdn.net/u010702509/docker_puppet
https://code.csdn.net/u010702509/docker_shareimage
https://code.csdn.net/u010702509/docker_buildimage
https://code.csdn.net/u010702509/docker_basic
https://code.csdn.net/u010702509/docker/file/Docker.md
http://www.liquidweb.com/kb/how-to-install-docker-on-ubuntu-14-04-lts/
https://docs.docker.com/engine/installation/linux/ubuntulinux/
https://code.csdn.net/u010702509/docker_helloword
https://segmentfault.com/a/1190000000751601

0x6: JAVA Tomcat Running Environment Installation

http://blog.csdn.net/junjun16818/article/details/34845613#comments

 

3. 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.cnblogs.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

 

4. Docker底层实现

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.cnblogs.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

An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other.
This approach is 'hybrid' because the objects that appear in the filesystem do not all appear to belong to that filesystem. In many cases an object accessed in the union will be indistinguishable from accessing the corresponding object from the original filesystem. This is most obvious from the 'st_dev'(设备号) field returned by stat.
While directories will report an st_dev from the overlay-filesystem, all non-directory objects will report an st_dev from the lower or upper filesystem that is providing the object.  Similarly st_ino will only be unique when combined with st_dev, and both of these can change over the lifetime of a non-directory object.  Many applications and tools ignore these values and will not be affected.

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. 列出每一个虚拟机容器须要独立使用的目录,例如/store一、/store二、/store三、/store4
3. 为每一个虚拟机准备一个空目录,例如/container一、/container二、/container三、/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的文件目录进行了一层抽象,对外提供了一层虚拟的视图

1. Upper and Lower

An overlay filesystem combines two filesystems

1. an 'upper' filesystem
The upper filesystem will normally be writable and if it is it must support the creation of trusted.* extended attributes, and must provide valid d_type in readdir responses, so NFS is not suitable.
A read-only overlay of two read-only filesystems may use any filesystem type.

2. a 'lower' filesystem
The lower filesystem can be any filesystem supported by Linux and does not need to be writable.  The lower filesystem can even be another overlayfs

When a name exists in both filesystems, the object in the 'upper' filesystem is visible while the object in the 'lower' filesystem is either hidden or, in the case of directories, merged with the 'upper' object.

2. Directories

Overlaying mainly involves directories.  If a given name appears in both upper and lower filesystems and refers to a non-directory in either, then the lower object is hidden - the name refers only to the upper object.
Where both upper and lower objects are directories, a merged directory is formed.
At mount time, the two directories given as mount options "lowerdir" and "upperdir" are combined into a merged directory:

mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,workdir=/work /merged
//The "workdir" needs to be an empty directory on the same filesystem as upperdir.

Then whenever a lookup is requested in such a merged directory, the lookup is performed in each actual directory and the combined result is cached in the dentry belonging to the overlay filesystem.  
If both actual lookups find directories, both are stored and a merged directory is created, otherwise only one is stored: the upper if it exists, else the lower.
Only the lists of names from directories are merged.  Other content such as metadata and extended attributes are reported for the upper directory only.  These attributes of the lower directory are hidden.

3. whiteouts and opaque directories

In order to support rm and rmdir without changing the lower filesystem, an overlay filesystem needs to record in the upper filesystem that files have been removed.  This is done using whiteouts and opaque directories (non-directories are always opaque).

1. A whiteout is created as a character device with 0/0 device number. When a whiteout is found in the upper level of a merged directory, any matching name in the lower level is ignored, and the whiteout itself is also hidden.
2. A directory is made opaque by setting the xattr "trusted.overlay.opaque" to "y".  Where the upper filesystem contains an opaque directory, any directory in the lower filesystem with the same name is ignored.

4. readdir

When a 'readdir' request is made on a merged directory, the upper and lower directories are each read and the name lists merged in the obvious way (upper is read first, then lower - entries that already exist are not re-added).  This merged name list is cached in the 'struct file' and so remains as long as the file is kept open.  If the
directory is opened and read by two processes at the same time, they will each have separate caches.  A seekdir to the start of the directory (offset 0) followed by a readdir will cause the cache to be discarded and rebuilt.
This means that changes to the merged directory do not appear while a directory is being read.  This is unlikely to be noticed by many programs.
seek offsets are assigned sequentially when the directories are read. Thus if

1. read part of a directory
2. remember an offset, and close the directory
3. re-open the directory some time later
4. seek to the remembered offset

there may be little correlation between the old and new locations in the list of filenames, particularly if anything has changed in the directory.
Readdir on directories that are not merged is simply handled by the underlying directory (upper or lower).

5. Non-directories

Objects that are not directories (files, symlinks, device-special files etc.) are presented either from the upper or lower filesystem as appropriate

1. When a file in the lower filesystem is accessed in a way the requires write-access, such as opening for write access, changing some metadata etc.
2. the file is first copied from the lower filesystem to the upper filesystem (copy_up)
//Note that creating a hard-link also requires copy_up, though of course creation of a symlink does not.

The copy_up may turn out to be unnecessary, for example if the file is opened for read-write but the data is not modified.

1. The copy_up process first makes sure that the containing directory exists in the upper filesystem - creating it and any parents as necessary.
2. It then creates the object with the same metadata (owner,mode, mtime, symlink-target etc.) 
3. and then if the object is a file, the data is copied from the lower to the upper filesystem.  
4. Finally any extended attributes are copied up.
5. Once the copy_up is complete, the overlay filesystem simply provides direct access to the newly created file in the upper filesystem 
6. future operations on the file are barely noticed by the overlay filesystem (though an operation on the name of the file such as rename or unlink will of course be noticed and handled).

6. Multiple lower layers

Multiple lower layers can now be given using the the colon (":") as a separator character between the directory names.  For example:

mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 /merged
//As the example shows, "upperdir=" and "workdir=" may be omitted.  In that case the overlay will be read-only.

The specified lower directories will be stacked beginning from the rightmost one and going left.  In the above example lower1 will be the top, lower2 the middle and lower3 the bottom layer

7. Non-standard behavior

The copy_up operation essentially creates a new, identical file and moves it over to the old name.  The new file may be on a different filesystem, so both st_dev and st_ino of the file may change.
Any open files referring to this inode will access the old data and metadata.  Similarly any file locks obtained before copy_up will not apply to the copied up file.
On a file opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) and fsetxattr(2) will fail with EROFS.
If a file with multiple hard links is copied up, then this will "break" the link.  Changes will not be propagated to other names referring to the same inode.
Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory object in overlayfs will not contain valid absolute paths, only relative paths leading up to the filesystem's root.  This will be fixed in the future.
Some operations are not atomic, for example a crash during copy_up or rename will leave the filesystem in an inconsistent state.  This will be addressed in the future.

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

 

5. Docker网络配置

docker_networking

Dokcer 经过使用 Linux 桥接提供容器之间的通讯,docker0 桥接接口的目的就是方便 Docker 管理。当 Docker daemon 启动时须要作如下操做

1. creates the docker0 bridge if not present: 若是 docker0 不存在则建立
2. searches for an IP address range which doesn’t overlap with an existing route: 搜索一个与当前路由不冲突的 ip 段
3. picks an IP in the selected range: 在肯定的范围中选择 ip
4. assigns this IP to the docker0 bridge: 绑定 ip 到 docker0

0x1: Docker四种网络模式

docker run 建立 Docker 容器时,能够用 --net 选项指定容器的网络模式,Docker 有如下 4 种网络模式

1. host模式: 使用 --net=host 指定
2. container模式: 使用 --net=container:NAME_or_ID 指定 
3. none模式: 使用 --net=none 指定
4. bridge模式:使用 --net=bridge 指定,默认设置

1. host模式

若是启动容器的时候使用 host 模式,那么这个容器将不会得到一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出本身的网卡,配置本身的 IP 等,而是使用宿主机的 IP 和端口
例如,咱们在 10.10.101.105/24 的机器上用 host 模式启动一个含有 web 应用的 Docker 容器,监听 tcp 80 端口。当咱们在容器中执行任何相似 ifconfig 命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用 10.10.101.105:80 便可,不用任何 NAT 转换,就如直接跑在宿主机中同样。可是,容器的其余方面,如文件系统、进程列表等仍是和宿主机隔离的

2. container模式

这个模式指定新建立的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新建立的容器不会建立本身的网卡,配置本身的 IP,而是和一个指定的容器共享 IP、端口范围等。一样,两个容器除了网络方面,其余的如文件系统、进程列表等仍是隔离的。两个容器的进程能够经过 lo 网卡设备通讯

3. none模式

这个模式和前两个不一样。在这种模式下,Docker 容器拥有本身的 Network Namespace,可是,并不为 Docker容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。须要咱们本身为 Docker 容器添加网卡、配置 IP 等

4. bridge模式

vethbridge

bridge 模式是 Docker 默认的网络设置,此模式会为每个容器分配 Network Namespace、设置 IP 等,并将一个主机上的 Docker 容器链接到一个虚拟网桥上。当 Docker server 启动时,会在主机上建立一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会链接到这个虚拟网桥上。虚拟网桥的工做方式和物理交换机相似,这样主机上的全部容器就经过交换机连在了一个二层网络中
接下来就要为容器分配 IP 了,Docker 会从 RFC1918 所定义的私有 IP 网段中,选择一个和宿主机不一样的IP地址和子网分配给 docker0,链接到 docker0 的容器就从这个子网中选择一个未占用的 IP 使用。如通常 Docker 会使用 172.17.0.0/16 这个网段,并将 172.17.42.1/16 分配给 docker0 网桥(在主机上使用 ifconfig 命令是能够看到 docker0 的,能够认为它是网桥的管理接口,在宿主机上做为一块虚拟网卡使用)

Relevant Link:

https://opskumu.gitbooks.io/docker/content/chapter6.html
http://dockone.io/article/402
http://www.oschina.net/translate/docker-network-configuration

 

6. Dockerfile详解

docker  build -t edwardsbean/centos6-jdk1.7  .
//当前目录下包含Dockerfile,使用命令build来建立新的image,并命名为edwardsbean/centos6-jdk1.7

0x1: Format

# Comment
FROM {YOUR Base Image from which you are building}
INSTRUCTION arguments

Docker runs the instructions in a Dockerfile in order. The first instruction must be `FROM` in order to specify the Base Image from which you are building.

1. FROM: 基于哪一个镜像
2. RUN: 安装软件用
RUN echo 'we are running some # of cool things'

3. MAINTAINER: 镜像建立者
4. CMD: container启动时执行的命令,可是一个Dockerfile中只能有一条CMD命令,多条则只执行最后一条CMD.
CMD echo hello world
//CMD主要用于container时启动指定的服务,当docker run command的命令匹配到CMD command时,会替换CMD执行的命令

5. ENTRYPOINT: container启动时执行的命令,可是一个Dockerfile中只能有一条ENTRYPOINT命令,若是多条,则只执行最后一条
//ENTRYPOINT没有CMD的可替换特性

6. USER: 使用哪一个用户跑container
ENTRYPOINT ["memcached"]
USER daemon

7. EXPOSE: container内部服务开启的端口。主机上要用还得在启动container时,作host-container的端口映射
docker run -d -p 127.0.0.1:33301:22 centos6-ssh
//container ssh服务的22端口被映射到主机的33301端口

8. ENV: 用来设置环境变量
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8

9. ADD: 将文件<src>拷贝到container的文件系统对应的路径<dest>
全部拷贝到container中的文件和文件夹权限为0755,uid和gid为0
若是文件是可识别的压缩格式,则docker会帮忙解压缩
若是要ADD本地文件,则本地文件必须在 docker build <PATH>,指定的<PATH>目录下
若是要ADD远程文件,则远程文件必须在 docker build <PATH>,指定的<PATH>目录下 
/*
docker build github.com/creack/docker-firefox
docker-firefox目录下必须有Dockerfile和要ADD的文件
*/
注意:使用docker build - < somefile方式进行build,是不能直接将本地文件ADD到container中。只能ADD url file.
ADD只有在build镜像的时候运行一次,后面运行container的时候不会再从新加载了。

10. VOLUME: 将本地文件夹或者其余container的文件夹挂载到container中。
11. WORKDIR: 切换目录用,能够屡次切换(至关于cd命令),对RUN,CMD,ENTRYPOINT生效
12. ONBUILD: ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行

Relevant Link:

http://blog.csdn.net/wsscy2004/article/details/25878223
https://docs.docker.com/engine/reference/builder/

 

7. Docker Volume

Docker镜像是由多个文件系统(只读层)叠加而成。当咱们启动一个容器的时候,Docker会加载只读镜像层并在其上(镜像栈顶部)添加一个读写层。若是运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏
当删除Docker容器,并经过该镜像从新启动时,以前的更改将会丢失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统),这就是为何咱们能在每次启动容器时都得到一个"纯净"的新镜像系统,在容器内部任意的修改都不会影响到其余容器以及宿主机的镜像

0x1: 数据卷

为了可以保存(持久化)数据以及共享容器间的数据,Docker提出了Volume的概念。简单来讲,Volume就是目录或者文件,它能够绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上(即让容器和宿主机共享目录、文件)。数据卷是一种特殊的存在于一个或者多个docker内部的不一样于Union File System的目录。数据卷提供多种有用的特性用来持久化和共享数据

1. 数据卷在docker初始化时建立。若是容器的镜像包含外挂的数据,外挂的数据将在卷初始化时被拷贝到新的本地卷 
2. 数据卷能够被共享和在多个docker间复用
3. 能够对数据卷直接修改
4. 更新镜像时数据卷并不受影响
5. 即便镜像被删除,数据卷也仍然会持久化到本地

数据卷被设计用来持久化存储数据,独立于容器的生命周期。当你删除容器时,docker并不会自动删除数据卷,不使用的数据卷,也不会自动进行"垃圾回收"

0x1: 增长一个数据卷
咱们能够经过两种方式来初始化Volume,这两种方式有些细小而又重要的差异。咱们能够在运行时使用-v来声明Volume

docker run -it --name container-test -h CONTAINER -v /data debian /bin/bash
//上面的命令会将/data挂载到容器中,并绕过联合文件系统,咱们能够在主机上直接操做该目录。任何在该镜像/data路径的文件将会被复制到Volume
//当使用-v参数时,镜像目录下的任何文件都不会被复制到Volume中(宿主机的Volume会复制到镜像目录,镜像不会复制到卷)

docker中的卷默认是读写权限,但你也能够设置为只读

sudo docker run --rm -it -v /root/Limon/samples:/home/malware/samples ubuntu bash

0x2: 数据共享

若是要受权一个容器访问另外一个容器的Volume,咱们可使用-volumes-from参数来执行docker run

docker run -it -h NEWCONTAINER --volumes-from container-test debian /bin/bash
//值得注意的是无论container-test是否运行,它都会起做用。只要有容器链接Volume,它就不会被删除

0x3: 删除Volumes

若是你已经使用docker rm来删除你的容器,那可能有不少的孤立的Volume仍在占用着空间
Volume只有在下列状况下才能被删除

1. 该容器是用docker rm -v命令来删除的(-v是必不可少的)
2. docker run中使用了--rm参数
//即便用以上两种命令,也只能删除没有容器链接的Volume。链接到用户指定主机目录的Volume永远不会被docker删除

0x4: 使用共享卷的注意点

多个容器能够共享一个或者多个数据卷,可是同时写入的时候会发生冲突
数据卷在宿主里面是能够直接操做的。你可使用普通的linux工具操做它们。可是建议你不要这样直接作,由于容器和应用并不知道你的操做,这可能会致使数据操做冲突
Relevant Link:

https://www.goodmemory.cc/docker%E5%AE%B9%E5%99%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86/
http://dockone.io/article/128

 

Copyright (c) 2016 LittleHann All rights reserved