Rails on Docker: 用 docker-sync 改善文件同步性能
💡 Rails on Docker 系列文章是面向 Rails 程序员的 Docker 教程,描述了如何从开发环境到部署环境中应用 Docker。这是系列文章的第三篇。
在上一节中我们已经学习了用 Docker Compose 搭建开发环境,这一节将介绍如何用 docker-sync 改善开发环境的文件同步性能。
文件同步有什么问题?
在 Mac 下使用 Docker,你可能会发现性能差得离谱。一个在本地环境 2 秒启动的 Rails 应用,在容器里面要一分钟。如果项目依赖很多(例如 NPM),速度会慢得让你怀疑是不是已经死机。
性能低下的原因是文件同步太慢,这是 Docker for Mac 一个由来已久的问题(issue。Docker for Mac 内置的文件同步机制是 OSXFS,由于涉及文件系统转换,同步过程相当耗时,文件稍微多一些时就会明显拖慢性能。
Docker 4.6 版本引入了新的文件同步机制,据说大大提升了同步性能。在我测试中,新的同步机制虽然有了改善,但还是比理想情况慢了很多。一个不严谨的比较是:
旧同步机制(50s) > 新同步机制(10s)> docker-sync(2s)> 本地性能(1s)
所以如果你使用了新同步机制下还觉的慢,那么推荐使用 docker-sync。
docker-sync 简介
docker-sync 是一个命令行工具,用于替代 Docker Desktop 内置的文件同步机制,解决性能问题。
docker-sync 的原理可以看下图:
docker-sync 把同步机制分成了两步,第一步是通过 OSXFS 同步本地文件和虚拟机中的目录,第二步是将虚拟机的目录和要挂载的 volume 同步。最终挂载到 app 的 volume 是一个虚拟机的内部目录,避免直接调用 OSXFS,从而提高性能。详细的同步机制可以看 docker-sync 的文档。
使用 docker-sync 之后,虽然同步会有延迟(约 1 秒),但是应用执行速度很快,能满足开发的需要。
docker-sync 使用
首先安装 docker-sync 工具,它是一个 gem 包:
$ gem install docker-sync
在项目目录下创建文件 docker-sync.yml
,内容如下:
version: "2"
syncs:
# 卷名,通常是 AppName-sync
myapp-sync:
src: './app'
# 可以添加其他需要忽略的目录
sync_excludes: ['.git', 'tmp', 'log']
修改 docker-compose.yml
文件中的 volume 设置:
version: "3.9"
services:
web:
build: .
command: bin/rails server -b 0.0.0.0
volumes:
# 使用命名 volume,:nocopy 标记是必须的
- myapp-sync:/app:nocopy
ports:
- 3000:3000
depends_on:
- postgres
postgres:
image: postgres:13
environment:
POSTGRES_PASSWORD: postgres
# volumne 指向 docker-sync 维护的卷
volumes:
myapp-sync:
external: true
然后用下面命令启动开发环境:
$ docker-sync start
$ docker compose up
如果一切正常,我们会看到 docker compose 环境启动,并且应用性能会大幅提升。
更多 docker-sync 的设置,可以查看它的官方文档。
总结
通过引入 docker-sync,我们解决了 docker compose 在开发环境的一个痛点。不过每增加一个工具就增加一点复杂,希望 docker 本身的同步机制能继续优化,有一天可以抛弃 docker-sync。
下一节将会讲述 docker 在生产环境的应用。