将 Jupyter 发射到 LXD 轨道

您是否曾经不得不在 Linux 中尝试代码或系统实用程序,以便不必担心基本系统,也不必在应以 root 权限运行的代码中出现错误时破坏所有内容?

但是,假设您需要在一台计算机上测试或运行由各种微服务组成的整个集群,那又如何呢? 一百甚至一千?

通过虚拟机管理程序管理虚拟机,这些问题可以而且将会得到解决,但代价是什么? 例如,基于 Alpine Linux 发行版的 LXD 中的容器仅消耗 7.60MB RAM,以及启动后根分区所占用的位置 9.5MB! 你觉得怎么样,埃隆·马斯克? 我建议查看 LXD的基本能力——Linux中的容器系统

在大致了解 LXD 容器是什么之后,让我们进一步思考,如果有这样一个收割机平台,您可以在其中安全地为主机运行代码、生成图表、动态(交互式)将 UI 小部件与您的代码链接起来,用二十一点...格式的文本补充代码? 某种互动博客? 哇……我​​想要! 想! 🙂

看看猫下面我们将在容器中启动的地方 Jupyter实验室 - 下一代用户界面而不是过时的Jupyter Notebook,我们还将安装Python模块,例如 NumPy的, 熊猫, Matplotlib, IPyWidgets 这将允许您执行上面列出的所有操作并将其全部保存在一个特殊文件中 - IPython 笔记本电脑。

将 Jupyter 发射到 LXD 轨道

轨道起飞计划 ^

将 Jupyter 发射到 LXD 轨道

让我们概述一个简短的行动计划,以便我们更容易地实施上述计划:

  • 让我们安装并启动一个基于分发包的容器 高山Linux。 我们将使用这个发行版,因为它旨在极简主义,并且只会安装最必要的软件,没有多余的软件。
  • 让我们在容器中添加一个额外的虚拟磁盘并为其命名 - hostfs 并将其挂载到根文件系统。 该磁盘使得可以使用容器内给定目录中的主机上的文件。 因此,我们的数据将独立于容器。 如果容器被删除,数据将保留在主机上。 此外,该方案对于在多个容器之间共享相同的数据非常有用,而无需使用容器分发的标准网络机制。
  • 让我们安装 Bash、sudo、必要的库,添加并配置系统用户
  • 让我们安装 Python、模块并为它们编译二进制依赖项
  • 让我们安装并启动 Jupyter实验室,自定义外观,为其安装扩展。

在本文中,我们将从启动容器开始,我们不会考虑安装和配置 LXD,您可以在另一篇文章中找到所有这些 - LXD-Linux容器系统的基本特性.

基本系统的安装和配置 ^

我们使用在其中指定图像的命令创建一个容器 - alpine3,容器的标识符 - jupyterlab 如有必要,还有配置文件:

lxc init alpine3 jupyterlab --profile=default --profile=hddroot

这里我使用的是配置文件 hddroot 它指定创建一个带有根分区的容器 储存池 位于物理 HDD 磁盘上:

lxc profile show hddroot

config: {}
description: ""
devices:
  root:
    path: /
    pool: hddpool
    type: disk
name: hddroot
used_by: []
lxc storage show hddpool

config:
  size: 10GB
  source: /dev/loop1
  volatile.initial_source: /dev/loop1
description: ""
name: hddpool
driver: btrfs
used_by:
- /1.0/images/ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3
- /1.0/profiles/hddroot
status: Created
locations:
- none

这使我有机会在 HDD 磁盘上试验容器,从而节省 SSD 磁盘的资源,这在我的系统中也可用 🙂 我为其创建了单独的配置文件 ssdroot.

容器创建后,处于以下状态 STOPPED,所以我们需要通过运行 init 系统来启动它:

lxc start jupyterlab

让我们使用 key 显示 LXD 中的容器列表 -c 这表明哪个 c列显示:

lxc list -c ns4b
+------------+---------+-------------------+--------------+
|    NAME    |  STATE  |       IPV4        | STORAGE POOL |
+------------+---------+-------------------+--------------+
| jupyterlab | RUNNING | 10.0.5.198 (eth0) | hddpool      |
+------------+---------+-------------------+--------------+

