Lanzando Jupyter a la órbita LXD

¿Alguna vez ha tenido que experimentar con código o utilidades del sistema en Linux sin preocuparse por el sistema subyacente y derribarlo todo en caso de un error en el código que se supone debe ejecutarse con privilegios de root?

Pero ¿qué pasa con el hecho de que digamos que necesita probar o ejecutar un grupo completo de varios microservicios en una máquina? ¿Cien o incluso mil?

Con máquinas virtuales administradas por un hipervisor, estos problemas pueden resolverse y se resolverán, pero ¿a qué costo? Por ejemplo, un contenedor en LXD basado en la distribución Alpine Linux consume solo 7.60MB RAM y dónde ocupa la partición raíz después del inicio 9.5MB! ¿Qué te parece esto, Elon Musk? Recomiendo echarle un vistazo capacidades básicas de LXD: un sistema de contenedores en Linux

Después de que quedó claro en general qué son los contenedores LXD, vayamos más allá y pensemos, ¿qué pasaría si existiera una plataforma de recolección donde pudiera ejecutar código de forma segura para el host, generar gráficos, vincular dinámicamente (interactivamente) widgets de interfaz de usuario con su código? complementar el código con texto con formato blackjack...? ¿Algún tipo de blog interactivo? Vaya... ¡lo quiero! ¡Desear! 🙂

Mira debajo del gato donde lanzaremos en un contenedor. JupyterLab - la próxima generación de interfaz de usuario en lugar del obsoleto Jupyter Notebook, y también instalaremos módulos de Python como NumPy, pandas, matplotlib, IPyWidgets lo que le permitirá hacer todo lo mencionado anteriormente y guardarlo todo en un archivo especial: una computadora portátil IPython.

Lanzando Jupyter a la órbita LXD

Plan de despegue orbital ^

Lanzando Jupyter a la órbita LXD

Esbocemos un breve plan de acción para que nos resulte más fácil implementar el esquema anterior:

  • Instalemos y lancemos un contenedor basado en el kit de distribución. Alpine Linux. Usaremos esta distribución porque está orientada al minimalismo e instalaremos en ella solo el software más necesario, nada superfluo.
  • Agreguemos un disco virtual adicional en el contenedor y le demos un nombre: hostfs y montarlo en el sistema de archivos raíz. Este disco permitirá utilizar archivos en el host desde un directorio determinado dentro del contenedor. Así, nuestros datos serán independientes del contenedor. Si se elimina el contenedor, los datos permanecerán en el host. Además, este esquema es útil para compartir los mismos datos entre muchos contenedores sin utilizar los mecanismos de red estándar de distribución de contenedores.
  • Instalemos Bash, Sudo, las bibliotecas necesarias, agreguemos y configuremos un usuario del sistema.
  • Instalemos Python, módulos y compilemos dependencias binarias para ellos.
  • Instalemos y lancemos JupyterLab, personaliza la apariencia, instala extensiones.

En este artículo comenzaremos con el lanzamiento del contenedor, no consideraremos instalar y configurar LXD, puede encontrar todo esto en otro artículo: Características básicas de LXD: sistemas de contenedores Linux.

Instalación y configuración del sistema básico. ^

Creamos un contenedor con el comando en el que especificamos la imagen - alpine3, identificador del contenedor - jupyterlab y, si es necesario, perfiles de configuración:

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

Aquí estoy usando un perfil de configuración. hddroot que especifica crear un contenedor con una partición raíz en Grupo de almacenamiento ubicado en un disco HDD físico:

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

Esto me da la oportunidad de experimentar con contenedores en el disco HDD, guardando los recursos del disco SSD, que también está disponible en mi sistema 🙂 para lo cual he creado un perfil de configuración separado. ssdroot.

Una vez creado el contenedor, se encuentra en el estado STOPPED, entonces necesitamos iniciarlo ejecutando el sistema init en él:

