10. avgusta je na Sljormu započeo , u kojemu detaljno razrađujemo sve aspekte — od osnovnih apstrakcija do mrežnih parametara.
U ovom članku razgovarat ćemo o istoriji nastanka Dockera i njegovim osnovnim apstrakcijama: Image, Cli, Dockerfile. Predavanje je namijenjeno početnicima, tako da vjerojatno neće biti zanimljivo iskusnim korisnicima. Nećemo se baviti dubokim analizama. Samo osnovne informacije.

Šta je Docker
Pogledajmo definiciju Dockera iz Wikipedije.
Docker je softver za automatizaciju implementacije i upravljanje aplikacijama u okruženjima koja podržavaju kontejnerizaciju.
Iz ove definicije ništa nije jasno. Pogranično je nejasno što znači „u okruženjima koja podržavaju kontejnerizaciju“. Da bismo to razjasnili, vratimo se u prošlost. Počnimo iz doba koje naziva „Monolitna era“.
Monolitna era
Monolitna era je početak 2000-ih, kada su sve aplikacije bile monolitne, sa mnoštvom zavisnosti. Razvoj je trajao dugo. U to vreme nije bilo mnogo servera, svi smo ih znali po imenu i pratili ih. Postoji zanimljiva usporedba:

Ljubimci — to su kućni prijatelji. U monolitnoj eri odnosili smo se prema svojim serverima kao prema ljubimcima, brinuli smo se i pazili na njih, sklanjajući prašinu. Za bolje upravljanje resursima koristili smo virtualizaciju: uzeli smo server i podelili ga na nekoliko virtuelnih mašina, čime smo obezbedili izolaciju okruženja.
Sistemi virtualizacije na bazi hipervizora
O sistemima virtualizacije sigurno su svi čuli: VMware, VirtualBox, Hyper-V, Qemu KVM itd. Oni obezbeđuju izolaciju aplikacija i upravljanje resursima, ali imaju i nedostatke. Da bi se realizovala virtualizacija, potreban je hipervizor. A hipervizor je dodatno opterećenje resursa. Čak i sama virtuelna mašina obično je velika i teška — obiman imidž, na njemu je operativni sistem, Nginx, Apache, moguće i MySQL. Imidž je veliki, teško je upravljati virtuelnom mašinom. Kao posledica, rad sa virtuelnim mašinama može biti spor. Da bismo rešili taj problem, stvorene su sisteme virtualizacije na nivou jezgra.
Sistemi virtualizacije na nivou jezgra
Virtualizaciju na nivou jezgra podržavaju sistemi OpenVZ, Systemd-nspawn, LXC. Osvetljeni primer takve virtualizacije je LXC (Linux Containers).
LXC — sistem virtualizacije na nivoju operativnog sistema za pokretanje više izolovanih instanci operativnog sistema Linux na jednom čvoru. LXC ne koristi virtuelne mašine, već stvara virtuelno okruženje sa sopstvenim procesnim prostorom i mrežnim stekom.
U suštini, LXC stvara kontejnere. Koja je razlika između virtuelnih mašina i kontejnera?

Kontejner nije pogodan za izolaciju procesa: u sistemima virtualizacije na nivou jezgra postoje ranjivosti koje omogućavaju izlazak iz kontejnera na host. Stoga, ako vam je potrebna neka izolacija, bolje je koristiti virtuelnu mašinu.
Razlike između virtualizacije i kontejnerizacije mogu se videti na dijagramu.
Postoje hardverski hipervizori, hipervizori iznad OS i kontejneri.