创建容器时,IP 地址是随机选择的,因为我们使用了配置文件 default 之前在文章中配置过 LXD-Linux容器系统的基本特性.

我们将通过在容器级别(而不是像当前配置中那样在配置文件级别)创建网络接口来将此 IP 地址更改为更容易记住的地址。 您不必执行此操作,可以跳过它。

创建网络接口 eth0 我们链接到交换机(网桥) lxdbr0 我们根据上一篇文章启用了 NAT,容器现在可以访问互联网,并且我们还为接口分配了一个静态 IP 地址 - 10.0.5.5:

lxc config device add jupyterlab eth0 nic name=eth0 nictype=bridged parent=lxdbr0 ipv4.address=10.0.5.5

添加设备后,必须重新启动容器:

lxc restart jupyterlab

检查容器的状态:

lxc list -c ns4b
+------------+---------+------------------+--------------+
|    NAME    |  STATE  |       IPV4       | STORAGE POOL |
+------------+---------+------------------+--------------+
| jupyterlab | RUNNING | 10.0.5.5 (eth0)  | hddpool      |
+------------+---------+------------------+--------------+

安装基本软件并设置系统 ^

要管理我们的容器,您需要安装以下软件:

小包装
产品描述

打坏
GNU Bourne Again shell

bash 完成
bash shell 的可编程完成

须藤
赋予某些用户以 root 身份运行某些命令的能力

阴影
支持影子文件和 PAM 的密码和帐户管理工具套件

数据
时区和夏令时数据源

纳米
具有增强功能的 Pico 编辑器克隆

此外,您可以通过安装以下软件包在系统手册页中安装支持 - man man-pages mdocml-apropos less

lxc exec jupyterlab -- apk add bash bash-completion sudo shadow tzdata nano

让我们看看我们使用的命令和按键:

  • lxc — 致电 LXD 客户端
  • exec - 在容器中运行命令的 LXD 客户端方法
  • jupyterlab — 容器 ID
  • -- - 一个特殊的键,指定不将其他键解释为 lxc 并将字符串的其余部分按原样传递给容器
  • apk — Alpine Linux 发行版包管理器
  • add — 包管理器方法,用于安装命令后指定的包

接下来我们要在系统中设置一个时区 Europe/Moscow:

lxc exec jupyterlab -- cp /usr/share/zoneinfo/Europe/Moscow /etc/localtime

安装时区后,包 tzdata 系统不再需要了,它会占用空间,所以我们删除它:

lxc exec jupyterlab -- apk del tzdata

检查时区:

lxc exec jupyterlab -- date

Wed Apr 15 10:49:56 MSK 2020

为了不花费大量时间在容器中为新用户设置 Bash,在以下步骤中,我们将从主机系统复制现成的 skel 文件到容器中。 这将允许您在容器中以交互方式美化 Bash。 我的主机系统是 Manjaro Linux 并且正在复制文件 /etc/skel/.bash_profile, /etc/skel/.bashrc, /etc/skel/.dir_colors 原则上它们适用于 Alpine Linux,不会造成严重问题,但您可能有不同的发行版,您需要独立找出在容器中运行 Bash 时是否出现错误。

将 skel 文件复制到容器中。 钥匙 --create-dirs 如果必要的目录不存在,将创建它们:

lxc file push /etc/skel/.bash_profile jupyterlab/etc/skel/.bash_profile --create-dirs
lxc file push /etc/skel/.bashrc jupyterlab/etc/skel/.bashrc
lxc file push /etc/skel/.dir_colors jupyterlab/etc/skel/.dir_colors

对于现有的 root 用户,将刚刚复制到容器中的 skel 文件复制到主目录:

lxc exec jupyterlab -- cp /etc/skel/.bash_profile /root/.bash_profile
lxc exec jupyterlab -- cp /etc/skel/.bashrc /root/.bashrc
lxc exec jupyterlab -- cp /etc/skel/.dir_colors /root/.dir_colors

Alpine Linux 为用户安装系统 shell /bin/sh,我们将其替换为 root Bash 中的用户:

lxc exec jupyterlab -- usermod --shell=/bin/bash root

root 用户不是无密码的,他需要设置一个密码。 以下命令将为他生成并设置一个新的随机密码,执行后您将在控制台屏幕上看到该密码:

lxc exec jupyterlab -- /bin/bash -c "PASSWD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 12); echo "root:$PASSWD" | chpasswd && echo "New Password: $PASSWD""

New Password: sFiXEvBswuWA

另外,让我们创建一个新的系统用户 - jupyter 我们稍后将为其配置 Jupyter实验室:

lxc exec jupyterlab -- useradd --create-home --shell=/bin/bash jupyter

让我们为其生成并设置密码:

lxc exec jupyterlab -- /bin/bash -c "PASSWD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 12); echo "jupyter:$PASSWD" | chpasswd && echo "New Password: $PASSWD""

New Password: ZIcbzWrF8tki

接下来,我们将执行两个命令,第一个命令将创建一个系统组 sudo,第二个将向其中添加用户 jupyter:

lxc exec jupyterlab -- groupadd --system sudo
lxc exec jupyterlab -- groupmems --group sudo --add jupyter

让我们看看用户属于哪些组 jupyter:

lxc exec jupyterlab -- id -Gn jupyter

jupyter sudo

一切都好,我们继续吧。

允许属于该组成员的所有用户 sudo 使用命令 sudo。 为此,请运行以下脚本,其中 sed 取消配置文件中参数行的注释 /etc/sudoers:

lxc exec jupyterlab -- /bin/bash -c "sed --in-place -e '/^#[ t]*%sudo[ t]*ALL=(ALL)[ t]*ALL$/ s/^[# ]*//' /etc/sudoers"

安装和配置 JupyterLab ^

Jupyter实验室 是一个Python应用程序,所以我们必须首先安装这个解释器。 还, Jupyter实验室 我们将使用 Python 包管理器进行安装 pip,而不是系统的,因为它在系统存储库中可能已经过时,因此,我们必须通过安装以下软件包来手动解决它的依赖关系 - python3 python3-dev gcc libc-dev zeromq-dev:

lxc exec jupyterlab -- apk add python3 python3-dev gcc libc-dev zeromq-dev

让我们更新 python 模块和包管理器 pip 到当前版本:

lxc exec jupyterlab -- python3 -m pip install --upgrade pip setuptools wheel

Jupyter实验室 通过包管理器 pip:

lxc exec jupyterlab -- python3 -m pip install jupyterlab

由于扩展在 Jupyter实验室 是实验性的,并未随 jupyterlab 包正式发布,因此我们必须手动安装和配置它。

让我们安装 NodeJS 及其包管理器 - NPM,因为 Jupyter实验室 使用它们作为扩展:

lxc exec jupyterlab -- apk add nodejs npm

至扩展名 Jupyter实验室 我们将安装的工作正常,它们需要安装在用户目录中,因为应用程序将从用户启动 jupyter。 问题是启动命令中没有可以传递到目录的参数;应用程序只接受环境变量,因此我们必须定义它。 为此,我们将编写变量导出命令 JUPYTERLAB_DIR 在用户环境中 jupyter, 归档 .bashrc每次用户登录时都会执行:

lxc exec jupyterlab -- su -l jupyter -c "echo -e "nexport JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab" >> .bashrc"

下一个命令将安装一个特殊的扩展 - 扩展管理器 Jupyter实验室:

lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter labextension install --no-build @jupyter-widgets/jupyterlab-manager"

现在一切准备就绪,等待首次发布 Jupyter实验室,但我们仍然可以安装一些有用的扩展:

  • toc — 目录,生成文章/笔记本中的标题列表
  • jupyterlab-horizon-theme — 用户界面主题
  • jupyterlab_neon_theme — 用户界面主题
  • jupyterlab-ubu-theme - 另一个 作者的主题 这篇文章 :) 但在这种情况下,将显示来自 GitHub 存储库的安装

因此,依次运行以下命令来安装这些扩展:

lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter labextension install --no-build @jupyterlab/toc @mohirio/jupyterlab-horizon-theme @yeebc/jupyterlab_neon_theme"
lxc exec jupyterlab -- su -l jupyter -c "wget -c https://github.com/microcoder/jupyterlab-ubu-theme/archive/master.zip"
lxc exec jupyterlab -- su -l jupyter -c "unzip -q master.zip && rm master.zip"
lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter labextension install --no-build jupyterlab-ubu-theme-master"
lxc exec jupyterlab -- su -l jupyter -c "rm -r jupyterlab-ubu-theme-master"

