- 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 článku jsme si pohráli s Docker Swarm clusterem a viděli, že o rozmístění kontejnerů do hostitele rozhodne za nás. Můžeme mu do toho ale nějak promlouvat? Na to se zaměříme dnes.
Výběr hostitele pro nový kontejner můžeme nechat čistě na Docker Swarm, ale můžeme si říct, jakou strategii má při tom použít. Dá se ale i promlouvat do výběru důrazněji, ve výchozím stavu například Docker Swarm nedá kontejner na hostitele, který umřel, nebo který má potřebný TCP port aplikace obsazený už jiným kontejnerem. Můžete identifikovat hostitele podle tagů s nějakými vlastnostmi, umisťovat kontejner tak, aby dva co k sobě patří běžely u sebe a tak podobně.
UPDATE: Docker ve verzi 1.12 tohle posouvá ještě dál díky koncept “service”. Čtěte v 13. díle této série.
Strategie pro umisťování kontejerů
Výchozí strategie je spread, tedy rozprostřít kontejnery přes co nejvíce hostitelů. Swarn vezme v úvahu potřeby kontejneru (jsou-li definované) a pro každý node spočítá, jaký podíl místa (myšleno CPU a RAM) na něm zbude po případném spuštění kontejneru. Pokud údaje pro kontejner nebudou uvedeny nebo výsledek z pohledu zdrojů CPU a RAM bude u všech nodů stejný, rozhodovat bude počet už umístěných kontejnerů (pozor – jak těch běžících, tak těch, se statusem exited). Spread strategie si vybere ten node, ve kterém zbude nejvíc místa nebo kde je nejméně kontejnerů. Výsledkem je, že budou kontejnery rozprostřeny po celém clusteru. Výhodou je, že v případě havárie nodu je menší dopad.
Druhá používaná strategie (tu už ale musíte specificky uvést při vytváření clusteru) je binpack. V tomto případě je povinné uvádět spotřebu kontejneru co do procenta CPU hostitele a použité RAM. Swarm použije stejný mechanismus seřazení kontejnerů jako u předchozí strategie, jen obráceně. pokud se kontejner na node nevejde (není dost RAM apod.), není brán v úvahu. Z těch, kam se vejde, se vybere ten, u kterého po umístění kontejneru zbude nejméně volného místa. Strategie binpack tedy namačká kontejnery co nejvíc k sobě a pokusí se naplno využít potenciálu hostitelů (vezměte si, že vzhledem k velmi nízkému overhead kontejnerů jich na našlapaný moderní server dostanete doslova tisíce). Proč volit strategii namačkání kontejnerů? Nody využíváte velmi efektivně a když zjistíte, že je spousta z nich volná, můžete je jednoduše vypnout a do clusteru přidat až když to bude opravdu potřeba. Kombinace binpack strategie s automatizací na úrovni infrastruktury (přidávání a ubírání hostitelů) může být velmi efektivní variantou zejména pro provoz v public cloud, kde za hostitelskou VM nechcete platit zbytečně.
Třetí strategie je random, tedy náhodné určení hostitele.
Omezení na nody
Swarm obsahuje dva filtry (omezení) na nody, tedy hostitele. Prvním je health, který zabrání tomu, aby se systém pokusil spouštět kontejnery na mrtvém hostiteli. Druhý je constrain a ten už můžeme parametrizovat. Dá se například vynutit spuštění na konkrétním nodu, ale to není úplně běžné (ostatně to můžeme rovnou používat Docker bez Swarn, že). Zajímavější je omezit výběr nodu jen na ty vyhovující našim pravidlům. těmi jsou vlastnosti v metadatech, například label. Nodům můžete přiřadit charakteristiky a podle nich pak vybírat. Tak například některé nody označíte za produkční prostředí a jiné za testovací. Současně některé, které využívají SSD disky, označíte za rychlé, jiné za pomalejší. Při spouštění kontejneru tak můžete třeba říct, že má běžet jen na rychlých serverech v produkci, na testovacích bez ohledu na typ disku a tak podobně.
Pojďme si vytvořit nový Swarm cluster a při jeho zakládání necháme Docker Machine vytvořit i příslušné ukazatele, tedy label. V tomto případě na discovery používáme Consul (o tom jak ho získat si povíme příště), ale na tom teď nesejde (klidně to může být Docker Hub jako v minulém díle). Vytvoříme čtyři nody, dvěma dáme label prostredi=prod a dvěma prostredi=test.
docker-machine create -d virtualbox --swarm --swarm-master --swarm-discovery="consul://192.168.99.107:8500" --engine-opt="cluster-store=consul://192.168.99.107:8500" --engine-opt="cluster-advertise=eth1:2376" master docker-machine create -d virtualbox --swarm --swarm-discovery="consul://192.168.99.107:8500" --engine-opt="cluster-store=consul://192.168.99.107:8500" --engine-opt="cluster-advertise=eth1:2376" --engine-label prostredi=prod node1 docker-machine create -d virtualbox --swarm --swarm-discovery="consul://192.168.99.107:8500" --engine-opt="cluster-store=consul://192.168.99.107:8500" --engine-opt="cluster-advertise=eth1:2376" --engine-label prostredi=prod node2 docker-machine create -d virtualbox --swarm --swarm-discovery="consul://192.168.99.107:8500" --engine-opt="cluster-store=consul://192.168.99.107:8500" --engine-opt="cluster-advertise=eth1:2376" --engine-label prostredi=dev node3 docker-machine create -d virtualbox --swarm --swarm-discovery="consul://192.168.99.107:8500" --engine-opt="cluster-store=consul://192.168.99.107:8500" --engine-opt="cluster-advertise=eth1:2376" --engine-label prostredi=dev node4
Tohle je výsledek.
docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS consul - virtualbox Running tcp://192.168.99.107:2376 v1.9.1 master - virtualbox Running tcp://192.168.99.111:2376 master (master) v1.9.1 node1 - virtualbox Running tcp://192.168.99.112:2376 master v1.9.1 node2 - virtualbox Running tcp://192.168.99.115:2376 master v1.9.1 node3 - virtualbox Running tcp://192.168.99.113:2376 master v1.9.1 node4 - virtualbox Running tcp://192.168.99.114:2376 master v1.9.1
Načtěte si proměnné prostředí, abyste komunikovali se Swarm master (viz předchozí díl) a vypište si docker info – metadata jsou tam vidět.
docker info ... Filters: health, port, dependency, affinity, constraint Nodes: 5 master: 192.168.99.111:2376 ... └ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, provider=virtualbox, storagedriver=aufs node1: 192.168.99.112:2376 ... └ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, prostredi=prod, provider=virtualbox, storagedriver=aufs node2: 192.168.99.115:2376 ... └ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, prostredi=prod, provider=virtualbox, storagedriver=aufs ... └ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, prostredi=dev, provider=virtualbox, storagedriver=aufs node4: 192.168.99.114:2376 ... └ Labels: executiondriver=native-0.2, kernelversion=4.1.13-boot2docker, operatingsystem=Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015, prostredi=dev, provider=virtualbox, storagedriver=aufs ...
Spusťte teď pár kontejneru s tím, že mají běžet pouze v dev prostředí.
docker run --name app1 -e constraint:prostredi==dev busybox /bin/echo "Hopla" docker run --name app2 -e constraint:prostredi==dev busybox /bin/echo "Hopla" docker run --name app3 -e constraint:prostredi==dev busybox /bin/echo "Hopla" docker run --name app4 -e constraint:prostredi==dev busybox /bin/echo "Hopla" docker run --name app5 -e constraint:prostredi==dev busybox /bin/echo "Hopla" docker run --name app6 -e constraint:prostredi==dev busybox /bin/echo "Hopla"
Ověřme, že se tak stalo – naše kontejnery by měly běžet jen na nodech 3 a 4.
docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 00eacdeb8aa5 busybox "/bin/echo Hopla" 5 seconds ago Exited (0) 5 seconds ago node4/app6 033a38881723 busybox "/bin/echo Hopla" 7 seconds ago Exited (0) 6 seconds ago node3/app5 70513e5c0f1f busybox "/bin/echo Hopla" 7 seconds ago Exited (0) 7 seconds ago node4/app4 2d828557dfdf busybox "/bin/echo Hopla" 8 seconds ago Exited (0) 8 seconds ago node3/app3 f48cea049c74 busybox "/bin/echo Hopla" 10 seconds ago Exited (0) 9 seconds ago node3/app2 c87d0ed5fea0 busybox "/bin/echo Hopla" 17 seconds ago Exited (0) 16 seconds ago node4/app1 15f0c9578024 swarm:latest "/swarm join --advert" 5 minutes ago Up 5 minutes node2/swarm-agent 77fbeb00bcea swarm:latest "/swarm join --advert" 7 minutes ago Up 7 minutes node4/swarm-agent f512c8f141e5 swarm:latest "/swarm join --advert" 9 minutes ago Up 9 minutes node3/swarm-agent d22223e75e0a swarm:latest "/swarm join --advert" 10 minutes ago Up 10 minutes node1/swarm-agent 2200dbe10630 swarm:latest "/swarm join --advert" 14 minutes ago Up 14 minutes master/swarm-agent 12e6d4f8a940 swarm:latest "/swarm manage --tlsv" 14 minutes ago Up 14 minutes master/swarm-agent-master
Omezení na kontejnery
V základu používá Swarm filtery port a dependency, které hlídají, že spuštění kontejneru dobře dopadne, tedy nevyberou node, který má například obsazen příslušný veřejný port nebo nemá přístup k volume kontejneru apod. My si pohrajeme s filtrem affinity, který nám umožní říct, že některé kontejnery patří k sobě nebo naopak.
Vytvořte kontejner mojeDB a následně mojeAPP a mujWEB s tím, že chceme, aby tyto běželi na stejném nodu (z výkonnostních důvodů). Všimněte si, že neřešíme jaký konkrétní node to je. Jen chceme druhé dva kontejnery mít u toho prvního.
docker run --name mojeDB busybox /bin/echo "Hopla" docker run --name mojeAPP -e affinity:container==mojeDB busybox /bin/echo "Hopla" docker run --name mujWEB -e affinity:container==mojeDB busybox /bin/echo "Hopla"
Ověřte, že to dopadlo dle očekávání.
docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fd6303317b7d busybox "/bin/echo Hopla" 5 seconds ago Exited (0) 3 seconds ago node2/mujWEB 2665e6d2dbdb busybox "/bin/echo Hopla" 6 seconds ago Exited (0) 4 seconds ago node2/mojeAPP c1d228ba237f busybox "/bin/echo Hopla" 7 seconds ago Exited (0) 5 seconds ago node2/mojeDB 15f0c9578024 swarm:latest "/swarm join --advert" 53 minutes ago Up 53 minutes node2/swarm-agent 77fbeb00bcea swarm:latest "/swarm join --advert" 54 minutes ago Up 54 minutes node4/swarm-agent f512c8f141e5 swarm:latest "/swarm join --advert" 56 minutes ago Up 56 minutes node3/swarm-agent d22223e75e0a swarm:latest "/swarm join --advert" 58 minutes ago Up 58 minutes node1/swarm-agent 2200dbe10630 swarm:latest "/swarm join --advert" About an hour ago Up About an hour master/swarm-agent 12e6d4f8a940 swarm:latest "/swarm manage --tlsv" About an hour ago Up About an hour master/swarm-agent-master
Zjemněná pravidla a širší výběr
V pravidlech constrain a affinity nemusíme být tak přísní. Ve výchozím stavu Swarm odmítne kontejner spustit, pokud nevyhoví požadavkům – například přes affinity chceme kontejner na nodu, na kterém už není kapacita. Možná je náš požadavek ale spíše preference, než nutnost. V takovém případě použijte symbol ~, například affinity:container=~mojeDB. Pokud to půjde, Swarn ho dá na stejný node, ale pokud ne, dá ho prostě jinam.
Match může být i složitější, například negovaný. Použití “!=” může být docela užitečné. Například jste spustili kontejner s nějakým cluster masterem (třeba Redis master) a v druhém spoušíte slave – je vhodné, aby rozhodně nebyl na stejném nodu. Nebo chcete z výběru vyřadit jeden konkrétní node – například hostitelský systém je v havarijním stavu, třeba dává předporuchové hlášení selhání paměti a vy ho chcete v dohledné době vypnout a servisovat. Zatím na něm možná chcete nechat něco běžet a postupně to přesouvat, ale nové věci tam už rozhodně nepatří. Další možností je použití RegEx, který vrátí množinu nodů podle řetězcového patternu.