Docker Volume

és a buktatói:)

Alapvetően csak egy rövid írás akar lenni, de aki nincs képben, egy kis áttekintő:

# Áttekintő / bevezető
A docker, egy konténer, amibe szerveralkalmazásokat lehet csomagolni,
és pakolgatni egyik szerverről a másikra (ajánlás az egy program / egy konténer).

# Probléma leírása

Az alkalmazáshoz szükséges fájlokat mind tartalmazza a konténer.
De előbb-utóbb eljut az ember, oda, hogy kívülről akar fájlokat láthatóvá tenni a konténeren belül.

A legegyszerűbb példa,
hogy van egy program amit 4-5 különböző konfigurációs fájlokkal akar elindítani az ember.
Két lehetőség van, vagy készít az ember 4-5 konténer image-t, amiben már benne vannak a módosított konfigurációs fájlok.
Vagy pedig a konfigurációs fájlokat a konténeren kívülről veszi, és akkor elég
egy konténer imaget elkészíteni, a többit docker volume-mal oldjuk meg.

# A docker volume-ról

A docker volume, lényegében olyan, mint a linux alatt a mount parancs.
Külső meghajtót lehet a konténer alá becsatolni.

Pár hivatkozás:
https://docs.docker.com/engine/tutorials/dockervolumes/
http://container-solutions.com/understanding-volumes-docker/

Ezek a lehetőségek:

## Dockerfile-ban adjuk meg a volume-ot (könyvtárat)

FROM phusion/baseimage:0.9.18
VOLUME /data

Ezzel az a probléma, hogy a könyvtár helye random:
/var/lib/docker/volumes/fac362...80535/...

Ezt én nem szoktam használni.
Ez ugyanaz, mintha indításnál nem adnánk meg forrást a mountoláshoz:
-v /data

Dockerfile-ban nem adhatunk meg forráskönyvtárat,
mert onnantól nem hordozható a Dockerfile
(nem lehet elvárni, hogy ugyanaz a forráskönyvtár meglesz egy másik hoszt gépen is).

## docker indításnál könyvtárat mountolunk

Igazából ez a járható út:
-v /home/joarc/data/awesomeness_v2/usr/local/awe/config/:/usr/local/awe/config

Ez egy komplett könyvtárat bemountol a konténer alá

## docker indításnál fájlokat mountolgatunk

-v /home/joarc/data/awesomeness_v2/usr/local/awe/config/plugin:/usr/local/awe/config/plugin \
-v /home/joarc/data/awesomeness_v2/usr/local/awe/config/settings.ini:/usr/local/awe/config/settings.ini \
-v /home/joarc/data/awesomeness_v2/usr/local/awe/config/tls.ini:/usr/local/awe/config/tls.ini

Ez egy nagyon rossz ötlet, igazából emiatt írom a blogpostot. Alább kifejtem jobban.

## egy másik docker konténerből mountolunk fájlt

Ez hívják data volume-nak. Erre való a --volumes-from [konténernév] parancssor.

## valamilyen volume driver használata

Ez a flocker (-d flocker), és itt lehet amazon (aws), openstack, vagy valami kellően bonyolult:)

# Probléma

És akkor a probléma:) A volume-oknál mind a könyvtárakat, mind a fájlokat inode alapján figyeli docker. És elő tud fordulni, hogy a módosítások nem jutnak be a konténerbe.

