Docker for Mac 的发布确实给在 MacOS 上开发提供了很大的遍历,但是毕竟不是原生的底层容器实现,Docker for Mac 是运行在 Hypervisor 上的 一个 HyperKit 实现,毕竟还是虚拟化加容器的实现方式,而不是内核级别的实现,所以功能肯定是受限制的,比如网络访问上不能与容器实现子网络的 全栈访问 ,功能上的问题可以忍,但性能的问题却是致命的,例如在编译大一点的项目时编译速度比在Linux容器下慢得让人无法接受。
1.Docker for Mac 磁盘性能测试
分析了一下,原来是磁盘性能导致的,于是做了一组测试:分别在 Linux 和 MacOS 下使用容器对磁盘写入数据,每个平台分别使用非挂载(non-mount)和挂载(mount)的方式测试。
非挂载方式的测试命令为:
docker run --rm -it alpine \
time dd if=/dev/zero of=test.dat bs=1024 count=100000
挂载方式的测试命令为:
docker run --rm -it -v `pwd`:`pwd` -w `pwd` alpine \
time dd if=/dev/zero of=test.dat bs=1024 count=100000
Linux 测试结果:
MacOS 测试结果:
通过结果可以看出 Docker for Mac 在挂载本地磁盘的情况下,速度比非挂载情况下慢了整整100倍!而在 Linux 平台下却没有任何性能损失。
这个问题在 Docker 的论坛里被炒得很火,社区的不满情绪也很高胀,具体的原因可以参考这个链接:
https://forums.docker.com/t/file-access-in-mounted-volumes-extremely-slow-cpu-bound/8076/158
大体的意思就是:osxfs 文件系统效率太低,mac 和 container 的文件系统不一样,同步时需要做大量的格式转换。
2.Docker for Mac 磁盘性能调整
本来想通过虚拟机来解决这个问题,但是觉得太麻烦,于是发现了 docker-sync 方案,通过 unison 或者同类型的同步工具对docker 挂载磁盘进行同步。
docker-sync 的基本原理就是使用 daemon方式建立一个同步磁盘,然后在 docker 启动容器是挂载这个同步磁盘,下图是 native_osx 同步流程,可以解释 docker-sync 的基本原理。
图片选自 https://github.com/EugenMayer/docker-sync/wiki/8.-Strategies
下面实践一下 docker-sync 的安装,并且做一个基准测试,看看性能提升了多少。
安装比较简单,可以参考 docker-sync 的 Wiki:
brew install unison
brew install eugenmayer/dockersync/unox
安装成功后,创建一个 docker-sync 的配置文件 docker-sync.yml ,内容可以参考 Wiki
version: '2'
syncs:
mac_sync:
sync_strategy: 'unison'
src: './app'
然后启动 docker-sync 服务
docker-sync start
服务启动成功后使用下面命令完成一次基准测试:
docker run --rm -it -v mac_sync:/test -w /test alpine \
time dd if=/dev/zero of=test.dat bs=1024 count=100000
可以看出,速度与非挂载模式相差并不是太多了,但是同步的时间并没有测试,毕竟还是两种文件系统的同步,如果从数据安全的角度考虑,使用 Linux 下的 Docker 才是正确的打开方式。
参考文档:
- Docker for Mac: Performance Tweaks
- Faster I/O on Docker for Mac. Fact or fiction?
- 使用 docker-sync 让 mac 和 docker 之间的文件同步变快