Docker和OS X上的文件共享

7

好的。我正在尝试使用不同的工具来准备开发环境,Docker是一个很好的选择。我在docker中创建了整个开发环境,并可以在其中构建项目。

该项目的源代码存储在docker容器之外(在主机上)。这样,您可以使用IDE进行编辑,并使用docker构建它。

然而,存在一个问题:

a)OS X上的Docker使用VM(VirtualBox VM)

b)文件共享速度相对较慢(比主机上的文件IO慢得多)

c)该项目有数百万个文件(夸大了问题#a和#b)。

如果我将源代码移动到docker中,IDE将面临相同的问题(它将需要访问共享文件,速度会很慢)。

我听说过一些解决方法可以加快速度。然而,我似乎找不到任何关于这个问题的信息。

更新1

我使用了Docker的文件共享功能(意味着我运行)。

docker run -P -i  -v <VMDIR>:<DOCKERDIR> -t <imageName> /bin/bash

然而,虚拟机和Docker之间的共享并不是问题。它很快。

瓶颈在于主机和虚拟机之间的共享。


你所说的“文件共享”,是指 Virtualbox 的“共享文件夹”,还是一种文件共享容器,例如将 SMB 暴露给 Mac? - kojiro
我对我的问题进行了补充和更新。我使用docker -v命令(我相信这可以翻译为VirtualBox的“共享文件夹”)。 - Victor Ronin
1
这可能会有所帮助... http://viget.com/extend/how-to-use-docker-on-os-x-the-missing-guide - Mark Setchell
那篇指南很有用,可以帮助理解正在发生的事情,但是它有点过时了。特别是,boot2docker现在本地支持VirtualBox扩展——至少不需要它来进行共享文件夹。 - kojiro
@MarkSetchell 是的,这是一个有用的指南。然而,它并没有回答如何使它更快的问题 ;) - Victor Ronin
5个回答

2
我使用的解决方法是不使用boot2docker,而是使用一个已经安装了Docker的vagrant虚拟机(链接)。这样做不会有太大的代价来挂载文件夹从主机到vagrant再到docker。
缺点是,我必须预先将文件夹映射到vagrant中(基本上是我的整个工作目录),并且预先公开一系列端口,以便从主机直接访问docker服务。
优点是,当我想要清理未使用的docker垃圾(镜像、卷等)时,我只需销毁vagrant虚拟机,然后重新创建它 :)。 详细说明
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "trusty-docker"
  config.vm.box_url = "https://oss-binaries.phusionpassenger.com/vagrant/boxes/latest/ubuntu-14.04-amd64-vbox.box"
  config.vm.provision "docker"

  #by default we'll claim ports 9080-9090 on the host system
  for i in 9080..9090
    config.vm.network :forwarded_port, guest: i, host: i
  end

  #NB: this folder mapping will not have the boot2docker issue of slow sync
  config.vm.synced_folder "~/work", "/home/vagrant/work"
end

那样的话:
host$ vagrant up && vagrant ssh
vagrant$ docker run -it --rm -v $(pwd)/work:/work ubuntu:12.04 find /work

你能解释一下为什么这样做更好吗?据我理解,主机->虚拟机还是会共享VM文件夹的吧? - Victor Ronin
提供一个例子,希望更清晰。随时提问。是的,仍然有文件夹共享,但它比boot2docker的快得多,据我所记使用rsync。 - Mykola Gurov
你的项目有多大?对我来说它仍然非常缓慢。 - Victor Ronin
我的项目大约有40k个文件。我按照你的建议在vagrant中运行了docker(使用了你的文件)。然而,速度仍然很慢。我给虚拟机添加了内存。我检查了CPU利用率很低(大约20%)。但是,它仍然比在主机上构建要慢得多。你有什么建议来确定瓶颈在哪里吗? - Victor Ronin
我做了很多调查,仍然看不出它为什么更好。boot2docker本质上等于virtual box + docker。vagrant也等同于 virtual box + docker。在docker中复制文件(而不是使用共享)可以极大地帮助。使用NFS(而不是默认的virtual box共享)也有很大帮助。 - Victor Ronin
显示剩余3条评论

2

有两个步骤可以很好地提高您的性能:

  1. 切换到NFS。您可以使用此脚本来完成。

  2. 将VBox NIC驱动程序切换为FAST III 您可以通过运行以下命令在default机器上完成:

VBoxManage modifyvm default --nictype1 Am79C973 VBoxManage modifyvm default --nictype2 Am79C973


1
非常令人印象深刻的改进!我有一个在docker-machine(boot2docker)上运行的php项目,每个页面加载时间为4秒。现在它少于1秒! - chuangbo

