深入浅出Docker学习笔记——第一部分

  |   0 评论   |   0 浏览

这本书是一本关于 Docker 入门的书籍,感觉里面的内容不错,特意做下笔记。
书本中实验例子中的资源在作者的 GitHub 上,资源链接点我

第一部分 Docker 概况

第 1 章 容器发展之路

1.1 从物理机到容器

  业务是运行在应用之上的,而应用一开始只能运行在物理服务器上。为了保障应用的平稳运行,我们采购的服务器通常性能都大于业务需求的性能。甚至我们通常在一个服务器上只运行一个应用,目的是应用之间不会相互影响。这无疑对服务器资源是个极大的浪费。

  后来,出现了虚拟机,虚拟机把服务器的资源给虚拟化了,可以在一台服务器上安装部署多个虚拟机。每个虚拟机的环境完全独立,大大提高了服务器的资源利用率,最终为公司节约了大量的资金支出。

  虚拟机很美好,但是有一个明显的缺点,就是依赖其 OS。每个虚拟机都要安装一个 OS,OS 会占用额外的 CPU、RAM 和存储,此外 OS 还需要定期打补丁和监控,这些都需要资源。接下来就出现了容器技术,容器模型和虚拟机模型相似,其主要的区别在于,容器的运行不会独占操作系统。实际上,运行在相同宿主机上的容器是共享一个操作系统的,这样就能节约了大量的资源。虚拟机是虚拟化了硬件资源,而容器则是对系统做了虚拟化。这样带来的好处就是,资源利用率提高了,节省了资金成本。

  此外,容器技术还具有快速启动、便于迁移的特点,可以轻松把容器从笔记本迁移到服务器上。这就解决了一个运行环境的痛点了,不会再有人说为什么在我的电脑上能正常运行的,在服务器上就出错了,肯定是环境不一样造成的纠纷。

  说到容器技术,当然要提到其中的扛把子——Docker。容器技术不等于 Docker,但是提到容器多数人都第一时间想到的是 Docker。对容器发展影响比较大的技术包括内核命名空间(kernel Namespace)、控制组(Control Group)、联合文件系统(Union File System)以及 Docker。事实上,容器化技术很早就出现了,历史甚至可以追溯到大型机的时代。

1.2 Docker 在 Windows 及 Mac 的现状

  现代的容器技术源于 Linux,所以我们学习容器技术(Docker)首选是在 Linux 平台上学习。在 win10 以前,Docker 是没办法运行在 windows 内核上的。要在 windows 中使用 Docker,实际上是在 windows 中安装虚拟机,然后在 Linux 虚拟机中运行 Docker。在 win10 的情况不一样,现在 Docker 已经可以共享 win10 的内核了,也就是可以直接运行在 win10 上了。

  迄今为止,还没有出现 Mac 容器。要在 Mac 上运行 Docker,那就是使用 Docker for Mac 运行 Linux 容器。这是通过在 Mac 上启动一个轻量级的 Linux VM,然后在其上运行 Linux Docker 来实现的。

1.3 Kubernetes(K8S)

  Kubernetes 是谷歌的一个开源项目,并且开源之后迅速成为容器编排的领头羊。有一种很流行的说法:Kubernetes 是保证容器部署和运行的软件体系中很重要的一部分。

  目前 K8s 采用 Docker 作为其容器运行时(container runtime),包括 k8s 启动和停止容器,以及镜像的拉取等扽。但是,k8s 也提供了一个可插拔的容器运行时接口 CRI。CRI 能够帮助 k8s 实现将运行时环境从 Docker 快速替换为其他容器运行时。在未来,k8s 中的默认容器运行时可能由 docker 替换为 containerd。

  本书不会对 k8s 做详细的介绍,对于 k8s,作者有一本叫做The Kubernetes Book的书可以学习,目前只有英文版。

