Запуск графических приложений в Docker
Введение.
В основном, Docker привыкли использовать для запуска сервисов или процессов не предполагающих визуальной составляющей. Однако могут быть ситуации, когда в контейнере возникает необходимость открыть среду разработки и на месте продебажить один сервис или два сервиса, каждый в своем контейнере. В прошлой статье я писал, как запускать графические приложения в wsl, в текущей расскажу, как можно запустить разными способами в контейнере qtcreator. Аналогично можно будет поступить с любой средой разработки или программой.
Подготовка.
Включаем wsl на windows, если он отключен, говорим ему работать в режиме wsl2 — ровно так как описано в документации Майкрософт. Устанавливаем Docker.
Создаем для примера контейнер simpleimg_0 на основе ubuntu:18.04 и тут же запускаем его в интерактивном режиме:
docker run --name simpleimg_0 -it ubuntu:18.04 /bin/bash
Поставим mc по желанию для своего удобства:
apt update && apt install mc
Согласимся доставить все зависимости и получим:
Установка qtcreator.
Теперь устанавливаем qtcreator:
apt install qtcreator
Соглашаемся добавить 1,6 гб зависимостей:
При попытке запуска видим, что ничего не получиться. Теперь решим этот вопрос.
Запуск qtcreator.
Для того чтобы запустить графическое приложение из консоли линукс нужно на хостовой системе запустить х-сервер, в нашем случае это Vcxsrv.
Указываем при его запуске номер дисплея и запоминаем его:
На следующей оставляем все по умолчанию:
На последней снимаем средний флажок и устанавливаем последний:
Теперь видим значек х-сервера в трее около часов.
Теперь нам нужно узнать заветный адрес х-сервера, который нужно нам указать в контейнере. Для этого открываем консоль на хостовой ОС и запрашиваем информацию по сети:
ipconfig
Находим в выводе информацию по сети wsl:
Берем этот адрес и вносим его в переменную окружения DISPLAY в ОС контейнера, вспомнив про номер дисплея:
export DISPLAY=172.30.144.1:0
Повторно запускаем qtcreator и ура, он запускается в окне на заднем плане за консолью:
Заходим в настройки, проверяем, что компиляторы уже стоят:
Есть дебаггер, но нет Cmake и нет комплекта Qt.
Закрываем окно программы, переходим в консоль и доставляем Cmake:
apt install cmake
Проверяем и видим, что при следующем запуске Cmake уже подтянулся в настройках:
Любые зависимости таким образом можно самостоятельно доставить.
Посмотрим сколько весит наш контейнер для отладки — не очень то и много, т.к в несколько раз меньше чем виртуальная машина на основе убунты:
После того как мы завершили работу с контейнером, то запустить его снова в интерактивном режиме можно командой:
docker container start simpleimg_0 –i
Dockerfile, автоматизация.
Все то, что мы выше проделали руками, можно прописать в Dockerfile и создать все одной командой из консоли.
Qt в dockerfile можно установить несколькими способами — через apt install, через python утилиту aqt, через офиц. установщики qt.
Первый способ в ручном режиме разобрали в первой части статьи, предлагаю ниже разобрать установку через python. Создаем Dockerfile со следующим содержимым и переходим в консоли к нему на один уровень:
FROM ubuntu:18.04
RUN apt-get -y update && DEBIAN_FRONTEND=noninteractive apt-get -y install \
git \
cmake \
python3 \
python3-pip \
build-essential \
libdbus-1-3 \
libpulse-mainloop-glib0
RUN pip3 install aqtinstall
ARG QT=5.11.0
ARG QT_TOOLS=tools_qtcreator
ARG QT_HOST=linux
ARG QT_TARGET=desktop
ARG QT_ARCH=gcc_64
RUN aqt install-qt --outputdir /opt/qt ${QT_HOST} ${QT_TARGET} ${QT} ${QT_ARCH}
RUN aqt install-tool -O /opt/qtcreator ${QT_HOST} ${QT_TARGET} ${QT_TOOLS}
ENV PATH /opt/qt/${QT}/gcc_64/bin:/opt/qtcreator/Tools/QtCreator/bin:$PATH
ENV QT_PLUGIN_PATH /opt/qt/${QT}/gcc_64/plugins/
ENV QML_IMPORT_PATH /opt/qt/${QT}/gcc_64/qml/
ENV QML2_IMPORT_PATH /opt/qt/${QT}/gcc_64/qml/
Здесь мы сначала ставить необходимые зависимости для сборки, после этого ставим утилиту aqtinstall и выполняем ей две команды:
aqt install-qt — устанавливает библиотеки qt
aqt install-tool — устанавливает qtcreator.
Теперь создаем образ из этого файла:
docker build -f Dockerfile -t simpleimg_qtcr .
Запускаем, и вспоминаем, что нужно прописать актуальный адрес DISPLAY.
Минус этого способа — долгая установка, т.к все стягивается с офис.репозитория Qt. Документация для утилиты aqt.
Разберем еще один способ, лишенного этого недостатка — установка с использованием оффлайн-установщика с офиц. сайта. Качаем с офиц. репозитория установщик. Качаем скрипт не интерактивного установщика qt-installer-noninteractive.qs. Открываем последний скрипт в редакторе и кое-что правим.
Вписываем данные авторизации:
Controller.prototype.CredentialsPageCallback = function() {
var page = gui.pageWidgetByObjectName("CredentialsPage");
page.loginWidget.EmailLineEdit.setText("email");
page.loginWidget.PasswordLineEdit.setText("pass");
gui.clickButton(buttons.NextButton);
}
Вписываем куда установить фреймворк:
Controller.prototype.TargetDirectoryPageCallback = function()
{
//dev is the user in our docker image
gui.currentPageWidget().TargetDirectoryLineEdit.setText(installer.value("/opt/Qt5.11.0"));
gui.clickButton(buttons.NextButton);
}
В разделе Controller.prototype.ComponentSelectionPageCallback = function () указываем какие компоненты установить, а какие нет:
widget.deselectAll();
widget.selectComponent("qt.tools.qtcreator");
widget.selectComponent("qt.qt5.5110");
widget.selectComponent("qt.qt5.5110.gcc_64");
widget.deselectComponent("qt.qt5.5110.android_x86");
widget.deselectComponent("qt.qt5.5110.android_armv7");
widget.deselectComponent("qt.qt5.5110.android_armv7");
widget.deselectComponent("qt.qt5.5110.doc");
widget.deselectComponent("qt.qt5.5110.examples");
widget.deselectComponent("qt.qt5.5110.src");
На одном уровне с установщиком создаем dockerfile:
# run as:
# docker build -t offline_qtcr -f Dockerfile path_to_distrib
FROM ubuntu:18.04
MAINTAINER Chesnochenko
ARG DEBIAN_FRONTEND=noninteractive
RUN apt update && \
apt -o Dpkg::Options::="--force-confold" install -q -y mc build-essential \
mesa-common-dev libglu1-mesa-dev libdbus-1-dev x11-xkb-utils sudo curl \
libfontconfig1 libxrender1 libxi6 libgconf-2-4 libxcb-xinerama0 gdb cmake && \
apt clean && rm -rf /var/lib/apt/lists/*
RUN useradd -G users,video -ms /bin/bash user && \
echo 'user:12345678' | chpasswd -e && \
echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \
mkdir /run/user && \
chown user:user /run/user && \
apt update && apt install -y locales language-pack-ru libfontconfig1 && \
update-locale LANG=ru_RU.UTF-8 && \
echo 'LANG=ru_RU.UTF-8' >> /etc/default/locale && \
echo 'export LC_ALL=ru_RU.UTF-8' >> /home/user/.bashrc && \
echo 'export LANG=ru_RU.UTF-8' >> /home/user/.bashrc && \
locale-gen ru_RU.UTF-8 && \
apt install -y --reinstall locales && \
apt clean && rm -rf /var/lib/apt/lists/*
WORKDIR /tmp/
COPY qt-opensource-linux-x64-5.11.0.run .
COPY qt-installer-noninteractive.qs .
RUN chmod a+x qt-opensource-linux-x64-5.11.0.run \
&& chmod a+x qt-installer-noninteractive.qs
RUN curl https://www.openssl.org/source/openssl-1.0.2l.tar.gz | tar xz && cd openssl-1.0.2l && \
./config && make -j $(nproc) && make install && \
ln -sf /usr/local/ssl/bin/openssl `which openssl`
RUN ./qt-opensource-linux-x64-5.11.0.run -platform minimal --verbose --script ./qt-installer-noninteractive.qs
RUN rm -f qt-opensource-linux-x64-5.11.0.run qt-installer-noninteractive.qs
ENV DISPLAY=172.30.144.1:0
RUN echo 'export DISPLAY=172.30.144.1:0' >> /home/user/.bashrc
#RUN setxkbmap -model pc105 -layout us,ru -option grp:alt_shift_toggle
ARG QT=5.11.0
ARG QT_HOST=linux
ARG QT_TARGET=desktop
ARG QT_ARCH=gcc_64
ENV PATH /opt/Qt${QT}/${QT}/gcc_64/bin:/opt/Qt${QT}/Tools/QtCreator/bin/:$PATH
ENV QT_PLUGIN_PATH /opt/Qt${QT}/${QT}/gcc_64/plugins/
ENV QML_IMPORT_PATH /opt/Qt${QT}/${QT}/gcc_64/qml/
ENV QML2_IMPORT_PATH /opt/Qt${QT}/${QT}/gcc_64/qml/
ENV SHELL=/bin/bash
CMD bash
USER user
WORKDIR /home/user
CMD bash
В эту сборку добавили отдельного пользователя user, поддержку ввода на русском языке и возможность переключаться по alt+cntrl.
Два файла: qt-opensource-linux-x64–5.11.1.run и qt-installer-noninteractive.qs скопировали в контейнер, в папку /tmp. После установки подчистили за собой место. Сразу сохранили в контейнер информацию об адресе х-сервера. В случае, когда после перезагрузки компьютера адрес изменится, мы его установим через параметры запуска контейнера.
Создаем образ, в конце добавляем путь к каталогу где лежат дистрибутив qt и скрипт .qs:
docker build -t offline_qtcr -f Dockerfile d:\Distrib\Qt\single\qreator_linux\
Запускаем:
docker run --name offqtcont -it offline_qtcr /opt/Qt5.11.0/Tools/QtCreator/bin/qtcreator.sh
Запустился qtcreator:
Можем при запуске не указывать команду запуска самого qtcreator, тогда откроется консоль и в ней уже можем ввести путь до исполняемого файла.
Заключение.
Вы познакомились с тремя способами установить и запустить qtcreator в докере. Если вам не нужен сам qtcreator, то по такому же принципу можно в докере развернуть любое графическое приложение.