Magazín KPI
Časopis Katedry počítačov a informatiky FEI TUKE
kpi

Docker a jeho použitie pri kontajnerizácii

Tento článok slúži na vysvetlenie kontajnerizačných technológií. Postupne si vysvetlíme význam kontajnerov, ich fungovanie a výhody oproti virtuálnym strojom. Ako sa dajú využiť v modernom agilnom vývoji softvéru a ich využitie pri použití mikroservisov, a DevOps metodológií. Taktiež si názorne ukážeme vytváranie kontajnerov použitím Dockeru, popredným softvérom v oblasti kontajnerizácie.

Prečo vznikla kontajnerizácia?

V dnešnej dobe je veľmi populárny prechod na mikroservisovo orientovanú architektúru. Predstavme si situáciu, že potrebujeme nasadiť aplikáciu na server. Na serveri budeme potrebovať operačný systém a prostredie, v ktorom táto aplikácia bude vykonávať svoje úlohy. Ak by sme na danom serveri zapli iba jednu službu, tak by sme pravdepodobne nevyužili jeho celkový procesný výkon. Jediný spôsob ako nemrhať výkonom by bolo nasadiť viacero služieb na daný server. Čo ale ak tieto služby budú potrebovať rôzne verzie knižníc? Čo ak by sa jednotlivé služby ovplyvňovali navzájom? Takéto a mnohé iné problémy by mohli prekážať takémuto prístupu. Ďalšou alternatívou by bolo použiť viaceré virtuálne stroje, čo by nám dovolilo mať viacero rôznych prostredí, každé pre jednu službu. Takýto prístup funguje, ale vytvárať virtuálnej stroje pre jednotlivé služby je kontraproduktívne z pohľadu využitia procesného výkonu servera.

Čo je to kontajner?

Ako už názov naznačuje, nápad vznikol na základe kontajnera na prepravu tovaru. Tieto kontajnery sú vyrobené tak, aby sa dali ľahko prepraviť na rôznych prepravných prostriedkoch, či je to loď, vlak alebo kamión. S rovnakým cieľom, univerzálneho zapuzdrenia, vznikol aj kontajner v softvéri. Ide spôsob ako zabaliť aplikáciu tak, aby sa dala prepraviť na rôzne systémy — lokálne alebo na sieti. Najjednoduchšia definícia kontajnera ho popisuje ako samostatný balík softvéru, ktorý obsahuje všetko potrebné na spustenie a chod aplikácie.

Dlhšia definícia by ho popísala ako samostatný logický balík softvéru, ktorý enkapsuluje a oddeľuje aplikáciu spolu so všetkými jej závislosťami tak, aby bola aplikácia schopná bežať nezávisle od prostredia na ktorom bola vytvorená. Cieľom je oddeliť aplikáciu a všetky jej závislosti od operačného systému a jeho prostredia takým spôsobom, aby sa dala následne jednoducho, rýchlo a spoľahlivo zapnúť na hocijakom inom prostredí. Medzi závislosti sa rátajú kód, runtime, systémové nástroje a knižnice, a nastavenia. Ako prostredie môže byť použité čokoľvek, či už ide o pracovnú stanicu vývojára, testovacie prostredie na serveri či produkčná verzia fungujúca na cloude.

Tak ako sa na lodi prepravuje tovar v osobitných kontajneroch, takisto je to aj s kontajnermi vo vývoji softvéru. Pri vytváraní kontajnera by malo platiť pravidlo, že jeden kontajner je jedna služba.

Na to, aby sme docielili tieto vlastnosti kontajnerov, musíme dodržať 3 hlavné princípy kontajnerizácie: Štandardnosť (Standard), Jednoduchosť (Lightweight) a Izolovanosť (Isolated). Tieto princípy sú popísané na oficiálnej Docker stránke a taktiež ich uznáva aj Google.

Štandardnosť (Standard)

