Windows 11 安装 WSL 和 Docker

950 阅读3分钟

Windows 安装 Docker,看到比较多的做法是:

  • 启用所需 Windows 组件
  • 安装 WSL2
  • 安装 Docker Desktop for Windows

我这里的做法是:

  • 启用所需 Windows 组件
  • 安装 WSL2
  • 通过网络镜像模式启动 Linux VM
  • 在 WSL2 Linux 默认系统(Ubuntu 22.04)下安装 Docker

以下是步骤。

判断是否打开虚拟化

在 BIOS 中需要启用虚拟化指令,Intel VT-x 或 AMD-V。

如何判断是否已经打开:

PS C:\> Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All


FeatureName      : Microsoft-Hyper-V-All
DisplayName      : Hyper-V
Description      : 提供一些帮助创建和运行虚拟机及其资源的服务和管理工具。
RestartRequired  : Possible
State            : Enabled
CustomProperties :

Enabled 即说明可用了。

启用所需 Windows 组件

启用 Windows 功能。可以 win + r 键入 OptionalFeatures 呼出界面操作,或者通过如下命令行(PowerShell 管理员角色):

# 启用虚拟机平台
dism /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# 启用 “适用于 Linux 的 Windows 子系统”
dism /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

# 启用 "Hyper-V"
dism /online /enable-feature /featurename:HypervisorPlatform /all /norestart

# 启用 "Windows 虚拟机监控平台"
dism /online /enable-feature /featurename:HypervisorPlatform /all /norestart

安装 WSL

# 安装默认 Linux 系统
wsl --install

设置网络镜像模式

默认 WSL 使用的网络模式是 NAT,通过 DHCP 动态分配内存,造成局域网内访问设置繁琐,而且重启 VM 后 ip 地址还会变化。

2023-09 微软推出的 WSL 新版本支持一种新的模式,mirror,和虚拟机环境的 bridge 模式类似,可以直接使用宿主机的网络,或者说,将 Linux 网络接口 镜像 到宿主机。

做法是,编辑 c:\Users\xxx\.wslconfig 文件:

[wsl2]
networkingMode=mirrored

重启 wsl:

# 关闭
wsl --shutdown
# 启动
wsl

http proxy

镜像模式的一个好处是,默认使用 Windows 设置的 http proxy。但是如果不需要代理服务器,可以这样设置:

[wsl2]
networkingMode=mirrored
autoProxy=false

外部访问

mirror 设置了网络,如果需要让外部能访问到,还需要设置 windows 的防火墙策略。

比如在 ubuntu 下运行一个 web server:

cd /tmp
echo "test" > index.html
python3 -m http.server 8080 --bind 0.0.0.0

然后,需要在 Windows 下,PowerShell 管理员角色下允许 8080 端口入站访问:

# 设置策略
New-NetFirewallRule -DisplayName "Allow WSL2 Port 8080" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow

之后,就可以在外部通过windows的ip地址访问这个 web 服务了。

⚠️ 在 window是宿主机上无法通过该ip地址访问到,比如 windows ip 是 192.168.78.12,下面的命令在windows 的终端是会报错的:

C:\Users\yourname>curl 192.168.78.12:8080
curl: (28) Failed to connect to 192.168.78.12 port 8080 after 21018 ms: Couldn't connect to server

在 ubuntu 虚拟机或者局域网其他节点,都可以正常访问。

问题可能和镜像模式的路由方式有关。

安装 docker

运行下面代码:

# 替换到清华源
sudo sed -i s@/archive.ubuntu.com/@/mirrors.tuna.tsinghua.edu.cn/@g /etc/apt/sources.list
sudo apt-get update && sudo apt-get upgrade -y

sudo apt-get install ca-certificates curl -y
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

sudo usermod -aG docker $USER

docker 的正常运行

目前国内存在的问题是,docker 访问存在问题。

涉及2个问题:

  • 需要通过 http proxy 才能正常下载 docker image,需要 http proxy
  • docker 的 dns 记录在运营层面被修改,需要自己手动设置正确记录或者使用 dnscrypt-proxy

http proxy 设置

执行如下命令:

# 创建 docker.service.d 目录
sudo mkdir -p /etc/systemd/system/docker.service.d

# 创建并编辑 http-proxy.conf 文件
cat << EOF | sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://myproxy:7890"
Environment="HTTPS_PROXY=http://myproxy:7890"
Environment="NO_PROXY=localhost,127.0.0.1,docker-registry,.corp"
EOF

# 重新加载并重启 Docker 服务
sudo systemctl daemon-reload
sudo systemctl restart docker

使用 dnscrypt-proxy

docker-compose.yaml:

networks:
  dns-proxy:
services:
  dns-proxy:
    image: klutchell/dnscrypt-proxy
    container_name: dns-proxy
    restart: always
    networks:
      - dns-proxy
    # volumes:
    #   - /path/to/config:/config
    ports:
      - 53:5053/udp

让系统使用 dnscrypt-proxy dns 服务:

sudo sh -c "echo \"nameserver 127.0.0.1\" > /etc/resolv.conf"

使用 docker

Windows 安装 VS Code。

通过 VS Code 可以直接使用 WSL,和本地使用方式类似。