Привет, Хабр!
В этой статье хочется поделится с вами настройкой девелоперского окружения под разработку скриптов на Python и запуск их в изолированном окружении, практически за пару кликов в редакторе VS Code.
В качестве изолированного окружения будет рассмотрена первичная настройка и создание контейнера на базе LXC под управлением ОС Ubuntu 17.10. Почему не Docker? Сложно ответить, выдать какие-то аргументы. От части концепция виртуализации ОС субъективно ближе по духу, чем виртуализация процессов, но принцип который здесь будет изложен, с некоторыми поправками, подойдет к запуску кода в Docker-контейнерах.

Перед установкой LXD необходимо определиться, какой тип backend хранилища для контейнеров будет использоваться. Позже изменить будет нельзя. Доступно несколько вариантов: ZFS, btrfs, LVM или файловая система хоста. Для сравнения возможностей доступна таблица сравнения в официальной документации. Предлагаю выбрать ZFS который позволит в будущем легко создавать COW (copy-on-write) снимки (snapshots) контейнеров. Установим в системе пакет утилит работы с ZFS:
Здесь нет сложностей, пакет входит в стандартную поставку системы, поэтому командуем в консоли:
После установки LXD, текущий пользователь будет добавлен в системную группу lxd, но чтобы продолжить настройку с необходимыми привелегиями в системе, необходимо сейчас выполнить переактивацию сессии пользователя. Просто выйдите и заново войдите в сессию вашего Desktop Manager-а или перезагрузитесь полностью. Проверить, состоит ли текущая сессия пользователя в группе lxd можно через команду id:
Если вы видите группу lxd, то всё впорядке, можно продолжать дальше.
Инициализация LXD проходит в интерактивном режиме от имени текущего пользователя который состоит в группе lxd. Выполните команду и следуйте инструкциям и комментариям представленным ниже:
Если сеть не настроить сейчас, а приступить к созданию контейнеров, то при их создании мы получим предупреждение, что контейнер не присоединен ни к одной из сетей. Это не будет являться ошибкой, просто к ним не будет сетевого доступа через интерфейсы. В начале можно создать необходимое количество контейнеров, а затем сконфигурировать сеть и присоединить к ней контейнеры с помощью команды lxc network attach. Сейчас нам необходимо определится, какой тип сети строить. Доступно несколько вариантов построения LXC-сетей, мы же выберем вариант bridge (простой программный коммутатор между хостом и контейнерами) и построим сеть на его основе.
При создании сетевого моста мы можем сразу задать свойства после указания его имени или положиться на автоконфигурацию которая задаст подсеть IPv4 и IPv6 случайным выбором. По умолчанию, параметр равен ipv4.nat=false и по каким-то причинам пакеты транзитного трафика с контейнеров не будут маршрутизироваться дальше хоста на другие локальные сегменты сети даже тогда, когда в ядре хоста явно включить IP forwarding. Видимо NAT в LXD больше чем транслятор адресов с локальных сегментов сети в глобальные, так как при активации этого параметра также активируется IP forwarding на хосте, поэтому мы явно его включим:
Конфигурация контейнера условно делится на два уровня, глобальная и локальная. Глобальная конфигурация задается в профиле конфигурации который присоединяется к конкретному контейнеру или группе контейнеров, а локальная конфигурация применяется только для конкретного контейнера. Т.е., все установки в профиле наследуются контейнером, а локальные установки имеют приоритет над профилем. К одному контейнеру можно присоединить несколько профилей.
Создадим профиль LXD для того, чтобы во вновь создаваемых контейнерах по умолчанию был интерфейс типа nic который будет слинкован с коммутатором (сетевым мостом) lxdbr0 на хосте:
Для примера создадим контейнер и назовем его pytest, который будет доступен из хоста по этому имени. Выполним команду launch которая загрузит образ из репозитория ubuntu: версию 17.10 и архитектуры amd64 и из этого образа создаст контейнер. Дополнительно, опцией укажем, что этому контейнеру необходимо задать конфигурацию из профиля network0:
Далее пойдет загрузка из сети образа. Немного подождем, а чуть позже можем увидеть доступные контейнеры в системе и их состояние:
Здесь мы с вами установим необходимое ПО в контейнере. Запустим внутри контейнера пакетный менеджер который актуализирует систему:
Следом, установим менеджер пакетов pip (Python package installer), а также python-модуль ptvsd (Visual Studio remote debugging server for Python). Модуль ptvsd необходимо установить обязательно версии 3.0.0, на более свежих версиях (актуальная 3.2.1.0) я получил ошибку, которая обозначена в issue на github.com. Автор расширения Python к VS Code которое взаимодействует с ptvsd как временное решение рекомендует использовать версию 3.0.0.
По части LXD мы с вами завершили настройку.
Варианты установки приложения описаны на официальной страничке по адресу code.visualstudio.com/docs/setup/linux, мы же немного модифицируем команды:
После выполнения у нас в системе появится VS Code последней версии из репозитория Microsoft.
P.S. На момент написания статьи вышла новая версия 1.18.0 в которой, в стабильную сборку вошли на мой взгляд одни из наиболее ожидаемых (2 года) сообществом возможности «Multi-root workspaces» и «Git indicators in the Explorer» Обо всех изменениях можно почитать на этой страничке.
Приступим к установке расширений. Если вы впервые устанавливаете VS Code, например, после использования Atom (как автор), то рекомендую обратить внимание на расширения в списке ниже, а для достижения цели этой статьи будет достаточно установить только Python и Code Runner. Расширения устанавливаются с marketplace'а в левой части редактора.
Следующие настройки необязательны, они прямо не относятся к запуску Python скриптов в контейнерах, но это приблизит вас к тому, если хотите чтобы было визуально как в Atom'е.
В открытом редакторе откройте настроки редактора: file->Preferences->Settings. В открывшемся окне, справа, в USER_SETTINGS внесите следующие изменения и сохраните (Ctrl + S):
Мы с вами уже проделали большую работу и настало время заключительной части. Сейчас у нас почти всё готово для запуска скриптов в контейнере.
Создадим каталог projects, например, по адресу /home/user1/projects. В нём будут располагаться наши будущие python-проекты. Этот каталог мы слинкуем с контейнером, т.е., в контейнере создадим устройство типа disk и свяжим этот каталог с внутренним /mnt/hostfs. Выполняем следующие команды:
Если мы локально создадим каталог или файл в каталоге /home/user1/projects, то он немедленно отразится в контейнере по адресу /mnt/hostfs. Убедиться в этом можно запустив интерактивно оболочку BASH в контейнере и выполнив команду ls:
Вы увидите, что файлы и каталоги в контейнере будут доступны только для чтения и будут иметь UID:GID равным nobody:nogroup. Этого достаточно для запуска скриптов, но если вам необходимо сделать так, чтобы файлы и каталоги в контейнере были доступными на запись, прочтите главу "Direct user/group mapping" в этой статье.
И так, сейчас мы можем вернуться в наш редактор, если вы его закрыли, то вновь откройте. Нажмите в меню File -> New File. Создастся новая вкладка в которую нужно внести следующий python-код, который мы будем запускать в контейнере. Сохраните его в каталоге /home/user1/projects/pytest/test.py, а затем файл (вкладку) можно закрыть.
VS Code «скажет», что у вас не установлен модуль pylint, но он нам сейчас не нужен, вы его можете установить позже, самостоятельно, через менеджер модулей pip. Сейчас нужно открыть workspace в VS Code, для этого слева в File Explorer нажмите кнопку Open Folder и выберите каталог /home/user1/projects/pytest/:

VS Code переинициализируется, полностью закроются все окна и откроется workspace в котором будет виден файл test.py. Откройте его, дважды кликнув на имя слева в File Explorer VS Code.
Вызовите настройки workspace'а, нажав в меню File -> Preferences -> Setting, далее в окне справа вверху вместо USER_SETTINGS выберите из выпадающего списка WORKSPACE_SETTINGS:

Внесите и сохраните следующие настройки так, чтобы у вас получилось вот так:
В файловом эксплорере вы можете обнаружить файл settings.json в каталоге .vscode, там сохраняются настройки воркспейса (текущего проекта).
Вернитесь к открытому файлу test.py и запустите его на исполнение через команду из контекстного меню Run code:

В выводе интегрированного терминала вы увидите информацию в которой можно убедится, что код исполнялся на удаленной машине (контейнере). Теперь, всякий раз, когда нужно запустить проект в контейнере, достаточно внести настройки в WORKSPACE_SETTINGS или создать файл .vscode/settings.json относительно каждого проекта и затем немного подправить пути в настройках.
Раскомментируйте строчки в файле test.py и сохраните этот файл:
Всякий раз, когда есть необходимость удаленного дебага, эти строчки кода необходимо вставить в тот файл, который запускается на исполнение. Модуль ptvsd на стороне контейнера открывает порт 3000 и ожидает подключение внешнего дебаггера. При желании, вы можете сконфигурировать ptvsd на свой лад.
Запустите код, вызвав контекстное меню Run Code. В интегрированном терминале вы увидите сообщение, что скрипт ожидает подключения на порту 3000. Перейдите в дебаггер, и создайте новую конфигурацию для этого проекта:

