在OS X上使用Docker设置开发环境的正确方法是什么?

95

简介

我无法想出一种在OS X上使用Docker和Boot2Docker设置开发环境的好方法。 我遇到的问题是如何管理源代码,以便:

  1. 我可以使用已安装的工具(文本编辑器、IDE、git等)在OS X上修改代码。
  2. 这些修改会反映在Docker容器中,因此如果我重新运行测试或刷新网页,就可以立即看到我的更改。

理论上,通过将我的源代码挂载为卷应该很容易做到:

docker run -it -v /path/to/my/source/code:/src some-docker-image

不幸的是,这有两个主要问题,使其在OS X上完全无法使用:

问题#1:VirtualBox上挂载的卷(使用vboxsf)非常缓慢

例如,以下是Jekyll编译我的主页所需的时间,如果源代码是Docker映像的一部分:

> docker run -it brikis98/yevgeniy-brikman-homepage:v1 bash

root@7aaea30d98a1:/src# time bundle exec jekyll build

[...]

real    0m7.879s
user    0m7.360s
sys     0m0.600s

这是完全相同的 Docker 镜像,但这一次,我从 OS X 挂载了源代码:

> docker run -it -v $(pwd):/src brikis98/yevgeniy-brikman-homepage:v1 bash

root@1521b0b4ce6a:/src# time bundle exec jekyll build

[...]

real    1m14.701s
user    0m9.450s
sys     0m3.410s

问题 #2: 文件监视有问题

SBT、Jekyll 和 Grunt 中默认的监视机制使用诸如 inotify 等技术,如果它们在 Docker 容器中运行并且更改是在 OS X 上对挂载的文件夹进行时,这些技术将无法正常工作。

我尝试过的解决方法

我搜索了各种解决方案(包括 Stack Overflow 上的所有方案)并尝试了其中几个,但都没有找到成功的方法:

  1. 切换了 Boot2Docker 以使用 NFS,但速度仍然很慢。
  2. 我尝试使用Vagrant + NFS,但速度仍然很慢。
  3. 我尝试过Samba 挂载,但 Docker 容器中的文件夹总是显示为空。
  4. 我尝试使用Unison 文件系统,它可以短暂地同步文件,但后来始终显示连接错误
  5. 我在 Jekyll 中启用了轮询,但这显著增加了从我的更改被捕获的延迟时间。
  6. 我尝试了Dinghy,一个“更快、更友好的 Docker”,并取得了一些进展。与 Jekyll 编译速度慢 10-15 倍相比,它现在只慢了 2-3 倍。这是更好的,但仍然不能满足使用需求。

是否有人找到了实际可行的解决方法,并允许您使用 Docker 和 OS X 生产性开发代码?

更新:终于找到了一种解决方法!

最终,我使用 Boot2Docker + rsync 找到了一种看起来很可行的解决方法。我已经记录了如何在我的答案以及一个名为docker-osx-dev的开源项目中设置此项的详细信息。


你看过 https://github.com/boot2docker/boot2docker/issues/64 吗? - James Mills
6
与其在 OS X 上使用“boot2docker”这样的大而丑的 hack 工具,最好的 Docker 使用方式是本地直接运行 Linux 系统,或者在 Linux 虚拟机中进行开发工作。这样做不仅可以避免混乱和失望,而且更加规范。 - larsks
@JamesMills:阅读了所有70条评论后,我发现这个脚本应该可以将VirtualBox更改为使用NFS。运行后,挂载文件夹的性能仍然很差。我在原始问题中更新了示例时间。 - Yevgeniy Brikman
7
@larsks: 那并没有帮助。 - Yevgeniy Brikman
@JamesMills:你是按照这个脚本的流程启用NFS吗?还是采取了其他措施? - Yevgeniy Brikman
显示剩余13条评论
10个回答

46

我决定添加自己的答案,分享到目前为止我发现的最佳解决方案。如果我找到更好的选项,我将更新它。

目前为止最佳解决方案

我发现在OS X上使用Docker建立高效开发环境的最佳解决方案是:Boot2Docker + Rsync。通过rsync,在Docker容器中构建时间与直接在OSX上运行构建的时间相当!此外,文件监视器代码不需要轮询(inotify可用,因为rsync使用普通文件夹),所以热重载几乎和直接在本地运行一样快。

有两种设置方法:自动安装和手动安装。

自动安装

我将设置Boot2Docker与Rsync步骤打包成一个名为docker-osx-dev的开源项目。代码有些粗糙,但我已经成功地使用了几周,可以轻松切换3个具有不同技术堆栈的项目。试用一下,报告错误,并提交一些PR!另外,查看我的博客文章在OS X上使用Docker建立高效开发环境获取更多信息。