lxc start jupyterlab

Mostremos una lista de contenedores en LXD usando la clave -c que indica cual cvisualización de columnas:

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

Al crear el contenedor la dirección IP se eligió de forma aleatoria, ya que utilizamos un perfil de configuración default que fue configurado previamente en el artículo Características básicas de LXD: sistemas de contenedores Linux.

Cambiaremos esta dirección IP por una más memorable creando una interfaz de red en el nivel del contenedor, y no en el nivel del perfil de configuración como está ahora en la configuración actual. No es necesario que hagas esto, puedes omitirlo.

Creando una interfaz de red eth0 que vinculamos al switch (puente de red) lxdbr0 en el que habilitamos NAT según el artículo anterior y el contenedor ahora tendrá acceso a Internet, y también asignamos una dirección IP estática a la interfaz - 10.0.5.5:

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

Después de agregar un dispositivo, se debe reiniciar el contenedor:

lxc restart jupyterlab

Comprobando el estado del contenedor:

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

Instalación de software básico y configuración del sistema. ^

Para administrar nuestro contenedor, necesita instalar el siguiente software:

Contenido del Paquete
Descripción

golpear
El shell GNU Bourne Again

finalización de bash
Finalización programable para el shell bash

sudo
Dar a ciertos usuarios la posibilidad de ejecutar algunos comandos como root

sombra
Conjunto de herramientas de administración de cuentas y contraseñas con soporte para archivos ocultos y PAM

tzdatos
Fuentes de datos de zona horaria y horario de verano

nano
Clon del editor Pico con mejoras

Además, puede instalar soporte en las páginas de manual del sistema instalando los siguientes paquetes: man man-pages mdocml-apropos less

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

Veamos los comandos y claves que usamos:

  • lxc — Llamar al cliente LXD
  • exec - Método de cliente LXD que ejecuta un comando en el contenedor
  • jupyterlab — ID del contenedor
  • -- - Una clave especial que especifica no interpretar más claves como claves para lxc y pasar el resto de la cadena tal cual al contenedor
  • apk — Administrador de paquetes de distribución de Alpine Linux
  • add — Un método de administrador de paquetes que instala los paquetes especificados después del comando.

A continuación, estableceremos una zona horaria en el sistema. Europe/Moscow:

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

Después de instalar la zona horaria, el paquete tzdata Ya no es necesario en el sistema, ocupará espacio, así que eliminémoslo:

lxc exec jupyterlab -- apk del tzdata

Comprobando la zona horaria:

lxc exec jupyterlab -- date

Wed Apr 15 10:49:56 MSK 2020

Para no perder mucho tiempo configurando Bash para nuevos usuarios en el contenedor, en los siguientes pasos copiaremos archivos skel ya preparados desde el sistema host. Esto le permitirá embellecer Bash en un contenedor de forma interactiva. Mi sistema host es Manjaro Linux y los archivos que se están copiando /etc/skel/.bash_profile, /etc/skel/.bashrc, /etc/skel/.dir_colors En principio, son adecuados para Alpine Linux y no causan problemas críticos, pero es posible que tenga una distribución diferente y necesite averiguar usted mismo si hay un error al ejecutar Bash en el contenedor.

Copie los archivos skel al contenedor. Llave --create-dirs creará los directorios necesarios si no existen:

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

Para un usuario root existente, copie los archivos skel que acaba de copiar en el contenedor al directorio de inicio:

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 instala un shell del sistema para los usuarios /bin/sh, lo reemplazaremos con root usuario en Bash:

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

Que root el usuario no tenía contraseña, necesita establecer una contraseña. El siguiente comando generará y establecerá una nueva contraseña aleatoria para él, que verá en la pantalla de la consola después de su ejecución:

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

Además, creemos un nuevo usuario del sistema: jupyter para lo cual configuraremos más adelante JupyterLab:

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

Generemos y establezcamos una contraseña para ello:

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

