运维 在 Mac 上快速启用 docker-sync 优化文件同步速度 [附简要原理介绍]

SpiderEvgn · 2019年08月05日 · 最后由 canonpd 回复于 2020年12月08日 · 7901 次阅读

引言

相信所有在 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、启动。

1. 安装 gem

gem install docker-sync

2. 配置 yml

在项目根目录下,创建 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

3. 启动

在项目根目录下,先启动 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 主要做了以下几步:

  1. 用 osxfs 挂载本地目录到 sync-container 的 /host_sync
  2. Unison(文件同步工具)建立一个双向同步机制,同步 /host_sync 和 /app_sync
  3. 通过 Docker Volume 的方式,将 /app_sync 挂载到 app-container 的 /app

经过这样一层转换(新建一个 sync-container 优化数据同步),docker-sync 完成了如下几个目的:

  1. 因为采用 Unison,所以 /host_sync 到 /app_sync 的同步是 native-speed 的,没有了原本的因为不同文件系统带来的性能影响
  2. 通过 Docker Volume 来挂载 /app_sync 到 app-container,这一步是 hyperkit 层的,用的是 Docker LINUX-based 的原生挂载方式,所以也大大减小了对性能的影响(同样是 native-speed)。

其实,最关键的一步就是在 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 倍的性能提升。

支持支持,正好需要

不错,我以前也写了一篇类似的帖子。
https://ruby-china.org/topics/37289

话说好像还没解决这个 ISSUE。
https://github.com/docker/for-mac/issues/77

heroyct 回复

看过你的帖子 👍 因为主要是在介绍原因和两种不同方法,并且 docker-sync 的安装也有不同(不需要 brew install 依赖),所以我就新起一篇专门介绍 docker-sync 的

这个 issue 没有深入了解,但对普通的 Docker 开发环境来说,用 docker-sync 已经完全没问题啦

实际测试,测试机 macOS 系统。我的项目页面比较复杂,查询也相当多。

  • 本机直接运行,100 毫秒的样子。
  • docker 直接运行,1500 毫秒的样子。
  • 开启 docker-sync 后,250-300 毫秒。

确实是快了 5 倍,但依然还是本机直接运行最优。我感觉 docker 还是只适合部署,不适合开发用。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号