Lansarea Jupyter pe orbita LXD

Ați fost nevoit vreodată să experimentați cu cod sau utilități de sistem în Linux pentru a nu vă face griji pentru sistemul de bază și pentru a nu dărâma totul în cazul unei erori în codul care ar trebui să ruleze cu privilegii root?

Dar cum rămâne cu faptul că să presupunem că trebuie să testați sau să rulați un întreg cluster de diverse microservicii pe o singură mașină? O sută sau chiar o mie?

Cu mașinile virtuale gestionate de un hypervisor, astfel de probleme pot și vor fi rezolvate, dar cu ce preț? De exemplu, un container în LXD bazat pe distribuția Alpine Linux consumă numai 7.60MB RAM și unde ocupă partiția rădăcină după pornire 9.5MB! Cum îți place asta, Elon Musk? Recomand să verificați capabilitățile de bază ale LXD - un sistem container în Linux

După ce a devenit clar ce sunt containerele LXD, să mergem mai departe și să ne gândim, ce ar fi dacă ar exista o astfel de platformă de recoltat unde ai putea rula codul în siguranță pentru gazdă, ai putea genera grafice, a lega dinamic (interactiv) widget-urile UI cu codul tău, completati codul cu text cu blackjack... formatare? Un fel de blog interactiv? Wow... o vreau! Vrei! 🙂

Uită-te sub pisică unde vom lansa într-un container laborator jupyter - următoarea generație de interfață cu utilizatorul în locul notebook-ului Jupyter învechit și vom instala și module Python, cum ar fi NumPy, ursi panda, matplotlib, IPyWidgets ceea ce vă va permite să faceți tot ce este enumerat mai sus și să le salvați într-un fișier special - un laptop IPython.

Lansarea Jupyter pe orbita LXD

Planul de decolare orbital ^

Lansarea Jupyter pe orbita LXD

Să schițăm un scurt plan de acțiune pentru a ne ușura implementarea schemei de mai sus:

  • Să instalăm și să lansăm un container bazat pe kitul de distribuție Linux Alpine. Vom folosi această distribuție pentru că vizează minimalismul și vom instala în ea doar cel mai necesar software, nimic de prisos.
  • Să adăugăm un disc virtual suplimentar în container și să-i dăm un nume - hostfs și montați-l pe sistemul de fișiere rădăcină. Acest disc va face posibilă utilizarea fișierelor pe gazdă dintr-un anumit director din interiorul containerului. Astfel, datele noastre vor fi independente de container. Dacă containerul este șters, datele vor rămâne pe gazdă. De asemenea, această schemă este utilă pentru partajarea acelorași date între mai multe containere fără a utiliza mecanismele de rețea standard ale distribuției de containere.
  • Să instalăm Bash, sudo, bibliotecile necesare, să adăugăm și să configurem un utilizator de sistem
  • Să instalăm Python, module și să compilăm dependențe binare pentru ele
  • Hai să instalăm și să lansăm laborator jupyter, personalizați aspectul, instalați extensii pentru acesta.

În acest articol vom începe cu lansarea containerului, nu vom lua în considerare instalarea și configurarea LXD, toate acestea le puteți găsi într-un alt articol - Caracteristicile de bază ale sistemelor de containere LXD - Linux.

Instalarea și configurarea sistemului de bază ^

Creăm un container cu comanda în care specificăm imaginea - alpine3, identificator pentru container - jupyterlab și, dacă este necesar, profiluri de configurare:

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

Aici folosesc un profil de configurare hddroot care specifică crearea unui container cu o partiție rădăcină în Bazin de depozitare situat pe un disc HDD fizic:

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

Acest lucru îmi oferă posibilitatea de a experimenta cu containere de pe discul HDD, salvând resursele discului SSD, care este disponibil și în sistemul meu 🙂 pentru care am creat un profil de configurare separat ssdroot.

După ce containerul este creat, acesta este în stare STOPPED, așa că trebuie să-l pornim rulând sistemul init în el:

lxc start jupyterlab