A continuación, ejecutaremos dos comandos, el primero creará un grupo de sistemas sudo, y el segundo le agregará un usuario jupyter:

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

Veamos a qué grupos pertenece el usuario. jupyter:

lxc exec jupyterlab -- id -Gn jupyter

jupyter sudo

Todo está bien, sigamos adelante.

Permitir a todos los usuarios que sean miembros del grupo. sudo usar comando sudo. Para hacer esto, ejecute el siguiente script, donde sed descomenta la línea de parámetro en el archivo de configuración /etc/sudoers:

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

Instalación y configuración de JupyterLab ^

JupyterLab Es una aplicación Python, por lo que primero debemos instalar este intérprete. También, JupyterLab Lo instalaremos usando el administrador de paquetes de Python. pip, y no el del sistema, porque puede estar desactualizado en el repositorio del sistema y, por lo tanto, tenemos que resolver manualmente las dependencias instalando los siguientes paquetes: python3 python3-dev gcc libc-dev zeromq-dev:

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

Actualicemos los módulos de Python y el administrador de paquetes. pip a la versión actual:

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

Establecer JupyterLab a través del administrador de paquetes pip:

lxc exec jupyterlab -- python3 -m pip install jupyterlab

Desde las extensiones en JupyterLab son experimentales y no se envían oficialmente con el paquete jupyterlab, por lo que tenemos que instalarlo y configurarlo manualmente.

Instalemos NodeJS y su administrador de paquetes: NPM, ya que JupyterLab los usa para sus extensiones:

lxc exec jupyterlab -- apk add nodejs npm

a extensiones para JupyterLab que instalaremos funcionó, deben instalarse en el directorio de usuarios ya que la aplicación se iniciará desde el usuario jupyter. El problema es que no hay ningún parámetro en el comando de lanzamiento que se pueda pasar a un directorio, la aplicación solo acepta una variable de entorno y por lo tanto debemos definirla. Para hacer esto, escribiremos el comando de exportación de variables. JUPYTERLAB_DIR en el entorno del usuario jupyter, archivar .bashrcque se ejecuta cada vez que el usuario inicia sesión:

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

El siguiente comando instalará una extensión especial: administrador de extensiones en JupyterLab:

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

Ahora todo está listo para el primer lanzamiento. JupyterLab, pero aún podemos instalar algunas extensiones útiles:

  • toc — Tabla de contenido, genera una lista de títulos en un artículo/cuaderno
  • jupyterlab-horizon-theme — tema de la interfaz de usuario
  • jupyterlab_neon_theme — tema de la interfaz de usuario
  • jupyterlab-ubu-theme - Otro tema del autor este artículo :) Pero en este caso, se mostrará la instalación desde el repositorio de GitHub.

Entonces, ejecute los siguientes comandos secuencialmente para instalar estas extensiones:

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"

Luego de instalar las extensiones debemos compilarlas, ya que previamente durante la instalación especificamos la clave --no-build Para ganar tiempo. Ahora aceleraremos significativamente compilándolos de una sola vez:

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

Ahora ejecute los siguientes dos comandos para ejecutarlo por primera vez JupyterLab. Sería posible ejecutarlo con un comando, pero en este caso, el comando de inicio, que es difícil de recordar mentalmente, será recordado por bash en el contenedor, y no en el host, donde ya hay suficientes comandos. para registrarlos en la historia :)

Inicie sesión en el contenedor como usuario. jupyter:

lxc exec jupyterlab -- su -l jupyter

A continuación, ejecuta JupyterLab con claves y parámetros como se indica:

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

Vaya a la dirección en su navegador web http://10.0.5.5:8888 y en la página que se abre ingresa ficha acceso que verás en la consola. Cópielo y péguelo en la página, luego haga clic en Acceder. Después de iniciar sesión, vaya al menú de extensiones a la izquierda, como se muestra en la siguiente figura, donde se le pedirá, al activar el administrador de extensiones, que asuma riesgos de seguridad instalando extensiones de terceros para las cuales el comando Desarrollo de JupyterLab no es responsable:

Lanzando Jupyter a la órbita LXD

Sin embargo, estamos aislando a toda JupyterLab y colocarlo en un contenedor para que las extensiones de terceros que requieren y usan NodeJS no puedan al menos robar datos del disco que no sean los que abrimos dentro del contenedor. Acceda a sus documentos privados en el host en /home Es poco probable que los procesos del contenedor tengan éxito y, si lo hacen, entonces necesita tener privilegios sobre los archivos en el sistema host, ya que ejecutamos el contenedor en modo sin privilegios. Con base en esta información, puede evaluar el riesgo de incluir extensiones en JupyterLab.

Cuadernos IPython creados (páginas en JupyterLab) ahora se creará en el directorio de inicio del usuario - /home/jupyter, pero nuestros planes son dividir los datos (compartir) entre el host y el contenedor, así que regrese a la consola y deténgase. JupyterLab ejecutando la tecla de acceso rápido - CTRL+C y respondiendo y a pedido. Luego finalice la sesión interactiva del usuario. jupyter completando una tecla de acceso rápido CTRL+D.

Compartir datos con el anfitrión ^

Para compartir datos con el host, necesita crear un dispositivo en el contenedor que le permita hacer esto y, para hacerlo, ejecute el siguiente comando donde especificamos las siguientes claves:

  • lxc config device add — El comando agrega la configuración del dispositivo.
  • jupyter — ID del contenedor al que se agrega la configuración
  • hostfs - ID del dispositivo. Puede establecer cualquier nombre.
  • disk — Se indica el tipo de dispositivo
  • path — Especifica la ruta en el contenedor en la que LXD montará este dispositivo
  • source — Especifique la fuente, la ruta al directorio en el host que desea compartir con el contenedor. Especifica la ruta según tus preferencias
lxc config device add jupyterlab hostfs disk path=/mnt/hostfs source=/home/dv/projects/ipython-notebooks

Para el catálogo /home/dv/projects/ipython-notebooks El permiso debe establecerse para el usuario del contenedor que actualmente tiene un UID igual a SubUID + UID, ver capítulo Seguridad. Privilegios de contenedor Artículo Características básicas de LXD: sistemas de contenedores Linux.

Establezca el permiso en el host, donde el propietario será el usuario del contenedor. jupytery la variable $USER especificará su usuario anfitrión como un grupo:

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

¡Hola Mundo! ^

Si todavía tiene una sesión de consola abierta en el contenedor con JupyterLab, luego reinícielo con una nueva clave --notebook-dir estableciendo el valor /mnt/hostfs como la ruta a la raíz de las computadoras portátiles en el contenedor para el dispositivo que creamos en el paso anterior:

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

Luego ve a la página http://10.0.5.5:8888 y cree su primera computadora portátil haciendo clic en el botón de la página como se muestra en la siguiente imagen:

Lanzando Jupyter a la órbita LXD

Luego, en el campo de la página, ingrese el código Python que mostrará el clásico Hello World!. Cuando haya terminado de ingresar, presione CTRL+ENTER o el botón "reproducir" en la barra de herramientas en la parte superior para que JupyterLab haga esto:

Lanzando Jupyter a la órbita LXD

En este punto, casi todo está listo para usar, pero no será interesante si no instalamos módulos adicionales de Python (aplicaciones completas) que puedan ampliar significativamente las capacidades estándar de Python en JupyterLab, entonces sigamos adelante :)

PD: Lo interesante es que la implementación anterior Jupyter bajo el nombre en clave Cuaderno Jupyter no ha desaparecido y existe en paralelo con JupyterLab. Para cambiar a la versión anterior, siga el enlace agregando el sufijo en la dirección/tree, y la transición a la nueva versión se realiza con el sufijo /lab, pero no es necesario especificarlo:

