Docker是什么
Docker和容器不是一个意思,Docker包含实现虚拟化技术的一系列技术,而容器(container)只是其中的一个组件。Docker是基于Go语言实现的云开源项目。Docker的主要目标是build,ship and run any app,anywhere。也就是通过对应用组件的封装,分发,部署,运行等生命周期的管理,使用户的app及其运行环境能够做到“一次封装,到处运行”
Docker可以给你带来些什么?
- 更快交付你的应用
- 让部署和测试更简单
- 实现更高密度和更多的负载
目标
Docker项目的目标是实现轻量级的操作系统虚拟化解决方案,创建软件程序可移植的轻量容器。
底层实现
- Docker的基础是Linux容器(LXC)等技术,最新的版本开始使用Libcontainer替代LXC。
- 在LXC的基础上Docker进行了进一步的封装,让用户不需要去关心容易的管理,使得操作更为简便。
- Docker使用CGroups来提供容器隔离,而Union文件系统用于保存镜像并使容器变得短暂
Cgroups: Cgroups是Linux内核功能,它让两件事情变成可能:限制Linux进程组的资源占用(内存, CPU);为进程组制作PID,UTS,IPC,网络,用户,及装载命名空间。
Union文件系统:在union文件系统里,文件系统可以被装载在其他文件系统之下,其结果就是一个分层的积累变化。如下图
与虚拟机的关系
用户操作Docker的容器就像操作一个快速轻量级的虚拟机一样简单
但是虚拟机上的应用不仅包含了应用本身,必要的依赖(二进制和库包等),还包括了操作系统;而docker应用不同,共享系统内核,仅仅包含应用本身和依赖。
Docker相对于虚拟机来说的优势
启动更快(docker是秒级,而虚拟机是分钟级)
硬盘占用更少(docker一般为MB,而虚拟机一般为GB)
性能更好(docker更接近原生,而虚拟机若与原生)
系统支持量更庞大(单机支持上千个容器,而虚拟机一般几十个)
Docker的特性:
- 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上,例如运行一个一次性交互shell
- 文件系统隔离:每个进程容器运行在完全独立的根文件系统里
- 写时复制:采用写时复制方式创建根文件系统,这让不属于变得极其快捷,并且节省内存和硬盘空间
- 资源隔离: 可以使用cgroup为每个进程容器分配不同的系统资源
- 网络隔离:每个进程容器运行在自己的网络命名空间里,拥有自己的虚拟接口和IP地址
- 日志记录:Docker将会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索
- 变更管理:容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器。无需使用模板或手动配置
Docker就是通过
- 使用Cgroups隔离计算机资源,使计算机可以运行很多的服务
- 使用Namespace分离打包服务运行时需要的所有依赖----java,tomcat
- 使用Union文件系统,把所有的操作记录在Dockerfile(构建镜像的蓝图)
- 还有两个特别重要的功能,映射端口和外挂数据卷,映射端口负责接受把docker容器里的某个端口与主机某个端口绑定。外挂数据卷就是把war包放置的路径映射到主机上的某个路径,达到业务逻辑和数据持久化分割开,是不是颇有MVC的熟悉感。
注意:这里的端口映射有一个坑,在非Linux上安装docker,都是咋爱本机上安装Linux的虚拟机,所有当你在docker运行tomcat时,访问“localhost:8080”是不会有响应的,你应该把localhost换成运行此docker的Linux虚拟机的IP地址。但是在Linux上,就可以通过“localhost:8080”访问到tomcat。
namespace(命名空间):命名空间是Linux内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。docker实际上是一个进程容器,它通过namespace实现了进程和进程所使用的资源的隔离。使不同的进程之间彼此不可见
例子:
pid命名空间:用于隔离进程,容器都有自己独立的进程表和1号进程
net命名空间:用于管理网络,容器有自己独立的networkinfo
ipc命名空间:用于访问IPC资源(IPC:InterProcess Communication)
mnt命名空间:用于管理挂载点,每个容器都有自己惟一的目录挂载
uts命名空间:用于隔离内核和版本标识(UTS:UnixTimeProcess System),每个容器都有独立的hostname和domain
cgroup(控制组):是Linux内核的一个特性,主要用来对共享资源进行隔离,限制,审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。控制组技术最早是由Google的程序员2006年起提出,Linux内核自2.6.24开始支持。控制组可以提供对容器的内存,CPU,磁盘IO等资源的限制和审计管理。
UnionFS (联合文件系统):Union文件系统(UnionFS)是一种分层,轻重级并且高性能的文件系统,它支持对文件系统的修改,作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像,可以制作各种具体的应用镜像。另外,不同Docker容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
Docker中使用的AUFS(AnotherUnionFS)就是一种,UnionFS。 AUFS支持为每一个成员目录(类似Git的分支)设定只读(readonly),读写(readwrite)和写出(writeoue-able)权限,同时AUFS里有一个类似分层的概念,对只读权限的分支可以逻辑上进行增量的修改。Docker目前支持的Union文件系统种类包括 AUFS,btrfs,vfs和DeviceMapper。
Docker结构引擎
注意上图,显示的是docker主要组件
- Server,就是一个守护进程,它会一直运行在后台
- REST API,说明如何与server交互和指示它执行命令
- Client,是客户书写指令的地方,也俗称shell
- Image,俗称镜像
- Container,俗称容器,装载和运行镜像
- Network,俗称网络,容易通过暴露端口与主机端口绑定,达到接受来自主机的信号;
- Volume,俗称外挂,为了能够持久化数据以及共享容器间的数据,Docker提出了Volume的概念。
Docker运行流程
当我们想运行一个容器的时候,docker会:
- 拉取镜像,若本地已经存在该镜像,则不用到网上去拉取
- 创建新的容器
- 分配union文件系统并且挂着一个可读写的层,任何修改容器的操作都会被记录在这个读写层上,你可以保存这些修改成新的镜像,也可以选择不保存,那么下次运行该镜像的是时候所有修改操作都会被消除
- 分配网络/桥接接口,创建一个允许容易与本地主机通信的网络接口
- 设置ip地址,从池中寻找一个可用的ip地址附加到容器上,换句话说,localhost并不能访问到容器
- 运行你指定的程序
- 捕获并且提供应用输出,包括输入,输出,报错信息
用docker运行hello-world镜像
- 首先输入systemctl start docker来启动docker
- 在yum命令行中先切换到root用户下,然后输入docker run hello-world
如果你是第一次输入此行命令,你会发现在“Hello from Docker”上方会出现“Unable to find image ‘hello-world:latest’ locally”
这里的docker是如何运行的:
- docker run hello-world换句话说就是要start一个新的container通过运用名为hello-world的镜像
- 输入的指令被Docker Client接收,然后与Docker Server沟通。
- Docker Server首先会去image cache检查local本地是否已经有hello-world的镜像。
- 如果没有的话,就去访问Docker Hub去寻找该镜像并下载到本地(这就是为什么第二次不会出现unable to find image locally)
- 然后docker server就会用下载下来的镜像在container中运行并把结果投到terminal上
我们可以通过docker image ls来查看本地image cache里面存在哪些镜像,由于我们刚才已经下载了hello-world的镜像,所以我们会发现下图的情况
上图就显示了我们刚才下载的镜像名称,id啥的