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 的原理可以看下图:

native_osx.png

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 在生产环境的应用。

3
3
1