„Hardverski“ hipervizori su sjajna stvar ako zaista želite nešto da izolujete. Jer tu postoji mogućnost izolacije na nivou stranica memorije, procesora.
Postoje hipervizori kao program i postoje kontejneri, o kojima ćemo dalje govoriti. U sistemima kontejnerizacije ne postoji hipervizor, ali postoji Container Engine koji stvara kontejneri i upravlja njima. Ova stvar je lakša, pa zbog rada sa jezgrom overhead je manji ili ga uopšte nema.
Šta se koristi za kontejnerizaciju na nivou jezgra
Osnovne tehnologije koje omogućavaju stvaranje izolovanog kontejnera od drugih procesa su Namespaces i Control Groups.
Namespaces: PID, Networking, Mount i User. Ima još, ali radi jednostavnosti razumevanja ćemo se zadržati na ovim.
PID Namespace ograničava procese. Kada, na primer, stvaramo PID Namespace i smeštamo proces u njega, on postaje sa PID 1. Obično je u sistemima PID 1 — to je systemd ili init. Tako da, kada smeštamo proces u novi namespace, on takođe dobija PID 1.
Networking Namespace omogućava ograničavanje/izolaciju mreže i unutar nje smešta svoje interfejse. Mount — to je ograničenje po datotečnom sistemu. User — ograničenje po korisnicima.
Control Groups: Memory, CPU, IOPS, Network — ukupno oko 12 podešavanja. Inače ih još nazivaju Cgroups („C grupa“).
Control Groups upravljaju resursima za kontejner. Putem Control Groups možemo reći da kontejner ne sme trošiti više od određenog broja resursa.
Da bi kontejnerizacija potpuno funkcionisala, koriste se dodatne tehnologije: Capabilities, Copy-on-write i druge.
Capabilities su kada kažemo procesu šta može da radi, a šta ne može. Na nivou jezgra to su samo bitmape sa mnoštvom parametara. Na primer, korisnik root ima pune privilegije i može raditi sve. Server vremena može menjati sistemsko vreme: ima capabilities za Time Capsule i to je to. Pomoću privilegija možemo fleksibilno prilagoditi ograničenja za procese i tako se zaštititi.
Sistem Copy-on-write omogućava nam da radimo sa Docker slikama i koristimo ih efikasnije.
Trenutno Docker ima problema sa kompatibilnošću Cgroups v2, pa se u članku razmatraju upravo Cgroups v1.
Ali, vratimo se istoriji.
Kada su se pojavili sistemi virtuelizacije na nivou jezgra, počeli su se aktivno primenjivati. Overhead na hipervizoru je nestao, ali su neka pitanja ostala:
- velike slike: u istoj OpenVZ se gura operativni sistem, biblioteke, gomila različitog softvera, i na kraju slika i dalje bude prilično velika;
- nema normalnog standarda za pakovanje i isporuku, zbog čega ostaje problem zavisnosti. Bivaju situacije kada dva komada koda koriste istu biblioteku, ali sa različitim verzijama. Između njih može doći do sukoba.
Da bi se svi ovi problemi rešili, došla je sledeća era.
Era kontejnera
Kada je nastupila Era kontejnera, promenila se filozofija rada sa njima:
- Jedan proces - jedan kontejner.
- Sve potrebne zavisnosti za proces isporučujemo u njegov kontejner. To zahteva razbijanje monolitnih aplikacija na mikroslužbe.
- Što je manja slika, to je bolje - manje mogućih ranjivosti, brže se postavlja i tako dalje.
- Instanci postaju efemerne.
Setite se, rekao sam o ljubimcima i stoci? Pre je instanca bila poput kućnog ljubimca, a sada je postala kao stoka. Pre je postojala monolitna aplikacija - jedna aplikacija. Sada je to 100 mikroslužbi, 100 kontejnera. Neki od kontejnera mogu imati po 2-3 replikacije. Ne postaje nam toliko važno kontrolisati svaki kontejner. Važnija nam je dostupnost same usluge: onoga što radi ovaj skup kontejnera. To menja pristupe u monitoringu.
Godine 2014-2015 došlo je do uspona Dockera - te tehnologije o kojoj ćemo sada govoriti.
Docker je spremenil filozofijo in standardiziral pakiranje aplikacij. S pomočjo Dockera lahko zapakiramo aplikacijo, jo pošljemo v skladišče, prenesemo od tam in jo razporedimo.
V Docker kontejner vgradimo vse potrebno, zato je težava s odvisnostmi rešljena. Docker zagotavlja ponovljivost. Mislim, da se je veliko ljudi srečalo z neponovljivostjo: vse deluje na tvojem stroju, ko pa to pošlješ v produkcijo, ne deluje več. S Dockerjem ta težava izginja. Če se tvoj Docker kontejner zažene in naredi tisto, kar mora, ga bo verjetno mogoče zagnati tudi v produkciji in bo tam naredil isto.
Odtok o overheadu
Glede overheada nenehno potekajo razprave. Nekateri menijo, da Docker ne prinaša dodatne obremenitve, saj uporablja jedro Linuxa in vse njegove procese, potrebne za kontejnerizacijo. Pravi se, da 'če trdite, da je Docker overhead, potem je tudi jedro Linuxa overhead.'
Po drugi strani, če se poglobimo, v Dockerju res obstaja nekaj stvari, za katere lahko rečemo, da so overhead.
Prvo je PID namespace. Ko v namespace vključimo določen proces, mu je dodeljen PID 1. Hkrati pa ima ta proces še en PID, ki se nahaja v gostiteljskem namespace, izven kontejnerja. Na primer, če zagnamo Nginx v kontejnerju, je njegov PID 1 (master proces), medtem ko ima na gostitelju PID 12623. In težko je reči, koliko je to overhead.
Druga stvar so Cgroups. Vzamemo Cgroups za pomnilnik, torej možnost omejiti pomnilnik kontejnerju. Ko je to vključeno, se aktivirajo števcem, pomnilniško računanje: jedru je treba razumeti, koliko strani je dodeljenih in koliko je še prostih za ta kontejner. To bi lahko bil overhead, vendar natančnih raziskav o tem, kako to vpliva na zmogljivost, še nisem srečal. In sam nisem opazil, da bi aplikacija, zagnana v Dockerju, nenadoma drastično izgubila na zmogljivosti.
In še eno opombo o zmogljivosti. Nekatere nastavitve jedra se prenašajo iz gostitelja v kontejner. Zlasti nekateri omrežni parametri. Zato, če želite v Dockerju zagnati kaj visoko zmogljivega, na primer tisto, kar bo aktivno uporabljalo omrežje, boste morali te parametre vsaj malo prilagoditi. Na primer, nf_conntrack.
O konceptu Dockera
Docker je sestavljen iz več komponent:
- Docker Daemon — to je container engine; zažene kontejnerje.
- Docker CII — orodje za upravljanje z Dockerjem.
- Dockerfile — navodilo, kako zgraditi sliko.
- Image — slika, iz katere se ustvari kontejner.
- Kontejner.
- Docker registry — skladišče slik.
Shematsko to izgleda približno tako:

Na Docker_hostu deluje Docker daemon, ki zažene kontejnerje. Obstaja klient, ki prenaša ukaze: zgradi sliko, prenesi sliko, zaženi kontejner. Docker daemon dostopa do registryja in jih izvrši. Docker klient lahko dostopa tako lokalno (do unix-soka) kot tudi prek TCP z oddaljenega gostitelja.
Poglejmo vsak komponent.
Docker daemon (demon) — je strežniški del, deluje na gostiteljskem stroju: prenaša slike in iz njih zažene kontejnerje, ustvarja omrežje med kontejnerji, zbira dnevnike. Ko rečemo "ustvari sliko", se s tem prav tako ukvarja demon.
Docker CLI — je klientni del Dockerja, konzolno orodje za delo z demonom. Ponavljam, deluje lahko ne samo lokalno, ampak tudi prek omrežja.
Osnovni ukazi:
docker ps — prikaže kontejnerje, ki so trenutno zagnani na Docker gostitelju.
docker images — prikaže slike, prenesene lokalno.
docker search — iskanje slike v registryju.
docker pull — prenesi sliko iz registryja na napravo.
docker build <> — zgradi sliko.
docker run — zagon kontejnerja.
docker rm — odstrani kontejner.
docker logs — dnevniki kontejnerja
docker start/stop/restart — delo s kontejnerjem
Če osvojite te ukaze in jih boste znali samozavestno uporabljati, potem lahko štejete, da ste 70 % osvojili Docker na ravni uporabnika.
Dockerfile — navodila za ustvarjanje slike. Skoraj vsak ukaz v navodilu je nova plast. Poglejmo na primeru.

Približno tako izgleda Dockerfile: levo so ukazi, desno — argumenti. Vsak ukaz, ki je tukaj (in sploh piše v Dockerfile), ustvari novo plast v sliki.
Že z ogledom levega dela lahko približno razumemo, kaj se dogaja. Rečemo: "ustvari nam mapo" — to je ena plast. "Naredi mapo delovno" — to je še ena plast, in tako naprej. Plasti na torti poenostavijo življenje. Če ustvarim še en Dockerfile in v zadnji vrstici karkoli spremenim — zažene ne "python" "main.py", ampak nekaj drugega, ali namestim odvisnosti iz druge datoteke — bodo prejšnje plasti ponovno uporabljene, kot predpomnilnik.
Slika — to je kontejner paketa, iz kojeg se pokreću kontejneri. Ako gledamo na Docker kao na upravitelja paketa (kao da radimo s deb ili rpm paketima), tada je slika u suštini rpm paket. Preko yum install možemo instalirati aplikaciju, ukloniti je, pronaći u repozitoriju, preuzeti. Ovdje je otprilike isto: kontejneri se pokreću iz slike, pohranjeni su u Docker registry (analogno yum-u, u repozitoriju), a svaka slika ima SHA-256 hash, ime i oznaku.
Slika se sastavlja prema uputama iz Dockerfile-a. Svaka uputa iz Dockerfile-a stvara novu razinu. Razine se mogu ponovno koristiti.
Docker registry — to je repozitorij Docker slika. Analogno operativnim sustavima, Docker ima javno dostupan standardni registar — dockerhub. No, moguće je izgraditi vlastiti repozitorij, svoj Docker registry.
Kontejner — to je ono što se pokreće iz slike. Prema uputama iz Dockerfile-a, sastavili smo sliku, a zatim pokrećemo kontejner iz te slike. Ovaj kontejner je izoliran od ostalih kontejnera, i trebao bi sadržavati sve potrebno za rad aplikacije. Prilikom toga, jedan kontejner — jedan proces. Ponekad se mora izvoditi dva procesa, ali to je malo u suprotnosti s ideologijom Dockera.
Zahtjev "jedan kontejner — jedan proces" povezan je s PID Namespace. Kada se unutar Namespace-a pokrene proces s PID 1, ako on iznenada umre, tada cijeli kontejner također umire. Ako su tu pokrenuta dva procesa: jedan živi, a drugi je umro, kontejner će i dalje živjeti. No, ovo se tiče najbolje prakse, o kojima ćemo razgovarati u drugim materijalima.
Više detalja o specifičnostima i cjelovitom programu tečaja možete pronaći na linku: "».
Autor: Marcel Ibraev, certificirani Kubernetes administrator, praktični inženjer u tvrtki Southbridge, govornik i autor kurseva Schlerm.
Izvor: habr.com
