Лансирање на Јупитер во орбитата LXD

Дали некогаш сте морале да експериментирате со код или системски услужни програми во Linux за да не се грижите за основниот систем и да не уништите сè во случај на грешка во кодот што треба да работи со права на root?

Но, што е со фактот дека, да речеме, треба да тестирате или извршите цел кластер од различни микросервиси на една машина? Сто или дури илјада?

Со виртуелни машини управувани од хипервизор, ваквите проблеми можат и ќе се решат, но по која цена? На пример, контејнер во LXD базиран на дистрибуцијата на Alpine Linux троши само 7.60MB RAM меморија, и каде root партицијата зафаќа по стартувањето 9.5MB! Како ти се допаѓа тоа, Илон Маск? Препорачувам да се проверите основните можности на LXD - контејнерски систем во Linux

Откако стана јасно што се LXD контејнерите, ајде да одиме понатаму и да размислиме, што ако постоеше таква платформа за жетвар каде што можете безбедно да извршите код за домаќинот, да генерирате графикони, динамично (интерактивно) да ги поврзувате UI-виџетите со вашиот код, дополни го кодот со текст со блек џек... форматирање? Некој вид на интерактивен блог? Леле... сакам! Сака! 🙂

Погледнете под мачката каде што ќе лансираме во контејнер јупитер лабораторија - следната генерација на кориснички интерфејс наместо застарениот Jupyter Notebook, а ќе инсталираме и Python модули како на пр. Нуп, Панди, Матплотлиб, IPyWidgets што ќе ви овозможи да направите се што е наведено погоре и да го зачувате сето тоа во посебна датотека - лаптоп IPython.

Лансирање на Јупитер во орбитата LXD

План за орбитално полетување ^

Лансирање на Јупитер во орбитата LXD

Ајде да претставиме краток акционен план за да ни биде полесно да ја имплементираме шемата погоре:

  • Ајде да инсталираме и лансираме контејнер врз основа на комплетот за дистрибуција Alpine Linux. Ќе ја користиме оваа дистрибуција бидејќи е насочена кон минимализам и во неа ќе го инсталираме само најпотребниот софтвер, ништо излишно.
  • Ајде да додадеме дополнителен виртуелен диск во контејнерот и да му дадеме име - hostfs и монтирајте го во root датотечен систем. Овој диск ќе овозможи да се користат датотеки на домаќинот од даден директориум внатре во контејнерот. Така, нашите податоци ќе бидат независни од контејнерот. Ако контејнерот е избришан, податоците ќе останат на домаќинот. Исто така, оваа шема е корисна за споделување исти податоци помеѓу многу контејнери без користење на стандардните мрежни механизми на дистрибуцијата на контејнери.
  • Ајде да инсталираме Bash, sudo, потребните библиотеки, да додадеме и конфигурираме системски корисник
  • Ајде да инсталираме Python, модули и да составиме бинарни зависности за нив
  • Ајде да инсталираме и стартуваме јупитер лабораторија, прилагодете го изгледот, инсталирајте екстензии за него.

Во оваа статија ќе започнеме со лансирање на контејнерот, нема да размислуваме за инсталирање и конфигурирање на LXD, сето ова можете да го најдете во друга статија - Основни карактеристики на LXD - Linux контејнерските системи.

Инсталација и конфигурација на основниот систем ^

Создаваме контејнер со командата во која ја одредуваме сликата - alpine3, идентификатор за контејнерот - jupyterlab и, доколку е потребно, конфигурациски профили:

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

Еве јас користам профил за конфигурација hddroot кој одредува да се создаде контејнер со root партиција во Базен за складирање лоциран на физички 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, па затоа треба да го стартуваме со вклучување на системот иниција во него:

lxc start jupyterlab

Ајде да прикажеме листа на контејнери во 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

баш-завршување
Програмабилно завршување за баш школка

sudo
Дајте им на одредени корисници можност да извршуваат некои команди како root

сенка
Пакет алатки за управување со лозинки и сметки со поддршка за датотеки во сенка и PAM

тздата
Извори за податоци за временската зона и летното сметање на времето

нано
Клонирање на уредувачот Пико со подобрувања

Дополнително, можете да инсталирате поддршка во системските man-pages со инсталирање на следните пакети − man man-pages mdocml-apropos less

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

