Осилил запуск GUI-приложений в Docker

16 марта 2015

Как мы совсем недавно уже выясняли, есть целый ряд проблем, которые можно решить запихиванием приложений в Docker-контейнеры, в том числе десктопных приложений. Никакой хакер не поломает вас через браузер. Настроенную систему можно быстро разложить у нового сотрудника или на своем новом ноуте. Всякий мусор, необходимый только одной программе, можно изолировать от остальной системы и снести одной командой. Никаких конфликтов зависимостей. Можно попытаться обновить программу, и если что-то в новой версии сломалось, просто перезапустить контейнер без коммита. Можно даже запускать браузер на одной машине, IDE на другой, а рулить всем этим с ноутбука, пробросив на него X11! Самое интересное, что запускать GUI приложения в Docker оказалось на удивление просто.

Примечание: В этой заметке используются наработки из поста Зачем нужен Docker и практика работы с ним. Вам может захотеться прочитать его прежде, чем следовать далее. Или перечитать, если успели подзабыть содержание.

Собственно, половина ответа уже содержится во введении. Если вы зайдете на VDS, где вы поднимали OpenVPN (технарей без своего VPN не существует!), по SSH с флагом -X, проверив при этом, что в /etc/ssh/sshd_config есть строчка X11Forwarding yes, скажете sudo apt-get install x11-apps, а затем xcalc, то у вас запустится калькулятор, как если бы он работал на локальной машине. При этом приложение работает на VDS, а ваш X-сервер просто используется для отрисовки окошек.

Docker, как мы выясняли, правильно использовать не по те-еретическому принципу «по приложению на контейнер, потому что так правильно™», а беря за основу baseimage. Это значит, что контейнер для нас мало чем отличается от VDS, и то же самое пробрасование X11 должно работать. Другой вопрос, что делать со звуком? Но эту проблему мы тоже скоро решим. А пока что давайте попробуем запустить в контейнере веб-браузер Chromium хотя бы без звука.

Запускаем контейнер, используя созданный ранее образ baseimage-ssh:

sudo docker run --dns 8.8.8.8 -p 127.0.0.1:222:22 \
  -d -i -t baseimage-ssh /sbin/my_init

Заходи в контейнер:

ssh -p 222 root@localhost

Пытаемся поставить x11-apps. В моем случае система внезапно сообщила, что слыхом не слыхивала о таких чудесах, поэтому пришлось скопировать файл /etc/apt/sources.list с хост-системы. После этого все получилось:

apt-get update
apt-get install x11-apps

Перезаходим по SSH с флагом -X, пытаемся запустить xcalc. Лично я увидел ошибку:

X11 forwarding request failed

Запуск SSH с флагом -v помог понять ее причину:

debug1: Remote: No xauth program; cannot forward with spoofing.

После установки xauth в гостевой системе все заработало. Пробуем кое-что посерьезнее:

apt-get install chromium-browser

Chromium у меня так просто тоже не стал запускаться, сказав:

Failed to move to new namespace: PID namespaces supported, Network name
space supported, but failed: errno = Operation not permitted

Беглое гугление привело меня в обсуждение в группах Google, благодаря которому, а также благодаря приведенным в нем ссылкам, я понял, что это такая багофича Chromium при работе во всяких изолированных окружениях, и что правильно запускать его так:

chromium-browser --no-sandbox --user-data-dir /root

Следуте однако отметить, что шрифты могут вас шокировать. Вам может захотеться сначала сказать:

apt-get install fonts-dejavu fonts-dejavu-core fonts-dejavu-extra \
  fonts-droid fonts-freefont-ttf fonts-kacst fonts-kacst-one \
  fonts-khmeros-core fonts-lao fonts-liberation fonts-lklug-sinhala \
  fonts-nanum fonts-opensymbol fonts-sil-abyssinica fonts-sil-gentium \
  fonts-sil-gentium-basic fonts-sil-padauk fonts-takao-pgothic \
  fonts-thai-tlwg fonts-tibetan-machine fonts-tlwg-garuda \
  fonts-tlwg-kinnari fonts-tlwg-loma fonts-tlwg-mono \
  fonts-tlwg-norasi fonts-tlwg-purisa fonts-tlwg-sawasdee \
  fonts-tlwg-typewriter fonts-tlwg-typist fonts-tlwg-typo \
  fonts-tlwg-umpush fonts-tlwg-waree