手动设置

  1. 安装Boot2Dockerbrew install boot2docker
  2. 运行Boot2Docker,但禁用VirtualBox共享文件夹:boot2docker init && boot2docker start --vbox-share=disable
  3. 运行boot2docker shellinit并将其打印出的环境变量复制到您的~/.bash_profile文件中。
  4. 在Boot2Docker VM上安装rsync:boot2docker ssh "tce-load -wi rsync"
  5. 在Boot2Docker虚拟机上创建所需的基本文件夹并正确设置权限。例如,如果您要从OS X同步/foo/bar文件夹,则需要在Boot2Docker虚拟机上创建/foo/bar文件夹:boot2docker ssh "mkdir -p /foo/bar && chown -R docker /foo/bar"
  6. 运行rsync将文件同步到Boot2Docker VM:rsync --archive --rsh="ssh -i $HOME/.ssh/id_boot2docker -o StrictHostKeyChecking=no" /foo/bar docker@dockerhost:/foo。查看rsync文档以了解您可能想启用的各种设置,例如使用--exclude .git来排除同步时的.git文件夹。
  7. 使用文件监视器保持文件同步。例如,您可以使用fswatch (brew install fswatch)与rsync配合使用。
  8. 此时,您应该能够使用docker run启动Docker容器,并使用-v标志挂载正在同步的文件夹:docker run -v /foo/bar:/src some-docker-image
  9. 像往常一样在OS X上更新代码。更改应该非常快速地传播,使用rsync,普通文件监视器代码应该像往常一样检测到更改 (即使用inotify),构建应该快速运行,因为所有文件都是容器的“本地”文件。
  10. 如果您需要测试运行中的网站,则运行boot2docker ip命令以查找其IP。