2
这是目前Windows和OS X用户正在努力解决的典型问题,尤其是对于Windows用户来说,这个问题并不容易解决。主要罪魁祸首是VirtualBox的vboxfs,它用于文件共享,尽管非常有用,但导致了糟糕的文件系统I/O。
有许多情况会导致在虚拟机中开发项目源代码变得非常缓慢,主要有两种情况,一是由软件包管理器引入的大量第三方源码,二是具有相当历史记录的Git仓库。
显而易见的方法是将尽可能多的与项目相关的文件移出vboxfs,放到虚拟机内的其他位置。例如,可以将软件包管理器目录链接到项目的vboxfs树中,像这样: mkdir /var/cache/node_modules && ln -s /var/cache/node_modules /myproject/node_modules 仅仅这一步就使我的SSD上运行的一个具有几十个依赖项的Node.js应用程序的启动时间从约28秒减少到约4秒。
很遗憾,在管理Git存储库方面,除非在客户机内部署Git存储库本身,否则无法应用该方法,除非截断/缩短历史记录并提交数据丢失,这将迫使您拥有两个存储库:一个用于克隆环境以膨胀客户机,另一个包含实际的源代码,其中合并这两个世界变得非常困难。

处理这种情况的最佳方法是:

  1. 放弃使用vboxfs,采用共享传输机制来获得更好的客户机I/O性能,例如网络文件系统。不幸的是,对于Windows用户,获取NFS服务支持的唯一方法是运行Windows企业版(我相信对于Windows 10仍然如此)。
  2. 回到将原始磁盘分区挂载到客户机上,并注意提供超级管理员权限的相关风险。
如果你的开发人员受众完全由Linux和OS X用户组成,选项1可能是可行的。创建一个Vagrant虚拟机并在主机和客户机之间配置NFS共享即可。如果你有Windows用户,除非为他们购买企业许可证,最好只是要求他们重新分区他们的磁盘并在客户机中工作。

Windows host and Arch Linux guest with raw disk access

我个人使用的是Windows主机,有一个64 GB的分区在我的SSD上,我将其直接挂载到我的Arch Linux客户端并从那里操作。我还切换到了GPT和UEFI,并有一个选项可以直接启动Arch Linux,以便我想要规避虚拟化硬件的开销,从而在两个世界中获得最好的体验,几乎没有任何妥协。

我尝试了NFS。它比VirtualBox默认共享要好得多。然而,在如此大量的文件上,它仍然会产生巨大的性能影响。此外,在构建时,所有对项目目录的写操作都将被发送回主机(这会增加性能影响)。 - Victor Ronin

1
我运行一个简单的监视脚本,每当有任何更改时,它会在我的容器中启动一个rsync,从共享源代码卷复制到仅容器卷。我的入口点只从仅容器卷中读取,从而避免了性能问题,而rsync非常有效,特别是如果您正确设置以避免例如.git文件夹和不经常更改的库之类的事物。

只是好奇,你的项目有多大? - Victor Ronin
顺便说一下。我尝试了这个解决方案。它运行良好。但是,它必须检查文件夹中每个文件的时间戳/大小。因此,如果只更改了一个文件,它仍可能需要相当长的时间。 - Victor Ronin
有趣。我的项目大多是Node.js包,我们将其部署为微服务,因此它们不会太大。有很多常见的模块,但我已经让rsync忽略了node_modules文件夹中的所有更改,以便不会减慢速度。根据我的经验,它非常快。 - Abdullah Jibaly
当然。如果你忽略大部分文件(在你的情况下),并同步1k个文件,它几乎是瞬间完成的。对于我来说,这是一个庞大的单体项目(40k个文件)。我认为我可以通过忽略一些文件使其更小,但仍需要大约30秒来处理如此多的文件。 - Victor Ronin
1
是的,每当我知道需要同步所有内容时,我会运行完整传输,这大约需要30秒左右,但在我通常工作时很少发生。 - Abdullah Jibaly

0

我找到了一些信息

  • 我开始使用Vagrant来使用VirtualBox并在其中安装Docker。它提供了更大的灵活性。

  • Vagrant VirtualBox provisioning中的默认共享非常慢。

  • NFS共享速度更快。但是,如果您的构建过程将创建需要写回此共享的文件,则可能会相当缓慢。

  • Vagrant 1.5+具有rsync选项(使用rsync从主机复制文件到VM)。它更快,因为它不必写回任何更改。

  • 此rsync选项具有自动同步功能(以连续同步它)。

  • 此rsync选项消耗大量CPU,人们想出了一个gem来克服它(https://github.com/smerrill/vagrant-gatling-rsync

因此,对于我的情况,Vagrant + VirtualBox + Rsync共享文件夹+自动rsync + vagrant gatling看起来是一个不错的选择(仍在研究中)。

我尝试了vagrant gatling,但是它导致了不确定的行为。我从来不知道新文件是否已经复制到虚拟机中。如果只需要1秒钟,那就不是问题。但是可能需要20秒钟,这太长了(用户可能会在新文件还没有同步时切换窗口并开始构建)。

现在,我正在考虑一些仅复制更改的文件的方法。我仍处于研究阶段。想法是使用FSEvent监听文件更改并仅发送更改的文件。看起来有一些工具可以做到这一点。

顺便说一下,Gatling内部使用FSEvent。唯一的问题是它触发完整的rsync(它会开始比较40k个文件的日期/时间和大小)。


再多加一点想法。Rsync auto和Gatling都试图同步整个文件夹。我觉得可能有一种解决方案,只尝试同步修改过的文件。 - Victor Ronin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接