Docker是Docker Inc公司开源的一项基于Ubuntu LXC技术构建的应用容器引擎Docker Engine的简称,彻底基于Go语言开发并遵照Apache2.0协议开源。Docker可让开发者打包应用以及依赖包到一个轻量级、可移植的容器中,而后发布到任何流行的Linux版本机器上,也能够实现虚拟化。Docker容器彻底使用沙箱机制,容器相互之间不会有任何接口,而且容器性能开销极低。
Docker最初在Ubuntu 12.04上基于LXC实现,从0.7版本开始使用自行开发的libcontainer,从1.11开始,进一步演进为使用runC和containerd。RedHat从RHEL6.5开始对Docker进行支持。
Docker官网:http://www.docker.com
Github Docker源码:https://github.com/docker/dockerlinux
Docker Engine是一个Client-Server应用程序,包含三个组件:
A、docker daemon,是Docker守护进程。
B、REST API接口,用于与守护进程进行通讯。
C、Docker CLI,命令行界面(CLI)客户端。
Docker引擎组件的流程以下:git
Docker优势以下:
(1)更高效地利用系统资源
Docker容器不须要硬件虚拟技术支持,是内核级的虚拟化,不须要运行完整操做系统,能够实现更高性能。不管是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。所以,与虚拟机技术相比,相同配置的主机能够运行更多数量的应用。
(2)更快的启动时间
传统的虚拟机技术启动应用服务每每须要数十秒,而Docker容器应用直接运行于宿主机内核,无需启动完整的操做系统,所以能够作到秒级、甚至毫秒级的启动时间,大大节约开发、测试、部署时间。
(3)一致的运行环境
开发过程当中一般存在环境一致性问题。因为开发环境、测试环境、生产环境不一致,致使有些bug并未在开发过程当中被发现,而Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性。
(4)快速交付和部署
使用Docker能够经过定制应用镜像来实现持续集成、持续交付、部署。开发人员能够经过Dockerfile来进行镜像构建,并结合持续集成(Continuous Integration) 系统进行集成测试;而运维人员则能够直接在生产环境中快速部署镜像,甚至结合持续部署(Continuous Delivery/Deployment)系统进行自动部署,并且使用Dockerfile使镜像构建透明化,不只开发团队能够理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署镜像。
(5)更轻松的迁移
因为Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker能够在多种平台上运行,不管是物理机、虚拟机、公有云、私有云,其运行结果是一致的。所以用户能够很轻易地将在一个平台上运行的应用迁移到另外一个平台上,而不用担忧运行环境的变化致使应用没法正常运行的状况。
(6)更轻松的维护和扩展
Docker使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像很是简单。此外,Docker团队同各个开源项目团队一块儿维护了大批高质量的官方镜像,既能够直接在生产环境使用,又能够做为基础进一步定制,大大下降了应用服务的镜像制做成本。github
虚拟机是一个运行在宿主机上的完整的操做系统,虚拟机运行自身操做系统会占用较多的CPU、内存、硬盘资源。Docker容器不一样于虚拟机,只包含应用程序以及依赖库,基于libcontainer运行在宿主机上,并处于一个隔离的环境中,所以Docker容器更加轻量高效,启动Docker容器只需几秒钟内完成。因为Docker容器轻量、资源占用少,使得Docker能够轻易地应用到构建标准化的应用中。Docker容器缺点以下:
(1)隔离效果不如虚拟机,须要共享宿主机操做系统的一些基础库等。
(2)网络配置功能相对简单,主要以桥接方式为主。
(3)查看日志也不够方便灵活。docker
Docker架构遵循C/S架构,分为客户端、Docker主机、Docker镜像仓库三部分。
客户端(Client):Docker提供命令行界面(CLI)工具,客户端与Docker守护进程交互。当使用docker命令时,客户端将相应Docker命令发送到Docker主机的Docker守护进程进行运行,客户端能够构建、运行和中止应用程序。
Docker主机:包含容器、镜像和Docker守护程序,提供完整的环境来执行和运行应用程序。Docker守护进程是一个用于监听Docker API请求的进程,用于管理Docker对象,如Docker镜像、容器、网络等。
镜像仓库(Registry):Docker镜像仓库用于存储Docker镜像。Docker提供的Docker Hub和Docker Cloud是公共镜像仓库,Docker默认在Docker Hub上查找映像。当使用docker pull或docker run命令时,从配置的Docker镜像仓库中提取所需的镜像;当使用docker push命令时,镜像被推送到配置的镜像仓库中。shell
Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。Docker镜像不包含任何动态数据,其内容在构建后也不会被改变。
Docker的分层存储架构充分利用了Union FS技术。Docker镜像由一组文件系统或是多层文件系统联合组成。Docker镜像会一层层构建,前一层是后一层的基础,每一层构建完就不会再发生改变,后一层上的任何改变只发生在本身本层。好比,删除前一层文件的操做不是真的删除前一层的文件,而是仅在当前层标记为文件已删除。在Docker容器运行时,虽然不会看到文件,但实际上文件会一直跟随镜像。所以,在构建Docker镜像时须要额外当心,每一层尽可能只包含该层须要添加的东西,任何额外的东西应该在本层构建结束前清理掉。
分层存储的特征使得Docker镜像的复用、定制变的更为容易,可使用构建好的镜像做为基础层,而后进一步添加新层以定制本身所需的内容,构建新镜像。json
Docker镜像是静态的定义,Docker容器是Docker镜像运行时的实例,Docker容器能够被建立、启动、中止、删除、暂停等。
Docker容器的本质是进程,但与直接在宿主机执行的进程不一样,Docker容器进程运行于属于本身的独立的命名空间。所以Docker容器能够拥有本身的root文件系统、本身的网络配置、本身的进程空间,甚至本身的用户ID空间。Docker容器内的进程是运行在一个隔离的环境里,使得容器封装的应用比直接在宿主机运行更加安全。Docker容器使用分层存储,每个Docker容器运行时,以镜像为基础层,在其上建立一个当前容器的存储层。容器存储层的生存周期和容器同样,容器消亡时容器存储层也随之消亡。所以,任何保存于容器存储层的信息都会随容器删除而丢失。
按照Docker最佳实践要求,Docker容器不该该向其存储层内写入任何数据,Docker容器存储层要保持无状态化,全部的文件写入操做都应该使用数据卷(Volume)、或者绑定宿主机目录,在数据卷或宿主机目录位置的读写会跳过容器存储层,直接对宿主机(或网络存储)发生读写,其性能和稳定性更高。数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。所以,使用数据卷后,Docker容器删除或者从新运行后,数据却不会丢失。vim
Docker默认Registry是Docker公司运营提供的公共镜像仓库即Docker Hub,但访问Docker Hub速度一般很慢,所以能够在本地部署一个私有Registry只供局域网内使用。windows
Homebrew的Cask已经支持Docker for Mac:
加速器配置使用网易的镜像地址:http://hub-mirror.c.163.com。
在任务栏点击Docker for mac应用图标->Perferences... ->Daemon ->Registry mirrors。
在列表中填写加速器地址。修改完成后,点击 Apply & Restart 按钮,Docker就会重启并应用配置的镜像地址。
经过docker info来查看是否配置成功。安全
Docker运行在RHEL7上,要求系统为64位、系统内核版本为3.10以上。
Docker运行在 RHEL6.5 或更高的版本要求系统为64位、系统内核版本为2.6.32-431或者更高版本。
本文使用RHEL7.3安装Docker。
安装Docker:sudo yum install docker
启动Docker:sudo systemctl start docker
错误信息:Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
查看错误信息:systemctl status docker.service
错误缘由:SELinux不支持Docker服务
解决方法:编辑sudo vim /etc/sysconfig/docker网络
OPTIONS='--selinux-enabled=false --log-driver=journald --signature-verification=false' if [ -z "${DOCKER_CERT_PATH}" ]; then DOCKER_CERT_PATH=/etc/docker fi
运行示例:sudo docker run hello-world
Win七、Win8须要利用Docker Toolbox来安装,国内可使用阿里云的镜像来下载。
Docker ToolBox下载地址:
http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/
Docker ToolBox是一个工具集,主要包含:
A、Docker CLI客户端,用来运行docker引擎建立镜像和容器
B、Docker Machine,用于在Windows的命令行中运行docker引擎命令
C、Docker Compose,用来运行Docker Compose命令
D、Kitematic,Docker的GUI版本
E、Docker QuickStart shell,配置好Docker的命令行环境
F、Oracle VM Virtualbox,虚拟机
下载完成后直接点击安装,安装成功后,会出现三个图标:
点击Docker QuickStart图标来启动Docker Toolbox终端。
若是系统显示User Account Control窗口来运行VirtualBox,选择 Yes。
对于Win10专业版系统,Docker有专门的的安装包,须要开启Hyper-V。
Win10专业版系统Docker下载地址:
https://store.docker.com/editions/community/docker-ce-desktop-windows
Docker使用daemon.json文件做为Docker服务的配置文件,Linux操做系统使用/etc/docker/daemon.json,Windows操做系统使用%programdata%\docker\config\daemon.json来配置Docker服务。若是相应目录下不存在daemon.json文件,须要建立。
{ "registry-mirrors": ["http://hub-mirror.c.163.com"] }
网易的镜像地址:http://hub-mirror.c.163.com。
为了实现每一个用户实例之间相互隔离,硬件虚拟化方法的解决方案是VM,而LXC的解决方案是container,即kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace将container的进程、网络、消息、文件系统、UTS(UNIX Time-sharing System)和用户空间隔离开。
(1)pid namespace
不一样用户的进程经过pid namespace隔离开,且不一样namespace中能够有相同pid。全部的LXC进程在Docker中的父进程为Docker进程,每一个LXC进程具备不一样的namespace,同时因为容许嵌套,所以能够很方便的实现 Docker in Docker。
(2)net namespace
经过pid namespace,每一个namespace中的pid可以相互隔离,但网络端口还共享host的端口。网络隔离是经过net namespace实现的,每一个net namespace有独立的network devices、IP addresses、IP routing tables、/proc/net目录。经过net namespace,每一个container的网络就能隔离开来。Docker默认采用veth的方式将容器中的虚拟网卡同宿主机上的一个docker bridge:docker0链接在一块儿。
(3)ipc namespace
container中进程交互采用linux常见的进程间交互方法(interprocess communication - IPC),包括常见的信号量、消息队列和共享内存。然而与VM不一样,container的进程间交互仍是host上具备相同pid namespace中的进程间交互,所以须要在IPC资源申请时加入namespace信息——每一个IPC 资源有一个惟一的32位 ID。
(4)mnt namespace
mnt namespace容许不一样namespace的进程看到的文件结构不一样,每一个namespace中的进程所看到的文件目录就被隔离开。每一个namespace 中的container在/proc/mounts的信息只包含所在namespace的mount point。
(5)uts namespace
UTS(UNIX Time-sharing System)namespace容许每一个container拥有独立的hostname和domain name,使其在网络上能够被视做一个独立的节点而非Host上的一个进程。
(6)user namespace
每一个container能够有不一样的user和group id,能够在container内部用container内部的用户执行程序而非Host上的用户。
cgroups实现了对资源的配额和度量。在/cgroup目录下新建一个文件夹便可新建一个group,在此文件夹中新建task文件,并将pid 写入该文件,便可实现对该进程的资源控制。groups能够限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系统的资源,每一个子系统的详细说明以下:
有序列表blkio子系统设置限制每一个块设备的输入输出控制。例如:磁盘,光盘以及usb等。
cpu子系统使用调度程序为cgroup任务提供cpu的访问。
cpuacct:产生cgroup任务的cpu资源报告。
cpuset:对于多核心CPU,cpuset子系统会为cgroup任务分配单独的cpu和内存。
devices容许或拒绝cgroup任务对设备的访问。
freezer暂停和恢复cgroup任务。
memory设置每一个cgroup的内存限制以及产生内存资源报告。
net_cls标记每一个网络包以供cgroup方便使用。
ns名称空间子系统。
AUFS(Another Union FS)是一种Union FS,支持将不一样目录挂载到同一个虚拟文件系统下的文件系统。AUFS支持为每个成员目录设定readonly、readwrite和whiteout-able权限,同时AUFS有分层的概念,对readonly权限的branch能够逻辑上进行修改(增量地,不影响readonly部分)。
一般Union FS有两个用途,一是能够实现不借助LVM、RAID将多个disk挂到同一个目录下;一个是将一个readonly的branch和一个writeable的 branch联合在一块儿(Live CD能够容许在OS image不变的基础上容许用户在其上进行一些写操做)。
典型的启动Linux运行须要两个FS:bootfs + rootfs
bootfs(boot file system)主要包含bootloader 和 kernel,bootloader引导加载kernel,当boot成功后kernel被加载到内存中后bootfs就被umount。rootfs(root file system)包含典型Linux系统中的dev、proc、bin、etc等标准目录和文件。不一样Linux发行版中bootfs基本是一致的,但rootfs会有差异,所以不一样Linux发行版能够共用bootfs。
典型Linux在启动后,首先将rootfs设置为readonly,进行一系列检查,而后将其切换为readwrite供用户使用。在Docker中,初始化时将rootfs以readonly方式加载并检查,而后利用union mount方式将一个 readwrite文件系统挂载在readonly的rootfs上,而且容许再次将下层FS(file system)设定为readonly,而且向上叠加,readonly和writeable组成的结构构成一个container的运行时态,每个FS被称做一个FS层。
基于AUFS的特性,每个对readonly层文件/目录的修改都只会存在于上层writeable层中。因为不存在竞争,多个container能够共享readonly的FS层。所以,Docker将readonly的FS层称做image。Docker容器中,rootfs是read-write的,但全部的修改都写入最上层writeable层中,image不保存用户状态,只用于模板、新建和复制使用。
上层image依赖下层image,所以Docker中把下层image称做父image,没有父image的image称做base image。所以要从一个image启动一个容器,Docker会先加载image自己和依赖的父images以及 base image,用户进程运行在writeable的layer中。全部parent image中的数据信息以及ID、网络和LXC管理的资源限制等具体container的配置,构成一个Docker上的container。
Docker的安全特性包括三个方面:A、由kernel namespaces和cgroups实现的Linux系统固有的安全标准;B、Docker Deamon安全接口;C、Linux自己的安全加固解决方案,例如AppArmor,SELinux;