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

介绍

我不能找到一个好的方法来设置一个开发环境在 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)上挂载的卷非常慢

例如,如果源代码是 Docker 映像的一部分,Jekyll 需要多长时间来编译我的 网页:

> 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 中对挂载的文件夹进行更改,则这些技术将无法工作。

我试过了

我寻找解决方案(包括所有关于 SO 的解决方案) ,并尝试了其中的一些,但没有找到一个成功的解决方案:

  1. 我是 切换 Boot2Docker 使用 NFS但是速度一样慢。
  2. 我试了 流浪者 + NFS,也一样慢。
  3. 我尝试了 桑巴坐骑,但文件夹在 Docker 容器中总是显示为空。
  4. 我尝试使用 Unison 文件系统,它可以短暂地同步文件,但是保留了 显示连接错误
  5. 我启用了 Jekyll 的民意调查,但这显著增加了延迟,直到我的更改被拾取。
  6. 我尝试了 小艇,一个“更快,更友好的 Docker 在 OSX 与流浪汉”,并得到了 一些的改进。与 Jekyll 编译慢了10-15倍不同,它慢了2-3倍。好多了,但还是不太实用。

有没有人找到一个真正有效的解决方案,允许您使用 Docker 和 OSX 高效地开发代码?

更新: 终于有解决方案了!

我终于找到了一个使用 Boot2Docker + rsync 的解决方案。我已经掌握了关于如何在 我自己的答案中设置这个功能的细节,以及一个名为 Docker-osx-dev的开源项目。

16933 次浏览

Update: Now that docker for mac is in beta with non-hack functionality, going that route may be a lot more reasonable for local development without a essay's worth of hacks and workarounds.

Don't. I know that's not the answer you are probably hoping for, but take an honest evaluation of the cost/benefit of trying to get local source code + dockerized execution vs just doing local development on OSX.

At some point all the issues, setup effort, and operational pain points MAY be resolved well enough, but as of right now my take on this is it's a net loss.

Issue #1: Mounted volumes on Virtual Box (which use vboxfs) are extremely slow

Wait a while and this will almost certainly improve.

Issue #2: File watching is broken

I'm not sure a fix for this is in the near future. If this type of functionality is key to your development workflow, I would consider this a dealbreaker. It's not worth a major R&D effort when compared to just using rbenv/bundler to manage your jekyll/ruby installs and running them locally on OSX like folks have been doing successfully for the past decade+.

Just like "the cloud" has zero involvement in my local development setup, at the moment, docker is a win for testing/staging/deployment and for running databases and other third party components, but the applications I'm actually coding get run straight on OSX.

I've been developing in a OS X (mid 2011 Macbook Air) + Boot2Docker + Docker-compose environment for a few weeks now. Haven't run into major performance issues but I avoid running any sort of build when developing (why not use something like jekyll serve --skip-initial-build?). Here's an example docker-compose.yml file I'm using:

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

