是否可以在后台运行 WSL 应用程序?

Lux*_*voo 9 windows-subsystem-for-linux

我使用 snap store 在 ubuntu 中安装了 LXD,然后将其连接到 Windows 客户端,但为了能够从 Windows 运行容器,必须打开 Ubuntu 应用程序。有没有办法让 LXD 服务器在后台运行,或者我必须打开 Ubuntu 才能让它工作? wsl --status返回:

Default Distribution: Ubuntu
Default Version: 2
Run Code Online (Sandbox Code Playgroud)

wsl --version返回:

WSL version: 0.70.0.0
Kernel version: 5.15.68.1
WSLg version: 1.0.45
MSRDC version: 1.2.3575
Direct3D version: 1.606.4
DXCore version: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows version: 10.0.22000.1098
Run Code Online (Sandbox Code Playgroud)

cmd /c ver返回:

Microsoft Windows [Version 10.0.22000.1098]
Run Code Online (Sandbox Code Playgroud)

Not*_*1ds 8

老实说,这是一个很好的问题,正如我在经历以下各种场景时意识到的那样。我不得不承认,WSL 在这里的工作方式令人困惑。WSL Github 存储库上出现了许多与此相关的“问题”,但事实是这种行为是“设计使然”。

来自WSL/Systemd 公告