Ampliando las capacidades de Python ^

En esta sección, instalaremos módulos de lenguaje Python tan potentes como NumPy, pandas, matplotlib, IPyWidgets cuyos resultados están integrados en las computadoras portátiles JupyterLab.

Antes de instalar los módulos de Python enumerados a través del administrador de paquetes pip Primero debemos resolver las dependencias del sistema en Alpine Linux:

  • g++ — Necesario para compilar módulos, ya que algunos de ellos están implementados en el lenguaje C + + y conectarse a Python en tiempo de ejecución como módulos binarios
  • freetype-dev - dependencia del módulo Python matplotlib

Instalación de dependencias:

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

Hay un problema: en el estado actual de la distribución Alpine Linux, no será posible compilar la nueva versión de NumPy; aparecerá un error de compilación que no pude resolver:

ERROR: No se pudieron construir ruedas para numpy que usan PEP 517 y no se pueden instalar directamente

Por lo tanto, instalaremos este módulo como un paquete de sistema que distribuye una versión ya compilada, pero un poco más antigua que la que está disponible actualmente en el sitio:

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

A continuación, instale los módulos de Python a través del administrador de paquetes. pip. Tenga paciencia ya que algunos módulos se compilarán y pueden tardar unos minutos. En mi máquina, la compilación tomó ~15 minutos:

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

Borrar cachés de instalación:

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

Módulos de prueba en JupyterLab ^

si estas corriendo JupyterLab, reinícielo para que se activen los módulos recién instalados. Para hacer esto, en una sesión de consola, haga clic en CTRL+C donde lo tienes funcionando y entras y para detener la solicitud y luego comenzar de nuevo JupyterLab presionando la flecha hacia arriba en el teclado para no ingresar el comando nuevamente y luego Enter para iniciarlo:

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

Перейдите на страницу http://10.0.5.5:8888/lab o actualice la página en su navegador y luego ingrese el siguiente código en una nueva celda del cuaderno:

%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

Debería obtener un resultado como en la imagen de abajo, donde IPyWidgets genera un elemento de interfaz de usuario en la página que interactúa interactivamente con el código fuente, y también matplotlib muestra el resultado del código en forma de imagen como un gráfico de función:

Lanzando Jupyter a la órbita LXD

Muchos ejemplos IPyWidgets lo puedes encontrar en tutoriales aquí

Que mas ^

Enhorabuena si te quedaste y llegaste al final del artículo. Deliberadamente no publiqué un script listo para usar al final del artículo que instalaría JupyterLab en "un clic" para animar a los trabajadores :) Pero puedes hacerlo tú mismo, porque ya sabes cómo, habiendo recopilado los comandos en un único script Bash :)

Tú también puedes:

  • Establezca un nombre de red para el contenedor en lugar de una dirección IP escribiéndolo en un formato simple /etc/hosts y escribe la dirección en el navegador http://jupyter.local:8888
  • Juegue con el límite de recursos para el contenedor, para esto lea el capítulo en capacidades básicas de LXD u obtenga más información en el sitio para desarrolladores de LXD.
  • Cambiar el tema:

Lanzando Jupyter a la órbita LXD

¡Y mucho más puedes hacer! Eso es todo. ¡Te deseo éxito!

ACTUALIZACIÓN: 15.04.2020/18/30 XNUMX:XNUMX - Errores corregidos en el capítulo “¡Hola mundo!”
ACTUALIZACIÓN: 16.04.2020/10/00 XNUMX:XNUMX - Texto corregido y agregado en la descripción de la activación del administrador de extensiones JupyterLab
ACTUALIZACIÓN: 16.04.2020/10/40 XNUMX:XNUMX - Se corrigieron los errores encontrados en el texto y se modificó ligeramente para mejor el capítulo "Instalación del software básico y configuración del sistema"

Fuente: habr.com

Añadir un comentario