I sometimes use NFS (http://syskall.com/using-boot2docker-using-nfs-instead-of-vboxsf/) but haven't noticed a big performance difference when doing so.

For me, the convenience of a simple docker-compose up test to get my environment running has been worth the cost in performance (I routinely work on multiple projects with different stacks).

PS: nodemon is one of the few file watchers which work with vboxsf (see https://github.com/remy/nodemon/issues/419).

I feel you! I think I've tried pretty much everything you tried and unfortunately it was still slow. Then I came across this comment https://github.com/boot2docker/boot2docker/issues/64#issuecomment-70689254 that suggests using Vagrant and Parallels and instead of Virtualbox. This allowed me to use nfs and I did indeed saw a big performance boost for my project (Drupal).

Here's the Vagrant file. All you need to do is install vagrant, copy this in a file called Vagrantfile and put it in some folder. Go to that folder and just do a vagrant up instead of your normal 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

Getting docker to work as a development tool is possible. But its going to hurt. I've documented the process here :

http://harmingcola.blogspot.com/2015/05/how-to-setup-docker-as-development-tool.html

I've decided to add my own answer with the best solution I've found so far. I'll update this if I find better options.

Best solution so far

The best solution I've found for setting up a productive development environment with Docker on OS X is: Boot2Docker + Rsync. With rsync, build times in a Docker container are on par with running the build directly on OSX! Moreover, the file watcher code does not need polling (inotify works since rsync uses normal folders), so hot reload is almost as fast.

There are two ways to set it up: an automated install and a manual install.

Automated install

I've packaged all the steps for setting up Boot2Docker with Rsync into an open source project called docker-osx-dev. The code is a bit rough, but I've been successfully using it for several weeks to easily switch between 3 projects with 3 different tech stacks. Try it out, report bugs, and submit some PRs! Also, see my blog post, A productive development environment with Docker on OS X for more info.

Manual setup

  1. Install Boot2Docker: brew install boot2docker.
  2. Run Boot2Docker, but with VirtualBox shared folders disabled: boot2docker init && boot2docker start --vbox-share=disable.
  3. Run boot2docker shellinit and copy the environment variables it prints out into your ~/.bash_profile file.
  4. Install rsync on the Boot2Docker VM: boot2docker ssh "tce-load -wi rsync".
  5. Create the base folders you need on the Boot2Docker VM and set permissions correctly for them. For example, if you'll be syncing the /foo/bar folder from OS X, you need to create /foo/bar on the Boot2Docker VM: boot2docker ssh "mkdir -p /foo/bar && chown -R docker /foo/bar".
  6. Run rsync to sync the files to the Boot2Docker VM: rsync --archive --rsh="ssh -i $HOME/.ssh/id_boot2docker -o StrictHostKeyChecking=no" /foo/bar docker@dockerhost:/foo. Check the rsync docs for various settings you may want to enable, such as using --exclude .git to exclude the .git folder when syncing.
  7. Use a file watcher to keep files in sync. For example, you could use fswatch (brew install fswatch) piped into rsync.
  8. At this point, you should be able to use docker run to fire up your Docker container and use the -v flag to mount the folder you're syncing: docker run -v /foo/bar:/src some-docker-image.
  9. Update the code on OS X as usual. Changes should propagate very quickly using rsync, the normal file watcher code should pick up the changes as usual (ie, using inotify), and the build should run fast because all the files are "local" to the container.
  10. If you need to test a running website, run the boot2docker ip command to find out what IP it's on.

This method is the latest (Sep 2015) and easiest way to get Docker setup on Mac: link here:

You install Docker using Docker Toolbox link to instructions here:

It is a complete Docker setup package, that includes the following Docker tools:

Docker Machine for running the docker-machine binary

Docker Engine for running the docker binary

Docker Compose for running the docker-compose binary

Kitematic, the Docker GUI a shell preconfigured for a Docker command-line environment

Oracle VM VirtualBox

enter image description here

What's in the toolbox:

  • Docker Client
  • Docker Machine
  • Docker Compose (Mac only)
  • Docker Kitematic
  • VirtualBox

I'm also using Vagrant with parallels and boot2docker (https://github.com/Parallels/boot2docker-vagrant-box). Development was never easier for me. Works really well with docker-compose and large setups. I don't really feel a delay or massive resource consumption.

This is what my Vagrantfile looks like:

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

Docker Unison works like a charm! https://github.com/leighmcculloch/docker-unison

Bidirectional Sync with a very good performance!

Docker for Mac and Windows shall be the definitive way of developing with Docker on OS X (and Windows). A Docker product, the software is an “integrated, easy-to-deploy environment for building, assembling, and shipping applications from Mac or Windows.” It purports to be able to solve the issues presented by the OP. From its March 24, 2016 announcement:

  • Faster and more reliable: no more VirtualBox! The Docker engine is running in an Alpine Linux distribution on top of an xhyve Virtual Machine on Mac OS X or on a Hyper-V VM on Windows, and that VM is managed by the Docker application. You don’t need docker-machine to run Docker for Mac and Windows.
  • Tools integration: Docker for Mac is a Mac application and Docker for Windows is a Windows application, including a native user interface and auto-update capability. The Docker tool set comes bundled with it: Docker command line, Docker Compose, and Docker Notary command line.
  • Volume mounting for your code and data: volume data access works correctly, including file change notifications (on Mac inotify now works seamlessly inside containers for volume mounted directories). This enables edit/test cycles for “in container” development.
  • Easy access to running containers on the local host network: Docker for Mac and Windows include a DNS server for containers, and are integrated with the Mac OS X and Windows networking system. On a Mac, Docker can be used even when connected to a very restrictive corporate VPN.
  • Docker for Mac was architected from scratch to be able to fit the OS X sandbox security model and we are working closely with Apple to achieve this.

Disclaimer: I might be biased, since I am the author of docker-sync.

I probably tried all the solutions named here, including some more (see the compersion https://github.com/EugenMayer/docker-sync/wiki/Alternatives-to-docker-sync), but they basically either failed on the side of performance (most of them) or on the docker-machine (or none) used / enforced.

http://docker-sync.io has been built to merge all the solutions and provide the best strategies (implementing several, you can choose).

It can be used with rsync (1 way sync) including permission fixes for users, and with unison (2 way sync). It does neither force you into docker-machine or a specific hypervisor, nor requires you to have docker for Mac. It works with all of them.

The performance EugenMayer/docker-sync/wiki/4.-Performance is not influenced, it's like you have no shares at all.

docker-sync and its change-watchers are optimized and do work with projects with 12k files without issues.

Give it a try, if you like, I would love to hear feedback!