Să afișăm o listă de containere în LXD folosind tasta -c care indică care cAfișează coloane:

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

La crearea containerului, adresa IP a fost aleasă aleatoriu, deoarece am folosit un profil de configurare default care a fost configurat anterior în articol Caracteristicile de bază ale sistemelor de containere LXD - Linux.

Vom schimba această adresă IP cu una mai memorabilă prin crearea unei interfețe de rețea la nivel de container, și nu la nivelul profilului de configurare, așa cum este acum în configurația curentă. Nu trebuie să faci asta, poți sări peste el.

Crearea unei interfețe de rețea eth0 pe care îl conectăm la comutator (punte de rețea) lxdbr0 în care am activat NAT conform articolului anterior și containerul va avea acum acces la Internet și atribuim, de asemenea, o adresă IP statică interfeței - 10.0.5.5:

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

După adăugarea unui dispozitiv, containerul trebuie repornit:

lxc restart jupyterlab

Verificarea stării containerului:

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

Instalarea software-ului de bază și configurarea sistemului ^

Pentru a administra containerul nostru, trebuie să instalați următorul software:

Pachet
Descriere

pocni
Shell-ul GNU Bourne Again

bash-completare
Finalizare programabilă pentru shell-ul bash

sudo
Oferiți anumitor utilizatori posibilitatea de a rula unele comenzi ca root

umbră
Suită de instrumente de gestionare a parolelor și a contului cu suport pentru fișiere umbră și PAM

tzdata
Surse pentru date privind fusul orar și ora de vară

nano
Pico editor clonă cu îmbunătățiri

În plus, puteți instala suport în paginile de manual de sistem instalând următoarele pachete − man man-pages mdocml-apropos less

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

Să ne uităm la comenzile și tastele pe care le-am folosit:

  • lxc — Apelați clientul LXD
  • exec - Metoda client LXD care rulează o comandă în container
  • jupyterlab - ID container
  • -- — O cheie specială care specifică să nu se interpreteze alte chei ca chei pentru lxc și treceți restul sforii așa cum este în recipient
  • apk — Manager de pachete de distribuție Alpine Linux
  • add — O metodă de gestionare a pachetelor care instalează pachetele specificate după comandă

În continuare, vom seta un fus orar în sistem Europe/Moscow:

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

După instalarea fusului orar, pachetul tzdata nu mai este necesar în sistem, va ocupa spațiu, așa că să-l ștergem:

lxc exec jupyterlab -- apk del tzdata

Verificarea fusului orar:

lxc exec jupyterlab -- date

Wed Apr 15 10:49:56 MSK 2020

Pentru a nu petrece mult timp instalând Bash pentru utilizatori noi în container, în următorii pași vom copia fișiere skel gata făcute din sistemul gazdă în acesta. Acest lucru vă va permite să înfrumusețați Bash într-un container în mod interactiv. Sistemul meu gazdă este Manjaro Linux și fișierele care sunt copiate /etc/skel/.bash_profile, /etc/skel/.bashrc, /etc/skel/.dir_colors în principiu, sunt potrivite pentru Alpine Linux și nu cauzează probleme critice, dar este posibil să aveți o distribuție diferită și trebuie să vă dați seama în mod independent dacă există o eroare la rularea Bash în container.

Copiați fișierele skel în container. Cheie --create-dirs va crea directoarele necesare dacă acestea nu există:

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

Pentru un utilizator root deja existent, copiați fișierele skel tocmai copiate în container în directorul principal:

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 instalează un shell de sistem pentru utilizatori /bin/sh, îl vom înlocui cu root utilizator în Bash:

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

root utilizatorul nu a fost fără parolă, trebuie să seteze o parolă. Următoarea comandă va genera și seta o nouă parolă aleatorie pentru el, pe care o veți vedea pe ecranul consolei după executarea acesteia:

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

De asemenea, să creăm un nou utilizator de sistem - jupyter pentru care vom configura ulterior laborator jupyter:

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

Să generăm și să setăm o parolă pentru aceasta:

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

