使用 docker-sync 将 Docker for Mac 的响应时间缩短一半
我真的很喜欢 Docker 和容器化的概念。我的 MAMP 开发环境已经一年多没动过了,本地的 PHP 命令行界面也几乎不用了。但是,性能问题一直存在。Laravel 应用的响应时间通常只有一秒,而规模较大的 WordPress 应用的响应时间也只有 3-7 秒。幸运的是,这个问题有一个解决方案,而且不需要你更换整个技术栈:docker-sync。
什么是 docker-sync?
Docker for Mac(以及 Windows)的性能问题根源在于 Docker 和操作系统之间的文件系统层。在 Linux 系统上,Docker 可以直接挂载文件系统中的文件和文件夹,而在 Mac 系统上,Docker 必须将请求传递给操作系统,由操作系统负责将文件写入磁盘。对于 macOS 而言,OSXFS 文件系统就是一个显而易见的缺陷。虽然这听起来似乎无关紧要,但实际上影响巨大。即使只有一毫秒的延迟,如果你的应用程序需要读取 500 个源文件,累积起来也会造成半秒的延迟。
幸运的是,如果你将文件放入卷中,Docker 可以使用原生挂载功能,这些卷由 Linux 内核处理。而这正是 docker-sync 的工作原理。它会创建一个卷来存放所有应用程序的源文件,并使其可供应用程序访问,应用程序可以快速地读写该卷。由于卷通常不与外部世界(即你的文件系统)绑定,docker-sync 实现了不同的工具来负责将容器内部与主机文件系统同步。这样,你就可以在编辑器中编辑任何文件,这些文件都会同步到卷中,你的应用程序可以访问它们。
docker-sync 基准测试
我对 docker-sync 进行了基准测试,因为我想查看具体的数值,而不是猜测请求速度是否更快。以下两个应用程序分别基于 Laravel 和 WordPress,并且都使用了Bitnami 的镜像来运行。这里使用的主要指标是 TTFB(首字节到达时间),单位为毫秒。我连续打开这两个应用程序的页面 10 次,没有启用任何页面缓存。两个应用程序都运行在 PHP 7.3 版本上。
| 应用程序 | docker-sync | 敏 | 最大限度 | 中位数 | 不同之处 |
|---|---|---|---|---|---|
| Laravel 5.8 | 离开 | 1035毫秒 | 2158毫秒 | 1386毫秒 | |
| 在 | 234毫秒 | 303毫秒 | 251毫秒 | -81% | |
| WordPress 5.2 | 离开 | 2467毫秒 | 3942毫秒 | 2722毫秒 | |
| 在 | 881毫秒 | 1589毫秒 | 1271毫秒 | -53% |
如何使用 docker-sync
我敢肯定你已经上瘾了,对吧?响应时间最多能缩短 80%,听起来确实有点不可思议,但……这是真的。那么,我们现在该如何设置 docker-sync 呢?
1. 安装该工具
docker-sync 是用 Ruby 编写的,因此即使您的 Ruby 版本没有升级(目前 macOS 自带的是 v2.3),也可以轻松安装。要安装它,请运行以下命令:
gem install --user-install docker-sync
# or globally via
sudo gem install docker-sync
2. 向项目中添加一个新的 docker-sync.yml 文件
此配置文件告诉 docker-sync 要存储和同步哪些文件、使用哪些模式等等。以下是一个基本配置文件,您可以直接将其放入根文件夹:
version: "2"
syncs:
your-app-files:
notify_terminal: true
src: './'
sync_excludes: ['.git', '.idea', 'node_modules']
首先,在syncs选项中,您可以指定要创建的卷。请注意,卷的名称(your-app-files此处)在您的整台机器上必须是唯一的。该src选项定义了默认情况下应复制到卷中的文件,您可以使用该sync_excludes选项排除特定的目录或文件。我在这里排除了 Git、PhpStorm 和 node_modules 文件夹。Git 和 IDE 文件夹与应用程序本身无关,因此容器中不需要它们。排除 node_modules 文件夹是因为它们对于常规 PHP 应用程序也不需要,因此可以删除,尤其是在同步 4596895 个文件和文件夹可能需要很长时间的情况下……
您可以在官方文档中找到有关卷的其他配置参数。
3. 添加 docker-compose-dev.yml 文件
当前版本的 Docker Compose 允许您覆盖先前 docker-compose.yml 文件中的某些配置。这非常方便,因为我们可以直接使用当前的 docker-compose.yml 文件,无需任何修改。如果您暂时不想使用 docker-sync,也可以使用常规docker-compose up命令启动应用程序。
以下是我使用的示例文件:
version: "2"
services:
php:
volumes:
- your-app-files:/app:nocopy
nginx:
volumes:
- your-app-files:/app:nocopy
volumes:
your-app-files:
external: true
这个文件告诉 Docker Compose 不要使用 docker-compose.yml 文件中的常规挂载点,而是将your-app-files卷挂载到容器中。请注意,您必须将卷添加到所有需要访问这些文件的容器中,在本例中包括 PHP 和 nginx 容器。基本就是这样。
4. 启动 docker-sync 堆栈
实际上有两种方法可以使用 docker-sync 启动堆栈:
- 通过使用
docker-sync-stack或 - 通过使用
docker-sync和docker-compose。
docker-sync-stack
docker-sync-stack start
这条命令首先会启动 docker-sync,它会创建卷并做好使用准备,然后通过调用 `docker run` 命令运行容器docker-compose -f docker-compose.yml -f docker-compose-dev.yml up,该命令会启动 Docker Compose 并使用两个 docker-compose 配置文件。
缺点是,同步和 Docker 堆栈都会在前台运行。我个人不喜欢这样,因为你需要不断地为同一个应用程序打开多个终端窗口,但它的确快速高效。
要停止堆栈,请按CMD+ C。
docker-sync + docker-compose
docker-sync start
# wait until the command finishes creating the volume, then:
docker-compose -f docker-compose.yml -f docker-compose-dev.yml up -d
这是我目前使用的方法,以后可能会为此编写一个 bash 函数或别名。您可以继续在终端中工作,我推荐使用Kitematic来快速查看容器日志。(附注:Kitematic 已内置于 Docker for Mac 安装包中。)
如何解决权限问题
如果你也像我一样遇到权限问题,比如 Laravel 无法写入日志,WordPress 无法存储上传文件,那么你可能需要指定另一个用户 ID。在我目前使用 Bitnami 容器的 Docker 环境中,我遇到了一个问题:docker-sync 默认使用 root 用户存储所有文件,而 PHP FPM 运行在普通daemon用户下。这会导致文件保存时发生冲突。为了避免这种情况,你需要sync_userid: '1'在 docker-sync.yml 配置文件中添加一行,其中 ` 1<userID>` 是容器内守护进程用户的用户 ID。
添加这行代码后,所有问题都立即消失了,我可以正常使用这个配置了。
结论
搭建完整的堆栈花了我不少时间。我觉得文档不太容易理解,不过通过研究项目维护者提供的各种示例,我最终还是搭建了一个干净的堆栈。在又花了几个小时解决权限问题后,我终于能够使用 docker-sync 堆栈运行我的应用程序,工作效率也得到了极大的提升。现在页面加载速度飞快,这个小工具带来的改变真是令人难以置信。
非常感谢维护者 Eugen Mayer 和所有贡献者,感谢他们发布了这款出色的工具。
本文最初发表于Blog.Kovah.de
文章来源:https://dev.to/kovah/cut-your-docker-for-mac-response-times-in-half-with-docker-sync-1e8j