У вас откроется файл launch.json на редактирование в котором уже будут предустановки. Внесите в него следующий блок кода:
Сохраните его, он появится в каталоге .vscode/launch.json рядом с файлом setting.json. Затем, выберите слева в низподающем списке Python LXC, это та конфигурация дебаггера, которую мы только что внесли:

Нажмите Start Debugging. В окне с файлом test.py вы увидите работающий дебагер и подтверждение, что код запущен удаленно:

На этом всё. Настройка завершена. Всё что нужно в дальнейшем для нового проекта python, это сконфигурировать два конфиг-файла .vscode/settings.json и .vscode/launche.json. Если у вас есть вопросы по теме, прошу задавать в комментариях. Спасибо за внимание, успешных вам проектов!
UPD от 10.11.2017 21:35 MSK.
В комментариях, пользователь SirEdvin задал вопрос о возможности автодополнения (или IntelliSense в терминах Microsoft) в редакторе тех python-модулей, которые установлены только в контейнере, т.е., этих модулей нет на локальной машине на которой запускается VS Code.
В статье этот момент был упущен, поэтому с радостью дополняю небольшой главою:
Например, в вашем проекте используется модуль, который не поставляется в коробке по умолчанию с python, и вы этот модуль установили только в контейнере. Как же сделать так, чтобы VS Code «понимал», автодополнял, выводил подсказки в редакторе при этом не устанавливая модуль на хосте, а получал из модуля в контейнере?
Для решения этого вопроса, откройте настройки WORKSPACE_SETTINGS по адресу: ВАШ_ПУТЬ_К_ПРОЕКТУ/.vscode/settings.json и добавьте параметр python.autoComplete.extraPaths, а в качестве ключей укажите список каталогов контейнера в которых находятся python модули.
Например, наш контейнер доступен в файловой системе хоста по адресу: /var/lib/lxd/containers/pytest/rootfs/. Это корневая файловая система контейнера pytest. Зная, где Python устанавливает внешние библиотеки, мы с легкостью можем добавить этот путь, чтобы получить полный путь к внешним библиотекам. Для таких модулей как numpy полный путь будет: /var/lib/lxd/containers/pytest/rootfs/usr/local/lib/python3.6/dist-packages. Этот путь мы добавим в настройку python.autoComplete.extraPaths, вот так:

Сохраните настройки и вернитесь к вашему проекту. Попробуйте импортировать модуль numpy и вызвать автодополнение клавишей CTRL + SPACE. У вас должно получиться так как на экране:

Если сразу не получается, не расстраивайтесь, VS Code кеширует результаты и это сразу может не заработать, попробуйте закрыть-открыть редактор, поиграться с клавишами CTRL+SPACE после ключевого слова from… import.
На этом всё :)
В этой статье хочется поделится с вами настройкой девелоперского окружения под разработку скриптов на Python и запуск их в изолированном окружении, практически за пару кликов в редакторе VS Code.
В качестве изолированного окружения будет рассмотрена первичная настройка и создание контейнера на базе LXC под управлением ОС Ubuntu 17.10. Почему не Docker? Сложно ответить, выдать какие-то аргументы. От части концепция виртуализации ОС субъективно ближе по духу, чем виртуализация процессов, но принцип который здесь будет изложен, с некоторыми поправками, подойдет к запуску кода в Docker-контейнерах.

Что вы получите?
- Научитесь запускать в один клик python-скрипты в контейнере, а также удаленный debug из VS Code
- Узнаете как установить LXD, настроить сеть и запустить первый контейнер
- Ознакомитесь с установкой и настройко�� редактора исходного кода VS Code, набором расширений которые позволят комфортно писать и отлаживать код.
Чего здесь не будет?
- Не будет полного обзора LXC/LXD, вам придется самостоятельно найти дополнительную информацию о Linux-контейнерах.
- Не будет рассмотрен python модуль virtualenv для создания виртуального окружения на хосте разработчика как альтернатива контейнерам.
- Не будет сравнения в духе Docker vs LXD, выводы вы сделаете самостоятельно на основании вашего опыта.
Содержание:
- Выбор backend хранилища
- Установка пакета LXD
- Инициализация LXD
- Конфигурация сети LXС
- Создание профиля конфигурации контейнера
- Создание контейнера
- Установка ПО в контейнере
- Установка VS Code и расширений
- Настройка конфигурации VS Code
- Линковка каталогов Хост <-> Контейнер
- Настройка VS Code на запуск скриптов в контейнере
- Удаленный Debug в VS Code
- IntelliSense для внешних Python-библиотек
Выбор backend хранилища
Перед установкой LXD необходимо определиться, какой тип backend хранилища для контейнеров будет использоваться. Позже изменить будет нельзя. Доступно несколько вариантов: ZFS, btrfs, LVM или файловая система хоста. Для сравнения возможностей доступна таблица сравнения в официальной документации. Предлагаю выбрать ZFS который позволит в будущем легко создавать COW (copy-on-write) снимки (snapshots) контейнеров. Установим в системе пакет утилит работы с ZFS:
$ sudo apt install zfsutils-linux
Установка пакета LXD
Здесь нет сложностей, пакет входит в стандартную поставку системы, поэтому командуем в консоли:
$ sudo apt install lxd
После установки LXD, текущий пользователь будет добавлен в системную группу lxd, но чтобы продолжить настройку с необходимыми привелегиями в системе, необходимо сейчас выполнить переактивацию сессии пользователя. Просто выйдите и заново войдите в сессию вашего Desktop Manager-а или перезагрузитесь полностью. Проверить, состоит ли текущая сессия пользователя в группе 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. Выполните команду и следуйте инструкциям и комментариям представленным ниже:
$ 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.
Конфигурация сети LXС
Если сеть не настроить сейчас, а приступить к созданию контейнеров, то при их создании мы получим предупреждение, что контейнер не присоединен ни к одной из сетей. Это не будет являться ошибкой, просто к ним не будет сетевого доступа через интерфейсы. В начале можно создать необходимое количество контейнеров, а затем сконфигурировать сеть и присоединить к ней контейнеры с помощью команды lxc network attach. Сейчас нам необходимо определится, какой тип сети строить. Доступно несколько вариантов построения 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. Автор расширения 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 мы с вами завершили настройку.
Установка VS Code и расширений
Варианты установки приложения описаны на официальной страничке по адресу code.visualstudio.com/docs/setup/linux, мы же немного модифицируем команды:
$ 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» Обо всех изменениях можно почитать на этой страничке.
Приступим к установке расширений. Если вы впервые устанавливаете VS Code, например, после использования Atom (как автор), то рекомендую обратить внимание на расширения в списке ниже, а для достижения цели этой статьи будет достаточно установить только Python и Code Runner. Расширения устанавливаются с marketplace'а в левой части редактора.
- IntelliSense for CSS class names
- Python
- Jinja
- Django Template
- file-icons
- One Dark Pro
- Subtle Match Brackets
- TODO Highlight
- Code Runner
Настройка конфигурации VS Code
Следующие настройки необязательны, они прямо не относятся к запуску 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/
Вы увидите, что файлы и каталоги в контейнере будут доступны только для чтения и будут иметь UID:GID равным nobody:nogroup. Этого достаточно для запуска скриптов, но если вам необходимо сделать так, чтобы файлы и каталоги в контейнере были доступными на запись, прочтите главу "Direct user/group mapping" в этой статье.
Настройка VS Code на запуск скриптов в контейнере
И так, сейчас мы можем вернуться в наш редактор, если вы его закрыли, то вновь откройте. Нажмите в меню 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/pytest/:

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 'cd /mnt/hostfs/pytest && python3 $fileName'" // Запуск от имени встроенного в контейнер пользователя ubuntu: "python": "lxc exec pytest -- /bin/bash -c 'su -l ubuntu -c \"cd /mnt/hostfs/pytest && python3 $fileName\"'" }, "code-runner.runInTerminal": true }
В файловом эксплорере вы можете обнаружить файл settings.json в каталоге .vscode, там сохраняются настройки воркспейса (текущего проекта).
Вернитесь к открытому файлу test.py и запустите его на исполнение через команду из контекстного меню Run code:

В выводе интегрированного терминала вы увидите информацию в которой можно убедится, что код исполнялся на удаленной машине (контейнере). Теперь, всякий раз, когда нужно запустить проект в контейнере, достаточно внести настройки в WORKSPACE_SETTINGS или создать файл .vscode/settings.json относительно каждого проекта и затем немного подправить пути в настройках.
Удаленный Debug в VS Code
Раскомментируйте строчки в файле 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. Если у вас есть вопросы по теме, прошу задавать в комментариях. Спасибо за внимание, успешных вам проектов!
UPD от 10.11.2017 21:35 MSK.
В комментариях, пользователь SirEdvin задал вопрос о возможности автодополнения (или IntelliSense в терминах Microsoft) в редакторе тех python-модулей, которые установлены только в контейнере, т.е., этих модулей нет на локальной машине на которой запускается VS Code.
В статье этот момент был упущен, поэтому с радостью дополняю небольшой главою:
Настройка автодополнения (IntelliSense) для внешних python-библиотек
Например, в вашем проекте используется модуль, который не поставляется в коробке по умолчанию с python, и вы этот модуль установили только в контейнере. Как же сделать так, чтобы VS Code «понимал», автодополнял, выводил подсказки в редакторе при этом не устанавливая модуль на хосте, а получал из модуля в контейнере?
Для решения этого вопроса, откройте настройки WORKSPACE_SETTINGS по адресу: ВАШ_ПУТЬ_К_ПРОЕКТУ/.vscode/settings.json и добавьте параметр python.autoComplete.extraPaths, а в качестве ключей укажите список каталогов контейнера в которых находятся python модули.
Например, наш контейнер доступен в файловой системе хоста по адресу: /var/lib/lxd/containers/pytest/rootfs/. Это корневая файловая система контейнера pytest. Зная, где Python устанавливает внешние библиотеки, мы с легкостью можем добавить этот путь, чтобы получить полный путь к внешним библиотекам. Для таких модулей как numpy полный путь будет: /var/lib/lxd/containers/pytest/rootfs/usr/local/lib/python3.6/dist-packages. Этот путь мы добавим в настройку python.autoComplete.extraPaths, вот так:

Сохраните настройки и вернитесь к вашему проекту. Попробуйте импортировать модуль numpy и вызвать автодополнение клавишей CTRL + SPACE. У вас должно получиться так как на экране:

Если сразу не получается, не расстраивайтесь, VS Code кеширует результаты и это сразу может не заработать, попробуйте закрыть-открыть редактор, поиграться с клавишами CTRL+SPACE после ключевого слова from… import.
На этом всё :)
