--- author: Matija Burić --- ### Mrežni i mobilni operacijski sustavi 2025/26 # Docker: Networking i Volumes Ova vježba fokusira se na mrežu točnije docker mrežu te volumene kojima se podaci mogu sačuvati i nakon što kontejner nestane. ## Docker mreže 1. **None** 2. **Bridge** 3. **Host** 4. **Overlay** 5. **Custom** Svaka od ovih Docker mreža ima svoje karakteristike i primjene. - None (bez mreže): - Ova mreža ne dodjeljuje kontejneru nikakvu mrežnu konfiguraciju. Kontejner nema pristup vanjskoj mreži niti drugim kontejnerima. - Ovo je korisno kada želite potpunu izolaciju kontejnera od ostalog svijeta, u svrhu testiranja ili sigurnosti. - Bridge (Izolirana mreža): - Bridge mreža je zadana mreža za kontejnere u Dockeru. Svaki kontejner povezan s ovom mrežom ima svoju unikatnu IP adresu unutar iste podmreže. - Kontejneri koji su članovi Bridge mreže mogu komunicirati međusobno pomoću IP adresa unutar iste podmreže, ali nisu dostupni izvan hosta osim ako nije konfiguriran port forwarding. - Ova mreža je često korištena za postavljanje različitih aplikacija unutar kontejnera na istom hostu. - Host (Djeljena mreža): - U Host mreži, kontejneri dijele mrežnu konfiguraciju s host operativnim sustavom. To znači da kontejneri koriste istu IP adresu kao i host. - Ova mreža omogućava brzu i jednostavnu komunikaciju između kontejnera i hosta, ali kontejneri nisu izolirani i dijele istu mrežu s hostom. - Overlay (Napredna mreža): - Overlay mreža omogućava komunikaciju između kontejnera koji se nalaze na različitim Docker hostovima (na različitim fizičkim računalima ili virtualnim strojevima). - Ova mreža se koristi za stvaranje distribuiranih aplikacija koje se temelje na mikroservisima, gdje različiti dijelovi aplikacije mogu biti raspoređeni na različite hostove. - Custom (Prilagođena mreža): - Custom mreža je mreža koju možete konfigurirati prema vašim potrebama. Možete odabrati podmrežu, postaviti IP adrese, VLAN-ove i druge mrežne parametre. - Ova mreža je korisna kada imate specifične zahtjeve za mrežnu konfiguraciju i želite stvoriti prilagođenu mrežu za svoje kontejnere. u okviru ovih vježbi obraditi ćemo prve tri budući da vježbe radimo na jednome računalu. ```graphviz digraph hierarchy { nodesep=1 node [fontsize=30, style="bold" fontname=arial,shape=box, color=blue, margin=0.2] "Docker Mreže"->{None[color=red] "Single Host" "Multi Host" } "Single Host"->{Bridge[color=red] Host[color=red] } "Multi Host" -> {Overlay } } ``` ### Pregled mreža putem CLI ```shell $ docker network ls NETWORK ID NAME DRIVER SCOPE f78ab30afc13 bridge bridge local bd53266ab167 host host local f6c080d8bffd none null local ``` - detaljan pregled bridge mreže ```shell! $ docker network inspect bridge ... "Name": "bridge", "Id": "f78ab30afc13e0948d1636b8edd1682...c5a77161c5f", "Created": "2023-10-16T08:58:42.456342842Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, ... "IPAM": {"Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" }]}, ... ``` ## Primjer umrežavanja kontejnera - U nastavku će se kroz primjer izvršiti umrežavanje 5 kontejnera: 1. Denholm 2. Jen 3. Roy 4. Moss 5. Richmond Pri čemu će se prvi postaviti u Host mrežu, drugi, treći i četvrti u zasebnu Bridge mrežu a zadnji kontejner u None mrežu. ```graphviz digraph hierarchy { nodesep=1 node [fontsize=20, style="bold" fontname=arial,shape=box, margin=0.2]; { rank=same HostMreza Internet } { rank=same DefaultB ITcrowdBridge NoneMreza } HostMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Host mreža</b></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; DefaultB [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Default Bridge </b></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; NoneMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>None mreža</b></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; Internet [ shape=ellipse label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>INTERNET</b></td></tr> </table>>]; ITcrowdBridge [ style=dotted color=red line=none label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left">* Denholm</td></tr> <tr><td align="left">* Jen</td></tr> <tr><td align="left">* Roy</td></tr> <tr><td align="left">* Moss</td></tr> <tr><td align="left">* Richmond</td></tr> </table>>]; HostMreza -> Internet[arrowhead=none, penwidth=3] HostMreza -> DefaultB[arrowhead=none, penwidth=3] } ``` ### Prvi korak - potrebno je izraditi kontejnere ```shell! $ docker run --name Jen --network bridge -d nginx ``` ili ```shell! $ docker run --name Jen -d nginx ``` - u oba slučaja će kontejner Jen biti spojen u Default Bridge mrežu. - kako bi provjerili je li kontejner spojen koristite slijedeću naredbu: ```shell $ docker network inspect bridge ... "Containers": { "6ce3a047982badd4d6265e2f4a5ef7ac8af5308a...406": { "Name": "Jen", "EndpointID": "2f42e806034fa474321628...9f1710f", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, ... ``` - na isti način spojite i ostale kontejnere. ```shell! $ docker run --name Roy -d nginx $ docker run --name Denholm -d nginx $ docker run --name Richmond -d nginx $ docker run --name Moss -d nginx ``` - te provjerite jesu li spojeni u Default Bridge mrežu ```shell $ docker network inspect bridge |grep 'Name\|IPv4' "Name": "Jen", "IPv4Address": "172.17.0.2/16", "Name": "Moss", "IPv4Address": "172.17.0.6/16", "Name": "Richmond", "IPv4Address": "172.17.0.5/16", "Name": "Denholm", "IPv4Address": "172.17.0.4/16", "Name": "Roy", "IPv4Address": "172.17.0.3/16", ``` ```graphviz digraph hierarchy { nodesep=1 node [fontsize=20, style="bold" fontname=arial,shape=box, margin=0.2]; { rank=same HostMreza Internet } { rank=same DefaultB NoneMreza } HostMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Host mreža</b></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; DefaultB [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Default Bridge </b></td></tr> <tr><td align="left">* Denholm</td></tr> <tr><td align="left">* Jen</td></tr> <tr><td align="left">* Roy</td></tr> <tr><td align="left">* Moss</td></tr> <tr><td align="left">* Richmond</td></tr> </table>>]; NoneMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>None mreža</b></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; Internet [ shape=ellipse label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>INTERNET</b></td></tr> </table>>]; HostMreza -> Internet[arrowhead=none, penwidth=3] HostMreza -> DefaultB[arrowhead=none, penwidth=3] } ``` ### Drugi korak - iz prethodne naredbe mogu se očitati IP adrese pojedinog kontejnera. Kako bi se testirala mreža može se koristiti naredba ping s hosta prema kontejeneru Jen koji ima adresu 172.17.0.2. ```shell $ ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2): 56 data bytes 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.178 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.082 ms ... ``` - radi li ping s kontejnera prema hostu? ```shell $ docker exec -it Jen bash > root@6ce3a047982b:/# ping 172.17.0.1 bash: ping: command not found ``` :::info - budući da nginx image ne sadrži ping alat potrebno ga je instalirati. ```shell > root@6ce3a047982b:/# apt-get update ... > root@6ce3a047982b:/# apt-get install iputils-ping -y ... ``` ::: ```shell > root@6ce3a047982b:/# ping 172.17.0.1 PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data. 64 bytes from 172.17.0.1: icmp_seq=1 ttl=64 time=0.102 ms ... ``` - radi li konekcija prema ostalim kontejnerima? - budući da u sebi imaju integrirani web server za testiranje koristimo naredbu curl koja vraća sadržaj stranice web servera. :::info - **curl** je naredba u Unix-like operativnim sustavima koja se koristi za preuzimanje sadržaja sa web servera putem HTTP, HTTPS, FTP i drugih protokola. Ova naredba omogućuje korisnicima da dobiju podatke s web stranica, web servisa ili drugih udaljenih izvora direktno iz terminala. Primjer upotrebe **curl** naredbe: ```shell $ curl https://www.example.com ``` - Ovom naredbom, **curl** će preuzeti sadržaj web stranice "https://www.example.com" i ispisati ga u terminalu. **curl** podržava mnoge opcije i može se koristiti za slanje HTTP zahtjeva, preuzimanje datoteka, testiranje API-ja i još mnogo toga. To je koristan alat za administratore sustava, programere i sve koji trebaju interagirati s web servisima iz terminala. ::: ```shell! > root@6ce3a047982b:/# curl 172.17.0.3 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ``` - radi li konekcija kada se koristi ime umjesto ip adrese? ```shell $ docker network inspect bridge |grep ... "Name": "Roy", "IPv4Address": "172.17.0.3/16", ... ``` ```shell! > root@6ce3a047982b:/# curl Roy curl: (6) Could not resolve host: Roy ``` :::info - zašto ne radi konekcija imenom nego samo ip adresom? - kako se ne bi smanjila sigurnost kontejnera. ::: - pogledajmo sadržaj hosts i resolv.conf datoteka :::info **/etc/hosts:** - je lokalna tekstualna datoteka na Unix-sličnim operacijskim sustavima koja povezuje imena računala s IP adresama. - Unosi u datoteci /etc/hosts imaju prednost nad DNS-om prilikom rješavanja imena računala, što znači da ako se ime računala nalazi u ovoj datoteci, sustav će koristiti odgovarajuću IP adresu bez traženja vanjskog DNS poslužitelja. **/etc/resolv.conf:** - je konfiguracijska datoteka na Unix-sličnim sustavima koja služi za specificiranje DNS (Domain Name System) informacija, kao što su IP adrese DNS poslužitelja i domene pretrage. Obično je generirana i upravljana alatima za konfiguraciju mreže te može ukazivati na DNS poslužitelje koje pruža vaš Internet pružatelj usluga (ISP) ili druge konfigurirane DNS poslužitelje. ::: ```shell! > root@6ce3a047982b:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 6ce3a047982b ``` - u hosts datoteci se nalazi putanja za localhost i ip6 adrese koje se ne koriste ```shell! > root@6ce3a047982b:/# cat /etc/resolv.conf search 51ur3jppi0eupdptvsj42kdvgc.bx.internal.cloudapp.net options ndots:0 nameserver 8.8.8.8 nameserver 8.8.4.4 ``` - resolv.conf datoteka sadrži DNS za internet adrese ali ne i lokalni DNS. :::info znate li čiji su DNS 8.8.8.8 i 8.8.4.4? ::: ### Treći korak - u ovom koraku će se izgraditi nova Bridge mreža s imenom ITcrowd te će se Jen, Roy i Moss prebaciti u novu mrežu. ```graphviz digraph hierarchy { nodesep=1 node [fontsize=20, style="bold" fontname=arial,shape=box, margin=0.2]; { rank=same HostMreza Internet } { rank=same NoneMreza DefaultB ITcrowdBridge } HostMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Host mreža</b></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; DefaultB [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Default Bridge </b></td></tr> <tr><td align="left">* Denholm</td></tr> <tr><td align="left">* Richmond</td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; NoneMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>None mreža</b></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; Internet [ shape=ellipse label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>INTERNET</b></td></tr> </table>>]; ITcrowdBridge [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>ITcrowd mreža </b></td></tr> <tr><td align="left">* Jen</td></tr> <tr><td align="left">* Roy</td></tr> <tr><td align="left">* Moss</td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; HostMreza -> Internet[arrowhead=none, penwidth=3] HostMreza -> DefaultB[arrowhead=none, penwidth=3] HostMreza -> ITcrowdBridge[arrowhead=none, penwidth=3] } ``` - Prvo je potrebno kreirati mrežu ```shell! $ docker network create ITcrowd ``` - provjerite je li kreirana nova mreža te njen tip ```shell! $ docker network ls NETWORK ID NAME DRIVER SCOPE 1164a74a2db0 ITcrowd bridge local f78ab30afc13 bridge bridge local bd53266ab167 host host local f6c080d8bffd none null local ``` #### kako se spojiti na novu mrežu? - odspojiti se od postojeće mreže pa se spojiti na novu ```shell! $ docker network disconnect bridge Jen $ docker network connect ITcrowd Jen ``` - ili izbrisati kontejner i napraviti novi koji se odmah spaja na mrežu ```shell! $ docker stop Jen $ docker rm Jen $ docker run --name Jen --network ITcrowd -d nginx ``` - provjerimo radi li i dalje veza ip adresom ```shell! > root@dd617949079d:/# curl http://172.17.0.3 ``` Zašto ne radi? Što se promjenilo? ```shell $ docker network inspect ITcrowd |grep 'Name\|IPv4' "Name": "ITcrowd", "Name": "Moss", "IPv4Address": "172.19.0.4/16", "Name": "Jen", "IPv4Address": "172.19.0.2/16", "Name": "Roy", "IPv4Address": "172.19.0.3/16", ``` - primjetite da se podmreža promijenila. pokušajte sa novom ip adresom. ```shell > root@dd617949079d:/# curl 172.19.0.3 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ... ``` - radi li sada korištenjem imena umjesto ip adrese? ```shell $ docker exec -it Jen bash > root@dd617949079d:/# curl Roy <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ... ``` - pogledajmo je li se promijenio DNS u kontejneru. ```shell > root@dd617949079d:/# cat /etc/resolv.conf search 51ur3jppi0eupdptvsj42kdvgc.bx.internal.cloudapp.net nameserver 127.0.0.11 options ndots:0 ``` :::info ## kako se spojiti u kontejner koristeći adresu hosta? - `-p` flag u docker `run naredbi` koristi se za mapiranje portova između host operativnog sustava i kontejnera. To omogućava komunikaciju između hosta i kontejnera preko određenih mrežnih portova. Flag `-p` ima dva argumenta: **<host-port>:<container-port>**. - **<host-port>** predstavlja port na hostu (tj. vašem računalu), dok - **<container-port>** predstavlja port unutar kontejnera. Na taj način možete usmjeriti promet sa specifičnog porta na hostu prema odgovarajućem portu unutar kontejnera. Primjer: ```shell docker run -p 8080:80 my-web-app ``` - U ovom primjeru, my-web-app kontejner će biti pokrenut, a port 80 unutar kontejnera bit će mapiran na port 8080 na hostu. To znači da ako pristupite hostu putem web preglednika na adresi http://localhost:8080, zahtjevi će biti preusmjereni na kontejner na portu 80, gdje se može nalaziti web aplikacija. - Ovaj flag je posebno koristan kada želite hostirati više kontejnera na istom hostu, svaki s različitim web aplikacijama, a da se ne bi sukobljali na istom portu. Mapiranjem portova možete imati više kontejnera koji koriste port 80, svaki sa svojim vlastitim host portom. ::: - pokušajmo sada rekreirati kontejnere koristeći `-p` flag ```shell! $ docker run --name Jen --network ITcrowd -d -p 8080:80 nginx ``` ```shell! $ docker run --name Roy --network ITcrowd -d -p 8081:80 nginx ``` ```shell! $ docker run --name Moss --network ITcrowd -d -p 8082:80 nginx ``` - Kako sada izgledaju kontejneri. obratite pažnju na **<host-port>** ```shell! $ docker ps CONTAINER ID IMAGE ... PORTS NAMES b12e6b635935 nginx ... 80/tcp Richmond 2acfacc0a904 nginx ... 80/tcp Denholm 93a01e571495 nginx ... 0.0.0.0:8082->80/tcp Moss 254b953296af nginx ... 0.0.0.0:8081->80/tcp Roy 820953e87ede nginx ... 0.0.0.0:8080->80/tcp Jen ``` - provjerimo radi li konekcija adrsom hosta i dodjeljnim portom ```shell $ curl 0.0.0.0:8080 <!DOCTYPE html> <html> <head> ... ``` ```shell $ curl 127.0.0.1:8080 <!DOCTYPE html> <html> <head> ... ``` ```shell $ curl localhost:8080 <!DOCTYPE html> <html> <head> ... ``` ### Četvrti korak - na isti način kao i prije možemo odspojiti se s mreže i spojit se na drugu ili rekreirati novi kontejner dirketno u mrežu. ```shell $ docker network disconnect bridge Richmond $ docker network connect none Richmond ``` ```shell! $ docker stop Denholm $ docker rm Denholm $ docker run --name Denholm --network host -d nginx ``` ```graphviz digraph hierarchy { nodesep=1 node [fontsize=20, style="bold" fontname=arial,shape=box, margin=0.2]; { rank=same HostMreza Internet } { rank=same NoneMreza DefaultB ITcrowdBridge } HostMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Host mreža</b></td></tr> <tr><td align="left">* Denholm</td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; DefaultB [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>Default Bridge </b></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; NoneMreza [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>None mreža</b></td></tr> <tr><td align="left">* Richmond</td></tr> </table>>]; Internet [ shape=ellipse label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>INTERNET</b></td></tr> </table>>]; ITcrowdBridge [ label=< <table border="0" cellborder="0" cellspacing="1"> <tr><td align="left"><b>ITcrowd mreža </b></td></tr> <tr><td align="left">* Jen</td></tr> <tr><td align="left">* Roy</td></tr> <tr><td align="left">* Moss</td></tr> <tr><td align="left"><br></br></td></tr> <tr><td align="left"><br></br></td></tr> </table>>]; HostMreza -> Internet[arrowhead=none, penwidth=3] HostMreza -> DefaultB[arrowhead=none, penwidth=3] HostMreza -> ITcrowdBridge[arrowhead=none, penwidth=3] } ``` - provjerimo radi li konekcija korištenjem host mreže - promijenimo sadržaj index.html dokumneta da vrati sadržaj koji nam odgovara ```shell! $ docker exec -it Denholm bash > cd /usr/share/nginx/html > echo "ovo je Denholm kojeg zovem sa hosta" > index.html > exit $ curl localhost ovo je Denholm kojeg zovem sa hosta ``` :::info - navedena linija `> echo "ovo je Denholm kojeg zovem sa hosta" > index.html` ispisuje poruku korištenjem echo naredbe i preusmjerava ju u dokumnet index.html pri čemu prepisuje sadržaj datoteke. ::: - koju ip adresu imaju kontejeneri ```shell! $ docker inspect Jen |grep "IPAddress" "IPAddress": "", "IPAddress": "172.19.0.2", $ docker inspect Denholm |grep "IPAddress" "IPAddress": "", "IPAddress": "", $ docker inspect Richmond |grep "IPAddress" "IPAddress": "", "IPAddress": "", ``` - pogledajmo kojoj mreži pripadaju kontejneri ```shell! $ docker inspect Jen |grep -A 1 "Networks" "Networks": { "ITcrowd": { $ docker inspect Denholm |grep -A 1 "Networks" "Networks": { "host": { $ docker inspect Richmond |grep -A 1 "Networks" "Networks": { "none": { ``` #### Peti korak - pogledajmo `ip addr` i `ifconfig` hosta - prije ```shell $ ip addr |grep inet inet 127.0.0.1/8 scope host lo inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 inet 192.168.0.28/23 scope global eth0 inet 172.18.0.57/16 scope global eth1 ``` ```shell! $ ifconfig |grep Link docker0 Link encap:Ethernet HWaddr 02:42:7D:41:BE:C8 eth0 Link encap:Ethernet HWaddr A6:A4:92:00:88:95 eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:39 lo Link encap:Local Loopback ``` - sada ```shell! $ ip addr |grep inet inet 127.0.0.1/8 scope host lo inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 inet 172.19.0.1/16 brd 172.19.255.255 scope global br-41b87dedcddf inet 192.168.0.28/23 scope global eth0 inet 172.18.0.57/16 scope global eth1 ``` ```shell! $ ifconfig |grep Link br-41b87dedcddf Link encap:Ethernet HWaddr 02:42:4E:4C:33:62 docker0 Link encap:Ethernet HWaddr 02:42:7D:41:BE:C8 eth0 Link encap:Ethernet HWaddr A6:A4:92:00:88:95 eth1 Link encap:Ethernet HWaddr 02:42:AC:12:00:39 lo Link encap:Local Loopback veth984bbb6 Link encap:Ethernet HWaddr 62:DD:61:BE:25:B4 vethcd178c6 Link encap:Ethernet HWaddr 22:F0:17:79:FA:89 vetheed5061 Link encap:Ethernet HWaddr 6A:9D:85:3B:84:B7 ``` - možete li zaključiti koji su novi mrežni interface-i i na što su povezani. :::info - novonastala ITcrowd mreža je br-41b87dedcddf, a veth* sučelja su sučelja Jen, Roy i Moss kontejenra koji imaju svoje adrese. ::: ## Što su Docker volumes? - Svrha korištenja Docker volumes je pohraniti podatke izvan kontejnera kako bi se mogli sigurnosno kopirati ili dijeliti. - Docker volumes su ovisni o Docker file sustavu i predstavljaju poželjni način pohrane podataka za Docker kontejnere i servise. Kada se kontejner pokrene, Docker učitava sloj samo za čitanje slike, dodaje sloj za čitanje i pisanje na vrh slike i montira volumes na file sustav kontejnera. ## Zašto koristiti Docker Volumene? - Ako koristite Docker za razvoj, morate biti upoznati s opcijom `-v` ili `--volume` koja omogućuje da montirate svoje lokalne datoteke u kontejner. Na primjer, možete montirati svoj lokalni direktorij ` ./target` na direktorij `/usr/share/nginx/html` u kontejneru ili u kontejneru s nginxom kako biste vizualizirali svoje HTML datoteke. ```shell! $ echo "<h1>Hello from Host</h1>" > ./target/index.html $ docker run -it --rm --name nginx -p 8080:80 -v "$(pwd)"/target:/usr/share/nginx/html nginx ``` - sada otvorite poveznicu `http://localhost:8080/` i trebali bi vidjeti sadržaj vašeg prvog volume-a. - Ovo se naziva bind mount i često se koristi od strane programera. Međutim, ako koristite Docker Desktop na sustavima Windows ili MacOS, bind mountovi imaju značajne probleme s performansama. Kao rezultat toga, upotreba volumena može biti najbolja alternativa za očuvanje stanja između pokretanja kontejnera. - Za razliku od bind mountova, gdje možete montirati bilo koji direktorij s vašeg domaćina, volumeni se pohranjuju na jednom mjestu (vjerojatno /var/lib/docker/volumes/ na Unix sustavima) i značajno olakšavaju upravljanje podacima (sigurnosno kopiranje, vraćanje i migracija). Docker volumeni se mogu sigurno dijeliti između nekoliko pokrenutih kontejnera. ## Stvaranje i Upravljanje Docker Volumenima - U ovoj dijelu vježbi, naučit ćete kako implicitno i eksplicitno stvoriti Docker volumen te ga zatim deklarirati iz Docker datoteke. Zatim ćete naučiti kako pregledati data volumen i montirati ga na kontejner. ### Implicitno Stvaranje Docker Volumena - Najjednostavniji način za stvaranje i upotrebu volumena je korištenje docker run naredbe i zastavice `-v` ili `--volume`. Ova zastava prima tri argumenta odvojena znakom `:`. ```shell! -v <source>:<destination>:<options> ``` - Ako je "source" putanja koja je korištena u prethodnom primjeru, Docker će koristiti volume binding. Ako je "source" ime, tada Docker pokušava pronaći taj volumen ili ga stvara ako nije pronađen. Niže je prikazan ažurirani prethodni primjer koji koristi volumen umjesto vezivanja za montiranje: ```shell! $ docker run -it --rm --name nginx -p 8080:80 -v moj-volume:/usr/share/nginx/html nginx ``` - Možete provjeriti je li spremnik pravilno stvoren koristeći `$docker volume ls` koji će izlistati sve postojeće volumene. ```shell $ docker volume ls DRIVER VOLUME NAME local moj-volume ``` - Možete provjeriti status vaših volumena na Linuxu. To vam omogućava da vidite gdje se volumeni nalaze: ```shell $ ls /var/lib/docker/volumes/moj-volume/_data 50x.html index.html ``` - Na Mac i Windows OS-ima je malo složenije. Kako biste stvari pojednostavili, možete montirati volumen na kontejner s Ubuntu i koristiti naredbu "ls" kako biste vidjeli sadržaj svog volumena: ```shell $ docker run -it --rm -v moj-volume:/opt/moj-volume ubuntu ls /opt/moj-volume 50x.html index.html ``` ### Stvorite Docker volumen eksplicitno - Alternativno, možete koristiti naredbu "docker volume create" kako biste eksplicitno stvorili podatkovni volumen. Ova naredba omogućava vam da odaberete i konfigurirate vozača za volumen. Implicitno stvaranje volumena uvijek koristi lokalnog vozača s zadanim postavkama. ```shell $ docker volume create --name moj-2volume ``` ### Deklarirajte Docker volumen iz Dockerfile-a - Volumeni se mogu deklarirati u vašem Dockerfile-u koristeći `VOLUME` naredbu. Ova naredba deklarira da određeni put kontejnera mora biti montiran na Docker volumen. Kada pokrenete kontejner, Docker će stvoriti anonimni volumen (volumen s jedinstvenim ID-em kao imenom) i montirati ga na određeni put. ```dockerfile FROM nginx:latest RUN echo "<h1>Pozdrav od tvog volume-a</h1>" > /usr/share/nginx/html/index.html VOLUME /usr/share/nginx/html ``` - Izgradimo i pokrenimo vašu novu sliku: ```shell $ docker build -t moj-volume-image . $ docker run -p 8081:80 moj-volume-image ``` - Sada možete provjeriti da nginx prikazuje vašu poruku na [http://localhost:8081/](http://localhost:8081/). - Važnije, stvoren je anonimni Docker volumen, i svaki put kad pokrenete novi kontejner, stvori se još jedan volumen s sadržajem `/usr/share/nginx/html`. ### pregled Volume-a - Da biste upravljali svojim podacima, ponekad trebate izlistati podatkovne volume s naredbenog retka kao referencu, što je brže od ponovnog provjeravanja konfiguracijskih datoteka. Možete koristiti naredbu `docker volume ls` za pregled popisa podatkovnih volumena. ```shell $ docker volume ls DRIVER VOLUME NAME local fb77b01385aa706f1764bd9f4cc3317815b6de5ac942f7cb49d4ca5666459401 local moj-volume ``` - detaljnini pregled: ```shell $ docker volume inspect moj-volume [ { "CreatedAt": "2023-10-30T19:37:03Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/moj-volume/_data", "Name": "moj-volume", "Options": null, "Scope": "local" } ] ``` ### Dodjeljivanje Volume kontejneru - Kao što ste vidjeli kroz različite primjere, `-v` i `--volume` su najčešći način za montiranje volumena na kontejner koristeći sintaksu: ```shell -v <name>:<destination>:<options> ``` - Jedna značajna opcija je `ro`, što znači da će volumen biti montiran samo za čitanje: ```shell $ docker run -it -v moj-3volume:/data:ro ubuntu ``` - Pokušajte zapisati u folder/data kako biste provjerili je li volumen u načinu samo za čitanje: ```shell echo "test" > /data/test ``` - Alternativa za `-v` je dodati opciju `--mount` naredbi docker run. `--mount` je detaljnija verzija `-v`. - Za pokretanje kontejnera i montiranje podatkovnog volumena, slijedite ovu sintaksu: ```shell docker run --mount source=[volume_name],destination=[path_in_container] [docker_image] ``` - npr. ```shell $ docker run --rm -it --mount source=moj-4volume,destination=/tu-je-volume ubuntu ``` - Sjetite se, ako volumen ne postoji, Docker će ga automatski stvoriti za vas. - Ispisujte sadržaj kontejnera kako biste provjerili je li volumen uspješno pričvršćen. Trebali biste pronaći naziv Docker volumena definiran u prethodnom sintaksnom podacima. ```shell $ docker run --rm -it --mount source=moj-4volume,destination=/tu-je-volume ubuntu root@f29ed57bc271:/# ls bin dev home lib32 libx32 mnt proc run srv tmp usr boot etc lib lib64 media opt root sbin sys tu-je-volume var ``` ### Kopiranje podatake između kontejnera - Pogledajmo kako Docker volumeni omogućavaju dijeljenje datoteka između kontejnera. - U ovom primjeru koristit ćemo prethodno definirani volumen i kontejner te izvršiti sljedeće naredbe: ```shell $ docker run -it --name=v_kon_1 --mount source=moj-5volume,destination=/data ubuntu root@f30f5b8dedef:/# touch /data/ovo_je_dokument_u_volume root@f30f5b8dedef:/# exit $ docker run -it --name=v_kon_2 --mount source=moj-5volume,destination=/data ubuntu root@8bbf9c809e41:/# ls /data ovo_je_dokument_u_volume ```