- Docker是什么?
Docker是一个开源的基于LXC技术之上构建的新一代容器引擎技术,它能够将应用程序打包成为一个轻量级容器当中,docker化的应用可以轻易的在各个环境中将它运行起来。在容器的基础上消除了环境的差异,从代码交付变成了容器交付。同时,基于docker hub你可以基于各式各样的镜像不断的扩展、组装、发布你的容器。docker整体基于go实现,源码地址在https://github.com/docker/docker
Docker使用C/S的架构模式,架构示意图如下:
Docker Daemond,Docker服务的守护进程。在安装了Docker服务的环境上,都有一个相应的Docker守护进程在进行工作,它会具体进行容器、镜像管理的一系列操作。
Docker Client,Docker客户端,用户在操作docker时,并不是直接对容器、镜像等进行操作,而是需要通过docker客户端来与docker守护进程进行通讯,由docker的守护进程来进行实际的操作。即为docker命令。
Docker Registry,Docker的镜像仓库。对docker镜像进行存储的地方。
Docker Images,Docker镜像,每一个Docker镜像都是一个模板,我们可以基于Docker的镜像创建出相应的Docker容器。
Docker Container,Docker容器,实际承载应用程序的容器,每一个容器都是基于docker镜像生成。它有着相应的运行周期,包含了一个应用所需要的所有运行环境。
再简单描述下它们之间的关系,Docker Client会与Docker Daemon进行通讯。Docker Daemon接收到Docker Client发过来的指令后,会进行一系列容器的创建、运行、停止、删除等操作。当Docker Client需要基于某个镜像(如基础linux环境)建立起一个应用容器时,Docker Daemon会接收到这条命令,并先尝试从本地加载相应镜像,若没有,则前往远程的镜像仓库拉取。拉取下载一个linux镜像到本地,当你执行run命令后,docker会启动一个进程,同时会为该进程分配相应的文件系统、网络资源和进程组。另外,作为一个拥有28个参数的命令,它可以根据相应的参数来决定容器的运行方式、容器运行所能获取到的资源和网络配置等。这意味着一个linux镜像run出来的容器,当你的参数配置了支持前台运行时,那么你就可以在这个容器的shell中进行你想做的任何操作,比如搭建java的开发环境。当你对容器做完一系列操作后,你可以选择保存这个镜像,每一次保存都意味着一次commit,最终,你可以通过这个镜像id对外发布提交你的镜像。这里再提一下dockerfile,dockerfile的作用就在于我们可以根据这个文件生成一个自定义的镜像,一份dockerfile文件更像是对一个docker镜像的语言化描述。根据dockerfile的语法,基于一个基础镜像,之后的每一行代表一个执行指令,最终执行生成一个自定义的镜像。并可直接从该自定义镜像中创建容器。
-
Docker的一些核心技术。
Docker的核心是一个在操作系统层面虚拟化的方法,它与虚拟机技术不同。在虚拟机技术中,是从底层往上的进行虚拟化,完全自己虚拟出了一个硬件平台,并在此之上可以搭建自己的操作系统。而docker则是依赖于宿主机的操作内核,属于操作系统级别的虚拟化,一些系统调用还是来源于宿主机,各个容器之间的隔离依赖于宿主机的各个进程之间的隔离。由于底层内核资源是共享的,因此相较与vm而言,可以节省出更多的资源。但是在隔离性上面,并不像vm这样实现了彻底的隔离。 -
隔离技术
对于docker的各个容器而言,他们是相互隔离,互不影响的。基于linux内核提供的namespace隔离的系统调用做了以下六个方面的隔离,首先先说说linux namespace。
个人对namespace的理解为,是linux自身的一种资源隔离机制。通过不同的namespace之间有着相应的资源隔离。被隔离开的资源只有在同一个namespace下才可见。同时我们可以使用clone方法在创建新进程时,我们可以指定是使用父进程的namespace,还是建立一个新的namespace。linxu启动时会创建一个namespace,可视为root namespace,之后可在该root namespace的基础上建立一系列的子namespace。 子namespace之间有着相应的资源隔离,仅能在namespace内互相可见。
因此,namespace有这几个特征: 1. 每个namespace都有自己pid=1的进程(类似linux的init进程)。 2. 每个namespace中的进程只能影响同一个namespace下的或子namespace中的进程。 3. 因为 /proc下能看到所有正在运行中的进程,因此,每一个container下的 /proc目录只能看到自己namespace的进程。 4. 因为namespace允许嵌套,父namespace可以影响子namespace的进程,所以子namespace的进程可以在父namespace中看到,但具有不同的pid(pid映射)
UTS隔离,该namespace隔离机制使得每个容器拥有独立的hostname和网络域名,使得该容器能够在网络被视为一个独立的节点
PID隔离,在linux系统下,不同的进程使用pid进行区分,而在不同的pid namespace下,则可以存在相同的pid。docker daemond与container在同一个namespace中(root namespace),而每一个container又单独维护一份 pid namespace。
IPC隔离,容器中进程间常用的通信方式有信号量、消息队列和共享内存。对于宿主机而言。容器中进程间的通信实际上为同一个pid namespace下的的进程间通信。每一个IPC namespace在新创建时会生成一个自己namespace的表示符,在后续申请IPC资源(进程交互时所需的资源)时,会带上该标识,使得该IPC资源自能在该namespace可见
Network隔离,提供了网络资源方面的隔离。每个net namespace有独立的network devices,IP Addresses,IP routing tables等,这样每个容器的网络就能隔离开,docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge: docker0连接在一起。 在docker server启动时,就会创建一个叫docker0的网桥,容器默认会连接到该网桥上。docker0的ip地址即为该server上所有容器的网关。docker内部有着自己的ip地址分配,但是我们可以通过自定义网桥的形式划分ip,使得容器和宿主机在同一网段上。
(eg1:veth pair是用于不同net namespace间的通信方式)
(eg2:host创建了一个虚拟的bridge,每个container对应一个虚拟网络设备,与bridge仪器构成了一个虚拟网络,并通过虚拟bridge的方式进行通信,整体结构如下)
(eg3: 如何实现容器之间的互连,1. 通过ip地址访问。2. 在docker run时通过 —link建立相应的hostname,通过hostname互相访问)
(eg4: 容器访问外网,默认网络模式与宿主机一致可直接访问外网)
(eg5: 外网访问容器,在run时通过配置将容器映射端口到宿主机,外网通过端口访问)
Mount隔离,通过对文件挂载点的隔离实现了对文件系统的隔离
User隔离,在新进程创建的新user namespace中可以拥有不同的用户和用户组。
-
AUFS文件系统
AUFS是一种Union FS,它支持将不同的目录挂载到同一个虚拟文件系统下。AUFS将挂载到同一虚拟文件系统下的多个目录分别设置成read-only,read-write以及whiteout-able权限,写操作只能在read-write目录中进行。在容器生成挂载不同的目录时,会按照不同目录的增量关系,将每层增量关系不断的进行覆盖,最后在最上层挂载一个read-write。即在一个个镜像的基础上,不断的进行增量操作。在最顶层会挂载一个read-write的目录。每一个容器都是在它镜像的基础上,多覆盖一层read-write的目录。 -
cgroups
cgroups是linux内核提供的一个可以限制、记录、隔离进程组所使用到的物理资源(CPU、内存、IO等)。
网友评论