1.3 小结

  在过去,每当业务部门想运行新的应用时,IT 部门就需要采购新的服务器来满足需求。接下来 VMWare 的出现终结了这个时代,使得 IT 部门可以更高效地利用现有的和新的机器资源,产生更大的价值。但即使 VMWare 和虚拟机模型这么优秀的技术,也存在其缺点。在 VMWare 和 Hypervisor 成功后,出现了更加高效并且更加轻量级的虚拟化技术——容器。但容器计数在发展之初是很难应用于生产环境的,并且只在拥有 Linux 内核工程师的 Web 巨头的数据中心内才能看到实际应用。接下来 Docker 公司出现了,突然之间容器虚拟化技术开始被大众广泛使用。

  说到 Docker,接下来就请读者跟随本书一起,来了解 Docker 是什么,以及为什么要使用 Docker 吧!

第 2 章 走进 Docker

2.1 Docker 简介

当人们说到 Docker 的时候,可能是指如下三种概念之一。

  • Docker 公司
  • Docker 的容器运行时和编排引擎
  • Docker 开源项目(Moby)

Docker 是一种运行于 Linux 和 Windows 上的软件,用于创建、管理和编排容器。Docker 是在 GitHub 上开发的 Moby 开源项目的一部分。Docker 公司,位于旧金山,是整个 Moby 开源项目的维护者。Docker 公司还提供包含支持服务的商业版本 Docker。

2.1 Docker 公司

内容介绍略,说明本书将始终使用“Docker 公司”来指代 Docker 这家公司,其他地方出现的 Docker 都是值容器技术或者开源项目。

注:Docker 一词来自英国口语,意思是码头工人(Docker Worker),即从船上装卸货物的人。

2.2 Docker 运行时与编排引擎

多数技术人员在谈到 Docker 时,主要是指 Docker 引擎。

Docker 引擎是用于运行和编排容器的基础设施工具,可以与 VMWare 中的 ESXI 作为类别。ESXI 是运行虚拟机的核心管理程序,而 Docker 引擎是运行容器的核心容器运行时。

目前 Docker 引擎主要有两个版本:企业版(EE)和社区版(CE)。每个季度,企业版和社区版都会发布一个稳定的版本。社区版本会提供 4 个月的支持,而企业版本会提供 12 个月的支持。

下图是围绕 Docker 引擎进行开发和集成的产品。

docker1.png

2.3 Docker 开源项目(Moby)

Docker 一词也会用于指代开源 Docker 项目。其中包含一系列可以从 Docker 官网下载和安装的工具,比如 Docker 服务端和 Docker 客户端。不过,该项目在 2017 年于 Austin 举办的 DockerCon 上正式命名为 Moby 项目。由于这次的改名,GitHub 上的 docker/docker 库也被转移到了 moby/moby,并且拥有了项目自己的 Logo。

Moby 项目的目标是基于开源的方式,发展成为 Docker 上游,并将 Docker 拆分为更多的模块化组件。Moby 项目托管于 GitHub 的 Moby 代码库,包含子项目和工具列表。核心的 Docker 引擎项目位于 GitHub 的 moby/moby,但是引擎中的代码正在持续被拆分和模块化。

2.4 容器生态

Docker 公司的一个核心哲学通常被称为“含电池,但可拆卸(Batteries included but removable)”。意思是许多 Docker 内置的组件都可以替换为第三方组件,网络技术栈就是一个很好的例子。早期的时候,第三方插件通常比内置的组件更加好用。当然随着 Docker 公司的努力,Docker 内置的电池也变得越来越好用了。

2.5 开放容器计划

如果不谈及开发容器计划(The Open Container Initiative,OCI)的话,对 Docker 和容器生态的探讨总是不完整。

OCI 是一个旨在对容器基础架构中的基础组件(如镜像格式与运行时)进行标准化的管理委员会。OCI 的历史与一个叫做 CoreOS 的公司息息相关,这家公司不大喜欢 Docker 的某些行事方式。因此,它就创建了一个新的开源标准,称为“appc”,该标准涉及诸如镜像格式和容器运行时等方面。

