Hai mai sperimentato con il codice o gli strumenti di sistema in Linux in modo da non dover temere per il sistema di base e non cancellare tutto in caso di errore di codice che dovrebbe essere eseguito con privilegi root?
E che dire del fatto che, ad esempio, è necessario testare o avviare un intero cluster di diversi microservizi su un'unica macchina? Centinaia o addirittura migliaia?
Con le macchine virtuali gestite da un hypervisor, è possibile risolvere tali compiti, ma a quale prezzo? Ad esempio, un container in LXD basato su una distribuzione Alpine Linux consuma minimalmente solo 7.60MB di RAM, e dove la partizione root dopo l'avvio occupa 9.5MB! Cosa ne pensi, Elon Musk? Ti consiglio di dare un'occhiata alle basi funzionalità di LXD — il sistema di container in Linux
Dopo che è diventato chiaro cosa sono i contenitori LXD, andiamo oltre e pensiamo a cosa succederebbe se ci fosse una piattaforma multifunzione, dove poter eseguire il codice per l'host in sicurezza, generare grafici, collegare dinamicamente (interattivamente) i widget UI al proprio codice, arricchire il codice con testo con tanto di blackjack… e formattazione? Qualcosa come un blog interattivo? Wow… Voglio! Voglio! 🙂
Dai un'occhiata sotto, dove avvieremo in un contenitore JupyterLab — l'interfaccia utente di nuova generazione al posto del vecchio Jupyter Notebook, e installeremo anche moduli Python come NumPy, Pandas, Matplotlib, IPyWidgets che ci permetteranno di fare tutto ciò che è sopra elencato e di salvare tutto in un file speciale — un notebook IPython.

Navigazione
- Piano per il decollo in orbita
- Installazione e configurazione del sistema di base
- Installazione del software di base e configurazione del sistema
- Installazione e configurazione di JupyterLab
- Condividiamo i dati con l'host
- Hello, World!
- Espandiamo le capacità di Python
- Testiamo i moduli in JupyterLab
- Cosa altro?
Piano per il decollo in orbita ^

