- Praktický úvod do Docker a kontejnerů (1) – od instalace po první kontejnery
- Praktický úvod do Docker a kontejnerů (2) – propojování
- Praktický úvod do Docker a kontejnerů (3) – víc najednou aneb něco užitečného s Docker Compose
- Praktický úvod do Docker a kontejnerů (4) – jak z nich získat maximum
- Praktický úvod do Docker a kontejnerů (5) – Docker Machine
- Praktický úvod do Docker a kontejnerů (6) – cluster hostitelů s Docker Swarm
- Praktický úvod do Docker a kontejnerů (7) – scheduler v Docker Swarm
- Praktický úvod do Docker a kontejnerů (8) – váš vlastní registr obrazů
- Praktický úvod do Docker a kontejnerů (9) – multi-host networking
- Praktický úvod do Docker a kontejnerů (10) – Windows kontejnery s Docker API
- Praktický úvod do Docker a kontejnerů (11) – Windows kontejnery s PowerShell
- Praktický úvod do Docker a kontejnerů (12) – Windows Hyper-V kontejner
- Praktický úvod do Docker a kontejnerů (13) – Swarm mode, service, balancing, scaling (v1.12)
V minulém díle jsme si Docker nainstalovali a rozjeli pár kontejnerů. Dnes pokračujeme dál, vrhněte se do moderního IT s cloudsvet.cz
Environmental variables
Raději bych v nadpisu preferoval češtinu, ale proměnná prostředí by možná nikomu nic neříkala. Nicméně v oblasti kontejnerů a Platform as a Service (PaaS) jde o dost zásadní prostředek předávání informací aplikacím. Většina procesů, služeb, démonů a jiných částí aplikací potřebuje ke svému běhu nějaké konfigurační informace – tak například aplikační kód musí vědět, kde je databáze, v které má data. Kontejner by měl vždy být jednoúčelový (tedy nikdy v něm nemá být jak databáze tak aplikace) a maximálně přenositelný. Jakou tedy provést konfiguraci?
Pokud dáte přímo do aplikačního kódu IP adresu a login databáze, cloudsvet.cz zřejmě není vhodný web pro vás 🙂 Nicméně rozeberme i příčetnější metody. Konfigurační soubor je pro složitější parametrizaci samozřejmě vhodný, ale otázkou je, jestli je dobré mít tolik laditelných parametrů ve vaší službě (o tom jindy, ale vrátíme se k tomu) – buď jak buď vstřikování změn v konfiguračním souboru není v souvislosti s kontejnery zrovna flexibilní. Musíte znát jeho obsah, nedělat chyby a je to tak komplexní, že versioning je dobrý nápad (proto si myslím, že masivní parametrizace patří developerům – ti mají pro provoz nabídnout jen pár nejzásadnějších konfigurací, zdaleka ne všechno). Technicky musíte ten soubor mít, upravovat, vstřikovat do kontejneru. Další možnost je předání parametrů při spouštění procesu. To není vůbec špatný nápad, ale musíte znát strukturu těchto vstupních parametrů (např. číst dokumentaci nebo prostě vědět) a nevíte, jaké jsou výchozí hodnoty. Přeskočme pár dalších možností a řekněme si proč zrovna environmentální proměnné jsou zajímavá volba.
Jaké mají výhody?
- Nemají žádný formát ani název souboru, princip je pro všechny služby stejný
- Můžete je mít přímo ve svém Dockerfile v nějakých výchozích hodnotách – každý pak snadno pochopí co s tím (nemusí studovat dokumentaci a konfigurační soubor)
- To, že je v Dockerfile, znamená, že parametry jsou součástí předpisu pro kontejner – verzujte Dockerfile a držíte si přehled o obojím najednou
- Jejich předávání lze dobře automatizovat (! tohle je klíčové) – Docker vám sám dosadí parametry zlinkovaných kontejnerů (v dnešní díle uvidíte), Cloud Foundry (a další PaaS) předají login do DB včetně jména databáze, login a parametry message queue apod.
- Lze je dobře kombinovat s jinými metodami, pokud chcete (například OpenStack CLI si může veškeré loginy vzít z proměnných prostředí, ale pokud vás baví zadávat je pořád dokola při spouštění, můžete)Dobrá, vyzkoušejme to. Spustíme kontejner postavený na image debianu (využijte přepínač –rm, takže hned po ukončení běhu se vám kontejner rovnou zase smaže) a přepínačem –env mu pošleme proměnnou prostředí, která mu řekne, co má každý rozumný člověk číst. V kontejneru spustíme příkaz env, který jednoduše všechny environmentální proměnně vypíše.
cloudsvet@ubuntu:~$ docker run --rm --env ctete=cloudsvet.cz debian env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=5b70531f9412 ctete=cloudsvet.cz HOME=/root
Je tam co jsme potřebovali. Sami už přijdete na to, jak to dobře použít ve svých aplikacích.
Propojení kontejnerů
Minule jsme si ukázali, jak může kontejner vystavit nějakou službu (port) tak, že ji lze konzumovat v rámci host. Takto by nám samozřejmě mohly mezi sebou komunikovat i kontejnery, ale existuje ještě jednodušší cesta (pro ty co jsou na stejném host). Tou je vytvoření linky. Nejen, že Docker zajistí příslušné lokálně- síťařské úkony (překlady adres apod.), ale cílovému kontejneru sdělí informace o službě toho prvního, tedy IP adresu, port, typ protokolu (a hádejte jak). Nicméně je dobré si říct, že v listopadu 2015 byl uveden Docker 1.9 a s ním nový networking včetně overlay režimu a multi-host implementace. Propojování kontejnerů přes –link tedy berte jako ukázku práce s environmentálními proměnnými (což se hodí třeba pro binding externích služeb), ale privátní sítě budeme v příštích dílech dělat ještě jinak.
Nejdřív se ubezpečte, že vám ještě běží kontejner s webovou aplikací z minulého dílu:
cloudsvet@ubuntu:~/docker/client$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c9a7add778ec cloudsvet:dalsiWeb "/bin/sh -c 'lighttpd" 40 hours ago Up 40 hours 0.0.0.0:32768->80/tcp dalsiWebKontejner2
Představme si teď, že to není web pro koncového klienta, ale jde o RESTful HTTP službu, kterou může jiná služba volat tu naší. Tvrdil jsem, že Docker cílovému kontejneru řekne vše potřebné a jistě jste uhodli, že to udělá environmentální proměnnou. Spustíme teď další kontejner na bázi debian image a příkazem –link ho propojíme s naším webovým kontejnerem s názvem dalsiWebKontejner2 a cílovému kontejneru ho naprezentujeme pod názvem mujweb (to je důležité – cílový kontejner bude vědět, že pod proměnnými mujweb najde informace o příslušné službě, takže vůbec netuší, jaký je název kontejneru s tou službou a nic nepotřebuje dopředu znát). V kontejneru spustíme env a podíváme se, jaké proměnné vidí:
cloudsvet@ubuntu:~/docker/client$ docker run --rm --link dalsiWebKontejner2:mujweb debian env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=e96ad04d6b6e MUJWEB_PORT=tcp://172.17.0.6:80 MUJWEB_PORT_80_TCP=tcp://172.17.0.6:80 MUJWEB_PORT_80_TCP_ADDR=172.17.0.6 MUJWEB_PORT_80_TCP_PORT=80 MUJWEB_PORT_80_TCP_PROTO=tcp MUJWEB_NAME=/modest_nobel/mujweb HOME=/root
Dostali jsme co jsme chtěli. Pojďme teď vytvořit kontejner s “aplikací”, která bude naši službu konzumovat – konkrétně to bude jednoduchý Linux OS s cURL (“prohlížeč” do příkazového řádku). Tady je jeho Dockerfile:
FROM debian RUN apt-get update && apt-get install curl -y CMD curl $MUJWEB_PORT_80_TCP_ADDR:$MUJWEB_PORT_80_TCP_PORT/index.html
Nainstalujeme tedy cURL a jako výchozí příkaz spustíme cURL a namíříme ho na webovou stránku tak, jak ji získáme z proměnných prostředí. Vybudujte image s názvem třeba cloudsvet/client:
cloudsvet@ubuntu:~/docker/client$ docker build -t cloudsvet/client . Sending build context to Docker daemon 2.048 kB Step 0 : FROM debian ---> 9a61b6b1315e Step 1 : RUN apt-get update && apt-get install curl -y ---> Running in f59c962345e6 ... ---> 28161221c2e1 Removing intermediate container f59c962345e6 Step 2 : CMD curl $MUJWEB_PORT_80_TCP_ADDR:$MUJWEB_PORT_80_TCP_PORT/index.html ---> Running in 6df07320b3e0 ---> a974f9698dec Removing intermediate container 6df07320b3e0 Successfully built a974f9698dec
Teď ho spustíme a nalinkujeme na náš web server. Povedlo se? Vidíme HTML?
cloudsvet@ubuntu:~$ docker run --rm --link dalsiWebKontejner2:mujweb cloudsvet/client % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0<H1>Tohle je druhy web</H1> 100 28 100 28 0 0 27 0 0:00:01 0:00:01 --:--:-- 27
Kontejnery máme svázané velmi volně, můžeme je různě prohazovat, měnit, restartovat a mít jich kolik chceme – nestaráme se o nějaká čísla portů běžících služeb ani IP adresy.
Volume kontejnery
Náš kontejner s web serverem má ještě jednu neoptimální vlastnost – jsou v něm data. Doporučované pravidlo kontejnerů je, aby splňovaly pouze jeden účel. Ten náš funguje jako web server a současně jako úložiště webových souborů.
Nejdřív si ukážeme něco, co není radno používat, pokud k tomu nepřidáme ještě speciální perzistentní nadstavby (jako je Flocker či REX-Rey, o kterých bude řeč později). Kontejneru můžete předhodit data na hostu a to včetně možnosti zapisování. Tak například obsah našeho web serveru by klidně mohl by být uložen na hostitelském systému. V praxi to není pro produkční nasazení vhodné, protože jednou z velkých výhod kontejnerů je přenositelnost a nezávislost na hostujícím systému. Nicméně pro testování je to rychlý a pohodlný způsob.
Vytvořte si adresář a soubor v host systému a namapujeme si ho do kontejneru:
cloudsvet@ubuntu:~$ mkdir hostdata cloudsvet@ubuntu:~$ touch hostdata/data.txt cloudsvet@ubuntu:~$ docker run --rm -it -v ~/hostdata/:/mojedata debian bash root@f5c011e9716b:/# ls mojedata/ data.txt
V některém z příštích dílů si vyzkoušíme použití implementace persistentního volume, jehož backendem může být OpenStack Cinder, tedy vaše hostující IaaS a tradiční pole jako je 3PAR nebo softwarově definovaný StoreVirtual.Další možnost je použít volume kontejner. Ve skutečnosti ten sice taky vytvoří soubor kdesi v host (zjistit kde se dá, ale neměli bychom to vlastně vědět), ale jeho fungování nás vede k chování nezávislému na host. Tento kontejner s daty pak namapujete do jiného kontejneru. Pro využívání volume kontejneru nám stačí cokoli, co má základní file operace – klidně použijte zase Debian, ale dá se nasadit třeba busybox, který je extrémně malý. Navíc kontejner (je to výjimka) nemusí běžet a přesto ho lze takto nasadit. Použijeme tedy příkaz create, spouštět ho nemusíme.
cloudsvet@ubuntu:~$ docker create -v /mojedata --name mujdatacont busybox Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox cf2616975b4a: Pull complete 6ce2e90b0bc7: Pull complete 8c2e06607696: Pull complete Digest: sha256:df9e13f36d2d5b30c16bfbf2a6110c45ebed0bfa1ea42d357651bc6c736d5322 Status: Downloaded newer image for busybox:latest 0058b9c4dc1f7296b99358d8ee638fcbd4befa001c4235d6eb0a58c3a5cfddb7
Datový kontejner je vytvořen. Pojďme teď spustit jiný interaktivní kontejner, kterému podhodíme data z našeho datového kontejneru. Až budeme uvnitř, vytvoříme nějaký soubor:
cloudsvet@ubuntu:~$ docker run -it --rm --volumes-from mujdatacont debian bash root@0e23529d1522:/# ls bin boot dev etc home lib lib64 media mnt mojedata opt proc root run sbin srv sys tmp usr var root@0e23529d1522:/# touch mojedata/file1.txt root@0e23529d1522:/# ls mojedata/ file1.txt root@0e23529d1522:/# exit exit
Spusťte teď jiný kontejner a zase mu přihoďte ten datový – najdete tam námi vytvořený soubor?
coudsvet@ubuntu:~$ docker run -it --rm --volumes-from mujdatacont debian bash root@685b6cda29fb:/# ls mojedata/ file1.txt
Co se stane když image kontejneru už stejný adresář má? Ten namapovaný zvítězí (překryje ten původní).
Ještě jedna důležitá věc – samotná data ve volume kontejneru se nikdy nestanou součástí obrazu. Pokud tedy na datovém kontejneru uděláte commit, data v tom nebudou. Pokud chcete datový kontejner množit, zálohovat nebo obnovovat, musíte použít kontejnerové prostředky. Ukažme si zálohu dat. Spustíte kontejner, namapujete mu datový kontejner a také lokální adresář z hosta. Jako příkaz spustíte tar zabalíte data z volume kontejneru a souboru na hostu.
cloudsvet@ubuntu:~$ docker run --rm --volumes-from mujdatacont -v $(pwd):/backup debian tar cvf /backup/backup.tar /mojedata tar: Removing leading `/' from member names /mojedata/ /mojedata/file1.txt
Už je to všechno?
Určitě vás už napadlo, že je to fajn, ale co když jsou kontejnery na jiných host systémech? Správná úvaha – pak to takhle nefunguje. Jakmile se budeme chtít dostat za hranici jednoho systému, bude to chtít trochu orchestrace. Já bych doporučoval využít seznámení s Docker na to, abyste rovnou skočili do Platform as a Service jako je Cloud Foundry (např. HP Helion Development Platform) – tam se Docker využívá, ale děje se podstatně víc kolem vašich aplikací. Další možností je použít některé novější Docker projekty, třeba Docker Network (od verze 1.9 z listopadu 2015), libnetwork (univerzálnější plugin systém), Swarm (orchestrace přímo od Docker produkčně od listopadu 2015). Případně použijete orchestraci z třetích stran, třeba Kubernetes nebo Mesos nebo Fleet clustering z CoreOS. Nebo si dáte orchestraci nad těmito nástroji v podobě OpenStack Magnum. Možná pak přijde čas na implementaci service discovery jako je Consul, Chubby (z dílny Google), Apache Zookeeper (původně z Yahoo – a je to trochu mazec), etcd (jednoduché a milé z CoreOS), Doozerd nebo SmartStack. Ale o tom někdy příště – doporučuji skočit rovnou na PaaS, je to jednodušší.
Co příště? Ukážeme si Docker nástroje na koordinované spuštění vícero kontejnerů (Docker Compose) a sestavíme si nějakou užitečnější aplikaci. Pak už se dostaneme k té části metodické, kde shrneme dosavadní poznatky a zaměříme se na tipy pro efektivní využití kontejnerových technologií.
Vyzkoušejte si Docker ještě dnes – ať už ho použijete přímo nebo jako součást PaaS, získané zkušenosti a návyky vám zůstanou a budou se pro moderní IT určitě hodit.
[…] první díle jsme se naučili základy Dockeru a v druhém jejich propojování. Dnes budeme pokračovat, ale sestavíme si něco, co bude už opravdu […]
[…] začátku seriálu jsme propojovali kontejnery starším způsobem vytvořením linku. Potíž je, že to bylo vymyšleno na spoje v rámci […]
Zdravim, len 1 dost podstatna otazka pre mna. Pouzivame docker v ramci coreos + fleet + nginx proxy( + etcd na discovery v ramci takeho mini interneho cloudu)
Data pre niektore sluzby su ulozene mimo ‘cloud’ na serveroch a mapovane prostrednictvom nfs. Docker kontajner tieto data pouziva a mapuje ich do vnutra kontaineru (ako priklad uvediem jenkins, ktory ma svoje data na nfs diskoch)
+ su tam rozne microsevices a tu prave prichadza otazka. Mame ‘sluzbu’ ktora bezi v 2 kontajneroch.
1) kontanjer je rest api (container1)
2) kontajner je frontend (container2)
Otazka znie, je lepsie aby rest api data boli v container1 (pripadne volume container) a frontend data v container2 (pripadne volume container) alebo je pouzitelnejsie nieco ako (ulozene na nfs diskoch):
Server
run.py
Database
Client
static
a.html
dynamic
a.js
index.html
a nasledne namapovane konkretne veci do konkretneho kontaineru (Server do container1) a (Client do container2)
Cize vo vysledku ako entry point container1 bude [‘python’, ‘run.py’] a entry point cointainer2 bude spustenie apachu, ktory nacita data.
Dufam, ze je to aspon z casti zrozumitelne
Podle mě záleží na tom čemu říkáme data. Jsem pro externalizaci dat, tedy nechť jsou mimo kontejner s aplikací. Strukturovaná “transakčnější” v relační DB, víceméně strukturovaná ve flexibilnější NoSQL, nestrukturovaná (obrázky, zvuky, dokumenty, věci je stažení, videa) v object store. File a blokový přístup bych nedělal. Uvedené věci nemusí být v kontejnerech (buď ve VM, bare metal, sjednocené v Mesos nebo kontejnerizované), ale ideálně scale out. Získání přístupu k těmto službám bych rozhodně řešil s Cloud Foundry PaaS a kdo se chce babrat v detailech, nechť si totéž udělá sám s Consul či Etcd.
Nicméně aplikace patří do kontejneru a měl bych rolovat nový kontejner s každou změnou (rozhodně jděte do Cloud Foundry nad Docker nebo alespoň Kubernetes, dělat canary release ručně v Dockeru je zbytečné, ten čas lze využít lépe). Skript myslím patří do kategorie aplikace. Je uložen ve version control typu Git? Měla by jeho změna vyvolat test v CI/CD pipeline? Pak je to aplikace a patří do kontejneru.
Dává to alespoň trochu smysl?