Networking
Subsistemul de networking Docker este de tip pluggable și folosește drivere. Mai multe astfel de drivere există implicit, ele oferind funcționalitate de bază pentru componenta de rețea. Driverul de rețea implicit este bridge, și presupune crearea unui bridge software care permite containerelor conectate la aceeași rețea de acest tip să comunice între ele, oferind totodată izolare față de containerele care nu sunt conectate la această rețea bridge. Driverul de bridge Docker instalează automat reguli pe mașina gazdă astfel încât containerele de pe rețele bridge diferite nu pot comunica direct unele cu altele. Rețelele de tip bridge se aplică doar containerelor care rulează pe aceeași mașină Docker.
Pentru comunicație între containere care rulează pe mașini Docker diferite, se poate gestiona rutarea la nivel de sistem de operare, sau se poate folosi o rețea de tip overlay. Așa cum se va detalia în laboratorul 2, rețelele de tip overlay conectează mai multe mașini Docker și permit serviciilor dintr-un swarm să comunice între ele. Rețelele overlay se mai pot folosi și pentru a facilita comunicația între un serviciu swarm și un container de sine stătător, sau între două containere care rulează pe mașini Docker diferite.
Alte drivere de rețea Docker mai sunt host (pentru containere de sine stătătoare, eliminând izolarea de rețea dintre container și gazda Docker, folosindu-se astfel infrastructura de rețea a gazdei direct), macvlan (permite asignarea de adrese MAC unui container, făcându-l să apară ca un dispozitiv fizic pe rețea), sau none.
Containerele din aceeași rețea pot comunica fără să expună porturi, prin intermediul named DNS. Acest lucru înseamnă că putem să accesam un container nu prin IP, ci prin numele său. Pentru comunicarea cu lumea exterioară (gazda, containere din afara rețelei, etc.) trebuie expuse porturi.
Pentru a demonstra modul în care funcționează rețelele de tip bridge în Docker, întâi vom porni două containere ce vor rula Alpine. În mod implicit, orice container Docker nou-creat se va afla într-o rețea numită „bridge”, așa că, pentru a demonstra faptul că două containere care nu sunt în aceeași rețea nu pot comunica, va trebui întâi să le scoate din acea rețea.
$ docker container run --name c1 -d -it alpine
f5a8653a325e8092151614d5a6a80b04b9410ea8b8a5fcfc4028f1ad33239ad9
$ docker container run --name c2 -d -it alpine
b063ad1ef7bd0ae82a7385582415e78938f7df531cef9eefc33e065af09cf92c
$ docker network disconnect bridge c1
$ docker network disconnect bridge c2
În comanda de docker run de mai sus, parametrul --name îi dă containerului un nume (sau alias) prin care îl putem referi mai ușor.
În acest moment, containerele c1 și c2 nu fac parte din nicio rețea. Mai departe, vom încerca să dăm ping dintr-un container în altul.
$ docker exec -it c1 ash
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # ping c2
ping: bad address 'c2'
/ # exit
Se poate observa mai sus că c1 nu are decât o adresă IP loopback și că nu poate accesa c2. De asemenea, ar fi interesant de menționat faptul că ne-am atașat la container folosind comanda docker exec rulând un shell (ash este shell-ul de pe Alpine).
Pentru a crea o rețea de tip bridge în Docker, putem folosi următoarea comandă:
$ docker network create -d bridge c1-c2-bridge
8644b8accd2a14d10c9911c36635ca6b161449b3aa527db878a727ec1bf980d0
Mai departe, putem vizualiza rețele existente astfel:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
ecd72738aa59 bridge bridge local
8644b8accd2a c1-c2-bridge bridge local
615363cafefa host host local
1e3b8e49b20d none null local
Putem adăuga un container într-o rețea fie atunci când pornim containerul, fie atunci când el deja a fost pornit. Pentru cazul de mai sus, unde c1 și c2 erau deja pornite, le putem adăuga în rețea astfel:
$ docker network connect c1-c2-bridge c1
$ docker network connect c1-c2-bridge c2
Dacă c1 și c2 nu ar fi fost deja pornite, le-am fi putut porni deja atașate la rețeaua c1-c2-bridge astfel:
$ docker container run --name c2 -d -it --network=c1-c2-bridge alpine
67dde5da9b793de63903ac85ff46574da77f0031df9b49acf44d58062687729c
$ docker container run --name c1 -d -it --network=c1-c2-bridge alpine
4de3e000700f81d31e0458dbd034abe90dfce6b1b992d23d760a44f748c0de0d
Putem vedea containerele dintr-o rețea astfel:
$ docker network inspect c1-c2-bridge
[...]
"Containers": {
"b063ad1ef7bd0ae82a7385582415e78938f7df531cef9eefc33e065af09cf92c": {
"Name": "c2",
"EndpointID": "a76463662d110804205e9211537e541eb0de2646fa90e8760d3419a6dc7d32c7",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"f5a8653a325e8092151614d5a6a80b04b9410ea8b8a5fcfc4028f1ad33239ad9": {
"Name": "c1",
"EndpointID": "95d9061b47f73f9b4cc7a82111924804bdc73d0b496549dec834216ee58c64ed",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
}
[...]
În acest moment, cele două containere fac parte din aceeași rețea și pot comunica:
$ docker exec -it c1 ash
/ # ping -c2 c2
PING c2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=6.258 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.109 ms
--- c2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.109/3.183/6.258 ms
/ # exit
$ docker exec -it c2 ash
/ # ping -c2 c1
PING c1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.111 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.268 ms
--- c1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.111/0.189/0.268 ms
/ # exit