4.1. Docker简介

4.1.1. 什么是Docker

Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新, 并于 2013 年 3 月以 Apache 2.0 授权协议开源。Docker 项目后来还加入了 Linux 基金会,并成立推动 开放容器联盟(OCI)

Docker 使用 Google 公司推出的 Go 语言进行开发实现,是一种基于 Linux 内核的 cgroupnamespace 功能的容器技术,其系统架构如下:

../_images/docker-1.png

容器(container) 是一种与虚拟机看起来类似,但原理上完全不同的技术。

  • 虚拟机是 虚拟化硬件: 虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。
  • 容器是 操作系统层虚拟化: 容器只有一个虚拟的环境,容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。

下面的图片比较了 Docker 和传统虚拟化方式的不同之处:

../_images/docker-2.png

因此容器要比传统虚拟机更为轻便,允许不同的环境、不同应用程序,在内核中独立运行,可以轻松的在单一机器上实现多个不同开发环境的部署。

4.1.2. 为什么要用Docker

不同的程序可能会有不同的应用环境,如果把他们依赖的软件都安装在一台机器上需要调试很久,而且很麻烦,甚至会造成一些冲突。 例如两个程序分别依赖 CUDA-8CUDA-10,然而一台机器只能装一个 CUDA

常规来讲,我们可以创建不同的虚拟机,在不同的虚拟机上放置不同的应用。但是虚拟机开销比较高,同时虚拟机不支持独立显卡,意味着在虚拟机中无法使用 CUDA,而使用 Docker 就可以实现该功能。

Docker 作为一种新兴的虚拟化方式,跟传统的虚拟化方式相比具有众多的优势:

  • 更高效的利用系统资源: 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。
  • 更快速的启动时间: 容器的应用直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。
  • 统一的运行环境: Docker 的镜像提供了除内核外完整的运行环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊,怎么到你这就有问题了」 这类问题。

4.1.3. Docker基本概念

Docker 包括三个基本概念: 镜像(Image)容器(Container)仓库(Repository)

4.1.3.1. 镜像(Image)

Docker 的镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了运行时的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。

Docker 的镜像是 分层存储 的。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。 比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。

分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

4.1.3.2. 容器(Container)

容器是镜像运行时的实例,一个镜像可以创建无数的容器。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。

容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人会混淆 Docker 和虚拟机。

前面讲过镜像是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。 容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失

4.1.3.3. 仓库(Repository)

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Repository 就是这样的服务。

一个 Docker Registry 中可以包含多个 仓库;每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。 如果不给出标签,将以 latest 作为默认标签。

Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。 我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest

Docker Registry 服务有公开服务和私有服务,最常使用的公开服务是官方的 Docker Hub,而私有服务需要自己搭建。