Docker是什么?
Docker是一个工具,能把应用打包部署于container里,这里可以把container看做是一个简易版的 Linux 环境和运行在其中的应用程序,每个container运行一个application。它诞生于 2013 年初,最初是 dotCloud公司内部的一个业余项目,创始人是Solomon Hykes。
Docker自开源后受到广泛的关注和讨论,Redhat已经在其 RHEL6.5 中明确支持Docker;Google也在其PaaS产品中广泛应用。Docker项目的目标是实现轻量级的操作系统虚拟化解决方案。 现在Docker已经从一个工具转化成平台,小生态圈。


Docker的优势有哪些?
以前企业部署软件会购买真正的服务器,这种模式的资源利用率很低。后来出现了云端的虚拟服务器,比如AWS,提高了一定的资源利用率,但是不同阶段的应用环境可能不同。

Docker对这些有很大的优化,比如:

1. Docker 容器可以实现秒级启动


2. 容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,系统的开销很小。传统虚拟机方式运行10个不同的应用就要起10个虚拟机,而Docker只需要启动10个隔离的应用即可。


下图是传统虚拟化方式和Docker的不同。Docker本质上是一种虚拟化的技术,不是虚拟机。Docker是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。在传统模式下,Guest OS会占用大量空间,而且不同的应用会需要不同的虚拟机。在Docker中只有一个OS,各种application运行在一个OS上。


*Hypervisor是一种虚拟化的技术
具体来说,Docker的优势包括:
  1. Faster developer onboarding
  2. No vendor lockin
  3. Eliminate environment inconsistencies
  4. Ship applications faster
  5. Scale quickly
  6. Easily remediate issues
Play with Docker container
下载安装完Docker后,可以尝试使用以下命令来运行一个聊天软件。
docker run -d -p 3000:3000 unclebarney/chit-chat
这个命令的含义是启动Docker容器。-d表示在后台启动。-p表示做端口的映射,把容器里的3000端口映射到宿主机上的3000。使用的镜像为unclebarney/chit-chat。


这个命令有两部分操作:
  1. 从Dockerhub(所有镜像存储的地方)下载此镜像,大概5到30秒(取决于带宽)
  2. 根据镜像启动container,并运行node server
Docker image
Docker image(镜像)是container的基础。所有container都是从image构建的。

Docker 运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker 会从镜像仓库下载(默认是 Docker Hub 公共注册服务器中的仓库)。
从下图可以看出image的具体含义
Docker每个运行的实例由最上层的container和下面的多层镜像构成。Docker使用Union FS(union filesystem)将这些不同镜像整合在一起。通常Union FS有两个用途, 一方面可以实现不借助LVM、RAID将多个disk挂到同一个目录下;另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起,Live CD正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作。


镜像的每一层都有以下这些信息:
  1. 这一层的meta data,以JSON的形式存储
  2. image filessystem changeset
  3. image ID,比如:74fe38d11401
镜像有两种构建方式:
  1. 启动一个最基础的容器,在里面运行一些命令,像git一样把这些命令commit,形成自己的镜像。
  2. 引用一个base image,再加上一些需要的指令。这些指令存在一个文件中,叫Dockerfile。
以下是Dockerfile的例子,是刚才提到的聊天软件的镜像的生成方式。
# 引用mhart/alpine-node这个镜像

# Dockerfile中第一个命令必须是FROM命令

FROM mhart/alpine-node:base

# 将Dockerfile所在文件夹中的内容添加到Docker镜像中

# 第一个点指的是Dockerfile所在的目录

# 第二个点指的是Docker镜像中的当前目录

ADD . .

# 为这个镜像暴露3000端口

EXPOSE 3000

# 运行node命令。值得注意的是在构建镜像的时候这个命令不会执行

# 而是在真正基于这个镜像启动了容器时才会执行这个命令

CMD [“node”, “index.js”]
More Explanation
如果传统方式做一个聊天软件。首先底层有个Linux系统,上层有个node.js,再上面有source code。user通过3000端口连接。假设Google需要这个应用,那么需要将整个程序package打包过去。最简单的打包方式是从Linux系统到source code都打包。虽然最主要的部分是source code,但是不能只打包它。如果另外有用户(Google 2)需要这个应用,还是要把整个系统打包。


如果使用Docker,这两个服务(service 1,service 2)的Linux,node.js是一样的,但是它们的source code不同。如果将它们分层,比如Linux系统部分叫image 1, Node.js部分叫image 2,Service 1的source code叫image 3,Service 2的source code叫image 4。这样可以把image 1,2,3给Google1,而把image1,2,4给Google 2。image 1,2是可以复用的。


如果image 1,2,3里都有file 0。image3会使得image 1和2里的file 0隐藏(如同覆盖)。从上层往下层看,如果拥有相同文件名,下层文件隐藏。


Docker中下层的文件都是只读的,只在最上方有可读写层。应用可以对可读写层进行修改。
Namespace
Docker运用Linux系统里的namespace(命名空间)技术实现最上层应用之间的分离。拥有相同namespace的进程拥有相同的资源。拥有不同namespace的进程拥有的资源相互独立。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。
Cgroups
Docker运用Cgroups(控制组)进行资源限制。它是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免多个容器同时运行时对系统资源的竞争。控制组技术最早是由Google的程序员提出。
Docker Components
下图是Docker的构成

Docker采用了C/S架构,包括客户端和服务端。 Docker daemon作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上,也可通过socket或者RESTful API来进行通信。Docker daemon一般在宿主主机后台运行,等待接收来自客户端的消息。 Docker客户端则为用户提供一系列可执行命令,用户用这些命令跟 Docker daemon交互。


Docker daemon包括两部分:
  1. 一个轻量级服务器,接收来自客户端的消息,为用户提供一系列可执行命令
  2. 一个engine,负责调度请求,是一个总入口,管理容器的生存周期
Docker registry是存储镜像的一个仓库。它与daemon沟通,处理从客户端发送来的镜像相关的请求。可以使用public的registry或者private的。


Docker在本地安装时还有一个功能是graphdb。graphdb是一个基于SQLite的一个小数据库。能够管理本地Docker镜像和它们之间的关系。当创建新的container时,或是下载某个镜像时,Docker会先查找原有的镜像,复用可用资源。


Docker driver允许用户定制Docker运行的环境。它包括三类:
  1. graph driver:存储相关
  2. network driver:网络相关
  3. exec driver:运行环境相关
一个container可以没有IP。在network driver里一个选项设为none,可以实现。
RunC
runC是一个抽象层,它介于Docker driver和Linux kernel之间。运用它可以调用很多linux内核的功能,包括namespace,cgroups,capabilities,filessystem access controls。
Open source
Docker不被任何运营商锁定,不被任何公司垄断。Docker项目已经加入了Linux基金会,遵从了 Apache 2.0协议,项目代码在GitHub上进行维护。
继续阅读
阅读原文