Všetky kontajnery by mali byť vytvorené podľa rovnakého štandardu. To znamená, že majú byť kompletne oddelené od ich pôvodného systému, výsledkom čoho je, že sú prenosné na akýkoľvek iný systém. Všetky závislosti, od konkrétnej verzie programovacieho jazyka až po potrebné knižnice, sú už súčasťou obsahu kontajnera. Prostredie je vytvorené iba pre potreby samotnej aplikácie a vďaka tomu je kontajner použiteľný na akomkoľvek systéme. Týmto sa dosiahne vyššia produktivita, znižuje sa výskyt programátorských chýb a problémov pri vývoji softvéru.

Jednoduchosť (Lightweight)

Princíp „Lightweight“ hovorí, že sa v jednom kontajneri nemá nachádzať viacero služieb. A to z toho dôvodu, že by to mohlo spôsobiť problémy v kompatibilite, čo by zvýšilo zložitosť pri identifikovaní zdroju problémov. Kontajnery zdieľajú jadro operačného systému a taktiež aj jeho zdroje, vďaka čomu nie je potrebný pre každý kontajner vlastný operačný systém. Tým sa značne zlepšuje ich efektívnosť na serveri v porovnaní s virtualnými strojmi. Keďže na rozdiel od virtuálnych strojov nemajú kontajnery operačný systém, tak aj ich veľkosť je značne menšia, vďaka čomu je aj ich rýchlosť inicializácie zvýšená.

Izolovanosť (Isolated)

Kontajnery virtualizujú centrálny procesor, pamäť, disk a sieť na úrovni operačného systému, čím poskytujú softvérovým vývojárom sandboxový model, ktorý je izolovaný od ostatných aplikácií. Keďže celý kontajner a jeho vnútro je izolované, nevznikajú žiadne problémy medzi internými procesmi kontajnera a externými procesmi hostiteľského operačného systému. Takisto je dosiahnutá aj väčšia bezpečnosť, keďže jediný spôsob, ako môže hostiteľ komunikovať s kontajnerom je prostredníctvom jadra.

Aký je rozdiel medzi kontajnerom a virtuálnym strojom?

Virtuálny stroj (ďalej už iba VM, od anglického Virtual Machine) je obraz, ktorý sa správa ako reálny počítač. Je vytvorený na hostiteľskom operačnom systéme a správa sa ako akýkoľvek iný program. V jeho vnútri je avšak nainštalovaný osobitný operačný systém a celý stroj je sa správa ako sandbox, čo znamená, že je oddelený od hostiteľského systému a softvér v jeho vnútri nemôže ovplyvniť hostiteľa. To nám dáva ideálne testovacie prostredie na prístup k aplikáciam, ktoré neboli upravené pre hostiteľský operačný systém. Na jednom hostiteľskom stroji môžu bežať viaceré VM, o ktoré sa stará takzvaný „Hypervisor“. Ten má na starosti ich chod a priradenie virtuálneho hardvéru. VM fungujú tak, že každý si vyhradí virtuálny hardvér — ako sú centrálny procesor, pamäť, úložiska a sieťové rozhrania, ktoré sú následne priradené na reálny hardvér.

Znázornenie rozdielu medzi virtuálnym strojom a kontajnerom
Znázornenie rozdielu medzi virtuálnym strojom a kontajnerom

Teraz sa dostávame k prvému problému VM oproti kontajnerom — každý potrebuje vlastný operačný systém. Nutnosť vlastného operačného systému znamená, že zaberajú oveľa viac miesta — zväčša ide o jednotky až desiatky gigabajtov namiesto niekoľkých megabajtov ako tomu je pri kontajneroch. Tak isto to znamená menej vyžadovanej procesorového výkonu a pamäte, čo nám dovoľuje mať na jednom serveri viac kontajnerov ako VM. Pri VM sa spúšťa jadro a viacero systémových služieb, zatiaľ čo v kontajteri sa zväčša spúšťa iba samotná aplikácia.

Ďalším problémom je čas potrebný na inicializáciu jedného VM. Ak daný VM zaberá niekoľko gigabajtov a potrebuje si aj vyhradiť vlastný hardvér, tak jeho inicializácia trvá dlhšie než by trvala inicializácia jedného kontajnera. Alternatívou by mohla byť pred-inicializácia VM. Takéto VM boli zapnuté a nečinné, čo by znamenalo zbytočné mrhanie hardvérovými zdrojmi. Kontajneri sa na rozdiel od VM dokážu inicializovať v priebehu niekoľkých sekúnd alebo milisekúnd, čo je preferovanejšie oproti VM. Hlavne pri použití mikroservisov, ktoré prijímajú veľké množstvo požiadaviek za krátky čas. Dobrým zdrojom informácií o rozdieloch je článok od Muhammada Razu.

