在WSL中使用docker

Docker on WSL

配置好了WLS后,最近慢慢的把以前在虚拟机上开发的项目都移到了WSL上,一切都像在原生的ubuntu下一样,只有一个用到docker的项目遇到了波折: 由于WSL 还不支持linux kernel的一些特性,在WSL下可以安装docker,但是 docker engine 的运行会有问题。Github和微软的feedback页面上有不少人都提出过这个问题 [1] [2] [3],但是WSL团队都没什么正面回答。能找到的就是WSL的PM、大帅哥Jack Hammons在Microsoft Build 2017上的回答提问时的一段话。

简单来说就是因为docker依赖的linux kernel特性过于复杂,在近期很难解决这个问题。虽说WSL团队对全面支持docker不乐观,但是工作却是没少做,已经有人在最新的1803版本上成功的运行了docker daemon。但是一些功能比如docker compose,还是不能运行,我自己也试了正在使用的docker image,会有比较奇怪的错误。所以还是决定使用现在证实有效的workaround:安装docker for windows, 然后在wsl下通过docker machine连接和操作windows下的docker engine。

Docker on Windows for WSL

在WSL上安装 Docker CLI

Ubuntu上默认的apt repository中docker版本都比较旧,可以按照官方安装文档添加docker官方repository安装最近版本Docker CE。

安装设置Docker CE for Windows

较老版本的Docker是通过Docker Toolbox在windows上运行的,本质上还是通过virtual box运行。现在版本的Docker CE是基于windows 10 原生的Hyper-V虚拟化技术的,相比docker toolbox速度和易用性上面好了很多,在官网下载安装包按照提示就可以完成安装。要在WSL中访问windows docker daemon, 还需要在Docker设置中打开TCP端口。

在WSl中设置docker host

最后把WSL中的DOCKER_HOST变量的设置添加到.bashrc中

1
export DOCKER_HOST=localhost:2375

由于wsl默认把磁盘mount到/mnt下,比如/mnt/c/your/folder,而Docker for Windows期望本地的文件路径是/c/your/folder,所以运行docker run -v /mnt/c/your/folder:/folder ... 会报错。这个问题可以在/etc/wsl.conf中修改automount的root解决。
1
2
3
4
5
[automount]
enabled = true
root = /
options = "metadata,umask=22,fmask=11"
mountFsTab = false

完成这些设置以后在WSl中已经可以使用docker了。

虽然以后大部分开发会在WSL中做,但是有些代码维护的工作还是需要打开虚拟机的。这时如果试图打开vmware 或者virtual box虚拟机的话,就会发现类似下面的错误。

根本原因是windows的Hyper-V和其他虚拟机对系统特性的设置不兼容,网上有很多人给出的解决方法都是关掉Hyper-V。但是关掉Hyper-V就没法使用docker了,只能在docker和虚拟机之间二选一。要切换docker和虚拟机就需要每次手动设置Hyper-V,还要重启windows,真是相当麻烦。现在能找到的最好的方法可能是:添加一个没有Hyper-V的windows启动项,如果临时需要虚拟机,就重启并用它启动windows。

Boot without Hyper-V

复制当前的启动设置,命名为“Windows 10 (No Hyper-V)”

1
2
C:\>bcdedit /copy {current} /d "Windows 10 (No Hyper-V)" 
The entry was successfully copied to {ff-23-113-824e-5c5144ea}.

修改这个新的启动设置,在启动时关闭Hyper-V。

1
2
C:\>bcdedit /set {ff-23-113-824e-5c5144ea} hypervisorlaunchtype off 
The operation completed successfully.

在启动windows时就可以看到下面的启动选项了。

现阶段要在WSL中使用docker,可以说是相当的折腾,希望不久的将来,WSL能完全支持docker的特性。