相信所有在 Mac 上使用 Docker 的人都有过这个感受,就是速度总比直接部署到 OS 上要慢很多。一个很重要的因素就是 Docker container 对共享文件的读写太慢,前几天研究了一下 docker-sync,它可以大大加快这个 volume I/O 过程,在此总结一下用法和心得,希望能帮到那些想快速无脑启用 docker-sync 的开发者。(docker-sync 同样试用于 Windows,但我并未测试,用 Windows 的同学有兴趣可以留言,谢谢)
先通过一个粗略、直观的测试来看看部署 docker-sync 后的效果。
选取两个页面,分别在使用 docker-sync 之前和之后各执行一次。
之前:
之后:
之前:
之后:
可以看到,速度的提升效果还是很明显的,能减少大约 3-5 倍的时间。
docker-sync 的用法其实很简单,只需要三步:安装 gem、配置 yml、启动。
gem install docker-sync
在项目根目录下,创建 docker-sync.yml
,内容如下:
version: '2'
syncs:
[volume-name]: # 自定义,将作为同步数据的 volume
src: './'
然后更改 docker-compose.yml
,用新的 volume 替代原来的同步方式。原本你的 volume 可能类似如下:
volumes:
- .:/app # 将项目根目录所有文件同步到 container 中的 /app 文件夹
修改后如下:
services:
web:
...
volumes:
- [volume-name]:/app:nocopy
volumes:
[volume-name]: # docker-sync.yml 中自定义的名字
external: true
在项目根目录下,先启动 docker-sync
:
docker-sync start
第一次启动会自动下载一个 eugenmayer/unison 的 docker image,以后便会直接启动一个 unison 的 container。
如果想深入配置 docker-sync.yml,可以看docker-sync 官网。实用主义者看到这就可以了。如果想进一步了解 docker-sync 的原理,它到底做了什么,请继续往下读。
在 Sierra 及以下版本的 macOS 默认用的文件系统是 HFS+,High Sierra 用的是 APFS。Docker Desktop for Mac 用一个叫 osxfs 的共享文件系统来实现 macOS 到 Docker containers 的文件系统绑定挂载。影响一个共享文件系统性能的因素有很多方面,比如 osxfs 集成了 macOS 的 FSEvents API 到 Linux 的 inotify API 之间的映射,还有一些诸如缓存的更加复杂的维度。
简而言之,由于操作系统之间不同文件系统的差异,共享文件系统的数据同步性能有着很大的不确定性。所以,docker-sync 的主要目的就是如何最大限度地弥补这个差异,优化共享文件系统的数据同步过程。先来看下图,来自 docker-sync 官方文档:
可以看到,docker-sync 主要做了以下几步:
经过这样一层转换(新建一个 sync-container 优化数据同步),docker-sync 完成了如下几个目的:
其实,最关键的一步就是在 sync-container 中的 /host_sync 到 /app_sync 的同步过程,通过 Unison,osxfs 对性能的影响被从文件系统的读/写中剥离了,Unison 用远比 osxfs 快得多的技术完成了 macOS 到 Docker container 的数据同步。至于 Unison 究竟是如果做到高效跨平台文件同步的,就留给更专业的大佬解读了。
如果你用 Mac,如果你又依赖 Docker 管理环境依赖,那 docker-sync 真是一个必不可少的绝佳工具。尽管需要在主机上安装一个 gem(当然还有其它几个依赖 gem),但也只需要安装一个 gem,没有任何其它系统层的依赖,也不需要跑任何多余进程,通过一个 Unison 的 Docker container,docker-sync 就完美地帮你实现了 3-5 倍的性能提升。