感谢分享!当他们说rsync是“单向”的时候,这是否意味着我不能使用OS X文件系统在两个容器之间共享文件?例如:容器1监视源文件并编译二进制文件,容器2用于运行已编译的二进制文件(在此示例中使用Haskell)。 - Nicolas Hery
1
@NicolasHery:我的理解是rsync会将OS X的更改复制到Docker容器中,但反过来则不行。因此,由Docker容器生成的任何文件(例如编译后的二进制文件)在OS X中都不可见。但是,如果这些文件生成到标记为“VOLUME”的文件夹中,则可以使用“--volumes-from”标志将另一个容器访问该卷。我还没有尝试过,但我认为它会起作用。 - Yevgeniy Brikman
1
很棒的答案。你可以为docker-machine(https://github.com/docker/machine)创建一个驱动程序,它可以为你处理大部分样板文件。 - dom
1
@dom:我喜欢那个想法,但是你知道如何为docker-machine创建驱动程序吗?是向存储库提交拉取请求的唯一方式还是可以在外部创建驱动程序? - Yevgeniy Brikman
1
这个教程是否适用于 Windows 上全新的 1.9.1 版本?我可以使用它吗,或者 Docker 已经有了针对这个“问题”的新解决方案吗? - user4412054
显示剩余6条评论

18
更新:现在Docker for Mac正在测试中,且具有非黑客功能,因此采取这种方式进行本地开发可能会更加合理,而无需大量麻烦和解决方法。

不要这么做。我知道这可能不是你希望得到的答案,但要诚实地评估尝试获取本地源代码 + Docker化执行与仅在OSX上进行本地开发之间的成本 / 效益。

在某些时候,所有问题,设置工作以及操作痛点可能会被很好地解决,但就目前而言,我的看法是这是一项净损失。

问题#1:Virtual Box上的挂载卷(使用vboxfs)非常慢

稍等一段时间,这几乎肯定会改善。

问题#2:文件监视已损坏

我不确定是否会在不久的将来修复此问题。如果此类功能对您的开发工作流程至关重要,则我认为这是一个绝杀因素。与像过去十多年一样成功地在OSX上直接使用rbenv / bundler来管理您的jekyll / ruby安装并在本地运行它们相比,这不值得进行主要的研发工作。

就像 “云” 没有参与我的本地开发设置一样,目前 Docker 对于测试/暂存/部署以及运行数据库和其他第三方组件是一个胜利,但我实际编码的应用程序会直接在OSX上运行。


1
我赞同。我们在OSX上进行开发,并直接在系统内运行应用程序(包括实时重新加载等)。然后,一旦应用程序完成,我们将其Docker化用于测试、预备和生产。 - ItalyPaleAle
4
嗯,有点令人失望。我一直在我的演示/生产环境中保持平衡。因为我在 OS X 上编写代码,所以开发环境总是例外。Docker 文档肯定让人觉得这是一个已解决的问题。我会再努力一天,看看能否使其正常工作。 - Yevgeniy Brikman
彼得,你现在还认为这个答案仍然有效吗?虽然时间只有几个月,但考虑到@Yevgeniy的项目和现在已经解决的2个问题,也许成本/效益比现在已经值得了!不是吗? - cregox
1
这是个人喜好的问题。作为顾问,我经常在多个项目之间切换,因此仍然不会去碰它。如果我是全职员工,在同一个项目上工作数周/数月,那么设置rsync/fswatch可能是值得的。 - Peter Lyons
Docker Toolbox 是当今正确的方式,因为如果您使用 Homebrew 或其他包管理器,Docker 工具版本将会失去同步,除非它们遵循 Docker Toolbox 的版本控制。 - taco
提醒一下,目前Docker for Mac比使用没有NFS的VirtualBox还要。https://forums.docker.com/t/file-access-in-mounted-volumes-extremely-slow-cpu-bound/8076 - cavalcade

12

Docker for Mac和Windows是在Mac OS X(和Windows)上使用Docker的确定性方法。作为Docker产品,该软件是“一种集成的、易于部署的环境,可用于从Mac或Windows构建、组装和运输应用程序”。它声称可以解决OP提出的问题。根据2016年3月24日的公告

  • 更快、更可靠:不再需要VirtualBox!Docker引擎在Alpine Linux发行版中运行,运行在xhyve虚拟机上(Mac OS X上)或Hyper-V VM(Windows上),并由Docker应用程序管理。您不需要docker-machine来运行Docker for Mac和Windows。
  • 工具集成:Docker for Mac是Mac应用程序,Docker for Windows是Windows应用程序,包括本地用户界面和自动更新功能。Docker工具集与之捆绑:Docker命令行、Docker Compose和Docker Notary命令行。
  • 挂载代码和数据的卷:卷数据访问正常工作,包括文件更改通知(在Mac上,inotify现在可以无缝地在容器内部为卷挂载的目录工作)。这使得进行“容器内”开发的编辑/测试循环成为可能。
  • 容易访问本地主机网络上运行的容器:Docker for Mac和Windows包括用于容器的DNS服务器,并与Mac OS X和Windows网络系统集成。在Mac上,即使连接到非常限制性的企业VPN,也可以使用Docker。
  • Docker for Mac是从头开始架构的,以适应OS X沙箱安全模型,我们正在与苹果密切合作实现这一目标。

我前几天刚看到这个,它似乎是迄今为止最有前途的解决方案。一旦它退出测试版,我非常兴奋地想试一试,如果它运行良好,我会将其更改为正式接受的答案。 - Yevgeniy Brikman
4
很遗憾,目前的Beta版本(1.11.0-beta7)似乎和其他方法一样慢,所以可能需要一段时间才能使用。有关在挂载卷中进行文件访问异常缓慢的讨论请参见https://forums.docker.com/t/file-access-in-mounted-volumes-extremely-slow-cpu-bound/8076 - walterra

3
免责声明:由于我是docker-sync的作者,所以我的观点可能有偏见。
我可能尝试了此处提到的所有解决方案,包括一些其他方案(请参见比较https://github.com/EugenMayer/docker-sync/wiki/Alternatives-to-docker-sync),但它们基本上要么在性能方面失败(其中大多数),要么在使用/强制执行docker-machine(或无)方面失败。 http://docker-sync.io已经被构建起来将所有解决方案合并,并提供最佳策略(实现多个,您可以选择)。
它可以与rsync(单向同步)一起使用,包括用户权限修复,也可以与unison(双向同步)一起使用。它既不会强制您进入docker-machine或特定的虚拟化程序,也不需要您拥有docker for Mac。它适用于所有这些。
性能EugenMayer/docker-sync/wiki/4.-Performance不受影响,就像您根本没有共享一样。
docker-sync及其更改监视器经过优化,可以处理具有12k文件的项目而不会出现问题。

如果您愿意,可以试试看,我很乐意听取反馈!


2
我理解您的困境!我认为我尝试过您尝试过的所有方法,但不幸的是速度仍然很慢。然后我看到了这个评论https://github.com/boot2docker/boot2docker/issues/64#issuecomment-70689254,建议使用Vagrant和Parallels代替Virtualbox。这使我能够使用nfs,我的项目(Drupal)确实看到了巨大的性能提升。

以下是Vagrant文件。您只需要安装vagrant,将此文件复制到名为Vagrantfile的文件中,然后将其放在某个文件夹中。进入该文件夹,只需执行vagrant up即可,而不是正常的boot2docker up。

Vagrant.configure(2) do |config|
  config.vm.box = "parallels/boot2docker"

  config.vm.network "forwarded_port", guest: 80, host: 80

  config.vm.synced_folder(
    "/Users/dicix/work/www", "/vagrant",
    type: 'nfs',
    nfs_udp: true,
    mount_options: %w[actimeo=2],
    bsd__nfs_options: %w[alldirs maproot=root:wheel]
  )
end

我假设这需要安装 Parallels 吗? - Yevgeniy Brikman

2
我也使用带有 Parallels 和 boot2docker 的 Vagrant(https://github.com/Parallels/boot2docker-vagrant-box)。对我来说,开发从未如此轻松。与 docker-compose 和大型设置非常兼容。我并没有感觉到延迟或大量资源消耗。
这是我的 Vagrantfile 的样子:
Vagrant.configure(2) do |config|

  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.box = "parallels/boot2docker"

  config.vm.synced_folder "/Users", "/Users", type: "nfs", mount_options: ["nolock", "vers=3", "udp"], id: "nfs-sync"

end

1
我已经在OS X(2011年中期的Macbook Air)+ Boot2Docker + Docker-compose环境下开发了几周。虽然没有遇到任何主要性能问题,但我在开发时避免运行任何构建(为什么不使用像 jekyll serve --skip-initial-build 这样的东西呢?)。这是我正在使用的一个示例 docker-compose.yml 文件:

docker-compose.yml:

test:
  build: .
  volumes:
    - ./client:/src/client
    - ./server:/src/server
    - ./test:/src/test
  command: nodemon --exec jasmine-node -- test/ --verbose --autotest --captureExceptions --color
  environment:
    - DEBUG=*

Dockerfile:

FROM node:0.12

RUN mkdir -p /src
WORKDIR /src

ENV PATH=/src/node_modules/.bin:$PATH

# We add package.json first so that we the
# image build can use the cache as long as the
# contents of package.json hasn't changed.

COPY package.json /src/
RUN npm install --unsafe-perm

COPY . /src

CMD [ "npm", "start" ]
EXPOSE 3000

我有时会使用NFS(http://syskall.com/using-boot2docker-using-nfs-instead-of-vboxsf/),但在这样做时并没有注意到很大的性能差异。
对我来说,简单的docker-compose up test让我的环境运行起来很方便,这个方便性值得我在性能上付出代价(我经常在不同堆栈的多个项目上工作)。
附注:nodemon是为数不多的可以与vboxsf一起使用的文件监视器之一(请参见https://github.com/remy/nodemon/issues/419)。

即使我跳过使用Jekyll进行初始构建,每次更改文件时,它仍然需要重新构建,如果源代码已挂载,则仍需花费1-3分钟的时间。这使得无法进行任何形式的更改和重新加载式开发。 - Yevgeniy Brikman
@YevgeniyBrikman 哦,我不知道那个 :( 我想最后的选择就是让你的代码存在 boot2docker VM 中,并使用 sshfs 在主机上挂载它。否则,我想你将不得不等待更好的挂载文件夹性能来使用 docker 作为开发环境。 - Olivier Lalonde

0

-1

谢谢您的发布,但是这如何解决挂载卷的性能问题呢? - Yevgeniy Brikman
啊,抱歉,您不再需要使用vBox来挂载任何内容了。您可以通过常规的Docker界面挂载文件夹。 - harmingcola

-4

这是在 Mac 上设置 Docker 的最新(2015 年 9 月)和最简单的方法: 链接在这里:

您可以使用Docker 工具箱此处链接至说明文件来安装 Docker。

它是一个完整的 Docker 安装包, 其中包括以下 Docker 工具:

Docker Machine 用于运行 docker-machine 二进制文件

Docker Engine 用于运行 docker 二进制文件

Docker Compose 用于运行 docker-compose 二进制文件

Kitematic,Docker GUI 一个预配置了 Docker 命令行环境的 shell

Oracle VM VirtualBox

enter image description here

工具箱中有什么:

  • Docker 客户端
  • Docker Machine
  • Docker Compose(仅限于 Mac)
  • Docker Kitematic
  • VirtualBox

3
是的,但不幸的是它没有解决最初提出的问题。 - Nick

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