Využitie kontajnerov pre mikroservisy a uľahčenie DevOps

Keďže pri kontajnerizácií, ako sme už povedali, chceme aby bol každý kontajner jedna služba, tak by sme mali dodržiavať ideológiu mikroservisovej architektúry. Ako už napovedá názov, pri tejto architektúre je funkcionalita softvéru rozdelená na jednotlivé „mikroservisy“. Snahou je vytvorenie aplikácie, ktorá bude čo najviac modulárna, aby sme zjednodušili jej udržiavateľnosť a škálovateľnosť. Výsledkom je rozdelenie funkcionality do jednotlivých mikroservisov, kde každý má na starosti iba jednu, oddelenú časť softvéru. Ak je potrebná zmena v systéme, tak je takéto mikroservisy veľmi jednoduché upraviť, je potrebné vykonať iba požadovanú zmenu, zostaviť daný mikroservis a opätovne ho nasadiť. Taktiež je lepšia odolnosť voči chybám a výpadkom, keďže ak by padla jedna služba, tak ostatné budú fungovať naďalej. To nám taktiež pomáha aj s testovaním a nájdením chýb v softvéri. Mikroservisy môžu taktiež efektívne využiť najnovšie technológie, keďže môžeme aktualizovať softvér po jednotlivých službách. Ak by ste chceli detailnejší popis mikroservisovej architektúry, tak by som vám odporúčal článok od Jamesa Lewisa a Martina Fowlera.

DevOps je metodológia softvérového vývoja, ktorá kombinuje vývoj softvéru (Dev) a konfiguráciu a manažment tohto softvéru (Ops). Pri použití takéhoto spôsobu vývoja sú tieto dva tímy spojené a vývojári pracujú na vývoji aplikácie spoločne, od jej vytvorenia, cez testovanie až po jej nasadenie a následné monitorovanie. Výhodami takéhoto prístupu sú rýchlosť vývoja, spoľahlivosť, monitorovanie a zlepšená komunikácia, a kolaborácia. Keďže celý vývoj aplikácie je vrámci jedného tímu, vývojári sú schopní rýchlejšie komunikovať medzi sebou, ale aj kolaborovať zo zákazníkom, čo znamená častejšie vydávanie nových verzií vyvíjaného softvéru. Keď je už nová verzia hotová, tým že sú Ops vývojári integrovaný do tímu, tak aj následné zostavenie, nasadenie na server a monitorovanie chodu aplikácie je značne zjednodušené. Dobrým zdrojom informácií je stránka o DevOps pripravená spoločnosťou Atlassian.

Úvod do Dockera alebo ako veľryba pracuje s kontajnermi

Docker je jedna z popredných otvorených platforiem na vývoj a kontajnerizáciu aplikácií. Poskytuje spôsob ako zabaliť infraštruktúru aplikácie do kontajnera, kde môže bežať izolovane od zvyšku systému a nástroje na kontrolu kontajnerov. Docker zjednodušuje vývojový proces softvéru využívaním už popísaných praktík kontajnerizácie a mikroservisov. Pekný článok od Preethi Kasireddy nám popisuje všetko, čo by sme mohli chcieť vedieť a Dockeri a kontajnerizácii.

Architektúra Dockeru

Docker používa klient-server architektúru. Vývojári používajú klienta na komunikáciu s Docker daemonom, ktorý zostavuje, štartuje a vykonáva rôzne ďalšie operácie nad kontajnermi. Klient a daemon môžu byť spoločne na rovnakom lokálnom systéme, alebo sa môže klient pripojiť na vzdialeného daemona. Pripojenie je zväčša riešené cez REST API.

