# 一、Docker 的四大组成对象

Docker 体系里,有四个对象 (Object) 是我们不得不进行介绍的,因为几乎所有 Docker 以及周边生态的功能,都是围绕着它们所展开的。它们分别是:镜像 ( Image )、容器 ( Container )、网络 ( Network )、数据卷 ( Volume )...

# 1.1 镜像

所谓镜像,可以理解为一个只读的文件包,其中包含了虚拟环境运行最原始文件系统的内容

# 1.2 容器

容器就是用来隔离虚拟环境的基础设施,而在 Docker 里,它也被引申为隔离出来的虚拟环境。

  • 如果把镜像理解为编程中的类,那么容器就可以理解为类的实例。镜像内存放的是不可变化的东西,当以它们为基础的容器启动后,容器内也就成为了一个“活”的空间

Docker 的容器应该有三项内容组成

  • 一个 Docker 镜像
  • 一个程序运行环境
  • 一个指令集合

# 1.3 网络

Docker 中,实现了强大的网络功能,我们不但能够十分轻松的对每个容器的网络进行配置,还能在容器间建立虚拟网络,将数个容器包裹其中,同时与其他网络环境隔离

Docker 能够在容器中营造独立的域名解析环境,这使得我们可以在不修改代码和配置的前提下直接迁移容器,Docker 会为我们完成新环境的网络适配。对于这个功能,我们甚至能够在不同的物理服务器间实现,让处在两台物理机上的两个 Docker 所提供的容器,加入到同一个虚拟网络中,形成完全屏蔽硬件的效果...

# 1.4 数据卷

  1. 除了网络之外,文件也是重要的进行数据交互的资源。在以往的虚拟机中,我们通常直接采用虚拟机的文件系统作为应用数据等文件的存储位置。然而这种方式其实并非完全安全的,当虚拟机或者容器出现问题导致文件系统无法使用时,虽然我们可以很快的通过镜像重置文件系统使得应用快速恢复运行,但是之前存放的数据也就消失了。
  2. 为了保证数据的独立性,我们通常会单独挂载一个文件系统来存放数据。这种操作在虚拟机中是繁琐的,因为我们不但要搞定挂载在不同宿主机中实现的方法,还要考虑挂载文件系统兼容性,虚拟操作系统配置等问题。值得庆幸的是,这些在 Docker 里都已经为我们轻松的实现了,我们只需要简单的一两个命令或参数,就能完成文件系统目录的挂载。
  3. 能够这么简单的实现挂载,主要还是得益于 Docker 底层的 Union File System 技术。在 UnionFS 的加持下,除了能够从宿主操作系统中挂载目录外,还能够建立独立的目录持久存放数据,或者在容器间共享。
  4. Docker 中,通过这几种方式进行数据共享或持久化的文件或目录,我们都称为数据卷 ( Volume )...

# 二、搭建运行Docker环境

# 2.1 Docker Engine 的版本

对于 Docker Engine 来说,其主要分为两个系列

  • 社区版 ( CE, Community Edition )
  • 企业版 ( EE, Enterprise Edition )
  1. 社区版 ( Docker Engine CE ) 主要提供了 Docker 中的容器管理等基础功能,主要针对开发者和小型团队进行开发和试验。而企业版 ( Docker Engine EE ) 则在社区版的基础上增加了诸如容器管理、镜像管理、插件、安全等额外服务与功能,为容器的稳定运行提供了支持,适合于中大型项目的线上运行...
  2. 社区版和企业版的另一区别就是免费与收费了。对于我们开发者来说,社区版已经提供了 Docker 所有核心的功能,足够满足我们在开发、测试中的需求,所以我们直接选择使用社区版进行开发即可。在这本小册中,所有的内容也是围绕着社区版的 Docker Engine 展开的...
  3. 从另外一个角度,Docker Engine 的迭代版本又会分为稳定版 ( Stable release ) 和预览版 ( Edge release )。不论是稳定版还是预览版,它们都会以发布时的年月来命名版本号,例如如 17 年 3 月的版本,版本号就是 17.03...

  1. Docker Engine 的稳定版固定为每三个月更新一次,而预览版则每月都会更新。在预览版中可以及时掌握到最新的功能特性,不过这对于我们仅是使用 Docker 的开发者来说,意义并不是特别重大的,所以我还是更推荐安装更有保障的稳定版本。
  2. 在主要版本之外,Docker 官方也以解决 Bug 为主要目的,不定期发布次要版本。次要版本的版本号由主要版本和发布序号组成,如:17.03.2就是对 17.03 版本的第二次修正...

