在WSL2上运行powershell内部VS docker代码

在WSL2上运行powershell内部VS docker代码,docker,powershell,visual-studio-code,wsl-2,Docker,Powershell,Visual Studio Code,Wsl 2,我正在尝试使用VS代码的“远程容器”功能,但部分构建脚本需要作为windows进程运行 因此,设置变得有点复杂: windows 10->WSL2->docker->VS代码(服务器)->bash->powershell 在没有docker的情况下,通过某种神奇的方式,这非常有效(windows运行WSL2启动windows可执行文件)。在docker内部,一些魔法并不存在 我发现我需要在特权模式下运行docker,以便能够装载/proc/sys/fs/binfmt_misc,在那里我可以找到W

我正在尝试使用VS代码的“远程容器”功能,但部分构建脚本需要作为windows进程运行

因此,设置变得有点复杂:

windows 10->WSL2->docker->VS代码(服务器)->bash->powershell

在没有docker的情况下,通过某种神奇的方式,这非常有效(windows运行WSL2启动windows可执行文件)。在docker内部,一些魔法并不存在

我发现我需要在特权模式下运行docker,以便能够装载
/proc/sys/fs/binfmt_misc
,在那里我可以找到
WSLInterop
-文件,但这显然是不够的

为了让WSL2执行windows进程,我还需要什么魔法

root@ea31e9627f7a:/# mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc/
root@ea31e9627f7a:/# cat /proc/sys/fs/binfmt_misc/WSLInterop 
enabled
interpreter /tools/init
flags: F
offset 0
magic 4d5a
root@ea31e9627f7a:/# powershell.exe
root@ea31e9627f7a:/# which powershell.exe
/opt/windows/System32/WindowsPowerShell/v1.0//powershell.exe
root@ea31e9627f7a:/# 
解释器/tools/init
的引用是我还没有弄明白的一种魔力。在WSL2中,我有:

$ mount | grep /init
tools on /init type 9p (ro,relatime,dirsync,aname=tools;fmask=022,loose,access=client,trans=fd,rfd=6,wfd=6)
但我还没有弄明白如何在docker内部复制这个(或者它是否重要)

我的开发环境如下:


(我想有人可能会说这个设置太复杂了,但是在docker容器中开发的体验真的很好)

好的,我想我已经解决了这个问题。在WSL中,init充当linux和windows之间的桥梁
$WSL\u INTEROP
指向
/run/WSL
中用于与init通信的套接字。不需要特权模式

比较

$ docker run --rm -i -t --volume /mnt/c/Windows/:/opt/windows alpine sh
/ # /opt/windows/System32/WindowsPowerShell/v1.0/powershell.exe -c '$PSVersionTable'
/ #

(直接从docker命令行运行windows命令不起作用,不确定原因)

除非你明白其中的含义,否则不要这样做。这基本上打破了容器中的一个漏洞,使容器中的进程能够直接与windows主机对话

还请注意,进程启动的当前目录设置为当前linux目录的windows等效目录,如果该命令是从某个不可用的目录启动的(或者如果WSL无法确定正确的windows目录),则该命令将以“无效参数”失败

现在,对于VSCode部分,我似乎需要首先在WSL中启动VSCode remote,然后从那里启动远程容器,这使docker装载可以引用linux目录而不是windows目录。我成功地使用了
devcontainer.json
,如下所示:

{
    "build": {"dockerfile": "Dockerfile"},
    "extensions": ["ms-vscode.cpptools"],
    "mounts": [
        "source=/mnt/c/Windows,target=/opt/windows,type=bind,ro=true",
        "source=/run/WSL/,target=/run/WSL,type=bind,ro=true"
    ],
    "remoteEnv": {
        "PATH": "${containerEnv:PATH}:/opt/windows/System32/WindowsPowerShell/v1.0/"
    }
}

关于WSL_互操作,请参阅讨论。

“我想有人可能会说这个设置太复杂了。”当然,但它真的需要这么复杂才能重现您的核心问题吗?换言之,为了简化问题和孤立问题,你能得到更多的答案吗?我在想(但仍在研究这个问题),你的核心问题是(对于初学者来说)如何使用WSL interop在Ubuntu docker容器内运行
powershell.exe
?我们现在真的不需要把VSCode引入等式,是吗?第二个问题(如果我不这样做,有人会问)。您的最终目标是powershell.exe,还是在运行其他Windows可执行文件之前,这只是您的测试用例?如果PowerShell是最终目标,那么它必须是Windows PowerShell吗?或者在容器中安装Linux PowerShell是可行的选择?我猜不会,但我不得不问。或者,我自己也没有试过,a是否可能代替Ubuntu作为容器库工作?好问题。我能够在没有VSCode的情况下重现问题,运行一个Alpine容器。最终目标不是powershell,而是通过串行网桥和USB将Sming固件上载到和ESP8266开发板。WSL无法访问windows COM端口,因此Sming生成系统通过powershell调用上载程序。这里可能的解决方法是在cygwin中运行Sming构建而不是WSL,或者将固件移出docker容器并手动上载。不过,如果能让集成的体验发挥作用,那就太好了。在使用Alpine和
strace
重现问题时,我已经能够将问题缩小到
/run/WSL
中的套接字。从Linux/WSL中启动docker,我能够挂载这个目录并调用windows,所以我有了进展。但是,从VSCode启动docker容器似乎只能访问windows目录。(docker,我甚至无法解释这些在虚拟linux和windows中是如何工作的,但linux是透明的。纯魔法!)“现在,对于VSCode部分,我似乎需要首先在WSL中启动VSCode remote”很酷-这很有意义。在Github上的互操作讨论中找到了很好的结果。我想这就解释了为什么我有时在alpenswsl实例中运行wrapping
pwsh.exe
inside
tmux
时管道破裂(希望是这样)。
{
    "build": {"dockerfile": "Dockerfile"},
    "extensions": ["ms-vscode.cpptools"],
    "mounts": [
        "source=/mnt/c/Windows,target=/opt/windows,type=bind,ro=true",
        "source=/run/WSL/,target=/run/WSL,type=bind,ro=true"
    ],
    "remoteEnv": {
        "PATH": "${containerEnv:PATH}:/opt/windows/System32/WindowsPowerShell/v1.0/"
    }
}