Ајде да ги погледнеме командите и копчињата што ги користевме:

  • lxc — Повикајте го клиентот LXD
  • exec - LXD клиент метод кој извршува команда во контејнерот
  • jupyterlab — ИД на контејнер
  • -- - Посебен клуч кој одредува да не се толкуваат понатамошни клучеви како клучеви за 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 за нови корисници во контејнерот, во следните чекори ќе ги копираме готовите скел-датотеки од системот домаќин на него. Ова ќе ви овозможи интерактивно да го разубавите Bash во контејнер. Мојот систем за домаќин е Manjaro Linux и датотеките се копираат /etc/skel/.bash_profile, /etc/skel/.bashrc, /etc/skel/.dir_colors во принцип тие се погодни за Alpine Linux и не предизвикуваат критични проблеми, но може да имате различна дистрибуција и треба самостојно да откриете дали има грешка при извршувањето на Bash во контејнерот.

Копирајте ги датотеките со скел во контејнерот. Клуч --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 инсталира системска школка за корисниците /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 за што подоцна ќе конфигурираме јупитер лабораторија:

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 ^

јупитер лабораторија е апликација за Python, затоа прво мора да го инсталираме овој толкувач. Исто така, јупитер лабораторија ќе инсталираме користејќи го менаџерот на пакети 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

Намести јупитер лабораторија преку менаџер на пакети pip:

lxc exec jupyterlab -- python3 -m pip install jupyterlab

Бидејќи проширувањата во јупитер лабораторија се експериментални и не се официјално испорачани со пакетот jupyterlab, затоа мораме рачно да го инсталираме и конфигурираме.

Ајде да инсталираме NodeJS и менаџерот на пакети за него - NPM, бидејќи јупитер лабораторија ги користи за своите екстензии:

lxc exec jupyterlab -- apk add nodejs npm

До екстензии за јупитер лабораторија кои ќе ги инсталираме работеа, тие треба да се инсталираат во корисничкиот директориум бидејќи апликацијата ќе биде лансирана од корисникот jupyter. Проблемот е што нема параметар во командата за лансирање што може да се пренесе во директориумот; апликацијата прифаќа само променлива на околината и затоа мора да ја дефинираме. За да го направите ова, ќе ја напишеме командата за променлива извоз JUPYTERLAB_DIR во околината на корисникот jupyter, да поднесе .bashrcшто се извршува секогаш кога корисникот се најавува:

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

Следната команда ќе инсталира специјална екстензија - менаџер на екстензии во јупитер лабораторија:

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

Сега сè е подготвено за првото лансирање јупитер лабораторија, но сепак можеме да инсталираме неколку корисни екстензии:

  • toc — Содржина, генерира листа на наслови во статија/тетратка
  • jupyterlab-horizon-theme - Тема на UI
  • jupyterlab_neon_theme - Тема на UI
  • 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:

lxc exec jupyterlab -- su -l jupyter

Следно, трчај јупитер лабораторија со копчиња и параметри како што е наведено:

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

Одете на адресата во вашиот веб-прелистувач http://10.0.5.5:8888 и на страницата што се отвора внесете знак пристап кој ќе го видите во конзолата. Копирајте ја и залепете ја на страницата, а потоа кликнете најави се. Откако ќе се најавите, одете во менито со екстензии лево, како што е прикажано на сликата подолу, каде што ќе ви биде побарано, при активирање на менаџерот за екстензии, да преземете безбедносни ризици со инсталирање на екстензии од трети страни за кои командата Развој на JupyterLab не е одговорен:

Лансирање на Јупитер во орбитата LXD

Сепак, ние го изолираме целиот јупитер лабораторија и ставете го во контејнер така што наставките од трети страни кои бараат и користат NodeJS не можат барем да украдат податоци на дискот, освен оние што ги отвораме во контејнерот. Дојдете до вашите приватни документи на домаќинот во /home процесите од контејнерот веројатно нема да успеат, а ако успеат, тогаш треба да имате привилегии за датотеките на системот домаќин, бидејќи го работиме контејнерот во непривилегиран режим. Врз основа на овие информации, можете да го процените ризикот од вклучување на екстензии во јупитер лабораторија.

Создадени IPython тетратки (страници во јупитер лабораторија) сега ќе се креира во домашниот директориум на корисникот - /home/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

Здраво свету! ^

Ако сè уште имате отворена сесија на конзола во контејнерот со јупитер лабораторија, потоа рестартирајте го со нов клуч --notebook-dir со поставување на вредноста /mnt/hostfs како патека до коренот на лаптопите во контејнерот за уредот што го создадовме во претходниот чекор:

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