# 2.2 Docker 的环境依赖

  • 由于 Docker 的容器隔离依赖于 Linux 内核中的相关支持,所以使用 Docker 首先需要确保安装机器的 Linux kernel中包含 Docker 所需要使用的特性。以目前 Docker 官方主要维护的版本为例,我们需要使用基于 Linux kernel 3.10 以上版本的 Linux 系统来安装 Docker...
  • 也许 Linux kernel 的版本还不够直观,下面的表格就直接展示了 Docker 对主流几款 Linux 系统版本的要求
操作系统 支持的系统版本
CentOS CentOS 7
Debian Debian Wheezy 7.7 (LTS)
Debian Jessie 8 (LTS)
Debian Stretch 9
Debian Buster 10
Fedora Fedora 26Fedora 27
Ubuntu Ubuntu Trusty 14.04 (LTS)
Ubuntu Xenial 16.04 (LTS)
Ubuntu Artful 17.10...

# 2.3 在 Linux 系统中安装 Docker

因为 Docker 本身就基于 Linux 的核心能力,同时目前主流的 Linux 系统中所拥有的软件包管理程序,已经可以很轻松的帮助我们处理各种依赖问题,所以在 Linux中安装 Docker 并非什么难事

CentOS

$ sudo yum install yum-utils device-mapper-persistent-data lvm2
$
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum install docker-ce
$
$ sudo systemctl enable docker
$ sudo systemctl start docker...
@程序员poetry: 代码已经复制到剪贴板

Debian

$ sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
$
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce
$
$ sudo systemctl enable docker
$ sudo systemctl start docker...
@程序员poetry: 代码已经复制到剪贴板

Fedora

$ sudo dnf -y install dnf-plugins-core
$
$ sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
$ sudo dnf install docker-ce
$
$ sudo systemctl enable docker
$ sudo systemctl start docker...
@程序员poetry: 代码已经复制到剪贴板

Ubuntu

$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
$
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce
$
$ sudo systemctl enable docker
$ sudo systemctl start docker...
@程序员poetry: 代码已经复制到剪贴板

# 2.4 上手使用

在安装 Docker 完成之后,我们需要先启动 docker daemon 使其能够为我们提供 Docker 服务,这样我们才能正常使用 Docker

在我们通过软件包的形式安装 Docker Engine 时,安装包已经为我们在 Linux 系统中注册了一个 Docker 服务,所以我们不需要直接启动 docker daemon 对应的 dockerd 这个程序,而是直接启动 Docker 服务即可。启动的 Docker 服务的命令其实我已经包含在了前面谈到的安装命令中,也就是...

sudo systemctl start docker
@程序员poetry: 代码已经复制到剪贴板

当然,为了实现 Docker 服务开机自启动,我们还可以运行这个命令

$ sudo systemctl enable docker
@程序员poetry: 代码已经复制到剪贴板

docker version

Docker服务启动之后,我们先来尝试一个最简单的查看 Docker 版本的命令:docker version

$ sudo docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:23:03 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:25:29 2018
  OS/Arch:          linux/amd64
  Experimental:     false...
@程序员poetry: 代码已经复制到剪贴板

这个命令能够显示 Docker C/S结构中的服务端 ( docker daemon ) 和客户端 ( docker CLI ) 相关的版本信息。在默认情况下,docker CLI 连接的是本机运行的 docker daemon ,由于 docker daemondocker CLI 通过RESTful 接口进行了解耦,所以我们也能修改配置用于操作其他机器上运行的 docker daemon...

docker info

如果想要了解 Docker Engine 更多相关的信息,我们还可以通过 docker info 这个命令

$ sudo docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 18.06.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
## ......
Live Restore Enabled: false...
@程序员poetry: 代码已经复制到剪贴板

配置国内镜像源

一个由 Docker 官方提供的国内镜像源 registry.docker-cn.com

那么有了地址,我们要如何将其配置到 Docker 中呢?