同样重要的是要注意,通过这些更改,systemd 服务将不会使您的 WSL 实例保持活动状态。您的 WSL 实例将以与之前相同的方式保持活动状态,您可以(在此处阅读更多信息]( https://devblogs.microsoft.com/commandline/background-task-support-in-wsl/)。

换句话说,WSL 旨在在某些情况下终止 Ubuntu,但链接的帖子并不太清楚这些情况到底是什么。为了更好地理解它们(以及 WSL 的行为方式),让我们从(至少)四种不同的方式开始,您可以在 WSL 上的 Ubuntu 上启动后台任务或服务(也称为守护进程):

  1. 交互式地,从命令行通过命令本身或使用service帮助程序。例如:

    sudo service cron start
    # or even
    sudo /usr/sbin/cron
    
    Run Code Online (Sandbox Code Playgroud)

    当然,这适用于任何版本的 WSL,但 SysVInitservice可能仅适用于某些发行版(例如 Ubuntu)和服务。

    (重要)请注意,为此目的,在 shell 启动脚本内运行的命令被视为“交互式”。这将在我的最终(hacky)解决方案中派上用场。

  2. 以交互方式,作为 shell 的后台任务。例如:

    nohup sleep 100000 &
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在 Windows 11 下,您可以通过 .WSL 启动时自动启动守护进程/etc/wsl.conf。例如:

    [boot]
    command = service cron start
    
    Run Code Online (Sandbox Code Playgroud)
  4. 从 WSL 0.67.6 开始,使用 Systemd。这可以交互地 ( sudo systemctl cron start)、通过/etc/systemd链接自动发生,或者作为另一个服务的依赖项发生。例如

    sudo systemctl cron start
    
    Run Code Online (Sandbox Code Playgroud)

    snapd请注意,一旦在 WSL 中启用,Snap 守护进程 ( ) 就会通过 Systemd 自动启动。


考虑到这些情况,我们需要考虑WSL何时终止 Ubuntu。正如我所说,这很“令人困惑”。我希望我能拿出一个总结性的陈述来描述这种行为,但我对此很挣扎。我能做的就是提供示例:

概括

  1. 不会终止
  2. 不会终止
  3. 将终止
  4. 将终止

详细信息和示例

  1. 通过命令行交互启动的服务将阻止 WSL 终止 Ubuntu。我们可以通过以下方式证明这一点:

    • 暂时禁用 Systemd/etc/wsl.conf
    • 退出Ubuntu
    • 启动 PowerShell
    • wsl --shutdown
    • 通过wsl ~(如果需要,wsl ~ -d Ubuntu-22.04等等)重新启动 Ubuntu
    • sudo service cron start
    • 退出外壳
    • 等待一分钟(默认情况下 25 秒就足够了)并检查wsl -l -vUbuntu 是否仍处于“运行”状态。
    • wsl -e ps axjff应该显示cron仍在运行,即使没有 shell 正在运行。
  2. 通过命令行交互启动的后台任务也将阻止 WSL 终止 Ubuntu。按照前面的示例:

    • 在 Systemd 仍被禁用的情况下,从 PowerShell 中,wsl --shutdown
    • 启动 Ubuntu(例如wsl ~
    • 跑步nohup sleep 100000 &
    • 再按Enter一次即可消除该nohup消息
    • 退出 shell/Ubuntu 返回 PowerShell。
    • 等待 30 秒到一分钟,wsl -l -v即可显示 Ubuntu 仍在运行。
    • wsl -e ps axjff应显示该sleep命令仍在运行,即使没有 shell 正在运行。
  3. /etc/wsl.conf另一方面,通过 启动的服务/进程不会阻止 WSL 终止 Ubuntu。

    • 从前面的示例开始(Systemd 已禁用)

    • 在 Ubuntu 中,sudo -e /etc/wsl.conf添加以下内容:

      [boot]
      command = service cron start
      
      Run Code Online (Sandbox Code Playgroud)
    • 退出 Ubuntu,然后从 PowerShell,wsl --shutdown

    • 通过以下方式重新启动 Ubuntuwsl ~

    • ps axjff表明它cron作为父进程之一的子进程运行/init

    • 退出 shell/Ubuntu

    • 30秒到一分钟后将wsl -l -v显示Ubuntu不再运行。它已被终止。

  4. 通过 Systemd 启动的服务/进程也不会阻止WSL 终止 Ubuntu。演示(虽然你正在经历这个):

    • 编辑/etc/wsl.conf并重新启用 Systemd,同时禁用(注释掉或删除)command.

    • 退出Ubuntu

    • 在 PowerShell 中,wsl --shutdown

    • wsl ~启动Ubuntu。

    • ps axjff将显示 Systemd 服务正在运行和/或正在启动。

    • 一分钟后:

      sudo systemctl stop cron
      sudo systemctl start cron
      
      Run Code Online (Sandbox Code Playgroud)

      显然,这具有简单地停止 cron 然后重新启动它的效果。这里的要点是表明,即使我们显式地以交互方式启动cron,这也不会阻止 WSL 终止 Ubuntu。

    • 退出 shell/Ubuntu

    • 30秒到一分钟后,wsl -l -v会显示Ubuntu已经停止

    至于你的特定问题,因为lxd它只是一个 Snap,它运行在由 Systemd 启动的容器化环境中,所以它也会被终止。嗯,无赖...

解决方案

希望有一个更永久的修复即将到来,因为一位 WSL 开发人员确实表示希望保持发行版运行

与此同时,一个解决方案(当然可能还有更多)是通过 shell 启动文件启动一个长时间运行的进程。就我而言,我通常运行keychain.

钥匙串有一些特性可以让它在这种情况下很好地工作:

  • 它可以在默认的 Ubuntu 存储库中找到
  • 它已经启动了 的单例实例ssh-agent。换句话说,如果ssh-agent已经在运行,它将附加到它而不是启动一个新的。
  • 安静运行,不加按键无需交互

要进行此设置:

sudo apt update && sudo apt install keychain -y
sudo -e /etc/profile.d/keep_wsl_running.sh
Run Code Online (Sandbox Code Playgroud)

并添加以下内容:

sudo service cron start
# or even
sudo /usr/sbin/cron
Run Code Online (Sandbox Code Playgroud)

这个脚本:

  • 当您启动 shell 时运行(假设大多数 shell,例如 Bash 和 Zsh)。请注意,如果您使用 Fish 作为 shell,它将不会运行。如果您(或任何未来的读者)确实想要使用 Fish(或其他不处理 的 shell /etc/profile.d),请就如何处理这种情况提出一个单独的问题。我确实有一个解决方案,但这个答案(像往常一样)已经足够长了;-)。

  • 评估 的输出keychain,以便找到任何现有的ssh-agent(如果没有,则启动一个新的)并设置 shell 的环境变量以指向它。

  • -q正如您可能想象的那样,只是keychain安静地运行,没有输出

运行ssh-agent(通过 启动/etc/profile.d)将阻止 WSL 终止 Ubuntu 发行版/实例/容器。关闭终端窗口后,Ubuntu 将继续运行,并且您的lxd(以及 Snap 安装的其他守护进程/服务)也将保持运行。

要让 Ubuntu 正常终止,只需删除ssh-agent. 这可以通过多种方式完成,包括:

keychain -k all
Run Code Online (Sandbox Code Playgroud)

当然,请确保以交互方式启动的任何其他服务也都消失了。一旦满足该条件,WSL 将正常终止 Systemd 及其单元/服务。

这里有一个极端的情况,那就是如果您开始一个wsl -u root会话。在这种情况下,ssh-agent将以root 身份运行,并且您需要.sudo keychain -k all