Потоа одете на страницата http://10.0.5.5:8888 и креирајте го вашиот прв лаптоп со кликнување на копчето на страницата како што е прикажано на сликата подолу:

Лансирање на Јупитер во орбитата LXD

Потоа, во полето на страницата, внесете го кодот на Python што ќе го прикаже класикот Hello World!. Кога ќе завршите со внесување, притиснете CTRL+ENTER или копчето „play“ на лентата со алатки на врвот за да може JupyterLab да го направи ова:

Лансирање на Јупитер во орбитата LXD

Во овој момент, речиси сè е подготвено за употреба, но ќе биде неинтересно ако не инсталираме дополнителни Python модули (целосни апликации) кои можат значително да ги прошират стандардните можности на Python во јупитер лабораторијазатоа, да продолжиме понатаму :)

PS Интересно е што старата имплементација Јупитер под кодно име Upупитер тетратка не исчезна и постои паралелно со јупитер лабораторија. За да се префрлите на старата верзија, следете ја врската со додавање на наставката во адресата/tree, а преминот кон новата верзија се врши со наставката /lab, но не мора да се специфицира:

Проширување на можностите на Python ^

Во овој дел, ќе инсталираме такви моќни јазични модули на Python како Нуп, Панди, Матплотлиб, IPyWidgets чии резултати се интегрирани во лаптопите јупитер лабораторија.

Пред да ги инсталирате наведените Python модули преку менаџерот на пакети pip прво мора да ги решиме системските зависности во Alpine Linux:

  • g++ — Потребни за компајлирање модули, бидејќи некои од нив се имплементирани на јазикот C + + и поврзете се со Python при извршување како бинарни модули
  • freetype-dev - зависност за модулот Python Матплотлиб

Инсталирање на зависности:

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

Има еден проблем: во моменталната состојба на дистрибуцијата на Alpine Linux, нема да биде можно да се компајлира новата верзија на NumPy; ќе се појави грешка во компилацијата што не можев да ја решам:

ГРЕШКА: Не може да се изградат тркала за numpy кои користат PEP 517 и не можат директно да се инсталираат

Затоа, ќе го инсталираме овој модул како системски пакет кој дистрибуира веќе компајлирана верзија, но малку постара од она што е моментално достапно на страницата:

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 ^

Ако трчате јупитер лабораторија, рестартирајте го за да се активираат новоинсталираните модули. За да го направите ова, во сесијата на конзолата, кликнете CTRL+C каде што го имате да работи и влезете y да го прекинете барањето и потоа да започнете повторно јупитер лабораторија со притискање на стрелката нагоре на тастатурата за да не се внесе наредбата повторно и потоа 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 елемент на страницата што интерактивно комуницира со изворниот код, а исто така Матплотлиб го прикажува резултатот од кодот во форма на слика како функционален график:

Лансирање на Јупитер во орбитата LXD

Многу примери IPyWidgets можете да го најдете во упатствата тука

Што друго? ^

Браво ако останавте и стигнавте до самиот крај на статијата. Јас намерно не објавив готова скрипта на крајот од статијата што ќе се инсталира јупитер лабораторија со „еден клик“ за да ги поттикнете работниците :) Но, можете сами да го направите тоа, бидејќи веќе знаете како, откако ги собравте командите во една скрипта на Bash :)

Можете исто така да:

  • Поставете име на мрежа за контејнерот наместо IP адреса со тоа што ќе го напишете на едноставен начин /etc/hosts и напишете ја адресата во прелистувачот http://jupyter.local:8888
  • Играјте околу ограничувањето на ресурсите за контејнерот, за ова прочитајте го поглавјето основни LXD способности или добијте повеќе информации на страницата за програмери на LXD.
  • Променете ја темата:

Лансирање на Јупитер во орбитата LXD

И многу повеќе што можете да направите! Тоа е се. Ти посакувам успех!

АЖУРИРАЊЕ: 15.04.2020 18:30 часот - Поправени грешки во поглавјето „Здраво, свето!“
АЖУРИРАЊЕ: 16.04.2020 10:00 — Поправен и додаден текст во описот на активирањето на менаџерот за екстензии јупитер лабораторија
АЖУРИРАЊЕ: 16.04.2020 10:40 — Поправени грешки пронајдени во текстот и малку изменети на подобро поглавјето „Инсталирање основен софтвер и поставување на системот“

Извор: www.habr.com

Додадете коментар