安装扩展后,我们必须编译它们,因为之前在安装过程中,我们指定了密钥 --no-build 为了省时间。 现在,我们将它们一次性编译在一起,从而显着加快速度:

lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter lab build"

现在运行以下两个命令来首次运行它 Jupyter实验室。 可以用一个命令来启动它,但在这种情况下,你很难记住的启动命令将被容器中的 bash 记住,而不是在主机上,因为主机上已经有足够的命令将它们记录在历史中:)

以用户身份登录容器 jupyter:

lxc exec jupyterlab -- su -l jupyter

接下来,运行 Jupyter实验室 键和参数如下所示:

[jupyter@jupyterlab ~]$ jupyter lab --ip=0.0.0.0 --no-browser

转到网络浏览器中的地址 http://10.0.5.5:8888 然后在打开的页面上输入 象征 您将在控制台中看到访问权限。 复制并粘贴到页面上,然后单击 登录 。 登录后,进入左侧扩展菜单,如下图所示,激活扩展管理器时会提示您安装第三方扩展,以承担安全风险,命令如下: JupyterLab开发 不负责:

将 Jupyter 发射到 LXD 轨道

然而,我们正在隔离整个 Jupyter实验室 并将其放置在容器中,这样需要并使用 NodeJS 的第三方扩展至少无法窃取磁盘上除我们在容器内打开的数据之外的数据。 获取您在主机上的私人文档 /home 来自容器的进程不太可能成功,如果成功,那么您需要对主机系统上的文件具有权限,因为我们在 非特权模式。 根据此信息,您可以评估将扩展包含在其中的风险 Jupyter实验室.

创建 IPython 笔记本(页面 Jupyter实验室) 现在将在用户的主目录中创建 - /home/jupyter,但是我们的计划是在主机和容器之间分割数据(共享),所以返回控制台并停止 Jupyter实验室 通过执行热键 - CTRL+C 并回答 y 根据要求。 然后终止用户的交互会话 jupyter 完成热键 CTRL+D.

与主机共享数据 ^

要与主机共享数据,您需要在容器中创建一个允许您执行此操作的设备,为此,请运行以下命令,其中我们指定以下键:

  • lxc config device add — 该命令添加设备配置
  • jupyter — 添加配置的容器ID
  • hostfs - 设备ID。 您可以设置任何名称。
  • disk — 指示设备类型
  • path — 指定 LXD 将安装此设备的容器中的路径
  • source — 指定源,即要与容器共享的主机上目录的路径。 根据自己的喜好指定路径
lxc config device add jupyterlab hostfs disk path=/mnt/hostfs source=/home/dv/projects/ipython-notebooks

对于目录 /home/dv/projects/ipython-notebooks 权限必须设置为当前 UID 等于的容器用户 SubUID + UID,参见章节 安全。 容器权限 文章 LXD-Linux容器系统的基本特性.

在主机上设置权限,所有者为容器用户 jupyter,以及变量 $USER 将指定您的主机用户作为一个组:

sudo chown 1001000:$USER /home/dv/projects/ipython-notebooks

你好,世界! ^

如果您仍然在容器中打开控制台会话 Jupyter实验室,然后用新密钥重新启动它 --notebook-dir 通过设置值 /mnt/hostfs 作为我们在上一步中创建的设备的容器中笔记本电脑根目录的路径:

jupyter lab --ip=0.0.0.0 --no-browser --notebook-dir=/mnt/hostfs

然后进入页面 http://10.0.5.5:8888 然后点击页面上的按钮创建你的第一台笔记本电脑,如下图所示:

将 Jupyter 发射到 LXD 轨道

然后,在页面上的字段中输入将显示经典的Python代码 Hello World!。 输入完毕后,按 CTRL+ENTER 或顶部工具栏上的“播放”按钮让 JupyterLab 执行此操作:

将 Jupyter 发射到 LXD 轨道

至此,几乎一切都已准备就绪,可以使用了,但如果我们不安装额外的 Python 模块(成熟的应用程序),这些模块可以显着扩展 Python 的标准功能,那就没什么意思了。 Jupyter实验室因此,让我们继续吧:)

