跳至主要內容

WSL

荒流2022年12月14日大约 9 分钟约 2719 字

如无特殊说明,本文中所述 WSL 将都是 WSL2,不再学习 WSL1 相关的内容。

1. 安装WSL

参考如何在 Windows 10 上安装 WSL 2 等。

2. WSL 的特殊性

2.1 WSL与宿主机的网络映射

官方文档:Accessing network applications with WSL | Microsoft Learn

在结合WSL开发网络应用时,有几点WSL的特殊性需要明确一下:

服务端客户端客户端访问方式
本机 WSL本机 Windowslocalhost 即可直接访问
本机 Windows本机 WSL必须通过宿主机的IP地址来访问
本机 Windows其他主机宿主机 IP+PORT,无须多言
本机 WSL其他主机需要将宿主机相应的端口映射到WSL,然后通过宿主机访问

在WSL中获取宿主机IP地址的一个方式为:

通过远程主机访问本地主机WSL中的应用程序时,WSL1 和 WSL2 略有区别:

宿主机 Windows 向 WSL 作映射时,通过 powershell 的一个命令即可。如下为一个操作示例:

2.2 Sysvinit

Sysvinit可参考技术|浅析 Linux 初始化 init 系统: sysvinit

WSL的Ubuntu,使用Sysvinit而不是Systemd,因此,当需要使用Systemd命令时,需要用Sysvinit的相应命令来代替:

Systemd commandSysvinit command
systemctl start service_nameservice service_name start
systemctl stop service_nameservice service_name stop
systemctl restart service_nameservice service_name restart
systemctl status service_nameservice service_name status
systemctl enable service_namechkconfig service_name on
systemctl disable service_namechkconfig service_name off

2.3 其他可配置项目

3. WSL中安装docker

3.1 安装过程

安装 docker 的过程大体上与 wsl 本身关系不大,直接参考官方所述的在 Linux 中安装 docker 的教程即可,这里以 Install Docker Engine on Ubuntu | Docker Docs 为例。

  1. 卸载旧 docker 以防版本冲突:

    for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
  2. 设置 docker 的 apt 数据源,执行如下脚本:

    # Add Docker's official GPG key:
    sudo apt-get update
    sudo apt-get install ca-certificates curl
    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
  3. 通过 apt 安装 docker:

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

3.2 WSL 的特殊设置

经过上述安装过程,实际上 docker 已经安装到你的机器上了,然而这时候你可能会发现你的 docker 死活启动不了,具体表现为:

chuan@wsl:~$ sudo service docker start
 * Starting Docker: docker                                                                           [ OK ]
chuan@wsl:~$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
chuan@wsl:~$ sudo service docker status
 * Docker is not running

此时,你需要执行如下两个命令:

参考自这篇博文:wsl2中docker启动不了的问题解决方法

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

至此,你会发现 docker 可以正常运行了:

chuan@wsl:~$ sudo service docker start
 * Starting Docker: docker                                                                           [ OK ]
chuan@wsl:~$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

3.3 让非root用户使用docker

默认情况下,安装好的 docker 只允许 root 用户随意访问,正如官方所言:

The Docker daemon binds to a Unix socket, not a TCP port. By default it's the root user that owns the Unix socket, and other users can only access it using sudo. The Docker daemon always runs as the root user.

在没有权限的情况下,你执行 docker 命令会报如下错误:

chuan@wsl:~$ docker ps
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.45/containers/json": dial unix /var/run/docker.sock: connect: permission denied

如果你希望非 root 用户也能随意使用 docker,执行下述命令:

这里再附上一个查看 docker 用户组设置情况的命令,以供辅助验证:

chuan@wsl:~$ grep docker /etc/group # 添加本人用户名之前
docker:x:999:
chuan@wsl:~$ grep docker /etc/group # 添加本人用户名之后
docker:x:999:chuan

3.4 卸载docker

4. WSL中安装nvm

直接参考官方:nvm-sh/nvm