În continuare, vom executa două comenzi, prima va crea un grup de sistem sudo, iar al doilea va adăuga un utilizator la acesta jupyter:

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

Să vedem la ce grupuri aparține utilizatorul jupyter:

lxc exec jupyterlab -- id -Gn jupyter

jupyter sudo

Totul e ok, hai sa mergem mai departe.

Permiteți tuturor utilizatorilor care sunt membri ai grupului sudo folosește comanda sudo. Pentru a face acest lucru, rulați următorul script, unde sed decommentează linia parametrilor din fișierul de configurare /etc/sudoers:

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

Instalarea și configurarea JupyterLab ^

laborator jupyter este o aplicație Python, așa că trebuie mai întâi să instalăm acest interpret. De asemenea, laborator jupyter vom instala folosind managerul de pachete Python pip, și nu cel de sistem, deoarece poate fi învechit în depozitul de sistem și, prin urmare, trebuie să rezolvăm manual dependențele pentru acesta instalând următoarele pachete - python3 python3-dev gcc libc-dev zeromq-dev:

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

Să actualizăm modulele Python și managerul de pachete pip la versiunea curentă:

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

Set laborator jupyter prin managerul de pachete pip:

lxc exec jupyterlab -- python3 -m pip install jupyterlab

Din moment ce extensiile în laborator jupyter sunt experimentale și nu sunt livrate oficial cu pachetul jupyterlab, așa că trebuie să îl instalăm și să îl configuram manual.

Să instalăm NodeJS și managerul de pachete pentru acesta - NPM, de atunci laborator jupyter le folosește pentru extensiile sale:

lxc exec jupyterlab -- apk add nodejs npm

La extensii pentru laborator jupyter pe care le vom instala au funcționat, acestea trebuie instalate în directorul utilizatorului deoarece aplicația va fi lansată de la utilizator jupyter. Problema este că nu există niciun parametru în comanda de lansare care să poată fi transmis într-un director; aplicația acceptă doar o variabilă de mediu și de aceea trebuie să o definim. Pentru a face acest lucru, vom scrie comanda de export variabilă JUPYTERLAB_DIR în mediul utilizatorului jupyter, la dosar .bashrccare se execută de fiecare dată când utilizatorul se conectează:

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

Următoarea comandă va instala o extensie specială - manager de extensii în laborator 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"

Acum totul este gata pentru prima lansare laborator jupyter, dar putem instala în continuare câteva extensii utile:

  • toc — Cuprins, generează o listă de titluri într-un articol/caiet
  • jupyterlab-horizon-theme - Tema interfeței de utilizare
  • jupyterlab_neon_theme - Tema interfeței de utilizare
  • jupyterlab-ubu-theme - Încă unul tema de la autor acest articol :) Dar în acest caz, instalarea din depozitul GitHub va fi afișată

Deci, executați următoarele comenzi secvenţial pentru a instala aceste extensii:

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"

După instalarea extensiilor, trebuie să le compilam, deoarece anterior, în timpul instalării, am specificat cheia --no-build pentru a salva timp. Acum vom accelera în mod semnificativ, compilându-le împreună dintr-o singură mișcare:

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

Acum rulați următoarele două comenzi pentru a o rula pentru prima dată laborator jupyter. Ar fi posibil să o lansați cu o singură comandă, dar în acest caz, comanda de lansare, care este greu de reținut în minte, va fi amintită prin bash în container, și nu pe gazdă, unde există deja suficiente comenzi sa le inregistrez in istorie :)

Conectați-vă la container ca utilizator jupyter:

lxc exec jupyterlab -- su -l jupyter

Apoi, fugi laborator jupyter cu cheile și parametrii indicați:

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

Accesați adresa din browserul dvs. web http://10.0.5.5:8888 iar pe pagina care se deschide intra semn acces pe care îl veți vedea în consolă. Copiați și inserați-l pe pagină, apoi faceți clic Conectare . După autentificare, accesați meniul de extensii din stânga, așa cum se arată în figura de mai jos, unde vi se va solicita, la activarea managerului de extensii, să vă asumați riscuri de securitate instalând extensii de la terți pentru care comanda Dezvoltare JupyterLab nu este responsabil:

Lansarea Jupyter pe orbita LXD

Cu toate acestea, izolăm întregul laborator jupyter și plasați-l într-un container astfel încât extensiile terțe care necesită și folosesc NodeJS să nu poată fura măcar date de pe disc, altele decât cele pe care le deschidem în interiorul containerului. Accesați documentele dvs. private pe gazdă în /home este puțin probabil ca procesele din container să reușească, iar dacă o reușesc, atunci trebuie să aveți privilegii asupra fișierelor din sistemul gazdă, deoarece rulăm containerul în modul neprivilegiat. Pe baza acestor informații, puteți evalua riscul includerii extensiilor în laborator jupyter.

S-au creat notebook-uri IPython (pagini în laborator jupyter) va fi acum creat în directorul principal al utilizatorului - /home/jupyter, dar planurile noastre sunt să împărțim datele (partajarea) între gazdă și container, așa că reveniți la consolă și opriți laborator jupyter prin executarea tastei rapide - CTRL+C si raspunzand y la cerere. Apoi închideți sesiunea interactivă a utilizatorului jupyter completând o tastă rapidă CTRL+D.

Partajarea datelor cu gazda ^

Pentru a partaja date cu gazda, trebuie să creați un dispozitiv în container care vă permite să faceți acest lucru și pentru a face acest lucru, rulați următoarea comandă unde specificăm următoarele chei:

  • lxc config device add — Comanda adaugă configurația dispozitivului
  • jupyter — ID-ul containerului la care se adaugă configurația
  • hostfs - Identificatorul dispozitivului. Puteți seta orice nume.
  • disk — Este indicat tipul de dispozitiv
  • path — Specifică calea din container pe care LXD va monta acest dispozitiv
  • source — Specificați sursa, calea către directorul de pe gazdă pe care doriți să-l partajați cu containerul. Specificați calea în funcție de preferințele dvs
lxc config device add jupyterlab hostfs disk path=/mnt/hostfs source=/home/dv/projects/ipython-notebooks

Pentru catalog /home/dv/projects/ipython-notebooks permisiunea trebuie setată pentru utilizatorul containerului care are în prezent un UID egal cu SubUID + UID, vezi capitolul Siguranță. Privilegii container în articol Caracteristicile de bază ale sistemelor de containere LXD - Linux.

Setați permisiunea pe gazdă, unde proprietarul va fi utilizatorul containerului jupyter, și variabila $USER va specifica utilizatorul gazdă ca grup:

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

Salut Lume! ^

Dacă mai aveți o sesiune de consolă deschisă în container cu laborator jupyter, apoi reporniți-l cu o cheie nouă --notebook-dir prin setarea valorii /mnt/hostfs ca cale către rădăcina laptopurilor din containerul pentru dispozitivul pe care l-am creat în pasul anterior:

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

Apoi mergi la pagina http://10.0.5.5:8888 și creează primul tău laptop făcând clic pe butonul de pe pagină, așa cum se arată în imaginea de mai jos:

Lansarea Jupyter pe orbita LXD

Apoi, în câmpul din pagină, introduceți codul Python care va afișa clasicul Hello World!. Când ați terminat de introdus, apăsați CTRL+ENTER sau butonul „play” din bara de instrumente din partea de sus pentru ca JupyterLab să facă acest lucru:

Lansarea Jupyter pe orbita LXD

În acest moment, aproape totul este gata de utilizare, dar va fi neinteresant dacă nu instalăm module Python suplimentare (aplicații cu drepturi depline) care pot extinde semnificativ capacitățile standard ale Python în laborator jupyter, deci, hai sa mergem mai departe :)

PS Lucrul interesant este că vechea implementare jupyter sub nume de cod Jupiter Notebook nu a dispărut și există în paralel cu laborator jupyter. Pentru a trece la versiunea veche, urmați linkul adăugând sufixul în adresă/tree, iar trecerea la noua versiune se realizează cu sufixul /lab, dar nu trebuie specificat:

Extinderea capabilităților Python ^

În această secțiune, vom instala module de limbaj Python atât de puternice precum NumPy, ursi panda, matplotlib, IPyWidgets ale căror rezultate sunt integrate în laptopuri laborator jupyter.

Înainte de a instala modulele Python enumerate prin managerul de pachete pip mai întâi trebuie să rezolvăm dependențele de sistem în Alpine Linux:

  • g++ — Necesar pentru compilarea modulelor, deoarece unele dintre ele sunt implementate în limbaj C ++ și conectați-vă la Python în timpul rulării ca module binare
  • freetype-dev - dependență pentru modulul Python matplotlib

Instalarea dependențelor:

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

Există o problemă: în starea actuală a distribuției Alpine Linux, nu va fi posibilă compilarea noii versiuni de NumPy; va apărea o eroare de compilare pe care nu am putut-o rezolva:

EROARE: Nu s-au putut construi roți pentru numpy care utilizează PEP 517 și nu pot fi instalate direct

Prin urmare, vom instala acest modul ca un pachet de sistem care distribuie o versiune deja compilată, dar puțin mai veche decât cea disponibilă în prezent pe site:

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

Apoi, instalați modulele Python prin managerul de pachete pip. Vă rugăm să aveți răbdare, deoarece unele module se vor compila și pot dura câteva minute. Pe mașina mea, compilarea a durat aproximativ 15 minute:

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

Ștergerea cache-urilor de instalare:

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

Testarea modulelor în JupyterLab ^

Dacă alergi laborator jupyter, reporniți-l astfel încât modulele nou instalate să fie activate. Pentru a face acest lucru, într-o sesiune de consolă, faceți clic CTRL+C unde il ai in functiune si intra y pentru a opri cererea și apoi a începe din nou laborator jupyter prin apăsarea săgeții sus de pe tastatură pentru a nu mai introduce comanda și apoi Enter pentru a o porni:

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

Accesați pagina http://10.0.5.5:8888/lab sau reîmprospătați pagina în browser și apoi introduceți următorul cod într-o nouă celulă de blocnotes:

%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

Ar trebui să obțineți un rezultat ca în imaginea de mai jos, unde IPyWidgets generează un element UI pe pagină care interacționează interactiv cu codul sursă și, de asemenea matplotlib afișează rezultatul codului sub forma unei imagini ca grafic al funcției:

Lansarea Jupyter pe orbita LXD

Multe exemple IPyWidgets il gasesti in tutoriale aici

Ce altceva? ^

Bravo dacă ai rămas și ai ajuns chiar la sfârșitul articolului. În mod deliberat, nu am postat un script gata făcut la sfârșitul articolului care să se instaleze laborator jupyter cu „un singur clic” pentru a încuraja lucrătorii :) Dar o puteți face singur, deoarece știți deja cum, după ce ați adunat comenzile într-un singur script Bash :)

Poti de asemenea:

  • Setați un nume de rețea pentru container în loc de o adresă IP scriind-o într-un mod simplu /etc/hosts și introduceți adresa în browser http://jupyter.local:8888
  • Joacă-te cu limita de resurse pentru container, pentru asta citește capitolul din capabilități de bază LXD sau obțineți mai multe informații pe site-ul pentru dezvoltatori LXD.
  • Schimbați tema:

Lansarea Jupyter pe orbita LXD

Și multe altele poți face! Asta e tot. Vă doresc succes!

UPDATE: 15.04.2020 18:30 - Erori corectate la capitolul „Bună, lume!”
UPDATE: 16.04.2020 10:00 — Text corectat și adăugat în descrierea activării managerului de extensii laborator jupyter
UPDATE: 16.04.2020/10/40 XNUMX:XNUMX — S-au corectat erorile găsite în text și s-a modificat ușor în bine capitolul „Instalarea software-ului de bază și configurarea sistemului”

Sursa: www.habr.com

Adauga un comentariu