两个处于竞争状态的标准将容器生态置于一种尴尬的境地,为了避免分裂的危险,同时也令消费者和用户陷入了两难。最后的结果就是大家一起成立了 OCI——一个旨在管理容器标准的轻量级的、敏捷型的委员会。

3. Docker 的安装

这里只介绍 DOcker 在 Linux 的安装部署方法和过程,具体可以查看我的博客

除了介绍如何安装部署 Docker 之外,书本中还介绍了 Docker 存储驱动的选择。目前较新的系统都是使用 Overlay2 作为存储驱动的(windows 的是 windows filter)。要查看当前 Docker 的存储驱动类型,可以使用命令来查看,具体内容不做介绍。

docker system info

4. 纵观 Docker

这里分别从运维视角和开发视角去看待理解 Docker,看看有什么不同。此外 Docker 还有一种快速启动的方式,叫做 Play With Docker(PWD)。PWD 是一个基于 Web 界面的 Docker 环境,并且可免费使用,可以作为临时启动 Docker 环境来用。

4.1 运维视角

安装 Docker 的时候,会涉及到两个主要组件:DOcker 客户端和 Docker daemon(有时也被称为“服务端”或者“引擎”)。
daemon 实现了 Docker 引擎的 API。
使用 Linux 默认安装时,客户端和 daomon 之间的通信是通过本地 IPC/UNIXSocket 完成的(/var/run/docker.sock)。可以通过 docker version来查看。

[pangcm@docker02 ~]$ docker version
Client: Docker Engine - Community
 Version:           19.03.4
 API version:       1.40
 Go version:        go1.12.10
 Git commit:        9013bf583a
 Built:             Fri Oct 18 15:52:22 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.4
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.10
  Git commit:       9013bf583a
  Built:            Fri Oct 18 15:50:54 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

4.1.1 镜像

将 Docker 镜像理解为一个包含了 OS 文件系统和应用的对象会很有帮助,与虚拟机做对比的话,可以类比为虚拟机的模板。在 Docker 的世界中,镜像实际上等价于未运行的容器。如果你是一名开发,可以把镜像类比为类(Class)。

要查看 Docker 的镜像,使用 docker image ls 命令来查看。

[pangcm@docker02 ~]$ docker image ls 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        10 months ago       1.84kB

上面的那个 hello-world 镜像是前面安装 docker 演示的时候拉取的,获取镜像的操作称为拉取(pulling),比如下面的命令我会拉取一个 Ubuntu 的镜像。

docker pull ubuntu

关于镜像的存储位置以及镜像内部构成,本书会在后续的章节中详细介绍。现在,读者只需要知道镜像包含了基础操作系统,已经应用程序运行所需要的代码和依赖包。上面拉取的 Ubuntu 镜像有一个精简版的 Ubuntu Linux 文件系统,其中包含部分的 Ubuntu 常用工具。如果拉取的是 nginx 这类的应用勇气,则里面还会包括了运行 Nginx 所需的代码。

重要的是,Docker 的每个镜像都有自己唯一的 ID。用户可以通过引用镜像的 ID 或名称来使用镜像。如果用户选择使用镜像 ID,通常只需要输入 ID 开头的几个字符即可——因为 ID 是唯一的,Docker 知道用户想要引用的具体镜像是哪一个。

4.1.2 容器

我们启动下前面我们拉取的 Ubuntu 镜像,使用docker container run命令来启动,当然你也可以不输入 container,直接使用docker run

[pangcm@docker02 ~]$ docker container run -it ubuntu:latest /bin/bash
root@fd1e2f056f5e:/# 

我们运行这个命令的时候,可以看到提示符发生了变化,这是因为 -it 参数会将 shell 切换到容器的终端中去,也就是说你已经位于容器内部了。

接下来分析下 docker container run 命令。docker container run 告诉 docker daemon 启动新的容器。其中 -it 参数告诉 Docker 开启容器的交互模式并将读者当前的 Shell 连接到容器的终端去。接下来,命令告诉 Docker,用于想基于 ubuntu:latest 镜像启动容器。最后,命令告诉 Docker,用户想要在容器内部运行哪个程序(bash).

