跳到主要内容

WSL + Docker 环境配置

本文介绍 WSL + Docker 环境配置

安利 wsl 工具

安装 WSL​

启用系统可选组件​

启用 “系统虚拟机平台” 和 "适用于 Linux 的 Windows 子系统" 可选组件。
在“控制面板-所有控制面板项-程序和功能”,选择“启用或者关闭Windows功能”,勾选所需功能选项,或者管理员权限打开终端执行:

# 启用 “系统虚拟机平台”
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# 启用 "适用于 Linux 的 Windows 子系统"
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

设置 WSL 版本​

设置默认或某个具体 linux 发行版的 wsl 版本

# 设置 wsl 默认版本
wsl --set-default-version 2
# 查看 wsl 版本
wsl -l -v
# 设置指定发行版 wsl 版本,<Distro> 替换为你的发行版的实际名称
wsl --set-version <Distro> 2

安装 wsl2 Linux 发行版​

wsl --list --online
wsl --install --distribution Ubuntu
可能遇到如下报错
Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0x800701bc
Error: 0x800701bc WSL 2 ?????????????????? https://aka.ms/wsl2kernel

Press any key to continue...

参考 https://github.com/microsoft/WSL/issues/5393 前往 微软WSL官网 下载 WSL2 Linux 内核即可。

配置 Ubuntu Linux 发行版​

export Current_User=$USER && sudo -E sh -c 'echo "$Current_User ALL=(ALL:ALL) NOPASSWD: ALL" >>/etc/sudoers'

sudo sh -c 'sed -i.bak "s/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list'

apt update && apt upgrade -y

sudo apt-get install ca-certificates

echo "export PS1=$'\\[\E[1m\E[34m\\]┌─[\\[\E[1m\E[32m\\]\\u@\h \\[\E[1m\E[35m\\]\\w\\[\E[1m\E[34m\\]]\n\\[\E[1m\E[34m\\]└──○ \[\e[1;33m\](\D{%H:%M.%S})\[\e[0m\] \\[\E[1m\E[34m\\]\$ '" >> ~/.bashrc
提示

安装 Docker​

Docker Desktop for windows​

  • 下载安装包: https://docs.docker.com/desktop/install/windows-install/
  • 启动 Docker Desktop for Windows,点击“设置”按钮,启用基于WSL2的引擎复选框 "Use the WSL 2 based engine"
  • 这时候在 WSL 里面执行 docker 命令还是找不到的
    在 Resources 的 WSL Integration 中设置要从哪个 WSL2 发行版中访问 Docker
  • 重启 Docker desktop for Windows,重启完成后我们就可以在 WSL2 里面使用 docker 命令了. 在 WSL2 里面执行 df -Th,会发现增加了一些新的与 docker 有关的挂载点。

Docker Server​

因为 wsl2 使用了完整的linux内核,所以可以安装 Docker Server 。

脚本安装​

curl -fsSL https://get.docker.com |bash -s -- --mirror Aliyun
提示

执行脚本安装过程中,脚本提示“建议使用Docker Desktop for windows”,20s内按Ctrl+C会退出安装,所以需要等待20s。

注意:WLS2下通过 apt install docker-ce 安装的 Docker 无法启动,因为 WSL2 方式的 Ubuntu 里面没有systemd。 上述官方 get-docker.sh 安装的 Docker,Dockerd 进程是用 Ubuntu 传统的 init 方式而非 systemd 启动的。

添加用户组​

把当前用户加入docker组,以获得 unix:///var/run/docker.sock 执行权限

