我在 ubuntu 中使用 snap store 安装了 LXD,然后将其连接到 Windows 客户端,但为了能够从 Windows 运行容器,Ubuntu 应用程序必须打开。有没有办法让 LXD 服务器在后台运行,还是必须打开 Ubuntu 才能使其工作?
wsl --status
返回:
Default Distribution: Ubuntu
Default Version: 2
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
并cmd /c ver
返回:
Microsoft Windows [Version 10.0.22000.1098]
答案1
说实话伟大的问题,正如我在经历以下各种场景时意识到的那样。我不得不承认,WSL 在这里的工作方式令人困惑。在 WSL Github repo 上出现了许多与此相关的“问题”,但事实是这种行为是“设计使然”。
还要注意的是,有了这些更改,systemd 服务将不会让您的 WSL 实例保持活动状态。您的 WSL 实例将以与以前相同的方式保持活动状态,您可以(在此处阅读更多信息)https://devblogs.microsoft.com/commandline/background-task-support-in-wsl/)。
换句话说,WSL 旨在在某些情况下终止 Ubuntu,但链接的帖子并没有清楚地说明这些场景到底是什么。为了更好地理解它们(以及 WSL 的行为方式),让我们从(至少)四种不同的方式开始,你可以在 WSL 上的 Ubuntu 上启动后台任务或服务(又名守护进程):
以交互方式,通过命令行本身或使用助手
service
。例如:sudo service cron start # or even sudo /usr/sbin/cron
当然,这适用于任何版本的 WSL,但 SysVInit
service
可能仅适用于某些发行版(例如 Ubuntu)和服务。(重要)请注意,在此目的中,在 shell 启动脚本中运行的命令被视为“交互式”命令。这将在我的最终(黑客式)解决方案中派上用场。
以交互方式,作为 shell 的后台任务。例如:
nohup sleep 100000 &
在 Windows 11 下,你可以通过 在 WSL 启动时自动启动守护进程
/etc/wsl.conf
。例如:[boot] command = service cron start
从 WSL 0.67.6 开始,使用 Systemd。这可以以交互方式 (
sudo systemctl cron start
)、通过/etc/systemd
链接自动进行,或作为另一项服务的依赖项进行。例如sudo systemctl cron start
请注意,一旦在 WSL 中启用,Snap 守护程序(
snapd
)就会通过 Systemd 自动启动。
考虑到这些情况,我们需要考虑什么时候WSL 将终止 Ubuntu。正如我所说,这很“令人困惑”。我希望我能想出一个总结性陈述来描述这种行为,但我很难做到。我能做的最好的就是举例说明:
概括
- 不会终止
- 不会终止
- 將终止
- 將终止
详细信息和示例
通过命令行交互启动的服务将阻止 WSL 终止 Ubuntu。我们可以通过以下方式证明这一点:
- 暂时禁用 Systemd
/etc/wsl.conf
- 退出 Ubuntu
- 启动 PowerShell
wsl --shutdown
- 通过以下方式重新启动 Ubuntu
wsl ~
(如果需要,wsl ~ -d Ubuntu-22.04
等等) sudo service cron start
- 退出 shell
- 等待一分钟(默认情况下 25 秒就足够了)并检查
wsl -l -v
Ubuntu 是否仍然处于跑步状态。 wsl -e ps axjff
应该显示cron
仍在运行,即使没有 shell 在运行。
- 暂时禁用 Systemd
通过命令行以交互方式启动的后台任务也将阻止 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 在运行。
- 由于 Systemd 仍处于禁用状态,因此从 PowerShell 中,
/etc/wsl.conf
另一方面,通过 启动的服务/进程将不会防止 WSL 终止 Ubuntu。从上一个示例开始(Systemd 已禁用)
在 Ubuntu 中,
sudo -e /etc/wsl.conf
添加以下内容:[boot] command = service cron start
退出 Ubuntu,然后从 PowerShell 中
wsl --shutdown
通过以下方式重启 Ubuntu
wsl ~
ps axjff
表明它cron
作为父进程之一的子进程运行/init
。退出 shell/Ubuntu
30秒到一分钟后将
wsl -l -v
显示Ubuntu不再运行。它已被终止。
通过 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
显然,这会产生停止 cron 然后重新启动的效果。这里的重点是表明,即使我们明确地以交互方式启动
cron
,这不会阻止 WSL 终止 Ubuntu。退出 shell/Ubuntu
30秒到一分钟后,
wsl -l -v
将显示Ubuntu已经已停止。
至于您的具体问题,由于
lxd
它只是一个 Snap,在由 Systemd 启动的容器化环境中运行,因此它也将被终止。好吧,真倒霉……
解决方案
希望有一个更永久的修复即将到来,因为其中一位 WSL 开发人员确实表示希望保持发行版运行。
与此同时,一个解决方案(当然可能还有更多)是通过 shell 启动文件启动一个长时间运行的进程。就我而言,我通常运行keychain
。
Keychain 的一些特点使其在这种情况下能够很好地工作:
- 它在默认的 Ubuntu 存储库中可用
- 它已经启动了 的一个单例实例
ssh-agent
。换句话说,如果ssh-agent
已经在运行,它将附加到它而不是启动一个新的。 - 它可以安静运行,并且如果不添加任何按键则无需交互
要进行设置:
sudo apt update && sudo apt install keychain -y
sudo -e /etc/profile.d/keep_wsl_running.sh
并添加以下内容:
#!/usr/bin/env sh
eval $(keychain -q)
此脚本:
启动 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
当然,确保你以交互方式启动的进程也会消失。一旦满足该条件,WSL 将正常终止 Systemd 及其单元/服务。
这里有一个特殊情况,那就是如果你开始一个会话wsl -u root
。在这种情况下,ssh-agent
还以 root 身份运行,并且您需要sudo keychain -k all
。
答案2
在 Windows 启动时运行此 vbs 脚本。只需将其放在 Windows 启动文件夹中 (crl+r -> shell:startup
)
wsl-启动.vbs:
# change '<Distro>' to the distro name you are using.
set ws=wscript.CreateObject("wscript.shell")
ws.run "wsl -d <Distro>", 0
形式:https://github.com/microsoft/WSL/issues/8854#issuecomment-1421910739
此后,每次启动机器并登录时,它都会启动 wsl 并等待输入。wsl 实例将保持活动状态。
然后您可以使用 systemd 在后台运行您想要的任何内容。
如果你使用以下命令手动重启 wsl 实例,请记得再次运行 vbswsl -t <distro> / wsl --shutdown