Ubuntu on Windows 10跨平台开发环境搭建权威指南

2018-03-03


Ubuntu on Windows 10 跨平台开发环境搭建权威指南

程序猿经常争论的一个话题是:日常开发到底 Windows 好还是 Linux 好?进而演化出另一个问题:到底选 MacBook 好还是 SurfaceBook 好?

选择 Linux 系统或者 mac 笔记本的同学最核心的理由是 Linux/Mac 开发、编译工具链比较完善,很多环境或者安装包都系统自带了,写出来的程序可以很方便的通过开发、测试与线上系统对接,开发测试效率比较高,而 Windows 下开发的同学可能需要考虑开发、测试代码的可移植性问题。就拿笔者来说,也曾经遇到过某些 java/python API 不支持 Windows 的问题,这给日常开发带来了不小的麻烦。

在 Windows10 以前,咱们为了解决 Windows 开发环境跨平台的问题,往往会选择 cygwin,这个项目本身已经很成熟了,笔者也用了很多年,它能在 Windows 下模拟一套类 Linux 的环境,用它应付一般的开发测试问题不大。但它的缺点在于组件、包管理器比较弱,对于日后的环境维护相当麻烦,而且一些底层 API 模拟的并不完善,对于一些涉及 Linux 底层的系统调用等场景显得很鸡肋。幸运的是在 2016 年,微软在 Windows10 WSL 里开始内置 Ubuntu,之后又开始在 Microsoft Store 以 UWP APP 的形式发布各个 Linux 系统。这样对于需要搭建跨平台开发环境的同学来说可以做到一套系统搞定多套平台环境,又多了一个舍弃 Mac 的理由 :)

本文今天会详细讲解下怎样在 Windows10 下安装 Ubuntu、搭建 Linux 开发环境,碰到的一些坑及其解决方案。

1、安装 Ubuntu on Windows10

首先更新你的 Windows10 系统到最新,然后开启“开发人员模式”,最后在 Microsoft Store 里输入 “Ubuntu” 然后选择安装,成功后即可点击启动。

注意:网上有些老的教程在命令行下用 lxrun /install 的形式安装,这里不推荐,因为这是早期 WSL beta 版本的做法,现在正式版直接在 Microsoft Store 以 UWP APP 的形式获取更便捷,也易于管理。

最终的系统安装在如下目录:

%LOCALAPPDATA%\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc

初始安装时,整个目录大概 600MB 左右,我更新了一些软件包并升级到 16.04 后,大小在 1G。

2、开启 sshd

2.1 设置 sshd

  • 重装openssh
  1. sudo apt-get remove openssh-server  
  2. sudo apt-get install openssh-server 
  • 修改 sshd 设置,添加以下配置到/etc/ssh/sshd_config
  1. AllowUsers yourusername  
  2. PasswordAuthentication=yes 
  • 重启 sshd
  1. sudo service ssh --full-restart 

  不出意外使用 ssh 客户端应该可以链接上 Bash on windows 了。

