Главная » Хабрахабр » Опыт настройки и использования WSL (подсистемы Linux в Windows 10)

Опыт настройки и использования WSL (подсистемы Linux в Windows 10)

Я, после нескольких лет использования систем на ядре Linux, около полугода назад перешел к использованию Windows 10 на домашнем ПК. К написанию данной статьи меня побудил вопрос на Тостере, связанный с WSL. Я выбрал второе, и остался вполне доволен. Зависимость от терминала и Linux окружения в моей работе практически сразу привели меня к вопросу: или ставить виртуалку или попробовать WSL.

Под катом я расскажу как установить и настроить WSL, на какие я наткнулся проблемы и ограничения, как запускать Linux приложения из Windows и наоборот, а так же как интегрировать элементы окружения Xfce в окружение рабочего стола Windows.

WSL я поставил чуть ли не сразу после установки системы, поигрался несколько вечеров, понял, что продукт для моих задач годный, но хочется более привычный терминал и вообще некоторых удобств. Никогда не думал, что однажды вернусь на Windows, но повод попробовать мне дали стечения обстоятельств: жена, далекая от IT, дергала почти каждый раз, когда у нее возникала необходимость воспользоваться компом; проснулась ностальгия по одной игре, но она никак не хотела адекватно работать под wine; а тут еще мне подарили коробочную Windows 10 Pro.

Установка WSL и дистрибутива

Данный способ больше не работает (после выхода WSL в стабильный релиз). Сразу оговорюсь, в интернете можно найти описание установки с помощью выполнения команды lxrun /install в командной строке или консоли PowerShell. Насколько мне известно, сейчас WSL можно установить только из Microsoft Store вместе с предпочитаемым дистрибутивом.

04 — последний я и установил. Так же отмечу, что когда установку производил я, на выбор были доступны дистрибутивы OpenSUSE, SUSE Linux Enterprise и Ubuntu 16. 04, Debian 9 и Kali Linux, возможно появятся и другие дистрибутивы. Сейчас также доступны Ubuntu 18. Так же, часть проблем описанных в статье может быть уже исправлена. Действия по установке могут отличаться.

Установка пройдет быстро, так как скачает только эмулятор ядра Linux и утилиту для запуска подсистемы, которая окажется в системной папке в трех экземплярах: wsl.exe, bash.exe и ubuntu.exe (вместо ubuntu будет имя Вашего дистрибутива). Находим в магазине желаемый дистрибутив и устанавливаем. При первом же запуске нас попросят придумать логин и пароль для пользователя по умолчанию, а после произойдет непосредственно установка дистрибутива. Все они равнозначны и делают одно и то же — запускают собственный эмулятор терминала, в нем linux'овый bash работающий под эмулятором ядра. Безопасность не пострадает, кроме того при подготовке материалов к статье, в англоязычном туториале, я наткнулся на информацию, что новые версии WSL теперь делают пользователем по умолчанию root без пароля без лишних вопросов. В качестве пользователя по умолчанию указываем root без пароля — это потребуется для дальнейших шагов.

Далее первым делом стоит обновить зеркала apt на ближайшие. Дожидаемся установки. В комплекте только vi, я же больше предпочитаю nano, поэтому ставлю его: Для этого понадобится CLI текстовый редактор.

apt install nano

Отредактируем файл /etc/apt/sources.list: sudo вводить не требуется, так как мы уже под root'ом.

nano /etc/apt/sources.list

У меня лучше всего работают зеркала Яндекса, поэтому мой файл выглядит так:

deb http://mirror.yandex.ru/ubuntu/ xenial main universe restricted
deb-src http://mirror.yandex.ru/ubuntu/ xenial main universe restricted deb http://mirror.yandex.ru/ubuntu/ xenial-security main universe restricted
deb-src http://mirror.yandex.ru/ubuntu/ xenial-security main universe restricted deb http://mirror.yandex.ru/ubuntu/ xenial-updates main universe restricted
deb-src http://mirror.yandex.ru/ubuntu/ xenial-updates main universe restricted

Теперь можно обновить систему до актуального состояния: Нажимаем Ctrl+O для сохранения и Ctrl+X для выхода.

apt update && apt upgrade

В данной статье я назову его user1, Вы же можете задать привычное имя: После обновления можно создать нашего основного пользователя.

addgroup --gid 1000 user1
adduser --home /home/user1 --shell /bin/bash --uid 1000 -G user1,sudo user1

Далее переходим в папку юзера, зайдем под ним, установим пароль и отредактируем файл ~/.bashrc:

cd /home/user1
su user1
passwd
nano .bashrc

Мой базовый .bashrc выглядит так