Az alapvető usecase az lett volna, hogy van egy könyvtár tele konfigurációs fájlokkal (/usr/local/awe/config/*), amiből csak néhányat módosítanék egy egy konténerhez.

Ha a könyvtárat mountolom:
-v /home/joarc/awe/usr/local/awe/config:/usr/local/awe/config
Akkor az eredeti (konténeren belüli) könyvtárat elrejti a hosztgépen lévő könyvtárral. Így csak az a pár konfigurációs fájl látszik, ami a hoszt gépen van.

Ha a módosított fájlokat mountolom egyesével:
Amint inode csere van, onnantól kezdve a kontéren belül a régi változat látszik.

Néhány inode változást kiváltó eset:
vi fájl, majd :wq
A vi előbb egy átmeneti fájlba ment, majd ezzel felülírja (átnevezi) az eredeti fájlt.
És tádá a fájlnak új inode-ja lett.

Azaz:
echo "uj tartalom" > valami2.txt
mv valami2.txt valami.txt

És innentől kezdve a valami.txt-nek új inode-ja lett.
Persze ez a helyes mentés is, mert így "atomic".
Csak ez a docker opció jelen formájában hasznavehetetlen.

A könyvtárak mountolásánál (-v /source/dir:/dest/dir) is vigyázni kell ugyanerre, tehát hogy új inodeja lesz, csak sokkal ritkább esetben fordul elő.

Azért egy példa (proba <-> proba2 könyvtárakat megcserélem):
mkdir /home/joarc/data/proba
echo "valami legyen benne" > /home/joarc/data/proba/valami.txt
docker run .... -v /home/joarc/data/proba:/proba
mkdir /home/joarc/data/proba2
mv /home/joarc/data/proba/* /home/joarc/data/proba2
mv proba proba-back
mv proba2 proba
mv proba-back proba2

Ismerni kell a docker volume limitációt. És akkor még elő se hoztam, hogy virtualbox/vmware-en belül az inode változás nem is megy át a hoszt és a docker kontéren belül:)

Az én esetemben a megoldás az, hogy a kontéren belül a könyvtárat kimentem a hoszt gépre és módosítom azt a párat amit akarok, majd a komplett könyvtárat mountolom a docker konténer alá.

Hátha másnak is tanulságos. Nekem egy röpke két napba tellett, mire leesett, hogy ez a baja.

Hozzászólások

subscribe

alias killall='echo "Wenn ist das Nunstück git und Slotermeyer? Ja. Beiherhund das Oder die Flipperwaldt gersput." | espeak -vde' #That's not funny.

A legegyszerűbb példa, hogy van egy program amit 4-5 különböző konfigurációs fájlokkal akar elindítani az ember.

ez egyaltalan nem a legegyszerubb use-case. Mondjuk ennyi info alapjan nem lehet eldonteni, hogy jobb 4-5 image, amibe bele vannak sutve a konfigok, vagy inkabb 30 konfig file-t adj at cli-bol a kontenernek. A best practice inkabb afele megy el, hogy - ha lehetseges, akkor - legyen az image-be sutve a szukseges konfig.

Mondjuk szerintem eleve inkabb a --env vagy --env-file lenne celszerubb runtime parameterek atpasszolasara a kontenernek.

Mivel a program livereloadingot tud, hogyha egy konfigfajlja megvaltozik, igy a fenti a tuti.

ENV-vel se elegansan ennyi konfigot atadni.
Az en esetemben ez 13 konfigfajlt jelent (300 sor) osszesen, amibol 5 valtozik konterek kozott.

Raadasul egy futo docker kontenerben nem lehet a kornyezeti valtozokat frissiteni.

---
Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

Csak az a baj, hogy a konténerezéshez passzoló konfig kezelési alternatívák eléggé nehézsúlyúak.

Először is, azt nagyon erősen antipattern-nek tartom, hogy a konfigonként külön image-et csináljon az ember. Még akkor is, ha a docker az image layer-ekkel elég takarékosan meg tudja oldani. Az image-eket nemcsak egyszer kell legyártani, hanem van karbantartási költségük is, sőt hosszabb távon ez lesz a domináns munka. Gondolj arra, ha kiderül, hogy pl security hiba miatt valamelyik random libet frissíteni kell az összes image-ben. Az image az maradjon csak meg 'template'-nek, amiből tetszőlegesen sok service instance-ot lehet indítani eltérő konfiggal.

Erre azt szokták csinálni, hogy valami etcd vagy consul vagy hasonló elosztott konfig key-value store-t üzemeltetnek legalább egy példányban a hoston (nyilván ezek inkább több node-os kubernetes vagy docker swarm clusterre vannak kitalálva), a konténeren belüli alkalmazás pedig ebből veszi ki a zoxigé... neki szóló paramétereket. A meglevő alkalmazások többségében nincs etcd vagy consul kliens (egyébként is szerintem rossz ötlet lenne mindenben függőséget kiépíteni ezekre), ezért vannak olyan toolok, mint confd, ami legenerál egy-egy konfigfile-t, és feliratkozik a változásokra a key-value store-ban, változtatás esetén újragenerálja. Így a konfigfile a teljes életét a konténeren belül éli le, nem kell volume-ozni. Ha inotify-os konfig reload van az alkalmazásban, akkor valószínűleg ez a legkulturáltabb megoldás. Csak igényel pár dedikált service-t és elég munkás megcsinálni a teljes konfig automatizálást.
---
Régóta vágyok én, az androidok mezonkincsére már!

"hanem van karbantartási költségük is, sőt hosszabb távon ez lesz a domináns munka." vs. "Csak igényel pár dedikált service-t és elég munkás megcsinálni a teljes konfig automatizálást."

ha az image build automatikusan (esetleg max. 1 parancs hatasara) tortenik, akkor megfrissited mondjuk az ubuntu base-t (vagy amire epul az egesz), aztan build, es kesz vagyunk. En nem latom ebben azt a hudenagy dominans munkat.

A confd, etcd, etc. is mukodhet, de ahogy irtad, azert munkas a dolog, es komplikaltabb az eredmeny. Nehez a konkret eset ismerete nelkul eldonteni, melyikkel jarunk jobban...

En nem gondolom, hogy tul esszeru 2-3-400MB-os kontereket toltogetni fel nehany konfiguracios fajl megvaltozasa miatt.

De az teny, hogy a fejlesztoi gepen gyorsan elkeszul, mivel csak nehany fajlban kulonbozik.

---
Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

ugyesen megvalaszoltad a sajat dilemmadat. Nem tudom, hogy 56k-s modemekkel van-e osszerakva a belso halotok, ahol a szerverben egy 850 MB-os Caviar hdd figyel, mert ha nem, akkor 5 x 400 MB-nak nem kene akkor szelhudest okoznia. De mondom, szerintem eleve ott a gond, ahogyan te kontenerezel...

Szerintem nem mondtam ellent magamnak. Egyik út sem lesz egyszerű és kevés munka. Csak az egyik esetben a költség nem az elején jelentkezik, hanem később fog megugrani, a másiknál az elején egy viszonylag nagyobb tervezési effort megy a központi konfig management kitalálására és bevezetésére, de később nyersz vele.

A dockerfile-ok elhitetik veled, hogy az image buildelés egy elhanyagolható költségű valami, ezért nem kell optimalizálnod az image-ek számát. Viszont, ha a konfig az image-ekbe belekerül, akkor az image variációk számában egyel több dimenziót vezettél be -> ordo-ban növelted a költséget. Az image build automatizálás viszont csak konstans szorzót javít. Szerintem ebből már érthető, hogy hosszú távon nagyon megbosszulja magát. És nem, a gyakorlatban a legritkább esetben működik az, hogy "majd áttérünk rá, ha nagyobbra növünk", mert az image-be égetett konfigoktól megszabadulás költsége is növekszik az image-ek számával. Ha az elején nem a hosszútávon jó irányba indultál, akkor idővel csak egyre messzebb kerülsz tőle.
---
Régóta vágyok én, az androidok mezonkincsére már!

nekem 13 szerverem van es 42 kontenerem.
A kontenert valahogy a fejlesztoi geptol el kell juttatni a szerverre.

A dockerezes azt is jelenti, hogy napi 2-3 valtozatot nyugodtan kitehetsz.

Es igen, ezeket mobilnet mogul tolom. Havi fogyasztasom 30-50GB kozott van.

---
Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

lehet egy mini build rendszer a fejlesztok gepen is, de az megint buko, hogy a sajat gepedeb elkeszited az image-et, amit mobilneten tolsz fel a szerverre. Ahelyett, hogy az egesz build a szerveren (vagy mellette egy build gepen) tortenne. Szoval meg mindig azt mondom, lehetne ezt jobban is csinalni...

Ez egy nagyon rossz irany mar mint ,hogy Te a fejlesztoi gepedrol juttatod el a kontenert a clusterbe erre ott a CI meg a deployment. Nalunk pl. Continous Deployment van es a CI buildeli magat a docker imaget. De mi elott ez megtortenne ugy-e futtatjuk a unit,e2e,integration teszteket es csak utana van buildelve es deployolva.

Mi egyaltalan nem hasznalunk semmien volumeot tul sok vele a macera es felesleges. Pl. nekunk az nginx/elasticsearch deploy is ugyan azon a folyamaton megy keresztul mint az alkalmazasok.

Nekunk 400-600 kontenerunk van terhelestol fuggoen. Van 50+ fajta szervizunk. Jah es Kubernetest hasznalunk.

--
"ssh in a for loop is not a solution" – Luke Kanies, Puppet developer

Bocs az egyenes szoert, de hulye vagy. Van harom kazal CI megoldas, ami szives-oromest buildelne helyetted (akar gombnyomasra is) a docker image-t es juttatna el a szerverre a fejlesztoi gep erintese nelkul. Es egy CI szervert fenntartani nem annyira koltseges, abbol a mobilnet fogyasztasbol, ami neked most van, siman 2-3 gep uzemeltetese is kijonne. Es lehet, hogy ez neked ingyen van (ertsd: nem a te fizetesedbol vonjak le), de ezert valaki valahol fizet.
--
Blog | @hron84
Üzemeltető macik

az en mobilnetem korlatlan. Pont ugyanannyit fizetek, hogyha 0kB-ot hasznalok, mintha 80GB-ot.

Ettol fuggetlenul lehetne CI szerverem is, ha egyszer eljutok oda, beallitok egyet. Eddig meg idom nem volt, hogy E2E teszteket irjak, igy a CI is elmaradt.

A mostani workflow kelloen gyors ahhoz, hogy a fentiekre ne szanjam ra magam.

A dicsero szot kulon koszonom. Valoszinu, a sorozat tovabbi reszeit megtartom magamnak (docker swarm vs. volume lett volna, de gondolom itt mar mindenki ismeri a bugokat), ha mar ilyen kedves a fogadtatas.

---
Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

Most mondok egy durvat: a CI szerver letet nem feltetlen kell ahhoz kotni, hogy vannak vagy nincsenek tesztek a Docker image-ra. Vegulis az, hogy megepul az image, az eleve egy teszt, a Dockerfile tesztje. :-) De a lenyeg: Ha a szandek megvan, akkor kb. mindegy, milyen sorrendben vezeted be a dolgot, a lenyeg, hogy ne a te gepedet terheld feleslegesen az epitesekkel.
--
Blog | @hron84
Üzemeltető macik

Mindez a legtobb esetben baromira nem szamit, mert a dockerben futtatott alkalmazas ujrainditasa (hogy fel is olvassa az uj/megvaltozott konfig fajlokat) altalaban amugy is a regi kontener lelovese utan egy uj kontener inditasaval tortenik meg, amikor is baromira mindegy, hogy a regi kontenerben konkretan milyen fajlvaltozasok latszodtak.

Ami necci lehet inkabb, az mondjuk egy apache alatti weboldal deploymentje, ha mondjuk ugy szervezed a dolgokat,hogy az apache van egy kontenerben, es a data volume-n levo weboldalt szolgalja ki. Lehet, hogy elsore furcsan hangzik, de nem feltetlen igy a legjobb szervezni a dolgokat, erdemes inkabb a kontener deploymentjet a weboldaleval osszekotni, es a weboldalt beleegetni az image-ba. Igen, ezzel elvesz az a nagyon szep (haha) lehetoseg, hogy on the fly fixaljuk meg az elcsuszott HTML kodot az oldalon, de hat azert egyebkent is kezletores jar jobb helyeken.

Es dockernel majdnem mindig kotelezo valami proxyt futtatni elotetnek, es egy image-bol 2-3 kontenert is nyomatni, hogy ha az egyik kiesik (pl ujrakrealas miatt), a masik meg mindig kiszolgaljon.

Sajnos a Docker gyokeresen mas gondolkodasmodot igenyel, mintha lenne egy kalap szolgaltatas felszorva egy gepre. Ez persze reszben nyilvan a technologia korlatja is, jobb lenne, ha ezeket a dolgokat a Docker normalisan (kinda) kezelne, de addig is egyutt kell ezekkel a korlatokkal elni.
--
Blog | @hron84
Üzemeltető macik