Docker daemon čaká na Docker API volania a stará sa o objekty ako sú kontajnery, obrazy, siete či zväzky. Taktiež komunikuje aj s ostatnými daemonmi ohľadom správy služieb. Používateľ používa Docker klienta na komunikáciu so samotným Dockerom. Prostredníctvom príkazov ako napríklad docker run dokáže volať daemona, ktorý sa už postará a vykonanie daného príkazu.

Ďalšou časťou architektúry je docker register. Register slúži ako úložisko na docker obrazy, o ktorých si povieme o chvíľu, z ktorého sú následne tieto obrazy sťahované. Existujú dva typy registrov — privátne a verejné. Privátne sú nami vytvorené, kde si môžeme ukladať obrazy, ku ktorým nechceme aby mal niekto prístup. Verejným registrom je Docker Hub. Docker Hub je veľká knižnica obsahujúca oficiálne obrazy rôznych produktov, od aplikačných rámcov ako napríklad Oracle WebLogic Server, cez databázy, ako MySQL Server, či DevOps nástroje, ako Jenkins, až po programovacie jazyky.

Docker objekty

Keď pracujeme s Dockerom, tak vytvárame rôzne objekty, ako sú obrazy, kontajnery či služby.

Obrazy sú read-only šablóny s príkazmi slúžiacimi na vytvorenie Docker kontajnera. Na vytvorenie obrazu stačí vytvoriť súbor Dockerfile, ktorý obsahuje dané príkazy. Zavolaním daemona sa tieto príkazy vykonajú krok po kroku, kde každý krok vytvára novú vrstvu a na konci vytvoria kompletný obraz. V prípade, že sa zmení nejaký príkaz, stačí ak docker vytvorí iba novú vrstvu, vďaka čomu sú obrazy malé a rýchle. Obrazy môžu byť aj založené na iných obrazoch, čo nám dovoľuje zobrať už vytvorený obraz a iba ku nemu pridať našu funkcionalitu.

Kontajner je bežiaca inštancia obrazu. Je vytvorený na základe príkazov použitých na vytvorenie obrazu, alebo príkazov, ktorými pridávame možností pri jeho zapnutí. Môžeme ho vytvoriť, zapnúť, vypnúť, odstrániť, pripojiť k rôznym sieťam alebo úložiskám použitím docker príkazov. Kontajner je natoľko izolovaný od hostiteľa, nakoľko ho nastavíme. Napríklad pridaním úložiska či siete znižujeme jeho izoláciu. Ak je kontajner odstránený, všetky zmeny vykonané v ňom, ktoré nie sú uložené na perzistentnom úložisku budú vymazané.

Služby sú používané na škálovanie kontajnerov na viacerých Docker daemonoch. Ak chceme naškálovať kontajner na viacero daemonov pre lepšie rozloženie záťaže, používame takzvaný swarm — súbor služieb. Používateľ uvidí iba jednu aplikáciu, ktorá je ale v realite beží na viacerých daemonoch, ktorí spolu komunikujú pomocou Docker API a vytvárajú viaceré repliky služby, aby dokázali obslúžiť záťaž.

Vytvorenie jednoduchého kontajnera pomocou Dockera

Ako prvé si jednoducho ukážeme celý proces, od vytvorenia Dockerfilu, až po zapnutie aplikácie bežiacej v kontajneri. V tomto príklade vytvoríme jednoduchú webovú aplikáciu napísanú v Pythone, ktorá bude pripojená na localhost a vypíše nám Hello World. Začneme s vytvorením Dockerfilu.

# Použi oficiálny python obraz na vytvorenie nášho obrazu
FROM python:3.7-stretch

# Nastav pracovný adresár na /app
WORKDIR /app

# Skopíruj celý obsah adresára v ktorom sa nachádzame, do adresára app nachádzajúceho sa v kontajneri
COPY . /app

# nainštaluj závislosti
RUN pip install --trusted-host pypi.python.org Flask

# odhaľ port 80 pre zvyšok systému
EXPOSE 80

# nastav premennú prostredia
ENV NAME World

# keď sa zapne kontajer, zapni python aplikáciu
CMD ["python", "app.py"]

