闲谈 - 我如何看待 Docker

Docker 的启蒙是来源于 innei ，我从 Mix Space CMS 这个项目中学习到了很多。

Docker 的本质#

首先，让我们来理清一下 Docker 的概念。官方宣传它是 “构建一次，到处运行”（Build once, run anywhere），但这句话需要有所解读。如果你是用 Docker 23.x 版本构建的镜像，那么在 Docker 19.x 上可能会出现异常。这有点类似于 Java 的 JDK 版本兼容性问题，低版本无法运行高版本的 Class 文件，这是我们所熟悉的情况。而低版本 Docker 构建的镜像呢？Docker 提供了迁移流程，通常可以正常运行，这与 JDK 不同，高版本中废弃的方法在低版本中是无法使用的。

说了那么多，Docker 到底是个什么呢？

我给其定性为，Docker 是具有一套隔离环境的守护程序。当然这个定义就比较通俗了，如果用更深一点的话来说，Docker 是一种容器化平台，通过提供隔离环境，使应用程序能够在独立的容器中运行。

那么我为啥强调守护程序这个概念呢？那是因为 Docker 和 Linux 的相通之处，在 Unix 派别的操作系统，在内核初始化完成以后，会启动一个 PID = 1 的 init 进程，由它来处理用户态的后续进程启动以及依赖关系等操作。在 Linux 下也是如此，有的发行系可能会把守护程序链接为 init ，有的没选择链接。但是不管怎么样，这些程序承担的都是 init 程序的责任。也就是说，所有程序都是这种 init 进程 fork 出来的，你可以通过 htop 等查看进程关系树。

容器化的适用场景#

那么什么样的程序适合使用 Docker 跑呢？我的实践经验告诉我，状态非自赋予的程序适合使用 Docker，比如常见的 Web 后端，PHP CMS 等等。

那么状态自赋予的程序是什么？比如数据库，它的状态是自己赋给自己的，不是由外部输入获得状态的。那么如果容器异常，自赋予需要写入到文件的东西就可能丢失。但是那些由外部输入状态的程序，就无需考虑这个问题。如果你能理解这个问题，那很好。接下来思考一个问题，数据库的容器化集群是否合适？

我的回答是不合适的，你也许会说，我可以使用数据卷等去持久化数据呀？那你其实忽视了容器集群的优势，可以根据需求任意增删容器，你使用数据卷取持久化数据，导致的结果就是让该容器和该节点强制绑定，这种强耦合是我不能接受的，所以我认为数据库容器化不太合适。那你也许会说，我直接使用外部存储呢？把数据直接持久化写入到外部存储。这种方案也看似不错，问题是怎么保证数据一致性问题，如果是单写多读，无需考虑，但实际的写入请求单数据库能抗下来么？

容器化解决了什么问题#

众所周知，技术的发展往往源于解决问题。这一点可以从我对 Docker 的定义中得知，它是一个具有隔离环境的守护程序。假设你需要在一个节点上运行多个相同类型的 Node.JS 服务，这些服务占用相同的端口。如果使用 pm2 或 systemd 等守护程序，你需要修改端口，才能让多个 Node.JS 服务正常运行。但在 Docker 中，你无需担心这个问题。它们可以共享相同的端口，并且可以使用 “容器名 + 端口” 的方式进行访问。此外，Dockerfile 和 docker-compose 的组合可以轻松实现单机容器编排。

Docker 的优点在于隔离性。此外，它也是一个守护程序。在容器中，也有一个 PID = 1 的程序。那么这个程序是守护程序吗？在容器内是守护程序，在容器外，由 Docker 管理。如果这个程序出现异常，Docker 就会判定整个容器异常。这也是很多人不知道如何解决 Docker 问题的原因之一，即不知道容器为何无法启动，或者为何 PID = 1 的进程异常。你可能会说，Docker 这种判断太过简单粗暴，只看 PID = 1 的程序是否异常。我只能说，作为守护程序，它只能如此。只要你能让这个程序持续运行，那么容器的状态就不会被 Docker 判定为异常。因此，Docker 不适合运行那些运行一段时间后自动退出的程序。

综上所述，隔离是 Docker 的核心，它解决了许多问题。通过进程隔离、网络隔离和文件系统隔离，帮助我们解决了一系列难题，例如部署多个相同服务的端口占用和计算资源分配。基于这种隔离性，我们还实现了容器集群这种更加灵活的东西。让我们的服务更加灵活。

代价#

当然，使用容器化技术并非没有代价，一点点的 CPU 性能损失，额外的内存占用（因为 libc 不和宿主机共享，需要加载到容器），磁盘 IO 性能损失。

此文由 Mix Space 同步更新至 xLog
原始链接为 https://www.timochan.cn/posts/any_pen/understanding_docker_for_me