Progettiamo un piano d'azione per semplificare l'attuazione dello schema sopra:
- Installeremo e avvieremo un contenitore basato su una distribuzione Alpine Linux. Utilizzeremo questa distribuzione in quanto è focalizzata sulla minimalità e installeremo solo il software più necessario, nulla di superfluo.
- Aggiungiamo un ulteriore disco virtuale nel contenitore a cui daremo il nome —
hostfse lo monteremo sul filesystem root. Questo disco ci permetterà di utilizzare i file sull'host da una directory specificata all'interno del contenitore. In questo modo, i dati saranno indipendenti dal contenitore. In caso di eliminazione del contenitore, i dati rimarranno sull'host. Inoltre, questo schema è utile per separare i dati tra diversi contenitori senza utilizzare i meccanismi di rete standard della distribuzione del contenitore. - Installeremo Bash, sudo, le librerie necessarie, aggiungeremo e configureremo un utente di sistema.
- Installeremo Python, i moduli e compileremo le dipendenze binarie per essi.
- Installeremo e avvieremo JupyterLab, configurando l'aspetto e installando le estensioni per esso.
In questo articolo inizieremo con l'avvio del contenitore; non considereremo l'installazione e la configurazione di LXD, tutto ciò lo puoi trovare in un altro articolo — Funzionalità di base di LXD — sistemi di contenitori in Linux..
Installazione e configurazione del sistema di base ^
Creiamo il contenitore con il comando in cui specifichiamo l'immagine — alpine3, l'identificativo per il contenitore — jupyterlab e se necessario profili di configurazione:
lxc init alpine3 jupyterlab --profile=default --profile=hddrootQui utilizzo un profilo di configurazione hddroot che indica di creare un contenitore con una partizione root in Storage Pool situata su un disco HDD fisico:
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:
- noneQuesto mi dà la possibilità di sperimentare con i contenitori su disco HDD risparmiando le risorse del disco SSD che ho anche nel mio sistema 🙂 per il quale ho creato un profilo di configurazione separato ssdroot.
Dopo la creazione del contenitore si trova in stato FERMATO, quindi dobbiamo avviarlo lanciando il sistema init al suo interno:
lxc start jupyterlabElencheremo i contenitori in LXD utilizzando la chiave -c che indica quali ccolonne visualizzare sullo schermo:
lxc list -c ns4b
+------------+---------+-------------------+--------------+
| NAME | STATE | IPV4 | STORAGE POOL |
+------------+---------+-------------------+--------------+
| jupyterlab | RUNNING | 10.0.5.198 (eth0) | hddpool |
+------------+---------+-------------------+--------------+Quando abbiamo creato il contenitore, l'indirizzo IP è stato scelto casualmente, poiché abbiamo utilizzato un profilo di configurazione default configurato in precedenza nell'articolo Funzionalità di base di LXD — sistemi di contenitori in Linux..
Modificheremo questo indirizzo IP in uno più memorabile, creando un'interfaccia di rete a livello di contenitore, anziché a livello di profilo di configurazione come attualmente nella configurazione corrente. Non è obbligatorio farlo; puoi anche saltare questo passaggio.
Creiamo un'interfaccia di rete eth0 che colleghiamo allo switch (bridge di rete) lxdbr0 nel quale abbiamo abilitato il NAT secondo l'articolo precedente e il contenitore avrà ora accesso a Internet, assegnando anche un indirizzo IP statico all'interfaccia — 10.0.5.5:
lxc config device add jupyterlab eth0 nic name=eth0 nictype=bridged parent=lxdbr0 ipv4.address=10.0.5.5Dopo aver aggiunto il dispositivo, è necessario riavviare il contenitore:
lxc restart jupyterlabControlliamo lo stato del contenitore:
lxc list -c ns4b
+------------+---------+------------------+--------------+
| NAME | STATE | IPV4 | STORAGE POOL |
+------------+---------+------------------+--------------+
| jupyterlab | RUNNING | 10.0.5.5 (eth0) | hddpool |
+------------+---------+------------------+--------------+Installazione del software di base e configurazione del sistema ^
Per amministrare il nostro contenitore, è necessario installare il seguente software:
Package
Descrizione
bash
La shell GNU Bourne Again
bash-completion
Completamento programmabile per la shell bash
sudo
Dai a determinati utenti la possibilità di eseguire alcuni comandi come root
shadow
Suite di strumenti per la gestione di password e account con supporto per file shadow e PAM
tzdata
Fonti per dati su fusi orari e ora legale
nano
Clone dell'editor Pico con migliorie
Inoltre, puoi installare il supporto per i man-pages installando i seguenti pacchetti — man man-pages mdocml-apropos less
lxc exec jupyterlab -- apk add bash bash-completion sudo shadow tzdata nanoAnalizziamo i comandi e le chiavi che abbiamo utilizzato:
lxc— Richiesta al client LXDexec— Metodo del client LXD che esegue un comando nel containerjupyterlab— Identificatore del container--— Chiave speciale che indica di non interpretare ulteriormente le chiavi come chiavi perlxce passare l'intera riga rimanente così com'è al containerapk— Gestore pacchetti della distribuzione Alpine Linuxadd— Metodo del gestore pacchetti che installa i pacchetti indicati dopo il comando
Successivamente, imposteremo il fuso orario nel sistema Europe/Moscow:
lxc exec jupyterlab -- cp /usr/share/zoneinfo/Europe/Moscow /etc/localtimeDopo aver impostato il fuso orario, il pacchetto tzdata non è più necessario nel sistema e occuperà spazio, quindi lo eliminiamo:
lxc exec jupyterlab -- apk del tzdataControlliamo il fuso orario:
lxc exec jupyterlab -- date
Mer Apr 15 10:49:56 MSK 2020Per risparmiare tempo nella configurazione di Bash per i nuovi utenti nel contenitore, procederemo copiando i file skel già pronti dal sistema host. Questo abbellirà Bash nel contenitore in modalità interattiva. Il mio sistema host è Manjaro Linux e i file copiati /etc/skel/.bash_profile, /etc/skel/.bashrc, /etc/skel/.dir_colors in linea di principio sono adatti ad Alpine Linux e non causano problemi critici, ma potreste avere un'altra distribuzione e dovrete affrontare eventuali errori di esecuzione di Bash nel contenitore.
Copiare i file skel nel contenitore. La chiave --create-dirs creerà le directory necessarie, se non esistono già:
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_colorsPer l'utente root già esistente, copieremo nella home directory i file skel appena copiati nel contenitore:
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_colorsIn Alpine Linux, per gli utenti viene impostata la shell di sistema /bin/sh, la sostituiremo con root per l'utente con Bash:
lxc exec jupyterlab -- usermod --shell=/bin/bash rootPer creare un file di esportazione del database di gestione sul server di origine: root l'utente non era senza password, deve impostare una password. Il comando seguente genererà e installerà una nuova password casuale che vedrai sullo schermo della console dopo l'esecuzione:
lxc exec jupyterlab -- /bin/bash -c "PASSWD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 12); echo "root:$PASSWD" | chpasswd && echo "Nuova Password: $PASSWD""
Nuova Password: sFiXEvBswuWAInoltre, creiamo un nuovo utente di sistema — jupyter per il quale configureremo in seguito JupyterLab:
lxc exec jupyterlab -- useradd --create-home --shell=/bin/bash jupyterGenereremo e installeremo una password per lui:
lxc exec jupyterlab -- /bin/bash -c "PASSWD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 12); echo "jupyter:$PASSWD" | chpasswd && echo "Nuova Password: $PASSWD""
Nuova Password: ZIcbzWrF8tkiPoi eseguiremo due comandi, il primo creerà un gruppo di sistema sudo, e il secondo aggiungerà l'utente a questo gruppo jupyter:
lxc exec jupyterlab -- groupadd --system sudo
lxc exec jupyterlab -- groupmems --group sudo --add jupyterControlliamo a quali gruppi appartiene l'utente jupyter:
lxc exec jupyterlab -- id -Gn jupyter
jupyter sudoTutto ok, proseguiamo.
Consentiamo a tutti gli utenti che appartengono al gruppo sudo di usare il comando sudo. Per fare ciò, eseguire il seguente script, che sed decommenta la riga del parametro nel file di configurazione /etc/sudoers:
lxc exec jupyterlab -- /bin/bash -c "sed --in-place -e '/^#[ t]*%sudo[ t]*ALL=(ALL)[ t]*ALL$/ s/^[# ]*//' /etc/sudoers"Installazione e configurazione di JupyterLab ^
JupyterLab — è un'applicazione Python, quindi dobbiamo prima installare questo interprete. Inoltre, JupyterLab installeremo utilizzando il gestore di pacchetti Python pip, e non quello di sistema, perché nel repository di sistema potrebbe essere obsoleto, quindi dobbiamo risolvere manualmente le dipendenze installando i seguenti pacchetti — python3 python3-dev gcc libc-dev zeromq-dev:
lxc exec jupyterlab -- apk add python3 python3-dev gcc libc-dev zeromq-devAggiorniamo i moduli Python e il gestore di pacchetti pip alla versione più recente:
lxc exec jupyterlab -- python3 -m pip install --upgrade pip setuptools wheelInstalliamo JupyterLab attraverso il gestore di pacchetti pip:
lxc exec jupyterlab -- python3 -m pip install jupyterlabPoiché le estensioni in JupyterLab sono sperimentali e non sono ufficialmente fornite insieme al pacchetto jupyterlab, dobbiamo installarle e configurarle manualmente.
Installeremo NodeJS e il suo gestore di pacchetti — NPM, poiché JupyterLab li utilizza per le sue estensioni:
lxc exec jupyterlab -- apk add nodejs npmAffinché le estensioni per JupyterLab funzionino, devono essere installate nella directory utente poiché l'applicazione verrà eseguita dall'utente jupyter. Il problema è che non c'è un parametro nel comando di avvio attraverso il quale possiamo passare una directory; l'applicazione riconosce solo la variabile d'ambiente e quindi dobbiamo definirla. Per farlo, scriveremo il comando per esportare la variabile. JUPYTERLAB_DIR nell'ambiente utente jupyter, in un file .bashrc, che viene eseguito ogni volta che l'utente accede al sistema:
lxc exec jupyterlab -- su -l jupyter -c "echo -e "nexport JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab" >> .bashrc"Con il comando successivo installeremo un'estensione speciale — il gestore delle estensioni in 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"Ora è tutto pronto per il primo avvio JupyterLab, ma possiamo anche installare alcune estensioni utili:
toc— Table of Contents, genera un elenco di intestazioni nell'articolo/notebookjupyterlab-horizon-theme— Tema dell'interfaccia utentejupyterlab_neon_theme— Tema dell'interfaccia utentejupyterlab-ubu-theme— Un altro tema dell'autore di questo articolo 🙂 Ma in questo caso, sarà mostrata l'installazione dal repository GitHub
Quindi, esegui consecutivamente i seguenti comandi per installare queste estensioni:
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"Dopo l'installazione delle estensioni, dobbiamo compilarle, poiché in precedenza avevamo specificato l'opzione --no-build per risparmiare tempo. Ora accelereremo notevolmente compilando tutto insieme in una sola volta:
lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter lab build"Adesso esegui i seguenti due comandi per il primo avvio JupyterLab. Si potrebbe avviarlo con un solo comando, ma in questo caso, il comando di avvio, che dovremmo ricordare, sarà memorizzato da bash nel contenitore, e non nell'host, dove ci sono già abbastanza comandi da registrare nella storia 🙂
Accediamo al contenitore come utente jupyter:
lxc exec jupyterlab -- su -l jupyterQuindi avvia JupyterLab con le opzioni e i parametri come indicato:
[jupyter@jupyterlab ~]$ jupyter lab --ip=0.0.0.0 --no-browserVai nel tuo browser web all'indirizzo http://10.0.5.5:8888 e nella pagina che si apre, inserisci il token di accesso che vedrai nella console. Copialo e incollalo nella pagina, poi premi Accesso. Dopo aver effettuato l'accesso, nel menu a sinistra delle estensioni vai come mostrato nell'immagine qui sotto, dove ti verrà chiesto di accettare i rischi di sicurezza all'attivazione del gestore delle estensioni installando estensioni di terze parti per le quali il team JupyterLab development non si assume responsabilità:

Tuttavia, noi proprio per questo isoliamo completamente JupyterLab e lo inseriamo in un contenitore, affinché le estensioni di terze parti che richiedono e utilizzano NodeJS non possano almeno rubare i dati sul disco, oltre a quelli che apriremo all'interno del contenitore. Accedere ai tuoi documenti privati sull'host /home dai processi del contenitore sarà difficile, e se ci riusciranno, avranno bisogno di privilegi sui file nel sistema host, poiché eseguiamo il contenitore in modalità non privilegiata. In base a queste informazioni puoi valutare il rischio di abilitare le estensioni in JupyterLab.
I notebook IPython creati (pagine in JupyterLab) verranno ora creati nella directory home dell'utente — /home/jupyter, ma nei nostri piani c'è l'intenzione di condividere i dati (condividere) tra l'host e il contenitore, quindi, torna alla console e ferma JupyterLab eseguendo la combinazione di tasti — CTRL+C e rispondendo y alla richiesta. Quindi termina la sessione interattiva dell'utente jupyter eseguendo la combinazione di tasti CTRL+D.
Condividiamo i dati con l'host ^
Per condividere i dati con l'host, è necessario creare nel contenitore un dispositivo che lo consenta e per questo esegui il seguente comando dove indichiamo le seguenti chiavi:
lxc config device add— Il comando aggiunge la configurazione del dispositivojupyter— L'identificatore del contenitore nel quale viene aggiunta la configurazionehostfs— L'identificatore del dispositivo. Puoi assegnare qualsiasi nome.disk— Viene specificato il tipo di dispositivopath— Viene specificato il percorso nel contenitore a cui LXD monterà questo dispositivosource— Viene specificata la sorgente, il percorso alla cartella sull'host che desideri condividere con il contenitore. Specifica il percorso secondo le tue preferenze
lxc config device add jupyterlab hostfs disk path=/mnt/hostfs source=/home/dv/projects/ipython-notebooksPer la cartella /home/dv/projects/ipython-notebooks deve essere impostato il permesso all'utente del contenitore che attualmente ha UID pari a SubUID + UID, vedi il capitolo Sicurezza. Privilegi dei contenitori nell'articolo Funzionalità di base di LXD — sistemi di contenitori in Linux..
Impostiamo le autorizzazioni sull'host, dove il proprietario sarà l'utente del contenitore jupyter, e la variabile $USER indicherà il tuo utente host come gruppo:
sudo chown 1001000:$USER /home/dv/projects/ipython-notebooksHello, World! ^
Se hai ancora una sessione della console aperta nel contenitore con JupyterLab, riavviala con il nuovo parametro --notebook-dir impostando il valore /mnt/hostfs come percorso della radice dei notebook nel contenitore per il dispositivo che abbiamo creato nel passaggio precedente:
jupyter lab --ip=0.0.0.0 --no-browser --notebook-dir=/mnt/hostfsPoi vai alla pagina http://10.0.5.5:8888 e crea il tuo primo notebook premendo il pulsante sulla pagina come indicato nell'immagine qui sotto:

Poi nel campo della pagina, inserisci il codice in Python che stamperà il classico Hello World!. Alla fine dell'inserimento, premi CTRL+ENTER o il pulsante «play» nella barra degli strumenti in alto affinché JupyterLab esegua questo:

Quasi tutto è pronto all'uso, ma non sarebbe interessante se non installassimo moduli Python aggiuntivi (applicazioni complete) che consentono di ampliare notevolmente le funzionalità standard di Python in JupyterLab, quindi, andiamo avanti 🙂
P.S. È interessante notare che la vecchia implementazione Jupyter con nome in codice Jupyter Notebook non è scomparsa e esiste parallelamente con JupyterLab. Per passare alla vecchia versione, vai al link aggiungendo il suffisso nell'indirizzo/tree, mentre il passaggio alla nuova versione avviene con il suffisso /lab, ma non è necessario specificarlo:
- Jupyter Notebook — http://10.0.5.5:8888/tree
- Jupyter Lab — http://10.0.5.5:8888/lab
Espandiamo le capacità di Python ^
In questa sezione installeremo potenti moduli del linguaggio Python come NumPy, Pandas, Matplotlib, IPyWidgets i cui risultati saranno integrati nei notebook JupyterLab.
Prima di installare i moduli Python elencati tramite il gestore pacchetti pip dobbiamo innanzitutto risolvere le dipendenze di sistema in Alpine Linux:
g++— Necessario per la compilazione dei moduli, poiché alcuni di essi sono implementati in C++ e vengono collegati a Python durante il runtime come moduli binarifreetype-dev— dipendenza per il modulo Python Matplotlib
Installa le dipendenze:
lxc exec jupyterlab -- apk add g++ freetype-devC'è un problema, attualmente in Alpine Linux non riesco a compilare una nuova versione di NumPy, si verificherà un errore di compilazione che non sono riuscito a risolvere:
ERROR: Impossibile costruire ruote per numpy che usano PEP 517 e non possono essere installate direttamente
Pertanto, installeremo questo modulo come pacchetto di sistema che distribuisce già una versione compilata, ma un po' più vecchia rispetto a quella attualmente disponibile sul sito:
lxc exec jupyterlab -- apk add py3-numpy py3-numpy-devSuccessivamente, installiamo i moduli Python tramite il gestore pacchetti pip. Abbiate pazienza, poiché alcuni moduli devono essere compilati e questo richiederà qualche minuto. Sulla mia macchina, la compilazione ha impiegato circa 15 minuti:
lxc exec jupyterlab -- python3 -m pip install pandas ipywidgets matplotlibPuliamo le cache delle installazioni:
lxc exec jupyterlab -- rm -rf /home/*/.cache/pip/*
lxc exec jupyterlab -- rm -rf /root/.cache/pip/*Testiamo i moduli in JupyterLab ^
Se hai avviato JupyterLab, riavvialo per attivare i nuovi moduli installati. Per farlo, nella sessione della console premi CTRL+C dove è in esecuzione e inserisci y alla richiesta di arresto, quindi riavvialo JupyterLab premendo il tasto «su» della tastiera, per non dover reinserire il comando, e poi Enter per avviare:
jupyter lab --ip=0.0.0.0 --no-browser --notebook-dir=/mnt/hostfsVai alla pagina http://10.0.5.5:8888/lab o ricarica la pagina nel browser, quindi inserisci il seguente codice in una nuova cella del notebook:
%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_plotDovresti ottenere un risultato simile all'immagine qui sotto, dove IPyWidgets genera un elemento UI sulla pagina che interagisce in modo interattivo con il codice sorgente, e anche Matplotlib visualizza il risultato del codice come un diagramma funzionale:

Molti esempi IPyWidgets puoi trovarli nei tutorial qui
Cosa altro? ^
Bravi a voi che siete arrivati fino alla fine dell'articolo. Non ho voluto pubblicare uno script pronto alla fine dell'articolo che installasse JupyterLab in «un clic», per incoraggiare i lavoratori 🙂 Ma potete farlo da soli, dato che già sapete come, raccogliendo i comandi in un unico script Bash 🙂
Inoltre, puoi:
- Impostare un nome di rete per il contenitore invece dell'indirizzo IP scrivendolo in semplice
/etc/hostse digitare l'indirizzo nel browser http://jupyter.local:8888 - Giocare con le limitazioni delle risorse per il contenitore, per questo leggi il capitolo su le funzionalità di base di LXD o ottieni maggiori informazioni sul sito dello sviluppatore di LXD.
- Cambiare il tema:

E molto altro ancora puoi fare! Questo è tutto. Ti auguro successo!
AGGIORNAMENTO: 15.04.2020 18:30 — Corretto gli errori nel capitolo «Hello, World!»
AGGIORNAMENTO: 16.04.2020 10:00 — Corretto e aggiunto testo nella descrizione dell'attivazione del gestore delle estensioni JupyterLab
AGGIORNAMENTO: 16.04.2020 10:40 — Corretto errori trovati nel testo e leggermente migliorato il capitolo «Installazione del software di base e configurazione del sistema»
Fonte: habr.com