Jednotlivé príkazy, alebo kľúčové slová, ktoré Docker rozpoznáva sa správne nazývajú inštrukcie. Inštrukcia FROM inicializuje nový build obrazu podľa základu, ktorý mu zadáme. Ako sme si už spomenuli, každá inštrukcia v Dockerfile vytvára novú vrstvu. Keďže táto inštrukcia vytvára prvotnú vrstvu, je povinná pre každý Dockerfile. Ak by sa v ňom nenachádzala, Docker by nevedel na základe čoho má vytvoriť nový obraz. Ak by sme chceli vytvoriť úplne čistý obraz, tak by sme mohli použiť ako základ takzvaný scratch. Našťastie nemusíme vždy zostaviť obrazy zo scratch-u, môžeme tiež využiť už existujúce obrazy a iba rozšíriť ich funkcionalitu. V tomto prípade je výhodnejšie zobrať oficiálny Python obraz, kde už je nainštalovaný Python 3.7 a iba rozšíriť náš obraz.

Ako ďalšia inštrukcia je WORKDIR. Tá nám nastaví pracovný adresár na /app. V nasledujúcej inštrukcii COPY, skopírujeme celý obsah adresára, v ktorom sa práve nachádzame, indikované ., a skopíruje ho do adresára app nachádzajúceho sa v kontajneri. Inštrukcia RUN vykoná zadaný príkaz. V tomto kroku zavoláme príkaz pip aby nám nainštaloval závislosť pre našu aplikáciu, ktorou je Flask. Flask je softvérový mikrorámec pre Python na jednoduchú tvorbu web aplikácií. Ak by vás zaujímal podrobnejšie, môžete sa naň pozrieť na oficiálnej stránke. Inštrukcia EXPOSE nám odhalí port 80 pre vonkajší svet, takže mimo kontajnera. Pomocou inštrukcie ENV môžeme zadať premenné prostrediu vo vnútri kontajnera. Zadáme mu premennú NAME a nastavíme ju na hodnotu World.

Poslednou inštrukciou je inštrukcia CMD. Udáva, čo sa má štandardne stať po zapnutí kontajnera. Môže udávať parametre alebo samotné príkazy. Ak sa v jednom Dockerfile nachádzajú viaceré CMD inštrukcie, vykoná sa iba posledná. V našom prípade nám hovorí, že ak sa zapne kontajner, tak pri jeho štarte sa zapne naša python aplikáciu app.py.

Nakoniec sa dostávame ku vytvoreniu samotnej aplikácie bežiacej vo vnútri kontajnera. Vytvorme si súbor app.py

from flask import Flask
import os
import socket

app = Flask(__name__)

@app.route("/")
def hello():
    html = "<h3>Hello {name}!</h3>" 
           "<b>Hostname:</b> {hostname}<br/>" 
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

Táto jednoduchá aplikácia vytvorená pomocou softvérového rámca Flask nám vytvorí čistú HTML stránku, ktorá nám vypíše Hello world, kde hodnotu world zoberie z našej premennej NAME, vytvorenej v Dockerfily, a taktiež nám vypíše náš hostname. Pri takomto pokuse o získanie hostname nám ale vráti ID kontajnera, v ktorom beží aplikácia, nie názov hostiteľského systému.

Teraz sa už môžeme dostať k zostaveniu nášho Docker obrazu. Použitím príkazu docker build -t hello . vytvoríme náš obraz. Príkazom docker voláme Docker daemona, build nám hovorí, že chceme z Dockerfilu vytvoriť obraz, -t hello alebo v dlhšom formáte --tag je jedna z možností príkazu docker build. Pomocou nej dokážeme pomenovať náš obraz. Príkaz ale ešte požaduje cestu k adresáru, v ktorom sa nachádza Dockerfile, podľa ktorého sa má obraz vytvoriť. Bodka (.) indikuje súčasný adresár Po vykonaní príkazu môžeme použiť príkaz docker image ls, ktorý nám vypíše naše obrazy.

REPOSITORY		TAG			IMAGE ID
hello			latest		960524bur552

