Har du noen gang måttet eksperimentere med kode eller systemverktøy i Linux for ikke å bekymre deg for basissystemet og ikke rive ned alt i tilfelle en feil i koden som skal kjøre med root-privilegier?
Men hva med det faktum at la oss si at du trenger å teste eller kjøre en hel klynge av forskjellige mikrotjenester på én maskin? Hundre eller til og med tusen?
Med virtuelle maskiner administrert av en hypervisor kan og vil slike problemer løses, men til hvilken pris? For eksempel bruker en beholder i LXD basert på Alpine Linux-distribusjonen kun 7.60MB
RAM, og hvor rotpartisjonen opptar etter oppstart 9.5MB
! Hvordan liker du det, Elon Musk? Jeg anbefaler å sjekke ut grunnleggende funksjoner i LXD - et containersystem i Linux
Etter at det generelt ble klart hva LXD-beholdere er, la oss gå videre og tenke, hva om det fantes en slik innhøstingsplattform der du trygt kunne kjøre kode for verten, generere grafer, dynamisk (interaktivt) koble UI-widgets med koden din, supplere koden med tekst med blackjack... formatering? En slags interaktiv blogg? Wow... jeg vil ha det! Ønsker! 🙂
Se under katten hvor vi skal lansere i en container jupyter lab - neste generasjon brukergrensesnitt i stedet for den utdaterte Jupyter Notebook, og vi vil også installere Python-moduler som f.eks. nusset, pandaer, Matplotlib, IPyWidgets som lar deg gjøre alt som er oppført ovenfor og lagre alt i en spesiell fil - en IPython bærbar PC.
Navigasjon
- Orbital take-off plan
- Installasjon og konfigurering av basissystemet
- Installere grunnleggende programvare og sette opp systemet
- Installere og konfigurere JupyterLab
- Dele data med verten
- Hei Verden!
- Utvide egenskapene til Python
- Testing av moduler i JupyterLab
- Hva annet?
Orbital take-off plan ^
La oss skissere en kort handlingsplan for å gjøre det lettere for oss å implementere ordningen ovenfor:
- La oss installere og lansere en beholder basert på distribusjonssettet Alpine Linux. Vi vil bruke denne distribusjonen fordi den er rettet mot minimalisme og vil kun installere den mest nødvendige programvaren i den, ikke noe overflødig.
- La oss legge til en ekstra virtuell disk i beholderen og gi den et navn -
hostfs
og monter den til rotfilsystemet. Denne disken vil gjøre det mulig å bruke filer på verten fra en gitt katalog inne i beholderen. Dermed vil våre data være uavhengige av containeren. Hvis beholderen slettes, forblir dataene på verten. Denne ordningen er også nyttig for å dele de samme dataene mellom mange containere uten å bruke standard nettverksmekanismer for containerdistribusjonen. - La oss installere Bash, sudo, de nødvendige bibliotekene, legge til og konfigurere en systembruker
- La oss installere Python, moduler og kompilere binære avhengigheter for dem
- La oss installere og starte jupyter lab, tilpass utseendet, installer utvidelser for det.
I denne artikkelen starter vi med å lansere beholderen, vi vil ikke vurdere å installere og konfigurere LXD, du kan finne alt dette i en annen artikkel - Grunnleggende funksjoner i LXD - Linux containersystemer.
Installasjon og konfigurering av basissystemet ^
Vi lager en beholder med kommandoen der vi spesifiserer bildet - alpine3
, identifikator for beholderen - jupyterlab
og, om nødvendig, konfigurasjonsprofiler:
lxc init alpine3 jupyterlab --profile=default --profile=hddroot
Her bruker jeg en konfigurasjonsprofil hddroot
som spesifiserer å lage en beholder med en rotpartisjon i Oppbevaringsbasseng plassert på en fysisk harddisk:
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
Dette gir meg muligheten til å eksperimentere med containere på HDD-disken, og sparer ressursene til SSD-disken, som også er tilgjengelig i systemet mitt 🙂 som jeg har laget en egen konfigurasjonsprofil for ssdroot
.
Etter at beholderen er opprettet, er den i tilstanden STOPPED
, så vi må starte den ved å kjøre init-systemet i den:
lxc start jupyterlab
La oss vise en liste over beholdere i LXD ved å bruke tasten -c
som indikerer hvilken cvisning av olumner:
lxc list -c ns4b
+------------+---------+-------------------+--------------+
| NAME | STATE | IPV4 | STORAGE POOL |
+------------+---------+-------------------+--------------+
| jupyterlab | RUNNING | 10.0.5.198 (eth0) | hddpool |
+------------+---------+-------------------+--------------+
Ved opprettelse av containeren ble IP-adressen valgt tilfeldig, siden vi brukte en konfigurasjonsprofil default
som tidligere ble konfigurert i artikkelen Grunnleggende funksjoner i LXD - Linux containersystemer.
Vi vil endre denne IP-adressen til en mer minneverdig ved å lage et nettverksgrensesnitt på containernivå, og ikke på konfigurasjonsprofilnivået slik det er nå i gjeldende konfigurasjon. Du trenger ikke å gjøre dette, du kan hoppe over det.
Opprette et nettverksgrensesnitt eth0
som vi kobler til svitsjen (nettverksbroen) lxdbr0
der vi aktiverte NAT i henhold til forrige artikkel, og beholderen vil nå ha tilgang til Internett, og vi tildeler også en statisk IP-adresse til grensesnittet - 10.0.5.5
:
lxc config device add jupyterlab eth0 nic name=eth0 nictype=bridged parent=lxdbr0 ipv4.address=10.0.5.5
Etter å ha lagt til en enhet, må beholderen startes på nytt:
lxc restart jupyterlab
Sjekke statusen til beholderen:
lxc list -c ns4b
+------------+---------+------------------+--------------+
| NAME | STATE | IPV4 | STORAGE POOL |
+------------+---------+------------------+--------------+
| jupyterlab | RUNNING | 10.0.5.5 (eth0) | hddpool |
+------------+---------+------------------+--------------+
Installere grunnleggende programvare og sette opp systemet ^
For å administrere beholderen vår må du installere følgende programvare:
Pakke
Beskrivelse
bash
GNU Bourne Again-skallet
bash-fullføring
Programmerbar komplettering for bash-skallet
sudo
Gi enkelte brukere muligheten til å kjøre noen kommandoer som root
skygge
Passord- og kontoadministrasjonsverktøypakke med støtte for skyggefiler og PAM
tzdata
Kilder for tidssone og sommertid
nano
Pico editor klon med forbedringer
I tillegg kan du installere støtte i systemman-sidene ved å installere følgende pakker - man man-pages mdocml-apropos less
lxc exec jupyterlab -- apk add bash bash-completion sudo shadow tzdata nano
La oss se på kommandoene og tastene vi brukte:
lxc
— Ring LXD-klientexec
- LXD-klientmetode som kjører en kommando i beholderenjupyterlab
— Container-ID--
- En spesiell nøkkel som spesifiserer å ikke tolke flere nøkler som nøkler forlxc
og før resten av strengen som den er til beholderenapk
— Alpine Linux distribusjonspakkebehandleradd
— En pakkebehandlingsmetode som installerer pakker spesifisert etter kommandoen
Deretter vil vi sette en tidssone i systemet Europe/Moscow
:
lxc exec jupyterlab -- cp /usr/share/zoneinfo/Europe/Moscow /etc/localtime
Etter å ha installert tidssonen, pakken tzdata
ikke lenger er nødvendig i systemet, vil det ta opp plass, så la oss slette det:
lxc exec jupyterlab -- apk del tzdata
Sjekke tidssonen:
lxc exec jupyterlab -- date
Wed Apr 15 10:49:56 MSK 2020
For ikke å bruke mye tid på å sette opp Bash for nye brukere i containeren, vil vi i de følgende trinnene kopiere ferdige skel-filer fra vertssystemet til den. Dette vil tillate deg å forskjønne Bash i en beholder interaktivt. Vertssystemet mitt er Manjaro Linux og filene som kopieres /etc/skel/.bash_profile
, /etc/skel/.bashrc
, /etc/skel/.dir_colors
i prinsippet er de egnet for Alpine Linux og forårsaker ikke kritiske problemer, men du kan ha en annen distribusjon og du må uavhengig finne ut om det er en feil når du kjører Bash i containeren.
Kopier skel-filene til beholderen. Nøkkel --create-dirs
vil opprette de nødvendige katalogene hvis de ikke eksisterer:
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
For en eksisterende rotbruker, kopier skel-filene som nettopp ble kopiert inn i beholderen til hjemmekatalogen:
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 installerer et system-skall for brukere /bin/sh
, vil vi erstatte den med root
bruker i Bash:
lxc exec jupyterlab -- usermod --shell=/bin/bash root
At root
brukeren var ikke passordløs, han må angi et passord. Følgende kommando vil generere og sette et nytt tilfeldig passord for ham, som du vil se på konsollskjermen etter at det er utført:
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
La oss også opprette en ny systembruker - jupyter
som vi vil konfigurere senere jupyter lab:
lxc exec jupyterlab -- useradd --create-home --shell=/bin/bash jupyter
La oss generere og angi et passord for det:
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
Deretter vil vi utføre to kommandoer, den første vil opprette en systemgruppe sudo
, og den andre vil legge til en bruker til den jupyter
:
lxc exec jupyterlab -- groupadd --system sudo
lxc exec jupyterlab -- groupmems --group sudo --add jupyter
La oss se hvilke grupper brukeren tilhører jupyter
:
lxc exec jupyterlab -- id -Gn jupyter
jupyter sudo
Alt er ok, la oss gå videre.
Tillat alle brukere som er medlemmer av gruppen sudo
bruk kommando sudo
. For å gjøre dette, kjør følgende skript, hvor sed
fjerner kommentarer fra parameterlinjen i konfigurasjonsfilen /etc/sudoers
:
lxc exec jupyterlab -- /bin/bash -c "sed --in-place -e '/^#[ t]*%sudo[ t]*ALL=(ALL)[ t]*ALL$/ s/^[# ]*//' /etc/sudoers"
Installere og konfigurere JupyterLab ^
jupyter lab er en Python-applikasjon, så vi må først installere denne tolken. Også, jupyter lab vi installerer ved å bruke Python-pakkebehandleren pip
, og ikke systemet, fordi det kan være utdatert i systemlageret, og derfor må vi løse avhengighetene for det manuelt ved å installere følgende pakker − python3 python3-dev gcc libc-dev zeromq-dev
:
lxc exec jupyterlab -- apk add python3 python3-dev gcc libc-dev zeromq-dev
La oss oppdatere python-moduler og pakkebehandling pip
til gjeldende versjon:
lxc exec jupyterlab -- python3 -m pip install --upgrade pip setuptools wheel
Satt jupyter lab via pakkebehandler pip
:
lxc exec jupyterlab -- python3 -m pip install jupyterlab
Siden utvidelsene i jupyter lab er eksperimentelle og leveres ikke offisielt med jupyterlab-pakken, så vi må installere og konfigurere den manuelt.
La oss installere NodeJS og pakkebehandleren for det - NPM, siden jupyter lab bruker dem for sine utvidelser:
lxc exec jupyterlab -- apk add nodejs npm
Til utvidelser for jupyter lab som vi vil installere fungerte, de må installeres i brukerkatalogen siden applikasjonen vil bli lansert fra brukeren jupyter
. Problemet er at det ikke er noen parameter i startkommandoen som kan sendes til en katalog; applikasjonen aksepterer bare en miljøvariabel og derfor må vi definere den. For å gjøre dette, vil vi skrive kommandoen for variabel eksport JUPYTERLAB_DIR
i brukerens miljø jupyter
, å lagre .bashrc
som utføres hver gang brukeren logger på:
lxc exec jupyterlab -- su -l jupyter -c "echo -e "nexport JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab" >> .bashrc"
Den neste kommandoen vil installere en spesiell utvidelse - extension manager in jupyter lab:
lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter labextension install --no-build @jupyter-widgets/jupyterlab-manager"
Nå er alt klart for første lansering jupyter lab, men vi kan fortsatt installere noen nyttige utvidelser:
toc
— Innholdsfortegnelse, genererer en liste over overskrifter i en artikkel/notatbokjupyterlab-horizon-theme
– UI-temajupyterlab_neon_theme
– UI-temajupyterlab-ubu-theme
- En annen tema fra forfatteren denne artikkelen :) Men i dette tilfellet vil installasjonen fra GitHub-depotet vises
Så kjør følgende kommandoer sekvensielt for å installere disse utvidelsene:
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"
Etter å ha installert utvidelsene, må vi kompilere dem, siden vi tidligere, under installasjonen, spesifiserte nøkkelen --no-build
for å spare tid. Nå vil vi øke hastigheten betraktelig ved å sette dem sammen på en gang:
lxc exec jupyterlab -- su -l jupyter -c "export JUPYTERLAB_DIR=$HOME/.local/share/jupyter/lab; jupyter lab build"
Kjør nå følgende to kommandoer for å kjøre den for første gang jupyter lab. Det ville være mulig å starte den med én kommando, men i dette tilfellet vil startkommandoen, som er vanskelig å huske i tankene dine, bli husket av bash i beholderen, og ikke på verten, der det allerede er nok kommandoer å registrere dem i historien :)
Logg på containeren som bruker jupyter
:
lxc exec jupyterlab -- su -l jupyter
Neste, løp jupyter lab med taster og parametere som angitt:
[jupyter@jupyterlab ~]$ jupyter lab --ip=0.0.0.0 --no-browser
Gå til adressen i nettleseren din http://10.0.5.5:8888 og skriv inn på siden som åpnes token tilgang som du vil se i konsollen. Kopier og lim den inn på siden, og klikk deretter Logg inn. Etter å ha logget inn, gå til utvidelsesmenyen til venstre, som vist i figuren nedenfor, hvor du vil bli bedt om, når du aktiverer utvidelsesbehandleren, å ta sikkerhetsrisikoer ved å installere utvidelser fra tredjeparter som kommandoen for JupyterLab utvikling er ikke ansvarlig:
Vi isolerer imidlertid hele jupyter lab og plasser den i en container slik at tredjepartsutvidelser som krever og bruker NodeJS i det minste ikke kan stjele data på disken andre enn de vi åpner inne i containeren. Få til dine private dokumenter på verten i /home
prosesser fra containeren er usannsynlig å lykkes, og hvis de gjør det, må du ha privilegier på filer på vertssystemet, siden vi kjører containeren i uprivilegert modus. Basert på denne informasjonen kan du vurdere risikoen for å inkludere utvidelser i jupyter lab.
Laget IPython-notatbøker (sider inn jupyter lab) vil nå bli opprettet i brukerens hjemmekatalog - /home/jupyter
, men planene våre er å dele dataene (delingen) mellom verten og beholderen, så gå tilbake til konsollen og stopp jupyter lab ved å kjøre hurtigtast - CTRL+C
og svarer y
på forespørsel. Avslutt deretter brukerens interaktive økt jupyter
fullføre en hurtigtast CTRL+D
.
Dele data med verten ^
For å dele data med verten, må du opprette en enhet i beholderen som lar deg gjøre dette, og for å gjøre dette, kjør følgende kommando der vi spesifiserer følgende nøkler:
lxc config device add
— Kommandoen legger til enhetskonfigurasjonenjupyter
— ID for beholderen som konfigurasjonen er lagt tilhostfs
— Enhets-ID. Du kan angi hvilket som helst navn.disk
— Type enhet er angittpath
— Angir banen i beholderen som LXD skal montere denne enheten tilsource
— Spesifiser kilden, banen til katalogen på verten du vil dele med beholderen. Spesifiser banen i henhold til dine preferanser
lxc config device add jupyterlab hostfs disk path=/mnt/hostfs source=/home/dv/projects/ipython-notebooks
For katalogen /home/dv/projects/ipython-notebooks
tillatelse må settes til containerbrukeren som for øyeblikket har en UID lik SubUID + UID
, se kapittel Sikkerhet. Containerprivilegier i artikkelen Grunnleggende funksjoner i LXD - Linux containersystemer.
Angi tillatelsen på verten, der eieren vil være beholderbrukeren jupyter
, og variabelen $USER
vil spesifisere vertsbrukeren din som en gruppe:
sudo chown 1001000:$USER /home/dv/projects/ipython-notebooks
Hei Verden! ^
Hvis du fortsatt har en konsolløkt åpen i beholderen med jupyter lab, og start den på nytt med en ny nøkkel --notebook-dir
ved å angi verdien /mnt/hostfs
som banen til roten til de bærbare datamaskinene i beholderen for enheten som vi opprettet i forrige trinn:
jupyter lab --ip=0.0.0.0 --no-browser --notebook-dir=/mnt/hostfs
Gå deretter til siden http://10.0.5.5:8888 og lag din første bærbare datamaskin ved å klikke på knappen på siden som vist på bildet nedenfor:
Deretter, i feltet på siden, skriver du inn Python-koden som skal vise klassikeren Hello World!
. Når du er ferdig med å legge inn, trykk CTRL+ENTER
eller "spill"-knappen på verktøylinjen øverst for å få JupyterLab til å gjøre dette:
På dette tidspunktet er nesten alt klart til bruk, men det vil være uinteressant hvis vi ikke installerer ytterligere Python-moduler (fullverdige applikasjoner) som kan utvide standardfunksjonene til Python betydelig i jupyter labderfor, la oss gå videre :)
PS Det interessante er at den gamle implementeringen jupyter under kodenavn Jupyter Notebook har ikke gått bort og den eksisterer parallelt med jupyter lab. For å bytte til den gamle versjonen, følg lenken som legger til suffikset i adressen/tree
, og overgangen til den nye versjonen utføres med suffikset /lab
, men det trenger ikke spesifiseres:
- Jupyter Notebook - http://10.0.5.5:8888/tree
- Jupyter Lab - http://10.0.5.5:8888/lab
Utvide egenskapene til Python ^
I denne delen vil vi installere så kraftige Python-språkmoduler som nusset, pandaer, Matplotlib, IPyWidgets resultatene er integrert i bærbare datamaskiner jupyter lab.
Før du installerer de oppførte Python-modulene gjennom pakkebehandlingen pip
vi må først løse systemavhengigheter i Alpine Linux:
g++
— Nødvendig for å kompilere moduler, siden noen av dem er implementert på språket C + + og koble til Python under kjøretid som binære modulerfreetype-dev
- avhengighet for Python-modulen Matplotlib
Installere avhengigheter:
lxc exec jupyterlab -- apk add g++ freetype-dev
Det er ett problem: i den nåværende tilstanden til Alpine Linux-distribusjonen vil det ikke være mulig å kompilere den nye versjonen av NumPy; en kompileringsfeil vil dukke opp som jeg ikke kunne løse:
FEIL: Kunne ikke bygge hjul for numpy som bruker PEP 517 og ikke kan installeres direkte
Derfor vil vi installere denne modulen som en systempakke som distribuerer en allerede kompilert versjon, men litt eldre enn det som for øyeblikket er tilgjengelig på siden:
lxc exec jupyterlab -- apk add py3-numpy py3-numpy-dev
Installer deretter Python-moduler gjennom pakkebehandlingen pip
. Vær tålmodig siden noen moduler vil kompileres og kan ta noen minutter. På maskinen min tok kompileringen ~15 minutter:
lxc exec jupyterlab -- python3 -m pip install pandas ipywidgets matplotlib
Tømme installasjonsbuffer:
lxc exec jupyterlab -- rm -rf /home/*/.cache/pip/*
lxc exec jupyterlab -- rm -rf /root/.cache/pip/*
Testing av moduler i JupyterLab ^
Hvis du løper jupyter lab, start den på nytt slik at de nylig installerte modulene aktiveres. For å gjøre dette, klikk i en konsolløkt CTRL+C
hvor du har den i gang og går inn y
for å stoppe forespørselen og deretter starte på nytt jupyter lab ved å trykke på pil opp på tastaturet for ikke å skrive inn kommandoen igjen og deretter Enter
for å starte det:
jupyter lab --ip=0.0.0.0 --no-browser --notebook-dir=/mnt/hostfs
Gå til siden http://10.0.5.5:8888/lab eller oppdater siden i nettleseren din, og skriv deretter inn følgende kode i en ny notatbokcelle:
%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
Du bør få et resultat som på bildet under, hvor IPyWidgets genererer et UI-element på siden som samhandler interaktivt med kildekoden, og også Matplotlib viser resultatet av koden i form av et bilde som en funksjonsgraf:
Mange eksempler IPyWidgets du finner det i opplæringsprogrammer her
Hva annet? ^
Godt gjort hvis du ble og nådde helt til slutten av artikkelen. Jeg la bevisst ikke ut et ferdig skript på slutten av artikkelen som ville installere jupyter lab med "ett klikk" for å oppmuntre arbeidere :) Men du kan gjøre det selv, siden du allerede vet hvordan, etter å ha samlet kommandoene i et enkelt Bash-skript :)
Du kan også:
- Angi et nettverksnavn for beholderen i stedet for en IP-adresse ved å skrive det på en enkel måte
/etc/hosts
og skriv inn adressen i nettleseren http://jupyter.local:8888 - Lek litt med ressursgrensen for beholderen, for dette kan du lese kapittelet i grunnleggende LXD-egenskaper eller få mer informasjon på LXD-utviklernettstedet.
- Endre tema:
Og mye mer du kan gjøre! Det er alt. Jeg ønsker deg suksess!
OPPDATERING: 15.04.2020/18/30 XNUMX:XNUMX - Rettet feil i kapittelet "Hei, verden!"
OPPDATERING: 16.04.2020/10/00 XNUMX:XNUMX — Rettet og lagt til tekst i beskrivelsen av aktivering av utvidelsesadministrator jupyter lab
OPPDATERING: 16.04.2020/10/40 XNUMX:XNUMX — Rettet feil funnet i teksten og litt endret til det bedre kapittelet "Installere grunnleggende programvare og sette opp systemet"
Kilde: www.habr.com