- PVSM.RU - https://www.pvsm.ru -
Привет!
В этой статье хочется поделится с вами настройкой девелоперского окружения под разработку скриптов на Python и запуск их в изолированном окружении, практически за пару кликов в редакторе VS Code [1].
В качестве изолированного окружения будет рассмотрена первичная настройка и создание контейнера на базе LXC [2] под управлением ОС Ubuntu 17.10. Почему не Docker? Сложно ответить, выдать какие-то аргументы. От части концепция виртуализации ОС субъективно ближе по духу, чем виртуализация процессов, но принцип который здесь будет изложен, с некоторыми поправками, подойдет к запуску кода в Docker-контейнерах.
Перед установкой LXD необходимо определиться, какой тип backend хранилища для контейнеров будет использоваться. Позже изменить будет нельзя. Доступно несколько вариантов: ZFS, btrfs, LVM или файловая система хоста. Для сравнения возможностей доступна таблица сравнения [16] в официальной документации. Предлагаю выбрать ZFS который позволит в будущем легко создавать COW [17] (copy-on-write) снимки (snapshots) контейнеров. Установим в системе пакет утилит работы с ZFS:
$ sudo apt install zfsutils-linux
Здесь нет сложностей, пакет входит в стандартную поставку системы, поэтому командуем в консоли:
$ sudo apt install lxd
После установки LXD, текущий пользователь будет добавлен в системную группу lxd, но чтобы продолжить настройку с необходимыми привелегиями в системе, необходимо сейчас выполнить переактивацию сессии пользователя. Просто выйдите и заново войдите в сессию вашего Desktop Meneger’а или перезагрузитесь полностью. Проверить, состоит ли текущая сессия пользователя в группе lxd можно через команду id:
$ id
uid=1000(user1) gid=1000(user1) groups=1000(user1),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),118(lpadmin),128(sambashare),129(lxd)
Если вы видите группу lxd, то всё впорядке, можно продолжать дальше.
Инициализация LXD проходит в интерактивном режиме от имени текущего пользователя который состоит в группе lxd. Выполните команду и следуйте инструкциям и комментариям представленным ниже:
$ lxd init
# Здесь нас спрашивают, хотим ли мы сейчас создать пул хранилища? Не путать с пулом ZFS!
# По умолчанию ответ <yes>, нажимаем <ENTER>
Do you want to configure a new storage pool (yes/no) [default=yes]?
# Задаем желаемое имя для пула хранилища и нажимаем <ENTER>
Name of the new storage pool [default=default]: lxdpool
# Здесь нам нужно определить тип пула хранилища, выбираем ZFS
Name of the storage backend to use (dir, lvm, zfs) [default=zfs]: zfs
# Создать сейчас ZFS пул? Т.е. в пуле хранилища lxdpool создастся ZFS пул.
# Соглашаемся и нажимаем <ENTER>
Create a new ZFS pool (yes/no) [default=yes]?
# Здесь спрашивают, хотим ли мы использовать существующее блочное устройство?
# Например, это может быть ранее нами подготовленный файл созданный через утилиту dd
# или это может быть отдельный жеский диск или партиция.
# По умолчанию ответ равен <no>, жмем <ENTER>
Would you like to use an existing block device (yes/no) [default=no]?
# Каким размером создать loop-устройство (zfs pool)?
# Указываем число в GB, минимально 1GB
Size in GB of the new loop device (1GB minimum) [default=15GB]: 5
# Желаете сделать LXD доступным по сети?
# По умолчанию LXD не слушает сеть, единственный способ говорить с ним - через локальный unix сокет /var/lib/lxd/unix.socket
# Отвечаем <no>, жмем <ENTER>:
Would you like LXD to be available over the network (yes/no) [default=no]?
# Желаете чтобы образы в локальном репозитории автоматически обновлялись?
Would you like stale cached images to be updated automatically (yes/no) [default=yes]? no
# Желаете сейчас создать сетевой мост? Отвечаем <no>, мы его позже создадим и настроим
Would you like to create a new network bridge (yes/no) [default=yes]? no
# LXD has been successfully configured.
Если сеть не настроить сейчас, а приступить к созданию контейнеров, то при их создании мы получим предупреждение, что контейнер не присоединен ни к одной из сетей. Это не будет являться ошибкой, просто к ним не будет сетевого доступа через интерфейсы. В начале можно создать необходимое количество контейнеров, а затем сконфигурировать сеть и присоединить к ней контейнеры с помощью команды lxc network attach. Сейчас нам необходимо определится, какой тип сети строить. Доступно несколько вариантов [18]построения LXC-сетей, мы же выберем вариант bridge (простой программный коммутатор между хостом и контейнерами) и построим сеть на его основе.
При создании сетевого моста мы можем сразу задать свойства после указания его имени или положиться на автоконфигурацию которая задаст подсеть IPv4 и IPv6 случайным выбором. По умолчанию, параметр равен ipv4.nat=false и по каким-то причинам пакеты транзитного трафика с контейнеров не будут маршрутизироваться дальше хоста на другие локальные сегменты сети даже тогда, когда в ядре хоста явно включить IP forwarding. Видимо NAT в LXD больше чем транслятор адресов с локальных сегментов сети в глобальные, так как при активации этого параметра также активируется IP forwarding на хосте, поэтому мы явно его включим:
$ lxc network create lxdbr0 ipv6.address=none ipv4.address=10.0.3.1/24 ipv4.nat=true
Network lxdbr0 created
$ lxc network list
+--------+----------+---------+-------------+---------+
| NAME | TYPE | MANAGED | DESCRIPTION | USED BY |
+--------+----------+---------+-------------+---------+
| ens33 | physical | NO | | 0 |
+--------+----------+---------+-------------+---------+
| lxdbr0 | bridge | YES | | 0 |
+--------+----------+---------+-------------+---------+
Конфигурация контейнера условно делится на два уровня, глобальная и локальная. Глобальная конфигурация задается в профиле конфигурации который присоединяется к конкретному контейнеру или группе контейнеров, а локальная конфигурация применяется только для конкретного контейнера. Т.е., все установки в профиле наследуются контейнером, а локальные установки имеют приоритет над профилем. К одному контейнеру можно присоединить несколько профилей.
Создадим профиль LXD для того, чтобы во вновь создаваемых контейнерах по умолчанию был интерфейс типа nic который будет слинкован с коммутатором (сетевым мостом) lxdbr0 на хосте:
$ lxc profile copy default network0
$ lxc profile device add network0 eth0 nic parent=lxdbr0 nictype=bridged
Для примера создадим контейнер и назовем его pytest, который будет доступен из хоста по этому имени. Выполним команду launch которая загрузит образ из репозитория ubuntu: версию 17.10 и архитектуры amd64 и из этого образа создаст контейнер. Дополнительно, опцией укажем, что этому контейнеру необходимо задать конфигурацию из профиля network0:
$ lxc launch ubuntu:17.10/amd64 --profile network0 pytest
Далее пойдет загрузка из сети образа. Немного подождем, а чуть позже можем увидеть доступные контейнеры в системе и их состояние:
$ lxc list
+--------+---------+------------------+------+------------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+--------+---------+------------------+------+------------+-----------+
| pytest | RUNNING | 10.0.3.13 (eth0) | | PERSISTENT | 0 |
+--------+---------+------------------+------+------------+-----------+
Здесь мы с вами установим необходимое ПО в контейнере. Запустим внутри контейнера пакетный менеджер который актуализирует систему:
$ lxc exec pytest -- /bin/bash -c 'apt update && apt upgrade -y'
Следом, установим менеджер пакетов pip (Python package installer), а также python-модуль ptvsd (Visual Studio remote debugging server for Python). Модуль ptvsd необходимо установить обязательно версии 3.0.0, на более свежих версиях (актуальная 3.2.1.0) я получил ошибку, которая обозначена в issue на github.com [19]. Автор расширения Python к VS Code которое взаимодействует с ptvsd как временное решение рекомендует использовать версию 3.0.0.
$ lxc exec pytest -- /bin/bash -c 'apt install python3-pip -y'
$ lxc exec pytest -- /bin/bash -c 'pip3 install ptvsd==3.0.0'
По части LXD мы с вами завершили настройку.
Варианты установки приложения описаны на официальной страничке по адресу code.visualstudio.com/docs/setup/linux [20], мы же немного модифицируем команды:
$ cd ~
$ wget -c https://packages.microsoft.com/keys/microsoft.asc
$ cat microsoft.asc | gpg --dearmor > microsoft.gpg
$ sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
$ sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list'
$ sudo apt update
$ sudo apt install code
После выполнения у нас в системе появится VS Code последней версии из репозитория Microsoft.
P.S. На момент написания статьи вышла новая версия 1.18.0 в которой, в стабильную сборку вошли на мой взгляд одни из наиболее ожидаемых (2 года) сообществом возможности «Multi-root workspaces» и «Git indicators in the Explorer» Обо всех изменениях можно почитать на этой страничке [21].
Приступим к установке расширений. Если вы впервые устанавливаете VS Code, например, после использования Atom [22] (как автор), то рекомендую обратить внимание на расширения в списке ниже, а для достижения цели этой статьи будет достаточно установить только Python и Code Runner. Расширения устанавливаются с marketplace'а в левой части редактора.
Следующие настройки необязательны, они прямо не относятся к запуску Python скриптов в контейнерах, но это приблизит вас к тому, если хотите чтобы было визуально как в Atom'е.
В открытом редакторе откройте настроки редактора: file->Preferences->Settings. В открывшемся окне, справа, в USER_SETTINGS внесите следующие изменения и сохраните (Ctrl + S):
{
// Общие настройки
"telemetry.enableTelemetry": false,
"editor.fontFamily": "Menlo, Consolas, 'DejaVu Sans Mono', monospace",
"editor.lineHeight": 21,
"editor.minimap.enabled": true,
"editor.minimap.showSlider": "always",
"editor.minimap.renderCharacters": false,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"explorer.openEditors.visible": 0,
// Настройка интегрированного терминала:
"terminal.integrated.lineHeight": 1.25,
"terminal.integrated.scrollback": 2000,
// Настройка темы:
"workbench.iconTheme": "file-icons",
"workbench.colorTheme": "One Dark Pro",
"workbench.colorCustomizations": {
// https://code.visualstudio.com/docs/getstarted/theme-color-reference
"editor.lineHighlightBackground": "#2C323C"
},
// Настройка подсветки скобок
"editor.matchBrackets": false,
"subtleBrackets.styles": {
"global": {
"color": "#61afef",
"borderColor": "#61afef",
"borderWidth": "1px",
"borderStyle": "none none solid none"
}
},
// Python
"python.pythonPath": "python3",
// Настройка кодо-запускателя:
"code-runner.executorMap": {
"python": "python3 $fileName"
}
}
Мы с вами уже проделали большую работу и настало время заключительной части. Сейчас у нас почти всё готово для запуска скриптов в контейнере.
Создадим каталог projects, например, по адресу /home/user1/projects. В нём будут располагаться наши будущие python-проекты. Этот каталог мы слинкуем с контейнером, т.е., в контейнере создадим устройство типа disk и свяжим этот каталог с внутренним /mnt/hostfs. Выполняем следующие команды:
$ mkdir ~/projects
$ lxc config device add pytest hostfs disk path=/mnt/hostfs source=/home/user1/projects/
Если мы локально создадим каталог или файл в каталоге /home/user1/projects, то он немедленно отразится в контейнере по адресу /mnt/hostfs. Убедиться в этом можно запустив интерактивно оболочку BASH в контейнере и выполнив команду ls:
$ lxc exec pytest -- /bin/bash
$ ls -l /mnt/hostfs/
И так, сейчас мы можем вернуться в наш редактор, если вы его закрыли, то вновь откройте. Нажмите в меню File -> New File. Создастся новая вкладка в которую нужно внести следующий python-код, который мы будем запускать в контейнере. Сохраните его в каталоге /home/user1/projects/pytest/test.py, а затем файл (вкладку) можно закрыть.
import os
#### BEGIN. Visual Studio remote debugging server for Python
# import ptvsd
# print('Waiting connection on port 3000')
# ptvsd.enable_attach('my_secret', address=('0.0.0.0', 3000))
# ptvsd.wait_for_attach()
# ptvsd.break_into_debugger()
#### END. Visual Studio remote debugging server for Python
with open('/etc/lsb-release') as f:
lsb_release = f.readlines()
info = {
'HOSTNAME': os.uname().nodename,
'DISTRIB': lsb_release[3][21:-2],
'USER': os.environ['USER'],
'LOGNAME': os.environ['LOGNAME'],
'HOME': os.environ['HOME'],
'PWD': os.environ['PWD']
}
print(info)
VS Code «скажет», что у вас не установлен модуль pylint, но он нам сейчас не нужен, вы его можете установить позже, самостоятельно, через менеджер модулей pip. Сейчас нужно открыть workspace в VS Code, для этого слева в File Explorer нажмите кнопку Open Folder и выберите каталог /home/user1/projects/:
VS Code переинициализируется, полностью закроются все окна и откроется workspace в котором будет виден файл test.py. Откройте его, дважды кликнув на имя слева в File Explorer VS Code.
Вызовите настройки workspace'а, нажав в меню File -> Preferences -> Setting, далее в окне справа вверху вместо USER_SETTINGS выберите из выпадающего списка WORKSPACE_SETTINGS:
Внесите и сохраните следующие настройки так, чтобы у вас получилось вот так:
{
"code-runner.executorMap": {
// Запуск от имени пользователя root:
// "python": "lxc exec pytest -- /bin/bash -c 'python3 /mnt/hostfs/pytest/$fileName'"
// Запуск от имени встроенного в контейнер пользователя ubuntu:
"python": "lxc exec pytest -- /bin/bash -c 'su -l ubuntu -c "python3 /mnt/hostfs/pytest/$fileName"'"
},
"code-runner.runInTerminal": true
}
В файловом эксплорере вы можете обнаружить файл settings.json в каталоге .vscode, там сохраняются настройки воркспейса (текущего проекта).
Вернитесь к открытому файлу test.py и запустите его на исполнение через команду из контекстного меню Run code:
В выводе интегрированного терминала вы увидите информацию в которой можно убедится, что код исполнялся на удаленной машине (контейнере). Теперь, всякий раз, когда нужно запустить проект в контейнере, достаточно внести настройки в WORKSPACE_SETTINGS или создать файл .vscode/settings.json относительно каждого проекта и затем немного подправить пути в настройках.
Раскомментируйте строчки в файле test.py и сохраните этот файл:
#### BEGIN. Visual Studio remote debugging server for Python
import ptvsd
print('Waiting connection on port 3000')
ptvsd.enable_attach('my_secret', address=('0.0.0.0', 3000))
ptvsd.wait_for_attach()
ptvsd.break_into_debugger()
#### END. Visual Studio remote debugging server for Python
Всякий раз, когда есть необходимость удаленного дебага, эти строчки кода необходимо вставить в тот файл, который запускается на исполнение. Модуль ptvsd на стороне контейнера открывает порт 3000 и ожидает подключение внешнего дебаггера. При желании, вы можете сконфигурировать ptvsd на свой лад.
Запустите код, вызвав контекстное меню Run Code. В интегрированном терминале вы увидите сообщение, что скрипт ожидает подключения на порту 3000. Перейдите в дебаггер, и создайте новую конфигурацию для этого проекта:
У вас откроется файл launch.json на редактирование в котором уже будут предустановки. Внесите в него следующий блок кода:
{
"name": "Python LXC",
"type": "python",
"request": "attach",
"localRoot": "${workspaceRoot}",
"remoteRoot": "/mnt/hostfs/pytest",
"host": "pytest",
"port": 3000,
"secret": "my_secret"
}
Сохраните его, он появится в каталоге .vscode/launch.json рядом с файлом setting.json. Затем, выберите слева в низподающем списке Python LXC, это та конфигурация дебаггера, которую мы только что внесли:
Нажмите Start Debugging. В окне с файлом test.py вы увидите работающий дебагер и подтверждение, что код запущен удаленно:
На этом всё. Настройка завершена. Всё что нужно в дальнейшем для нового проекта python, это сконфигурировать два конфиг-файла .vscode/settings.json и .vscode/launche.json. Если у вас есть вопросы по теме, прошу задавать в комментариях. Спасибо за внимание, успешных вам проектов!
Автор: microcoder
Источник [32]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/267951
Ссылки в тексте:
[1] VS Code: https://ru.wikipedia.org/wiki/Visual_Studio_Code
[2] LXC: https://ru.wikipedia.org/wiki/LXC
[3] virtualenv: https://virtualenv.pypa.io/en/stable/
[4] Выбор backend хранилища: #2
[5] Установка пакета LXD: #3
[6] Инициализация LXD: #4
[7] Конфигурация сети LXС: #5
[8] Создание профиля конфигурации контейнера: #6
[9] Создание контейнера: #7
[10] Установка ПО в контейнере: #8
[11] Установка VS Code и расширений: #9
[12] Настройка конфигурации VS Code: #10
[13] Линковка каталогов Хост <-> Контейнер: #11
[14] Настройка VS Code на запуск скриптов в контейнере: #12
[15] Удаленный Debug в VS Code: #13
[16] таблица сравнения: https://github.com/lxc/lxd/blob/master/doc/storage.md#storage-backends-and-supported-functions
[17] COW: https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8
[18] несколько вариантов : https://github.com/lxc/lxd/blob/master/doc/containers.md#type-nic
[19] issue на github.com: https://github.com/DonJayamanne/pythonVSCode/issues/981#issuecomment-342850698
[20] code.visualstudio.com/docs/setup/linux: https://code.visualstudio.com/docs/setup/linux
[21] этой страничке: https://code.visualstudio.com/updates/v1_18
[22] Atom: https://atom.io/
[23] IntelliSense for CSS class names: https://marketplace.visualstudio.com/items?itemName=Zignd.html-css-class-completion
[24] Python: https://marketplace.visualstudio.com/items?itemName=donjayamanne.python
[25] Jinja: https://marketplace.visualstudio.com/items?itemName=wholroyd.jinja
[26] Django Template: https://marketplace.visualstudio.com/items?itemName=bibhasdn.django-html
[27] file-icons: https://marketplace.visualstudio.com/items?itemName=file-icons.file-icons
[28] One Dark Pro: https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme
[29] Subtle Match Brackets: https://marketplace.visualstudio.com/items?itemName=rafamel.subtle-brackets
[30] TODO Highlight: https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight
[31] Code Runner: https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner
[32] Источник: https://habrahabr.ru/post/342080/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.