在 Linux 环境下,我们可以通过修改 /etc/docker/daemon.json ( 如果文件不存在,你可以直接创建它 ) 这个 Docker 服务的配置文件达到效果

{
    "registry-mirrors": [
        "https://registry.docker-cn.com"
    ]
}

@程序员poetry: 代码已经复制到剪贴板

在修改之后,别忘了重新启动 docker daemon 来让配置生效

$ sudo systemctl restart docker
@程序员poetry: 代码已经复制到剪贴板

要验证我们配置的镜像源是否生效,我们可以通过 docker info 来查阅当前注册的镜像源列表

$ sudo docker info
## ......
Registry Mirrors:
 https://registry.docker-cn.com/
## ......
@程序员poetry: 代码已经复制到剪贴板

# 三、在 Windows 和 Mac 中使用 Docker

# 3.1 Docker Desktop

对于 Windows 系统来说,安装 Docker for Windows 需要符合以下条件

  • 必须使用 Windows 10 Pro ( 专业版 )
  • 必须使用 64 bit 版本的 Windows

对于 macOS 系统来说,安装 Docker for Mac 需要符合以下条件

  • Mac硬件必须为 2010 年以后的型号
  • 必须使用 macOS El Capitan 10.11 及以后的版本

另外,虚拟机软件 VirtualBoxDocker Desktop 兼容性不佳,建议在安装 Docker for WindowsDocker for Mac 之前先卸载 VirtualBox

在确认系统能够支持 Docker Desktop 之后,我们就从 Docker 官方网站下载这两个软件的安装程序,这里直接附上 Docker Store 的下载链接,供大家直接下载

# 3.2 启动 Docker

  • Linux 中一样,我们要在 WindowsmacOS 中使用 Docker 前,我们需要先将 Docker服务启动起来。在这两个系统中,我们需要启动的就是刚才我们安装的 Docker for WindowsDocker for Mac 了...
  • 启动两个软件的方式很简单,我们只需要通过操作系统的快捷访问功能查找到 Docker for WindowsDocker for Mac 并启动即可
  • 打开软件之后,我们会在Windows 的任务栏或者 macOS 的状态栏中看到 Docker 的大鲸鱼图标

Docker Desktop 为我们在 WindowsmacOS 中使用 Docker提供了与 Linux 中几乎一致的方法,我们只需要打开 Windows 中的 PowerShell 获得 macOS 中的 Terminal,亦或者 Git BashCmderiTerm等控制台类软件,输入 docker 命令即可...

使用 docker version 能够看到 Docker 客户端的信息,我们可以在这里发现程序运行的平台

λ docker version
Client:
## ......
 OS/Arch:  windows/amd64
## ......
@程序员poetry: 代码已经复制到剪贴板

# 3.3 Docker Desktop 的实现原理

我们知道 Docker 的核心功能,也就是容器实现,是基于 Linux内核中 NamespacesCGroups 等功能的。那么大体上可以说,Docker 是依赖于 Linux 而存在的。那么问题来了,Docker Desktop 是如何实现让我们在 WindowsmacOS 中如此顺畅的使用 Docker 的呢?...

  • 其实 Docker Desktop 的实现逻辑很简单:既然 WindowsmacOS 中没有 Docker能够利用的 Linux 环境,那么我们生造一个 Linux 环境就行啦!Docker for WindowsDocker for Mac 正是这么实现的...
  • 由于虚拟化在云计算时代的广泛使用,WindowsMacOS 也将虚拟化引入到了系统本身的实现中,这其中就包含了之前我们所提到的通过 Hypervisor实现虚拟化的功能。在 Windows 中,我们可以通过 Hyper-V 实现虚拟化,而在 macOS 中,我们可以通过 HyperKit 实现虚拟化...
  • Docker for WindowsDocker for Mac 这里利用了这两个操作系统提供的功能来搭建一个虚拟 Linux 系统,并在其之上安装和运行 docker daemon

除了搭建 Linux 系统并运行 docker daemon 之外,Docker Desktop 系列最突出的一项功能就是我们能够直接通过 PowerShellTerminal 这类的控制台软件在 WindowsmacOS 中直接操作虚拟 Linux 系统中运行的 docker daemon...