在容器内部运行 ps 命令查看当前运行的全部进程。

root@fd1e2f056f5e:/# ps -ef 
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 13:54 pts/0    00:00:00 /bin/bash
root         10      1  0 13:58 pts/0    00:00:00 ps -ef

可以看到,容器中实际运行的进程只有一开始指定的 /bin/bash。输入 exit 会退出容器,并且会关闭容器。要退出容器的同时还保持容器的运行,请使用组合键 Ctrl-PQ。我们使用组合键退出后用 ps 命令(也就是看我们主机的进程)

[pangcm@docker02 ~]$ ps -efl 
F S UID         PID   PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root          1      0  0  80   0 - 31395 ep_pol 17:33 ?        00:00:02 /usr/lib/syste
1 S root          2      0  0  80   0 -     0 kthrea 17:33 ?        00:00:00 [kthreadd]
1 S root          4      2  0  60 -20 -     0 worker 17:33 ?        00:00:00 [kworker/0:0H]
1 S root          6      2  0  80   0 -     0 smpboo 17:33 ?        00:00:00 [ksoftirqd/0]
1 S root          7      2  0 -40   - -     0 smpboo 17:33 ?        00:00:00 [migration/0]
1 S root          8      2  0  80   0 -     0 rcu_gp 17:33 ?        00:00:00 [rcu_bh]
1 S root          9      2  0  80   0 -     0 rcu_gp 17:33 ?        00:00:00 [rcu_sched]
......

可以明显看到主机运行的进程比容器中的进程多很多的,要查看运行状态的容器,可以使用docker container ls来查看。

[pangcm@docker02 ~]$ docker container ls 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
fd1e2f056f5e        ubuntu:latest       "/bin/bash"         11 minutes ago      Up 11 minutes                           musing_easley

这里可以看到这个容器是在 11 分钟之前创建的,并且一直在运行着的。

4.1.3 连接到运行中的容器

执行 docker container exec 命令,可以将 shell 连接到一个运行中的容器终端。因为之前示例中的容器已经被关闭,我按照上面的办法重新运行了一个 Ubuntu 的镜像,下面使用命令连接到该容器上。

[pangcm@qcloud01 ~]$ docker container exec -it d69 bash
root@d691ce0106ab:/# 

这里使用的是镜像 ID 的前面 3 个字符,其实我们很少这么操作。通常情况下我们都是在启动容器的时候,给容器指定一个名称,后续对容器的操作都是用这个名字。这方面的内容后面会有介绍。可以看到 wo

这里可以看到我们已经连接进入到了 docker 容器里面了。那些参数的使用和前面介绍的 docker container run 的时候一样的。

下面我们来演示如何停止以及删除容器,首先我们和前面一样用组合键(Ctrl-PQ)退出容器,然后使用 docker container stop 和 docker container rm 命令来停止并删除容器。

[pangcm@qcloud01 ~]$ docker stop d69
d69
[pangcm@qcloud01 ~]$ docker rm d69
d69

然后我们使用 docker container ls -a 去确认还有没有该容器的存在。

4.2 开发视角

容器即应用!

开发人员可以使用 Dockerfile 来构建他们的应用,将应用代码容器化,最终以容器的方式运行。

这里书中有演示一个 Node.js 的 Web 应用,需要从作者的 GitHub 上下载示例的 Dockerfile。这里不做介绍,针对 Dockerfile 后面会有详细的介绍。

4.3 本章小结

在运维部分,我们下载了 Docker 镜像,启动容器并且登录到容器内部执行相应的命令,最后停止删除容器。

在开发部分,我们完成了简单应用容器化的过程:从 GitHub 拉取应用源代码,并且通过 Dockerfile 中的指令,将应用代码构建到镜像中。接着运行了该容器化应用。


标题:深入浅出Docker学习笔记——第一部分
作者:pangcm
地址:http://pangcm.club/articles/2019/11/18/1574060593162.html