Po vytvorení obrazu môžeme zapnúť kontajner. Keďže sme inštrukciou CMD špecifikovali, že po zapnutí kontajnera sa má spustiť aj aplikácia, tak po zadaní nasledujúceho príkazu sa zapne kontajner aj naša aplikácia. Príkaz na zapnutie kontajnera je docker run -p 4000:80 hello. Príkaz run zapne kontajner, -p 4000:80 namapuje odhalený port kontajnera 80 na hostiteľský port 4000 a hello je názov obrazu, z ktorého chceme vytvoriť kontajner. Aplikácia beží vo vnútri kontajnera na http://0.0.0.0:80, ale keďže sme odhalili port 80 a nastavili ho pomocou možnosti príkazu run na 4000:80, tak v našom systéme môžeme použiť https://localhost:4000.

Takto ale náš kontajner beží na popredí. Ak ho chceme zapnúť na pozadí, môžeme použiť príkaz docker run -d -p 4000:80 hello. Možnosť -d, alebo celým názvom --detach, nám ho dovolí zapnúť na pozadí. Tak ako sme si mohli vypísať Docker obrazy v našom systéme, tak si môžeme vypísať aj kontajnery príkazom docker container ls.

CONTAINER ID		IMAGE		COMMAND					CREATED
28cf52hl9p63		hello		"python app.py"			1 minute ago

Na ukončenie kontajnera môžeme použiť príkaz docker container stop 28cf52hl9p63 a na odstránenie docker container rm 28cf52hl9p63. Keďže sme nášmu kontajneru nezadali žiadny názov, tak musíme použiť ID kontajnera.

Vrstvy v Docker obrazoch

Ďalšou dôležitou vecou, ktorú sa treba pri Dockeri naučiť sú vrstvy. Dockerfile píšeme ako postupnosť viacerých inštrukcií. Ak ho následne zapneme, tak vo výpise by sme videli, že každá inštrukcia sa vykoná ako samostatný krok a každý samostatný krok je nová vrstva. Výsledný obraz pozostáva zo série vrstiev, ktoré sú iba čitateľné až na poslednú, ktorá je výsledný kompletný obraz. Jednotlivé medzivrstvy sú usporiadané za sebou podľa inštrukcií, ktoré boli zapísané v Dockerfile a každá obsahuje iba rozdiel oproti predchádzajúcej vrstve. Predstavme si nasledujúci dockerfile:

FROM ubuntu
COPY . /app
RUN apt-get update
RUN apt-get install -y apache2
RUN make /app
CMD python /app/app.py

Takýto dockerfile by sa vykonal ako postupnosť šiestich krokov, takže by vytvoril šesť vrstiev obrazu. FROM by vytvoril prvú vrstvu z obrazu ubuntu. Následne by príkazom COPY pridal druhú vrstvu, vykonaním príkazov RUN pridal ďalšie a výsledná by bola vrstva, v ktorej sa vykonal CMD. Keby sme si ho pozreli vo výpise buildu:

Sending build context to Docker daemon  10.096kB
Step 1/6 : FROM ubuntu
 ---> 368f5665a747
Step 2/6 : COPY . /app
 ---> 96hr3s854f96
Removing intermediate container ftg856sa258a
Step 3/6 : RUN apt-get update
 ---> Running in 635tr1452uo6
 ---> zh963az5fs95
Removing intermediate container 854topp63dr1
Step 4/6 : RUN apt-get install -y apache2
 ---> Running in 745rtg24ay18
 ---> utg965adcc85
Removing intermediate container prh854a1v462
Step 5/6 : RUN make /app
 ---> Running in er741289a547
 ---> i85d85af2f8g
Removing intermediate container rt749635a41c
Step 6/6 : CMD python /app/app.py
 ---> Running in tfs742a963a4
 ---> ft85p96354a7
Removing intermediate container 74a85df9rd36
Successfully built ft85p96354a7
Successfully tagged random/app:test

Keby sme si dali vypísať históriu nášho obrazu príkazom docker history, tak môžeme pekne vidieť, ako boli postupne tieto vrstvy vytvorené.