Теперь имеем Chromium, как Chromium. Так и не скажешь, что под Docker запущен.

На первый взгляд, в контейнере как-то без разницы, под рутом ты сидишь или нет. Но под рутом можно случайно удалить или испортить файлы, которые удалять или портить не хотелось, и придется откатываться к последнему коммиту, потеряв все другие сделанные изменения. Поэтому на всякий случай заведем нового пользователя:

adduser afiskon
usermod -G sudo afiskon

Под рутом говорим:

xauth list

Появится одна или несколько строчек вроде таких:

089a234b1567/unix:10 MIT-MAGIC-COOKIE-1 0489a12c89a67b567ef012cd...

Переключаемся на юзера:

su afiskon

Для каждой ранее уведенной строчечки говорим:

xauth add (строчечка)

В дальнейшем так далать не понадобится, все сохраняется в файлики.

Теперь говорим:

chromium-browser --no-sandbox

Для удобства можно прописать алиас в .bashrc. В целом все отлично работает, страницы грузятся быстро, даже видео на YouTube можно смотреть. Только звука пока что нет. Давайте же это исправим!

В гостевой системе:

sudo apt-get install libpulse0 pulseaudio

В хост-системе:

sudo apt-get install paprefs

Запускаем paprefs, во вкладке Network Server ставим галочку Enable network access to local sound devices, а также Don’t require authentication. Затем:

sudo service pulseaudio restart

В netstat -tuwpan должны увидеть, что процесс pulseaudio слушает порт 4713. Вам может захотеться добавить парочку правил фаервола, если по умолчанию вы разрешаете кому угодно стучатся на любые ваши порты. Если после выполнения приведенной выше команды ничего не изменилось, попробуйте:

pulseaudio -k
pulseaudio --start

У меня как-то не с первого раза получилось, но в итоге все заработало без необходимости перезагружать Ubuntu.

Теперь пробрасываем порт на гостевую систему:

ssh -X -p 222 -R3333:localhost:4713 root@localhost

В гостевой системе говорим:

PULSE_SERVER="tcp:localhost:3333" chromium-browser --no-sandbox

… и звук пошел! Самое главное теперь — не забудьте сделать commit!

Что интересно, контейнеры не обязательно должны быть запущены локально. Вы можете проделать все описанное выше на удаленной машине и это тоже будет работать, в том числе ssh -X на машину, а потом ssh -X в гостевую систему на этой машине успешно пробросит вам GUI. Учтите однако, что хорошо работать это будет только в локальной сети. Если вы в Москве, а сервер в Амстердаме, пользоваться проброшенным интерфейсом будет нереально, я проверял. Возможно, тут имеет смысл попробовать VNC.

Как оказалось, моя любимая IntelliJ IDEA таким образом также прекрасно запускается. Похоже, можно без проблем запускать в Docker-контейнерах практически любые приложения, кроме, возможно, чего-то вроде игр. Если вдруг кому-то интересно, размер экспортированного образа с IDE, компилятором Scala, SBT, а также кучей джавных/скальных библиотек, скопированных с хост-системы, получился 9 Гб без сжатия и 5.4 Гб после сжатия. Накладных расходов на виртуализацию замечено не было, я даже несколько раз сравнивал скорость компиляции проекта в хост-системе и в Docker — никакой разницы.

Ссылки по теме:

А какие GUI-приложения вы пробовали запускать в Docker и с какими проблемами при этом столкнулись?

Дополнение: Контейнерная виртуализация при помощи OpenVZ

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.