派玩python之Jupyter使用远程kernel(3)- WSL环境
经过上一期《派玩python之Jupyter使用远程kernel(2)》的介绍也有一段时间了。 这次继续介绍如何使用WSL环境(运行端)作为主要Python运行环境,满足如机器学习,显卡硬件设备等运行要求,并且连接到远程树莓派部署的Jupyter编辑器(开发端)上开发写代码。
WSL2环境设置
WSL是Microsoft开发的Linux子系统,可以方便地在Windows操作系统上进行类Linux系统开发。本例使用WSL2上安装的Ubuntu子系统进行演示。
WSL安装和SSH安装设置
我们假设你已经安装好了WSL,如果没有,请自行查看WSL安装文档。
安装完成后, 执行wsl -l
, 输出类似以下内容,就是安装成功了。
适用于 Linux 的 Windows 子系统分发版:
docker-desktop-data (默认)
Ubuntu-20.04
docker-desktop
如果有多个WSL子系统,比如我这个是3个,并且默认不是你想要的WSL,那么接下来所有wsl命令都需要指定。 为了不这么麻烦, 务必执行类似以下命令切换默认系统就可以了。我这里默认使用Ubuntu-20.04这个。
wsl -s Ubuntu-20.04
接下来参考网上,进行安装配置SSH相关内容:
- 在wsl2下重装ssh
sudo apt-get remove openssh-server
sudo apt-get install openssh-server
- 编辑sshd_config文件,修改几处配置
sudo vi /etc/ssh/sshd_config
Port 222
PermitRootLogin
yesPasswordAuthentication yes
- 编辑
sudo vim /etc/hosts.allow
,添加一行
sudo vim /etc/hosts.allow
添加的内容为 sshd: ALL
sudo visudo
然后加入
%sudo ALL=(ALL) NOPASSWD: /etc/init.d/ssh
- 重启ssh服务
sudo service ssh --full-restart
宿主Windows的SSH转发WSL设置
Windows作为宿主机,本身是也可以安装SSH服务的。 这样就可以远程ssh登录Windows。我们在上一篇文章中就是这种方式。 本次的WSL也是可以安装SSH服务的。这时候就需要区分,ssh到Windows,还是ssh到WSL子系统。 我们存在两个SSH服务。 我们采取3)方式进行转发,来达到两个SSH服务都可以使用的目的。
IP 端口 SSH服务
宿主机 22 Windows的SSH服务 1)
WSL内部IP 222 WSL子系统的SSH服务 2)
宿主机 222->222 WSL子系统的SSH服务 3)
转发命令一句话就可以搞定,类似
netsh interface portproxy add v4tov4 listenport=222 connectport=22 connectaddress=<WSL的内部IP>
但是这个WSL子系统每次启动IP可能会变,或者宿主机启动,以上转发配置没有了。 因此我推荐使用自动化脚本(附录中的脚本1
,来自网络),并且添加到Windows自动启动的任务计划程序中。
注意脚本1
中的$Ports = (222)
部分,可以按自己情况修改, 之后仍然可以执行netsh interface portproxy show v4tov4
确认脚本执行后的情况。
建立jupter的kernel连接
这部分可以直接按照上一篇文章的利用remoteikernel自动远程连接章节即可。 当然是要在jupter环境中设置好对于WSL的SSH免密码登录, 可以参考SSH免密登录
关键的添加kernel命令大概是这个样子:
remote_ikernel manage --add --kernel_cmd="ipython kernel -f {connection_file}" --name="Remote WSL" --interface=ssh --host=user@host:222 --workdir="~/" --verbose
注意修改--host=user@host:222
部分。如果使用了conda
环境, 可以把--kernel_cmd="ipython kernel -f {connection_file}"
修改成 --kernel_cmd="$CONDA_PREFIX/bin/python -m ipykernel_launcher -f {connection_file}"
可能需要把conda安装位置和jupyter环境上conda保持一致。
sudo ln -s /path/to/miniconda3 /opt/conda
到这里,如果能在jupyterlab上能够选择并且正常使用这个kernel,就证明一切OK了。
总结
本文介绍了WSL和jupyterlab进行远程连接的方法。 非常适合在jupyter上进行开发和测试,但是需要在WSL环境中运行的场景。 当然了, 本文介绍的方法同样也适用于在同一台主机的情况,即jupyter在Windows宿主机上,运行在WSL子系统。 这个时候不需要安装remote_ikernel
, 其他都是一样的。
全文完。
附录
脚本1
# Start SSH Service.
#wsl sudo service ssh start
wsl sudo /etc/init.d/ssh start
# WSL2 network port forwarding script v1
# for enable script, 'Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser' in Powershell,
# for delete exist rules and ports use 'delete' as parameter, for show ports use 'list' as parameter.
# written by Daehyuk Ahn, Aug-1-2020
# Display all portproxy information
If ($Args[0] -eq "list") {
netsh interface portproxy show v4tov4;
exit;
}
# If elevation needed, start new process
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
# Relaunch as an elevated process:
Start-Process powershell.exe "-File",('"{0}"' -f $MyInvocation.MyCommand.Path),"$Args runas" -Verb RunAs
exit
}
# You should modify '$Ports' for your applications
#$Ports = (2222,80,443,8080)
$Ports = (222)
# Check WSL ip address
wsl hostname -I | Set-Variable -Name "WSL"
$found = $WSL -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if (-not $found) {
echo "WSL2 cannot be found. Terminate script.";
exit;
}
# Remove and Create NetFireWallRule
Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock';
if ($Args[0] -ne "delete") {
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $Ports -Action Allow -Protocol TCP;
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $Ports -Action Allow -Protocol TCP;
}
# Add each port into portproxy
$Addr = "0.0.0.0"
#$Addr = "*"
Foreach ($Port in $Ports) {
iex "netsh interface portproxy delete v4tov4 listenaddress=$Addr listenport=$Port | Out-Null";
if ($Args[0] -ne "delete") {
iex "netsh interface portproxy add v4tov4 listenaddress=$Addr listenport=$Port connectaddress=$WSL connectport=$Port | Out-Null";
}
}
# Display all portproxy information
netsh interface portproxy show v4tov4;
# Give user to chance to see above list when relaunched start
If ($Args[0] -eq "runas" -Or $Args[1] -eq "runas") {
Write-Host -NoNewLine 'Press any key to close! ';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}