PS 有趣的是旧的实现 朱皮特 在代号下 Jupyter笔记本 并没有消失,并且与以下平行存在 Jupyter实验室。 要切换到旧版本,请点击链接并在地址中添加后缀/tree,并以后缀进行向新版本的过渡 /lab,但不必指定:

扩展 Python 的功能 ^

在本节中,我们将安装强大的Python语言模块,例如 NumPy的, 熊猫, Matplotlib, IPyWidgets 其结果被集成到笔记本电脑中 Jupyter实验室.

在通过包管理器安装列出的 Python 模块之前 pip 我们必须首先解决 Alpine Linux 中的系统依赖关系:

  • g++ — 编译模块所需,因为其中一些模块是用语言实现的 C + +中 并在运行时作为二进制模块连接到 Python
  • freetype-dev - Python 模块的依赖 Matplotlib

安装依赖项:

lxc exec jupyterlab -- apk add g++ freetype-dev

有一个问题:在 Alpine Linux 发行版的当前状态下,将无法编译新版本的 NumPy;会出现一个我无法解决的编译错误:

ERROR: 无法为使用 PEP 517 的 numpy 构建轮子,并且无法直接安装

因此,我们将将此模块安装为系​​统包,分发已编译的版本,但比网站上当前可用的版本稍旧:

lxc exec jupyterlab -- apk add py3-numpy py3-numpy-dev

接下来,通过包管理器安装Python模块 pip。 请耐心等待,因为某些模块将编译,可能需要几分钟的时间。 在我的机器上,编译大约需要 15 分钟:

lxc exec jupyterlab -- python3 -m pip install pandas ipywidgets matplotlib

清除安装缓存:

lxc exec jupyterlab -- rm -rf /home/*/.cache/pip/*
lxc exec jupyterlab -- rm -rf /root/.cache/pip/*

在 JupyterLab 中测试模块 ^

如果你正在跑步 Jupyter实验室,重新启动以便激活新安装的模块。 为此,请在控制台会话中单击 CTRL+C 你运行它的地方并输入 y 停止请求然后重新开始 Jupyter实验室 按键盘上的向上箭头,以免再次输入命令,然后 Enter 启动它:

jupyter lab --ip=0.0.0.0 --no-browser --notebook-dir=/mnt/hostfs

Перейдитенастраницу http://10.0.5.5:8888/lab 或在浏览器中刷新页面,然后在新的笔记本单元格中输入以下代码:

%matplotlib inline

from ipywidgets import interactive
import matplotlib.pyplot as plt
import numpy as np

def f(m, b):
    plt.figure(2)
    x = np.linspace(-10, 10, num=1000)
    plt.plot(x, m * x + b)
    plt.ylim(-5, 5)
    plt.show()

interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '350px'
interactive_plot

您应该得到如下图所示的结果,其中 IPyWidgets 在页面上生成一个与源代码交互的 UI 元素,并且 Matplotlib 将代码的结果以图片的形式显示为函数图:

将 Jupyter 发射到 LXD 轨道

很多例子 IPyWidgets 你可以在教程中找到它 这里

还有什么? ^

如果您坚持下来并读到文章的最后,那就太好了。 我故意没有在文章最后贴出现成的安装脚本 Jupyter实验室 “一键点击”来鼓励员工:)但是您可以自己做,因为您已经知道如何操作,并将命令收集到单个 Bash 脚本中:)

你也可以:

  • 通过以简单的方式编写容器的网络名称而不是 IP 地址 /etc/hosts 然后在浏览器中输入地址 http://jupyter.local:8888
  • 尝试使用容器的资源限制,为此请阅读以下章节 基本 LXD 功能 或者在 LXD 开发者网站上获取更多信息。
  • 更改主题:

将 Jupyter 发射到 LXD 轨道

您还可以做更多事情! 就这样。 祝你成功!

更新:15.04.2020 年 18 月 30 日 XNUMX:XNUMX - 更正了“Hello, World!”一章中的错误
更新:16.04.2020 年 10 月 00 日 XNUMX:XNUMX — 更正并添加了扩展管理器激活描述中的文本 Jupyter实验室
更新:16.04.2020/10/40 XNUMX:XNUMX - 更正了文本中发现的错误,并稍微修改了“安装基本软件和设置系统”一章

来源: habr.com

添加评论