# 3.4 主机文件挂载

  1. 控制能够直接在主机操作系统中进行,给我们使用 Docker Desktop 系列软件提供了极大的方便。除此之外,文件的挂载也是 Docker Desktop 所提供的大幅简化我们工作效率且简化使用的功能之一。
  2. 之前我们谈到了,Docker 容器中能够通过数据卷的方式挂载宿主操作系统中的文件或目录,宿主操作系统在 Windows 和 macOS 环境下的 Docker Desktop 中,指的是虚拟的 Linux 系统。
  3. 当然,如果只能从虚拟的 Linux 系统中进行挂载,显然不足以达到我们的期望,因为最方便的方式必然是直接从 Windows 和 macOS 里挂载文件了。
  4. 要实现我们所期望的效果,也就是 Docker 容器直接挂载主机系统的目录,我们可以先将目录挂载到虚拟 Linux 系统上,再利用 Docker 挂载到容器之中。这个过程被集成在了 Docker Desktop 系列软件中,我们不需要人工进行任何操作,整个过程已经实现了自动化...

Docker DesktopWindowsmacOS 到虚拟 Linux 系统,再到 Docker 容器中的挂载进行了实现,我们只需要直接选择能够被挂载的主机目录 ( 这个过程更多也是为了安全所考虑 ),剩下的过程全部由 Docker Desktop 代替我们完成。...

# 四、使用容器:镜像与容器

# 4.1 Docker 镜像

  1. 如果进行形象的表述,我们可以将 Docker 镜像理解为包含应用程序以及其相关依赖的一个基础文件系统,在 Docker 容器启动的过程中,它以只读的方式被用于创建容器的运行环境。
  2. 从另一个角度看,在之前的小节里我们讲到了,Docker 镜像其实是由基于 UnionFS 文件系统的一组镜像层依次挂载而得,而每个镜像层包含的其实是对上一镜像层的修改,这些修改其实是发生在容器运行的过程中的。所以,我们也可以反过来理解,镜像是对容器运行环境进行持久化存储的结果...

# 4.2 查看镜像

  1. 镜像是由 Docker 进行管理的,所以它们的存储位置和存储方式等我们并不需要过多的关心,我们只需要利用 Docker 所提供的一些接口或命令对它们进行控制即可。
  2. 如果要查看当前连接的 docker daemon 中存放和管理了哪些镜像,我们可以使用 docker images这个命令 ( LinuxmacOS 还是 Windows 上都是一致的 )
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
php                 7-fpm               f214b5c48a25        9 days ago          368MB
redis               3.2                 2fef532eadb3        11 days ago         76MB
redis               4.0                 e1a73233e3be        11 days ago         83.4MB
cogset/cron         latest              c01d5ac6fc8a        15 months ago       125MB...
@程序员poetry: 代码已经复制到剪贴板

docker images 命令的结果中,我们可以看到镜像的 ID ( IMAGE ID)、构建时间 ( CREATED )、占用空间 ( SIZE ) 等数据

这里需要注意一点,我们发现在结果中镜像 ID 的长度只有 12 个字符,这和我们之前说的 64 个字符貌似不一致。其实为了避免屏幕的空间都被这些看似“乱码”的镜像 ID 所挤占,所以 Docker 只显示了镜像 ID 的前 12 个字符,大部分情况下,它们已经能够让我们在单一主机中识别出不同的镜像了...

# 4.3 镜像命名

  • 镜像层的 ID 既可以识别每个镜像层,也可以用来直接识别镜像 ( 因为根据最上层镜像能够找出所有依赖的下层镜像,所以最上层进行的镜像层 ID 就能表示镜像的 ID ),但是使用这种无意义的超长哈希码显然是违背人性的,所以这里我们还要介绍镜像的命名,通过镜像名我们能够更容易的识别镜像...
  • docker images 命令打印出的内容中,我们还能看到两个与镜像命名有关的数据:REPOSITORYTAG,这两者其实就组成了 docker 对镜像的命名规则

准确的来说,镜像的命名我们可以分成三个部分:username、repository 和 tag

  • username: 主要用于识别上传镜像的不同用户,与 GitHub 中的用户空间类似。
  • repository:主要用于识别进行的内容,形成对镜像的表意描述。
  • tag:主要用户表示镜像的版本,方便区分进行内容的不同细节