IMAGE         CREATED         CREATED BY                                 SIZE      
ft85p96354a7  10 minutes ago  /bin/sh -c CMD python /app/app.py          3.28 MB
i85d85af2f8g  10 minutes ago  /bin/sh -c RUN make /app                   3.25 MB
utg965adcc85  10 minutes ago  /bin/sh -c RUN apt-get install -y apache2  3.23 MB
zh963az5fs95  10 minutes ago  /bin/sh -c RUN apt-get update              3.2 MB
96hr3s854f96  10 minutes ago  /bin/sh -c COPY . /app                     3.1 MB
368f5665a747  10 minutes ago  /bin/sh -c FROM ubuntu                     25 B

Takýto Dockerfile by sme ale mohli upraviť tak, že by sme spojili všetky RUN inštrukcie dokopy a tým vytvorili iba jeden krok, takže iba jednu vrstvu namiesto troch.

FROM ubuntu
COPY . /app
RUN apt-get update \
    && RUN apt-get install -y apache2 \
    && RUN make /app
CMD python /app/app.py

Správa dát v Dockeri

Už sme rozprávali o tom, aká je architektúra v Dockeri a ako je schopný bežať priamo na hostiteľskom systéme, avšak ako je to s dátami? Ako môžeme dostať dáta a zdroje do kontajnera?

Znázornenie rozdielu medzi použitím zväzkov a pripojení súborového systému
Znázornenie rozdielu medzi použitím zväzkov a pripojení súborového systému

Zväzky sú najlepším spôsobom ako perzistovať dáta pri použití Docker kontajnerizácie. Sú uložené v časti súborového systému, ktorá je manažovaná Dockerom a ostatné procesy na nich nemajú žiadny vplyv. Sú vytvárané Dockerom, či už príkazom docker volume create v príkazovom riadku, pripojením pri zapínaní kontajnera použitím prepínača -v, inštrukciou VOLUME v Dockerfile, či pripojením v Docker compose súbore. Keď vytvoríme zväzok, tak je uložený v adresári v hostiteľovom súborovom systéme. Ak ho následne pripojíme ku kontajneru, tak vlastne pripájame tento adresár. Jeden zväzok môže byť pripojený na viaceré kontajnery zároveň, a ak budú všetky kontajnery odstránené, tak tento zväzok bude stále existovať. Zväzky sú odstránené až keď ich vymažeme samostatne. Ďalšou výhodou je aj to, že zväzky sa menia dynamicky, čo znamená, že ak ho zmeníme v našom hostiteľskom adresári, tak sa zmení aj v kontajneri bez potreby ho reštartovať. Použitím zväzkov vieme ľahko vykonať zálohu alebo migráciu dát či už lokálne, alebo aj vzdialene. Podrobnejšie informácie, či už o ich funkcionalite alebo aj konkrétne ich vytvorení, pripojení ku kontajneru alebo službe si môžete pozrieť v oficiálnej dokumentácii.

Pripojenie úložiska je podobné zväzkom, avšak s nejakými odlišnosťami. Pripojenia môžu byť uložené hocikde na hostiteľskom systéme, a iné procesy ich môžu ľahko zmeniť a sú referencované absolútnou cestou, takže v prípade ich presunutia musíme zmeniť aj ich cestu. Vo všeobecnosti sa odporúča používať zväzky, ktoré sú považované za bezpečnejšie. Bližšie informácie sú znovu v dokumentácií.

Prečo použiť Docker compose

Ukázali sme si ako vytvoriť kontajner z obrazu vytvoreného pomocou Dockerfilu. Avšak to bolo iba vytvorenie jednej služby, v našom prípade webovej aplikácie. Reálny softvér sa ale bude skladať z viacerých služieb. Ak by sme chceli vytvoriť viacero Docker kontainerov naraz, tak s tým nám pomôže Docker Compose. Docker Compose je nástroj ktorým môže definovať, vytvoriť a zapnúť viaceré kontajnery jedným príkazom. Jediné, čo na to potrebujeme, je vytvoriť yaml súbor, v ktorom si zadefinujeme jednotlivé služby.

Povedzme, že by sme chceli vytvoriť Oracle databázu a ešte k nej pridať aj napríklad Oracle Fusion Middleware, ktoré vieme jednoducho získať z oficiálnych repozitárov na Githube (Fusion Middleware a Databáza). Následne si vytvoríme yaml súbor a nazveme ho docker-compose.yml. Tento súbor bude vyzerať nasledovne:

version: "3"

services:

  oracle:
  build: ./oracledb/12.1.0.2/
    image: oracle12:db
    ports:
      - "1521:1521"
      - "5500:5500"
    container_name: db12_container
    env_file:
      - ./oracledb/12.1.0.2/common.env
    volumes:
      - ../workspace/:/mnt/workspace
      - ./oracledb/12.1.0.2/scripts/startup:/docker-entrypoint-initdb.d/startup
      - ./oracledb/12.1.0.2/scripts/setup:/docker-entrypoint-initdb.d/setup

  fmw12:
    build: ./fmw/12.2.1.3/
    image: oracle12:fmw
    ports:
      - "4005:5005"
    container_name: fmw12_container
    env_file:
      - ./fmw/12.2.1.3/infraDomain.env.list
      - ./common.env
    depends_on:
      - oracle

version znamená verziu formátu súboru compose, ktorá je momentálne 3.7. Následne si definujeme služby, ktoré chceme vytvoriť. Prvou bude oracle, t.j. naša databáza. Build znamená cestu k Dockerfilu, z ktorého sa bude obraz vytvárať; image je názov obrazu, ktorý bude vytvorený; ports udáva ktoré porty budú na aké porty namapované, kde prvým je port hostiteľa a druhý je port kontajnera; ďalej zadáme názov kontajnera, ktorý má vytvoriť a pomocou volumes definujeme zväzky, ktoré sa pripoja ku kontajneru.

env_file udáva súbor, z ktorého si má zobrať premenné prostredia. Týmto si môžeme jednoducho definovať premenné už dopredu a pri vytvorení budú automatický nastavené. Všetko čo potrebujeme na vytvorenie env_file je súbor s príponou .env. Na vytvorenie validného súboru ale musíme dodržať určitú syntax. Každá premenná musí byť na novom riadku a dodržiavať formát syntaxe VAR=VAL, kde VAR je názov premennej a VAL je jej hodnota. Nie je potrebné používať úvodzovky, syntax ich nerozoznáva. Všetky prázdne riadky sú v takomto súbore ignorované a komentuje sa použitím symbolu #.

Druhou službou bude fmw12, teda náš Fusion Middleware. Syntax bude rovnaká, akurát zmeníme cesty k fmw súborom. Tu sme ale pridali aj jeden nový príkaz a to depends_on. Ten znamená, že compose má počkať kým sa kompletne dokončí spustenie prvej služby oracle a až tak sa spustí druhá služba.

Na ovládanie Docker composu používame príkaz docker-compose. Ak by sme chceli zostaviť služby, tak použijeme príkaz docker-compose build, na zapnutie kontajnerov docker-compose up, na odstránenie kontajnerov docker-compose down. Ak by sme mali viacero docker-compose súborov, tak na zapnutie jedného konkrétneho môžeme použiť možnosť -f, takže v našom prípade na vymazanie kontajnerov by príkaz bol docker-compose down -f docker-compose.yml. Zoznam a popis všetkých dostupných príkazov je dostupný v dokumentácii k Docker compose.

Záver

Docker a samotná kontajnerizácia je zaujímavá a rýchlo sa rozvíjajúca technológia, ktorá sa vo svete mikroservisov, cloudov a DevOps princípov rýchlo uchytila a umožňuje zrýchliť a zefektívniť či už vývoj, údržbu alebo testovanie softvéru. To, čo ale bolo prebraté v tomto článku je ale iba základ kontajnerizácie a Dockera a je ešte veľa ďalších pokročilejších tém, ku ktorým som sa ale nedostal. Verím, že som Vás týmto aj inšpiroval vyhľadať si a dozvedieť sa viac o kontajnerizácii, keďže je to veľmi rýchlo rastúca technológia, ktorá si na svoju stranu rýchlo priťahuje mnohé firmy. Dúfam, že tento príspevok Vám aspoň z časti priblížil a objasnil kontajnerizáciu, Docker a prácu s ním, čo by Vám malo slúžiť ako dostatočný úvod do danej problematiky.

Linkovať