依次按以下步骤执行即可:

  1. 下载安装脚本:

    wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh > install-nvm.sh
  2. 切换为 root 用户,设置 nvm 的安装目录(我这里设置为/opt/nvm,如果默认的安装目录~/.nvm已经满足你的需求则可跳过这一步):

    $ sudo su root
    $ echo $NVM_DIR # 查看当前是否有环境变量NVM_DIR
    
    $ mkdir /opt/nvm # 创建nvm的安装目录
    $ NVM_DIR=/opt/nvm # 设置一个(局部)变量
    $ export NVM_DIR # 将变量提升为全局变量,以便后续在执行 install-nvm.sh 脚本时,脚本能够读取到此变量
    $ echo $NVM_DIR
    /opt/nvm
  3. 执行安装脚本:

    $ bash install-nvm.sh
    => Downloading nvm from git to '/opt/nvm'
    => Cloning into '/opt/nvm'...
    remote: Enumerating objects: 365, done.
    remote: Counting objects: 100% (365/365), done.
    remote: Compressing objects: 100% (313/313), done.
    remote: Total 365 (delta 43), reused 166 (delta 26), pack-reused 0
    Receiving objects: 100% (365/365), 365.08 KiB | 350.00 KiB/s, done.
    Resolving deltas: 100% (43/43), done.
    * (HEAD detached at FETCH_HEAD)
      master
    => Compressing and cleaning up git repository
    
    => Appending nvm source string to /root/.bashrc
    => Appending bash_completion source string to /root/.bashrc
    => Close and reopen your terminal to start using nvm or run the following to use it now:
    
    export NVM_DIR="/opt/nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
  4. 根据安装脚本时出现的提示语,重启一下你的 shell 客户端,则可使用 nvm 了:

    $ sudo su root
    $ nvm
    
    Node Version Manager (v0.39.7)
    
    Note: <version> refers to any version-like string nvm understands. This includes:
      - full or partial version numbers, starting with an optional "v" (0.10, v0.1.2, v1)
      - default (built-in) aliases: node, stable, unstable, iojs, system
      - custom aliases you define with `nvm alias foo`
    
    ......
    
    Note:
      to remove, delete, or uninstall nvm - just remove the `$NVM_DIR` folder (usually `~/.nvm`)
    
    $ nvm ls
                N/A
    iojs -> N/A (default)
    node -> stable (-> N/A) (default)
    unstable -> N/A (default)
  5. nvm 已经安装成功,此时借助 nvm 安装你需要的 node 版本即可了,比如我这里安装一个 20.x 的 node:

    $ nvm ls
    ->     v20.12.2
    default -> 20 (-> v20.12.2)
    iojs -> N/A (default)
    unstable -> N/A (default)
    node -> stable (-> v20.12.2) (default)
    stable -> 20.12 (-> v20.12.2) (default)
    lts/* -> lts/iron (-> v20.12.2)
    lts/argon -> v4.9.1 (-> N/A)
    lts/boron -> v6.17.1 (-> N/A)
    lts/carbon -> v8.17.0 (-> N/A)
    lts/dubnium -> v10.24.1 (-> N/A)
    lts/erbium -> v12.22.12 (-> N/A)
    lts/fermium -> v14.21.3 (-> N/A)
    lts/gallium -> v16.20.2 (-> N/A)
    lts/hydrogen -> v18.20.2 (-> N/A)
    lts/iron -> v20.12.2
    $ node
    Welcome to Node.js v20.12.2.
    Type ".help" for more information.
    >
  6. 执行完毕。通过上述安装过程中 nvm 给出的提示来看,所谓安装 nvm,实际就是:

    • 找到一个 nvm 安装目录,所有 nvm 程序的内容都会安装到这里;

    • shell 绑定 nvm 程序的路径 NVM_DIR,从而在命令行中输入 nvm 时能够找到对应的 nvm 程序,具体而言,官方默认是通过在你的 ~/.bashrc 文件中添加如下代码来实现的:

      $ vim ~/.bashrc
      ......
      # nvm
      export NVM_DIR="/opt/nvm"
      [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
      [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
    • 因此,正如 nvm 命令所提示的,当删除 nvm 时,只要删除安装目录 NVM_DIR,然后删除 ~/.bashrc 文件中关于 nvm 的上述代码片段就可以了。

细究一下,上述过程实质上是通过 root 用户来安装的,而且在 ~/.bashrc 中设置环境变量的做法显示跟特定的用户绑定了,故而会导致普通用户(比如chuan)依旧无法使用 nvm。这种情况的解决方案其实也很简单,在普通用户chuan~/.bashrc 文件中添加上述环境变量代码片段,然后重启客户端即可。