对于 username 来说,在上面我们展示的 docker images 结果中,有的镜像有 username 这个部分,而有的镜像是没有的。没有 username 这个部分的镜像,表示镜像是由 Docker 官方所维护和提供的,所以就不单独标记用户了...

# 4.4 容器的生命周期

容器运行的状态流转图

图中展示了几种常见对 Docker 容器的操作命令,以及执行它们之后容器运行状态的变化。这里我们撇开命令,着重看看容器的几个核心状态,也就是图中色块表示的:CreatedRunningPausedStoppedDeleted

在这几种状态中,Running 是最为关键的状态,在这种状态中的容器,就是真正正在运行的容器了

# 4.5 主进程

  1. 如果单纯去看容器的生命周期会有一些难理解的地方,而 Docker 中对容器生命周期的定义其实并不是独立存在的。
  2. Docker 的设计中,容器的生命周期其实与容器中 PID1 这个进程有着密切的关系。更确切的说,它们其实是共患难,同生死的兄弟。容器的启动,本质上可以理解为这个进程的启动,而容器的停止也就意味着这个进程的停止,反过来理解亦然。
  3. 当我们启动容器时,Docker 其实会按照镜像中的定义,启动对应的程序,并将这个程序的主进程作为容器的主进程 ( 也就是 PID1 的进程 )。而当我们控制容器停止时,Docker 会向主进程发送结束信号,通知程序退出。
  4. 而当容器中的主进程主动关闭时 ( 正常结束或出错停止 ),也会让容器随之停止。
  5. 通过之前提到的几个方面来看,Docker 不仅是从设计上推崇轻量化的容器,也是许多机制上是以此为原则去实现的。所以,我们最佳的 Docker 实践方法是遵循着它的逻辑,逐渐习惯这种容器即应用,应用即容器的虚拟化方式。虽然在 Docker 中我们也能够实现在同一个容器中运行多个不同类型的程序,但这么做的话,Docker 就无法跟踪不同应用的生命周期,有可能造成应用的非正常关闭,进而影响系统、数据的稳定性...

# 五、使用容器:从镜像仓库获得镜像

# 5.1 镜像仓库

如果说我们把镜像的结构用 Git 项目的结构做类比,那么镜像仓库就可以看似 GitLabGitHub 等的托管平台,只不过 Docker 的镜像仓库托管的不是代码项目,而是镜像

当然,存储镜像并不是镜像仓库最值得炫耀的功能,其最大的作用是实现了 Docker 镜像的分发。借助镜像仓库,我们得到了一个镜像的中转站,我们可以将开发环境上所使用的镜像推送至镜像仓库,并在测试或生产环境上拉取到它们,而这个过程仅需要几个命令,甚至自动化完成...

# 5.2 获取镜像

虽然有很多种方式将镜像引入到 Docker 之中,但我们最为常用的获取现有镜像的方式还是直接从镜像仓库中拉取,因为这种方式简单、快速、有保障

要拉取镜像,我们可以使用 docker pull 命令,命令的参数就是我们之前所提到的镜像仓库名。

$ sudo docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
124c757242f8: Downloading [===============================================>   ]  30.19MB/31.76MB
9d866f8bde2a: Download complete 
fa3f2f277e67: Download complete 
398d32b153e8: Download complete 
afde35469481: Download complete...
@程序员poetry: 代码已经复制到剪贴板
  • 当我们运行这个命令后,Docker 就会开始从镜像仓库中拉取我们所指定的镜像了,在控制台中,我们可以看到镜像拉取的进度。下载进度会分为几行,其实每一行代表的就是一个镜像层。Docker 首先会拉取镜像所基于的所有镜像层,之后再单独拉取每一个镜像层并组合成这个镜像。当然,如果在本地已经存在相同的镜像层 ( 共享于其他的镜像 ),那么 Docker 就直接略过这个镜像层的拉取而直接采用本地的内容。
  • 上面是一个拉取官方镜像并且没有给出镜像标签的例子,大家注意到,当我们没有提供镜像标签时,Docker 会默认使用 latest 这个标签...

我们也能够使用完整的镜像命名来拉取镜像

<
阅读全文
Last Updated: 3/30/2025, 1:18:33 PM