# If not running interactively, don't do anything
case $- in *i*) ;; *) return;;
esac # don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth # append to the history file, don't overwrite it
shopt -s histappend # for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000 # check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize # If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar # make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" # set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot)
fi # set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in xterm|xterm-color|*-256color) color_prompt=yes;;
esac # uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fi
fi if [ "$color_prompt" = yes ]; then if [[ ${EUID} == 0 ]] ; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\h\[\033[01;34m\] \W \$\[\033[00m\] ' else PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\w \$\[\033[00m\] ' fi
else PS1='${debian_chroot:+($debian_chroot)}\u@\h \w \$ '
fi
unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*) PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h \w\a\]$PS1" ;;
*) ;;
esac # enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" alias ls='ls --color=auto' #alias dir='dir --color=auto' #alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto'
fi # colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' # some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF' # Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' # Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package. if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases
fi # enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi
fi

Все, подсистема готова к использованию… почти...

Установка X-сервера, Xfce и прочих GUI'шных приложений

Кроме того, данный эмулятор не умеет вкладки, а каждый его экземпляр запускает все в новом пространстве процессов, с отдельным init'ом (который кстати не заменить). Первая же проблема, на которую я натолкнулся — bash-completion в предлагаемом эмуляторе терминала работал, мягко говоря, некорректно. Мне захотелось нормальный эмулятор терминала, некоторых других GUI приложений, а так же панельку, чтоб это все быстро запускать.

На данный момент всех этих проблем нет. Когда я гуглил этот вопрос, я наткнулся на множество проблем, вроде необходимости перевода dbus на tcp протокол. В подсистеме нормально работают unix-domain-socket'ы и все спокойно общается через них.

Лично я использую для этих целей VcXsrv — порт X11 на Windows. Первым делом нам понадобится X-сервер, притом установленный в основную систему (в Windows). Официальный сайт указанный в about самой утилиты его сейчас не предоставляет, поэтому гуглим установщик и устанавливаем все по умолчанию.

Первым делом настроим русские локали: Пока идет установка возвращаемся в терминал WSL, командой exit выходим обратно в root'а.

locale-gen ru_RU
locale-gen ru_RU.UTF-8
update-locale

Можно конечно установить его целиком из мета-пакета, но большинство компонентов нам не понадобится, а модульная архитектура Xfce позволяет нам поставить только необходимое: Далее установим некоторые компоненты Xfce.

apt install -y xfce4-session xfce4-notifyd xfce4-appfinder xfce4-panel xfce4-quicklauncher-plugin xfce4-whiskermenu-plugin xfce4-xkb-plugin xfce4-settings xfce4-terminal xfce4-taskmanager mousepad

Для этого в основной системе создадим в удобном для нас месте папку, а в ней 3 файла для запуска: Запускать каждый раз окружение руками не очень удобно, поэтому я автоматизировал данный процесс.

  1. config.xlaunch — файл настроек для VcXsrv

    <?xml version="1.0" encoding="UTF-8"?>
    <XLaunch
    WindowMode="MultiWindow"
    ClientMode="NoClient"
    LocalClient="False"
    Display="0"
    LocalProgram="xcalc"
    RemoteProgram="xterm"
    RemotePassword=""
    PrivateKey=""
    RemoteHost=""
    RemoteUser=""
    XDMCPHost=""
    XDMCPBroadcast="False"
    XDMCPIndirect="False"
    Clipboard="True"
    ClipboardPrimary="True"
    ExtraParams=""
    Wgl="True"
    DisableAC="False"
    XDMCPTerminate="False"
    />

  2. Чтоб данное окно не мозолило глаза, неплохо его запускать скрытым. x-run.vbs — WSL всегда запускается со своим эмулятором терминала, если его закрыть — завершатся все его дочерние процессы. К счастью в Windows встроен интерпретатор VBScript, который позволяет это сделать в одну строчку:

    WScript.CreateObject("Shell.Application").ShellExecute "wsl", "cd /home/user1; DISPLAY=:0 LANG=ru_RU.UTF-8 su user1 -c xfce4-session", "", "open", 0

    Мы говорим VBscript выполнить приложение wsl с параметром cd /home/user1; DISPLAY=:0 LANG=ru_RU. Поясню, что здесь происходит. Самому wsl мы отдаем команду на выполнение: переход в папку пользователя, затем с установкой переменных окружения DISPLAY (дисплей X-сервера) и LANG (используемая локаль) мы запускаем xfce4-session от имени нашего пользователя user1 (благодаря команде su) UTF-8 su user1 -c xfce4-session, папка запуска нам не важна, поэтому пустая строка, действие open — запуск, 0 — скрытый режим.

  3. start.bat — batch файл для запуска, по желанию его можно засунуть в автозагрузку

    start config.xlaunch
    wscript x-run.vbs