sudo groupadd docker # 建立docker用户组
sudo usermod -aG docker $USER #将当前用户加入 docker 组
su - $USER # 重新登录ssh终端 刷新权限
提示
  • Docker Desktop for windows 方式,是利用 Docker 的 C/S 架构,将 Windows 模式下的 docker.sock 和 Docker 数据目录挂载到 WSL2 的 linux 机器里面,WSL中的 Docker 客户端执行命令,通过挂载的 /var/run/docker.sock 与 Windows 中的 Docker Daemon 进程通信。

  • 我们在 linux 下重启 linux 下 Docker Daemon 进程,/var/run/docker.sock 会被 Linux 下的 Docker Server 覆盖,此时 Docker 客户端通过 /var/run/docker.sock 文件与 linux 下的 Docker Daemon 服务端通信。

  • 也可以使用 docker -H tcp://<IP>:2375 来指定连接 Windows 上的 Docker Daemon 还是 Linux 上的 Docker Daemon 。

    也可以这样理解
    sudo rm docker.sock && sudo ln -s /mnt/wsl/shared-docker/docker.sock /var/run/docker.sock

Docker-Compose​

从 Docker 1.29 版本开始,"docker-compose" 命令被合并到 Docker CLI 中,并且可以通过 "docker compose" 命令运行。因此,现在 Docker 官方文档中推荐使用 "docker compose" 命令。

export Version="v2.17.2"
curl -L https://github.com/docker/compose/releases/download/${Version}/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

FAQ​

不支持 iptables 模式 导致 WSL 无法启动 Docker​

1. 现象

$ sudo service docker restart
* Starting Docker: [ OK ]
$ sudo service docker status
[FAIL] Docker is not running ..failed!
$ sudo cat /var/log/docker.log
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables/1.8.7 Failed to initialize nft: Protocol not supported
(exit status 1)

2. 原因&解决
Ubuntu 22.04 默认使用 nftables 作为防火墙,而非 iptables 。输入下面命令从 nftables 切换到 iptables。

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

参考文档: https://github.com/microsoft/WSL/discussions/4872?sort=top#discussioncomment-99164

网络冲突导致 WSL 无法启动 Docker​

WSL 获得了一个与 Docker 网络冲突的 IP 地址,因此必须更改 WSL 或 Docker 的网络。更改 Docker 网络更容易,所以我建议这样做。创建或编辑/etc/docker/daemon.json并添加地址池设置:

{
"default-address-pools": [
{
"base": "192.168.0.0/16",
"size": 24
}
]
}

WSL2 如何安装多个 Ubuntu​

1. 下载 Ubuntu WSL 系统文件

到 https://cloud-images.ubuntu.com/releases/ 下载最新的 WSL 系统文件。
例如 https://cloud-images.ubuntu.com/releases/21.10/release/ubuntu-21.10-server-cloudimg-amd64-wsl.rootfs.tar.gz

2. Import Ubuntu

运行一下命令导入 Ubuntu 的文件系统

wsl --import <Distro 系统名称> <InstallLocation 安装目录> <FileName 镜像包> [Options]

# 例如
wsl --import ubuntu-2 "C:\Users\myname\WSL2\ubuntu2" "C:\Users\myname\Downloads\ubuntu-21.10-server-cloudimg-amd64-wsl.rootfs.tar.gz"

登录指定系统

wsl -d <Distribution Name>

WSL 如何迁移​

查看已安装的 wsl 子系统发行版

wsl -l --all -v

关闭指定 wsl 子系统发行版

wsl --shutdown              #优雅关闭全部 WSL 实例
wsl --shutdown -d Ubuntu #优雅关闭 WSL 实例
wsl --terminate -t Ubuntu #强制终止 WSL 实例

导出 wsl 子系统发行版

wsl --export Ubuntu c:\wsl-ubuntu.tar

删除 wsl 子系统发行版

wsl --unregister Ubuntu

导入并安装 wsl 子系统发行版

wsl --import Ubuntu c:\wsl-ubuntu c:\wsl-ubuntu.tar --version 2

设置为默认 wsl 子系统发行版

wsl --set-default Ubuntu
# 登录
wsl -d Ubuntu

wsl import 之后的子系统,会默认root用户登录,如何指定用户?​

  • 手动指定用户
wsl -d <distro> -u <username>
  • 命令指定默认用户