2.2 问题1:sshd启动报错

  1. # /etc/init.d/ssh restart  
  2. sshd: ../sysdeps/posix/getaddrinfo.c:2603: getaddrinfo: Assertion `IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32)' failed. Aborted (core dumped) 

原因是 ipv6 的问题,修改sshd_config配置添加 ListenAddress 0.0.0.0 即可

  1. sudo vi /etc/ssh/sshd_config 

2.3 问题2:ssh 连接一直提示密码错误

这个问题查起来还是比较复杂的,需要有比较系统的排查方法和理论,笔者这里折腾了不少时间。

现象就是 sshd 服务起来了,ps aux 和 top 都能见到,但是 ssh 连接的时候一直提示密码错误或者没有权限,但密码确认是对的,包括新建账户也不行,按照上篇《记一次诡异的 ssh 互信免密码登录失败》的排查思路发现 sshd 服务压根就没有监听指定的 sshd 端口,换做其它端口也有同样的问题:

  1. nc -l 127.0.0.1 4444  
  2. #on powershell:  
  3. netstat -a -n -q | findstr "4444" 

那可能是系统层面的问题,进一步分析 Windows 系统事件发现是 TDI 筛选器的问题:

image

在 windows/system32 下咱们可以找到这个驱动文件:

image

本质上是因为一些软件厂商用了微软过时的 API 导致的,比如 QQGame 和一些 VPN 软件被证实存在这样的问题,确认原因就好办了,首先根据软件名字找到对应注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services,按图修改:

image

重启电脑,再次测试 ok:

image

3、sshd 开机启动

一旦关掉 bash.exe 进程,ssh 就无法连接了。解决这个问题分三个步骤:

  1. 添加启动项,让 bash.exe 随机启动
  2. 使用命令 sudo service ssh start 启动 sshd
  3. 因为 sudo service ssh start 命令需要输入密码不能自动化,所以需要 visudo 来免除输入密码的操作。

3.1 理清思路接下来记录一些过程:

  • 使用 vbs 启动隐藏窗口开启 bash 和 运行 sudo service ssh start
  1. set ws=wscript.createobject("wscript.shell" 
  2. ws.run "C:\Windows\System32\bash.exe",0  
  3. ws.run "C:\Windows\System32\bash.exe  -c 'sudo /usr/sbin/service ssh --full-restart'",0 
  • 运行 sudo visudo,添加如下配置
  1. toor ALL = (root) NOPASSWD: /usr/sbin/service 

其中 toor 是我的用户名。

  • 添加vbs文件到windows 启动项,将 vbs 文件放入到如下目录下。
  1. %AppData%\Microsoft\Windows\Start Menu\Programs\Startup 

重启,测试不出意外就可以连接上 ssh 了。

另外一种方案是使用windows自带的定时任务计划添加开机启动Ubuntu ssh服务的任务:

  搜索“任务计划程序”,操作-- 创建基本任务

  触发器:当计算机启动时

  操作:启动程序

  程序名:bash.exe

  参数为-c \"sudo /usr/sbin/sshd -D\"" 意思是打开bash,执行sshd命令开启ssh服务

  选择“点击完成打开属性页”按钮,点击完成,打开属性页

  在属性页选择“使用最高权限运行”,避免错误。

3.2 问题1:重启/开机后无 sshd 进程

首先确保上述三步每一步的代码都正确,其次看看系统日志是何原因失败,我这里遇到的是 sudo 还需要密码,导致开机的 VB 脚本执行出错。仔细研究了下, 这个配置文件如下:

  1. ...  
  2. User privilege specification  
  3. root    ALL=(ALL:ALLALL  
  4. my-username   ALL=(ALL) NOPASSWD: ALL  # ---> the line added by me   
  5. # Members of the admin group may gain root privileges  
  6. %admin ALL=(ALLALL   
  7. # Allow members of group sudo to execute any command  
  8. %sudo   ALL=(ALL:ALLALL  
  9. # See sudoers(5) for more information on "#include" directives:  
  10. #includedir /etc/sudoers.d 

可以看到我的配置加在了中间,后面还有几条配置,导致我的配置被后面的覆盖了。解决方案是把我的配置移动到最后,再次试了下,sudo 不再需要密码了。

3.3 问题2:secureCRT卡死/乱码

这里的 secureCRT卡死/乱码和字符集有关,注意设置正确的终端字符集和系统字符集,Ubuntu on Windows 默认字符集是 Latin。

  1. sudo vim /etc/default/locale   
  2. LANG=zh_CN.UTF-8     
  3. LANGUAGE=”zh_CN:zh”    
  4.  
  5. #################################  
  6. # sudo dpkg-reconfigure locales  
  7. # en_US.UTF-8、zh_CN.GBK、zh_CN.UTF-8  
  8.  
  9. #################################  
  10.  
  11. WARNING! Your environment specifies an invalid locale.  
  12.  The unknown environment variables are:  
  13.    LC_CTYPE=zh_CN.UTF-8 LC_MESSAGES=zh_CN.UTF-8 LC_ALL=  
  14.  This can affect your user experience significantly, including the  
  15.  ability to manage packages. You may install the locales by running:  
  16.    sudo apt-get install language-pack-zh  
  17.      or  
  18.    sudo locale-gen zh_CN.UTF-8  
  19.  
  20. To see all available language packs, run:  
  21.    apt-cache search "^language-pack-[a-z][a-z]$"  
  22. To disable this message for all users, run:  
  23.    sudo touch /var/lib/cloud/instance/locale-check.skip 

另外一种方案不修改配置,在bash中依次执行如下命令:

  1. apt-get update  
  2. apt-get install language-pack-zh-hans  
  3. update-locale LANG=zh_CN.UTF-8 

这几条命令安装了中文补丁,并且把本地编码改为了中文编码。

然后重启WSL(关掉窗口,重新打开),再执行命令

  1. echo $LANG 

可以看到输出为

  1. zh_CN.UTF-8 

之后可以看到终端中输出的中文能够正常显示了。

4、WSL Ubuntu 更新

4.1 ubuntu 系统升级:

(1)版本升级 

  1. //更新软件源,最后会读取软件包列表  
  2.     sudo apt-get update    
  3.     sudo update-manager -c -d 

  然后选择 upgrade:apt-get -y --force-yes upgrade

(2)普通升级 

  1. sudo apt-get update  
  2.    sudo apt-get -y upgrade  
  3.    # apt-get -y --force-yes --fix-missing upgrade 

(3)升级单一软件

  1. sudo apt-get update  
  2. sudo apt-get upgrade package_name_your_want_to_upgrade 

(4)全部升级

  1. //更新所有的软件  
  2. sudo apt-get dist-upgrade  

4.2 修改 Ubuntu 镜像源:

WSL 自带的 Ubuntu 更新源国内访问非常慢,很容易出现部分源IP无法连接上,进而部分索引文件下载失败,最后导致整个更新失败,这里推荐阿里云的镜像比较稳定可靠,当然也可以参考国内各个大学的镜像源。

(1)Ubuntu 的软件源配置文件是 /etc/apt/sources.list,先将系统自带的该文件做个备份:

  (cd /etc/apt && sudo cp sources.list sources.list.bak.`date -I`)

(2)将源文件中的 URL 替换为国内任意源,比如阿里云:http://mirrors.aliyun.com/ubuntu 

  1. deb http://cn.archive.ubuntu.com/ubuntu/ trusty main restricted universe multiverse  
  2. deb http://cn.archive.ubuntu.com/ubuntu/ trusty-security main restricted universe multiverse  
  3. deb http://cn.archive.ubuntu.com/ubuntu/ trusty-updates main restricted universe multiverse  
  4. deb http://cn.archive.ubuntu.com/ubuntu/ trusty-backports main restricted universe multiverse  
  5. # 如要用于其他版本,把 trusty 换成版本代号就好,比如:15.10 willy、14.04 trusty  
  6. # 具体请参考:http://wiki.ubuntu.org.cn/%E6%BA%90%E5%88%97%E8%A1%A8        http://wiki.ubuntu.org.cn/%E6%A8%A1%E6%9D%BF:14.04source 

(3)sudo apt-get update,刷新列表使其生效。

  1. # 注意:一定要选对版本  
  2. # 注意:一定要执行刷新,重新加载配置 

在 vim 中可以直接:

  1. :%s#deb http://archive.ubuntu.com/ubuntu/#deb http://mirrors.aliyun.com/ubuntu/#g  
  2. :%s#deb http://security.ubuntu.com/ubuntu/#deb http://mirrors.aliyun.com/ubuntu/#g 

5、借助 X Server 在 WSL 上使用 GUI 桌面程序

5.1 X 窗口系统 (X Window System) 简介

X 窗口系统( X Window System,也常称为 X11 或 X)是一种以位图方式显示的软件窗口系统。最初是 1984 年麻省理工学院的研究,之后变成 UNIX、类 UNIX、以及 OpenVMS 等操作系统所一致适用的标准化软件工具包及显示架构的运作协议。X 窗口系统通过软件工具及架构协议来创建操作系统所用的图形用户界面,此后则逐渐扩展适用到各形各色的其他操作系统上。现在几乎所有的操作系统都能支持与使用 X。更重要的是,今日知名的桌面环境——GNOME 和 KDE 也都是以 X 窗口系统为基础建构成的。

X Window System 主要由 X Server 和 X Client 两部分组成。其中 X Server 负责接受对图形输出 (窗口) 的请求并反馈用户输入,而 X Client 则是使用图形界面的应用程序。由于 WSL 本身不支持图形界面,我们需要额外安装 X Server 并指定图形输出位置,使得带有 GUI 的桌面程序可以被显示和运行。

5.2 X Server 的选择

Windows 上常用的 X Server 有:Xmanager, Xming, VcXsrv 等,简单比较一下:

  • Xmanager 是商业软件,需要付费
  • Xming 虽然是开源软件,但是从从 2007 年最后一个免费版本 (6.9.0.31) 之后,就需要捐助才能下载。不过免费版本虽然老旧,但由于 X Windows System 近年来变化不大,免费版还是基本够用
  • VcXsrv 为开源免费软件,使用方式及界面与 Xming 极为相近,还在不断更新,因此我最终选择此软件

5.3 VcXsrv 的安装和启动   

下载 VcXsrv 并进行安装后,运行 XLaunch,一直点 Next 至启动完成。

5.4 WSL 设置     

启动 X Server 后,需要在 WSL 中输入如下两条指令,重启 Bash,即可运行带有图形界面的 Linux 程序了

  1. echo export DISPLAY=:0.0>>~/.bashrc  
  2. sudo sed -i 's$<listen>.*</listen>$<listen>tcp:host=localhost,port=0</listen>$' /etc/dbus-1/session.conf 

这里对这两条指令简单解释一下:

  • 第一条指令

该指令将export DISPLAY=:0.0 指令添加进 ~/.bashrc 中,使得每次开启新的 Bash 时,自动指定图形程序显示的位置。

也可直接输入以下指令运行程序,无需export,但作用效果只有一次,再运行其他程序时,还要重新输入指令。

  1. DISPLAY=:0.0 gvim &    //gvim 为你想要打开的程序 

tips:gvim 后的 & 不是必须要加,它表示程序以后台启动的方式运行,这样在图形界面运行时,命令行窗口还可以继续使用。要是忘记加 &, 也可以在程序运行时按ctrl+z, 将程序进程挂起,并输入bg,使其在后台运行

  •     第二条指令(可选)

第一条输入,重启 Bash 后 , 理论上就可以运行 Linux 程序了,但程序一般不会运行很久就挂掉了,并会提示 D-Bus异常,该异常会使得许多 Linux 的图形程序无法很好地运行。 这是因为 D-Bus 需要使用socket来通信,但 WSL 目前并不支持 socket。

Reddit 上对此的解决方案为:用 tcp 代替 sockets 来使 D-Bus 运行。

具体实现为:在 /etc/dbus-1/session.conf 中(需要 Root 权限),将<listen>unix:tmpdir=/tmp</listen>字段替换为 <listen>tcp:host=localhost,port=0</listen>,简单写就是第二条指令了。

Refer:

[1] bash on windows可以升级为16.04吗?

https://www.zhihu.com/question/49411626

[2] How can I SSH into “Bash on Ubuntu on Windows 10”?

https://superuser.com/questions/1111591/how-can-i-ssh-into-bash-on-ubuntu-on-windows-10

[3] SSHD server is running but Connection refused on WSL #2376

https://github.com/Microsoft/WSL/issues/2376

[4] Issue with WLS listening to TCP ports #1554

https://github.com/Microsoft/WSL/issues/1554

[5] 折腾 Bash on Windows 开启 SSHD 并开机启动

https://stray.love/itshou-zha/bash-on-windows-kai-qi-ssh-bing-kai-ji-qi-dong

[6] ubuntu16.04下安装pip

http://blog.csdn.net/weixin_37911283/article/details/70799481

[7] Win10 linux子系统下显示图形界面

http://blog.csdn.net/shuzfan/article/details/73658451