Замечу, что здесь я наткнулся на еще одну проблему — панель прекрасно отображается поверх всех окон, но вот выделить себе место, как панель на рабочем столе Windows она не может. Далее можем запустить наш start.bat и настроить панель Xfce под себя. Если кто знает решение данной проблемы, поделитесь в комментариях.

Ну и под конец данной части, скриншот моего рабочего стола:

Взаимодействие окружения Windows и окружения подсистемы Linux

Не забываем, что по умолчанию запуск идет от root, поэтому стоит понижать привилегии через su, так же нужно не забывать передавать переменную окружения DISPLAY=:0 если приложению требуется X-сервер. Запускать Linux приложения напрямую из Windows можно через те же 3 команды — bash, wsl или ubuntu. Пример, посчитаем md5 для file.txt на диске D средствами Linux'овой md5sum: Так же нужно менять папку, из которой должно работать приложение, через cd внутри WSL.

wsl md5sum < d:\file.txt

UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs. Доступ к файловой системе Linux так же имеется, лежит она в %localappdata%\Packages\CanonicalGroupLimited. Думаю проблема в том, что Windows не умеет работать с правами и владельцами файловой системы Linux. Читать таким образом файлы можно, а вот писать — не желательно, можно поломать файловую систему.

Просто запускаем exe-шник и он выполнится в основной системе. Из Linux так же можно запускать Windows приложения.

Например диск D будет смонтирован в /mnt/d. Диски Windows монтируются в /mnt в соответствии со своими буквами в нижнем регистре. Можно делать на них симлинки. Из Linux можно свободно читать и писать файлы Windows. Права у таких файлов всегда будут 0777, а владельцем будет root.

Сервер поднятый в Linux будет доступен на localhost в Windows и наоборот. Сетевой стек у подсистемы общий с Windows. Выход во внешнюю сеть у Linux так же есть, в том числе можно слушать порты, если этого не запрещает фаервол.
ifconfig в Linux и ipconfig в Windows выдают одинаковую информацию о сетевых интерфейсах. Однако unix-domain-socket для Windows будет просто пустым файлом, работать с этим можно только внутри Linux.

Однако Linux увидит только свои процессы. Из диспетчера задач Windows можно спокойно прибить процесс внутри подсистемы Linux.

Особенности, ограничения и подводные камни

Это всего лишь прослойка-эмулятор, которая часть Linux-специфичных задач выполняет сама, а часть проксирует напрямую в ядро winNT. Ядро Linux в WSL не настоящее. Свое ядро собрать не получится, как и не получится подключить модули ядра (.ko, Kernel Object). Большая часть api в нем реализована, но не все.

У меня давно есть желание написать менеджер демонов на go, который бы работал с файлами юнитов system.d и предоставлял бы схожий интерфейс, да все руки не доходят. Init процесс у WSL тоже свой и заменить его, например, на system.d не выйдет.

Так же нельзя сделать mount из файла, mount вообще ничего кроме bind здесь, похоже, не умеет. Нет поддержки openFUSE, соответственно примонтировать виртуальную или удаленную файловую систему не получится.

Так же нет никакой возможности разбить файловую систему Linux на несколько разделов/дисков.

Все таки мы находимся в песочнице Windows, а не в полноценном Linux. Прямой доступ к железу практически отсутствует. Доступ к GPU — только через X-сервер, напрямую — никак, так что нейросети обучать придется в Windows. /dev и /sys заметно пустуют, в них лишь проц да виртуальные устройства.

В JS разработке столкнулся с тем, что electron.js отказался запускаться в WSL, пришлось дублировать окружение node.js в Windows.

Итоги

Виртуалка с Linux за полгода так и не понадобилась. Статья получилась довольно длинной, надеюсь, что она окажется еще и полезной.
WSL для меня лично оказался инструментом вполне юзабельным, решающим мои задачи fullstack backend разработчика. По общим ощущениям Windows+WSL намного функциональнее, чем Linux+Wine.

3, данный дистрибутив мне более симпатичен, чем Ubuntu, поэтому буду пробовать ставить. Пока писал статью, обнаружил, что в Microsoft Store появилась сборка WSL с Debian 9.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Всемирная организация здравоохранения официально признала существование игровой зависимости

В новую версию Международной классификации болезней, которую разрабатывает Всемирная организация здравоохранения, наряду с зависимостью от азартных игр вошла зависимость от онлайн- и офлайн-видеоигр как психическое расстройство. Отдельный идентификатор получили «опасные игры», которые увеличивают риск нанесения физического или психического вреда пациенту ...

[Перевод] Конструкция async/await в JavaScript: сильные стороны, подводные камни и особенности использования

Конструкция async/await появилась в стандарте ES7. Её можно считать замечательным улучшением в сфере асинхронного программирования на JavaScript. Она позволяет писать код, который выглядит как синхронный, но используется для решения асинхронных задач и не блокирует главный поток. Несмотря на то, что ...