ubuntu config --default-user <username>
  • 配置文件指定默认用户 打开 WSL 发行版的 Linux 终端并编辑 /etc/wsl.conf 文件。如果该文件不存在,请创建它。在该文件中添加以下行:
[user]
default=<username>
  • 修改注册表指定默认用户 Windows + R 输入 regedit 并按回车键,打开注册表。导航到以下注册表路径:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\<distribution_GUID>
# <distribution_GUID>" 替换为您要更改默认用户的 WSL 发行版的 GUID。
# 可以查看 <distribution_GUID> 文件夹内的 DistributionName 来确定发行版
  1. 在右侧窗格中,找到 "DefaultUid" 键,并双击它以编辑其值。
  2. 在 "编辑 DWORD (32 位) 值" 对话框中,将 "数值数据" 更改为您要设置为默认用户的 Linux 用户的 UID(如1000)。
  3. 单击 "确定" 保存更改并关闭注册表编辑器。

VS Code 配置默认终端为 WSL​

wsl 将 Windows 目录挂载到了 Linux 中,这一点比 Vagrnt/Docker + Remote Development 要方便,最起码不用为了同步目录而烦恼了。我们可以在任何目录下面执行 Linux 命令。

Ctrl+, 打开 VS Code 设置,搜索框输入 Terminal › Integrated › Default Profile: Windows ,将其改为 Ubuntu (WSL)

VS Code 中的 WSL 乱码​

sudo dpkg-reconfigure locales
# 使用空格键选中en_US.UTF-8、zh_CN.UTF-8
# 使用Tab键切换至OK,再将en_US.UTF-8选为默认。

Ubuntu上的Node版本不支持“空位合并”运算符(??=)​

我:

在wsl ubuntu 中运行node项目 报错如下,可是在windows和Linux中运行都没有问题,怀疑和wsl有关,帮我看一下
/core/bin/docusaurus.mjs:30
process.env.BABEL_ENV ??= 'development';

ChatGPT:

这个错误可能是因为在WSL Ubuntu上的Node版本不支持“空位合并”运算符(??=),而在Windows和Linux上的Node版本支持该运算符。您可以检查在WSL Ubuntu上安装的Node版本并确保它支持该运算符。或者,您可以考虑在代码中使用传统的变量赋值运算符(=)来避免这个问题。

ChatGPT YYDS !!!

然后我跑去升级 nodejs 版本后就解决了

关于 WSL 的网络堆栈​

WSL (Windows Subsystem for Linux) 实际上是在 Windows 系统上运行的一个 Linux 虚拟机,它与 Windows 系统共享同一个网络栈。因此,当在WSL中运行的应用程序监听本地端口时,它们实际上是在 Windows 系统上监听该端口,因此可以通过 Windows 系统上的 IP 地址和端口号来访问这些应用程序。这种共享本地端口的机制使得 WSL 可以与 Windows 系统之间进行无缝的网络通信。

不想 wsl 与 Windows 系统共享同一个网络栈

如果您不想WSL与Windows系统共享同一个网络栈,可以通过配置 WSL 的网络模式来实现。WSL 支持两种网络模式:默认的 “基于Windows的网络模式” 和 “桥接网络模式” 。在 “桥接网络模式” 下, WSL 将使用自己的网络栈,与Windows 系统分开。要启用 “桥接网络模式” ,请按照以下步骤操作:

  • 运行命令:wsl --set-version <distribution name> 2 将WSL版本设置为2。
  • 在 WSL 中编辑 /etc/wsl.conf 文件(如果文件不存在,则创建它),添加以下内容:
    [network]
    generateResolvConf = false
  • 在 WSL 中编辑 /etc/resolv.conf 文件,将其中的DNS服务器地址设置为您的路由器或互联网服务提供商提供的 DNS 服务器地址。
  • 重启 WSL ,使更改生效。
    wsl --shutdown -d Ubuntu    #优雅关闭 WSL 实例,直到再次打开 WSL 并开始使用它。