Tìm hiểu và làm việc với docker container networks (P2)
Trong bài viết trước chúng ta đã tìm hiểu về các loại networking bên trong Docker native. Ở bài viết này chúng ta tiếp tục đi sâu vào các command của Docker Engine CLI giúp tương tác với Docker networks và containers bên trong chúng. Các command đó là: docker network create docker ...
Trong bài viết trước chúng ta đã tìm hiểu về các loại networking bên trong Docker native. Ở bài viết này chúng ta tiếp tục đi sâu vào các command của Docker Engine CLI giúp tương tác với Docker networks và containers bên trong chúng. Các command đó là:
- docker network create
- docker network connect
- docker network ls
- docker network rm
- docker network disconnect
- docker network inspect
1. Create networks
Docker Engine tự động tạo ra bridge network sau khi nó được cài đặt. Network này tương ứng với docker0 bridge. Hơn nữa, với kiểu network này bạn có thể tự tạo ra bridge network của riêng mình hoặc overlay network.
Một bridge network chứa một single host chạy trên một instance của Docker Engine. Nếu bạn thực thi câu lệnh : docker network create và truyền vào một network name, Nó sẽ tạo ra một bridge network cho bạn.
$ docker network create simple-network 69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a $ docker network inspect simple-network [ { "Name": "simple-network", "Id": "69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a", "Scope": "local", "Driver": "bridge", "IPAM": { "Driver": "default", "Config": [ { "Subnet": "172.22.0.0/16", "Gateway": "172.22.0.1/16" } ] }, "Containers": {}, "Options": {} } ]
2. Connect containers
Chúng ta có thể kết nối động các container tới một hoặc nhiều networks. Các networks có thể cùng giống hoặc khác network drivers. Với mỗi một kết nối, containers có thể giao tiếp với nhau thông qua container’s IP address hoặc container's name.
Với overlay networks hoặc custom plugins hỗ trợ multi-host connectivity, các containers kết nối tới cùng một multi-host network nhưng chạy trên các hosts khác nhau vẫn có thể giao tiếp với nhau qua cách này.
Hãy thử create 2 containers làm ví dụ:
$ docker run -itd --name=container1 busybox 18c062ef45ac0c026ee48a83afa39d25635ee5f02b58de4abc8f467bcaa28731 $ docker run -itd --name=container2 busybox 498eaaaf328e1018042c04b2de04036fc04719a6e39a097a4f4866043a2c2152
Sau đó create một isolated, bridge network để kiểm tra:
$ docker network create -d bridge --subnet 172.25.0.0/16 isolated_nw 06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8
Connect container2 vào network vừa được tạo và inspect network để xác nhận connection:
$ docker network connect isolated_nw container2 $ docker network inspect isolated_nw [ { "Name": "isolated_nw", "Id": "06a62f1c73c4e3107c0f555b7a5f163309827bfbbf999840166065a8f35455a8", "Scope": "local", "Driver": "bridge", "IPAM": { "Driver": "default", "Config": [ { "Subnet": "172.25.0.0/16", "Gateway": "172.25.0.1/16" } ] }, "Containers": { "90e1f3ec71caf82ae776a827e0712a68a110a3f175954e5bd4222fd142ac9428": { "Name": "container2", "EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d", "MacAddress": "02:42:ac:19:00:02", "IPv4Address": "172.25.0.2/16", "IPv6Address": "" } }, "Options": {} } ]
Bạn có thể thấy rằng Engine tự động assigns một IP address vào container2. Cho chúng ta 1 --subnet khi network được tạo, Engine sẽ sinh một address từ subnet này. Ngay bây giờ hãy thử start container3 và connect nó tới network bằng command docker run --network option:
$ docker run --network=isolated_nw --ip=172.25.3.3 -itd --name=container3 busybox 467a7863c3f0277ef8e661b38427737f28099b61fa55622d6c30fb288d88c551
Như bạn đã thấy, chúng ta có thể chỉ định ip address cho container. Có thể lựa chọn giữa IPv4 hoặc IPv6 address(es) cho container khi chạy câu lệnh docker run và docker network connect bằng việc truyền vào --ip và --ip6 flags cho IPv4 và IPv6. Selected IP address trở thành một phần của container networking configuration và sẽ được giữ nguyên ngay cả khi reload container. Tính năng này chỉ có đối với user defined networks, vì chúng đảm bảo subnets configuration không đổi đối với daemon reload.
Nào, hãy cùng inspect network resources được sử dụng bởi container3:
$ docker inspect --format=' container3 {"isolated_nw":{"IPAMConfig":{"IPv4Address":"172.25.3.3"},"NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b", "EndpointID":"dffc7ec2915af58cc827d995e6ebdc897342be0420123277103c40ae35579103","Gateway":"172.25.0.1","IPAddress":"172.25.3.3","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:19:03:03"}}
Lặp lại câu lệnh này cho container2. Nếu máy bạn có cài python, có thể hiển thị đẹp hơn như sau:
$ docker inspect --format=' container2 | python -m json.tool { "bridge": { "NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812", "EndpointID": "0099f9efb5a3727f6a554f176b1e96fca34cae773da68b3b6a26d046c12cb365", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAMConfig": null, "IPAddress": "172.17.0.3", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:03" }, "isolated_nw": { "NetworkID":"1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b", "EndpointID": "11cedac1810e864d6b1589d92da12af66203879ab89f4ccd8c8fdaa9b1c48b1d", "Gateway": "172.25.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAMConfig": null, "IPAddress": "172.25.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:19:00:02" } }
Bạn sẽ thấy rằng container2 thuộc về 2 networks. Bridge network mặc định và isolated_nw.
Với trường hợp của container3, Bạn đã kết nối thông qua docker run tới isolated_nw nên nó ko kết nối tới bridge network mặc định.
Sử dụng câu lệnh docker attach để kết nối tới container2 đang khởi chạy và khám phá networking stack của nó, ta được:
$ docker attach container2
Phân tích network stack của container2, chúng ta sẽ thấy 2 Ethernet interfaces, 1 cho default bridge network và 1 cho isolated_nw network.
/ # ifconfig eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03 inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:648 (648.0 B) TX bytes:648 (648.0 B) eth1 Link encap:Ethernet HWaddr 02:42:AC:15:00:02 inet addr:172.25.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe19:2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:648 (648.0 B) TX bytes:648 (648.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host 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:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Trên isolated_nw, Docker nhúng DNS server để resolve name cho các containers khác cùng mạng. Bên trong container2, ta có thể ping container3 bằng container's name.
/ # ping -w 4 container3 PING container3 (172.25.3.3): 56 data bytes 64 bytes from 172.25.3.3: seq=0 ttl=64 time=0.070 ms 64 bytes from 172.25.3.3: seq=1 ttl=64 time=0.080 ms 64 bytes from 172.25.3.3: seq=2 ttl=64 time=0.080 ms 64 bytes from 172.25.3.3: seq=3 ttl=64 time=0.097 ms --- container3 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.070/0.081/0.097 ms
Nếu bạn muốn, bạn có thể kết nối container1 với container2 bằng câu lệnh docker run --link, khi đó 2 container này có thể giao tiếp với nhau qua tên hoặc địa chỉ IP.
Detach container2 và vẫn để nó chạy bằng cách sử dụng tổ hợp phím CTRL-p CTRL-q.
Trong ví dụ này, container2 được kết nối tới cả 2 networks, do đó nó có thể tương tác với cả container1 và container3. Tuy nhiên, container3 và container1 thì ko cùng nằm trong 1 network và ko thể giao tiếp với nhau được. Để kiểm chức việc này, ta dùng lệnh ping tới contianer1 bên trong container 3:
$ docker attach container3 / # ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2): 56 data bytes ^C --- 172.17.0.2 ping statistics --- 10 packets transmitted, 0 packets received, 100% packet loss
Linking containers in user-defined networks
Trong ví dụ trên, container2 có thể tự động resolve container3’s name trong isolated_nw network, nhưng name resolution lại ko được thực hiện một cách tự động trong default bridge network. Sở dĩ có điều này là để duy trì khả năng tương thích ngược với các legacy link (tồn tại trước đó).
legacy link đưa ra 4 chức năng chính cho default bridge network:
- name resolution
- name alias cho các container đã được liên kết bằng cách sử dụng --link=CONTAINER-NAME:ALIAS
- secured container connectivity (in isolation via --icc=false)
- environment variable injection
So sánh 4 chức năng kể trên với isolated_nw (non-default user-defined networks) trong ví dụ này, docker network cung cấp:
- name resolution tự động bằng DNS
- Tự động cô lập environment của các containers trong một network
- Khả năng attach và detach multiple networks
- Hỗ trợ --link option để cung cấp name alias cho các container đã liên kết
Tiếp tục ví dụ trên, chúng ta sẽ tạo ra container4 trong isolated_nw với option --link tới name resolution sử dụng alias cho các containers khác cùng chung một network.
$ docker run --network=isolated_nw -itd --name=container4 --link container5:c5 busybox 01b5df970834b77a9eadbaff39051f237957bd35c4c56f11193e0594cfd5117c
Nhờ có option --link mà từ giờ container4 có thể kết nối tới container5 với aliased name c5.
Bạn cần lưu ý một điều là khi tạo ra container4, chúng ta đã link tới container5 (thực tế còn chưa được tạo ra). Đây có thể coi là một sự khác biệt với legacy link trong default bridge network.
Bây giờ hãy thử chạy container5 link tới container4 với alias là c4.
$ docker run --network=isolated_nw -itd --name=container5 --link container4:c4 busybox 72eccf2208336f31e9e33ba327734125af00d1e1d2657878e2ee8154fbb23c7a
Đúng như mong đợi, container4 sẽ kết nối được với container5 bằng cả container name và alias c5, ngược lại container5 sẽ kết nối được với container4 bằng cả container name và alias c4:
$ docker attach container4 / # ping -w 4 c5 PING c5 (172.25.0.5): 56 data bytes 64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms 64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms 64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms 64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms --- c5 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.070/0.081/0.097 ms / # ping -w 4 container5 PING container5 (172.25.0.5): 56 data bytes 64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms 64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms 64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms 64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms --- container5 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.070/0.081/0.097 ms
$ docker attach container5 / # ping -w 4 c4 PING c4 (172.25.0.4): 56 data bytes 64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms 64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms 64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms 64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms --- c4 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.065/0.070/0.082 ms / # ping -w 4 container4 PING container4 (172.25.0.4): 56 data bytes 64 bytes from 172.25.0.4: seq=0 ttl=64 time=0.065 ms 64 bytes from 172.25.0.4: seq=1 ttl=64 time=0.070 ms 64 bytes from 172.25.0.4: seq=2 ttl=64 time=0.067 ms 64 bytes from 172.25.0.4: seq=3 ttl=64 time=0.082 ms --- container4 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.065/0.070/0.082 ms
Cũng cần lưu ý một điều rằng nếu một container thuộc về nhiều networks, linked alias sẽ có phạm vi trong mạng đã cho. Do đó, các container có thể liên kết tới các alias khác nhau trên các mạng khác nhau.
Mở rộng ví dụ, chúng ta sẽ tạo 1 network khác có tên là local_alias
$ docker network create -d bridge --subnet 172.26.0.0/24 local_alias 76b7dc932e037589e6553f59f76008e5b76fa069638cd39776b890607f567aaa
Connect container4 và container5 tới mạng network local_alias
$ docker network connect --link container5:foo local_alias container4 $ docker network connect --link container4:bar local_alias container5
$ docker attach container4 / # ping -w 4 foo PING foo (172.26.0.3): 56 data bytes 64 bytes from 172.26.0.3: seq=0 ttl=64 time=0.070 ms 64 bytes from 172.26.0.3: seq=1 ttl=64 time=0.080 ms 64 bytes from 172.26.0.3: seq=2 ttl=64 time=0.080 ms 64 bytes from 172.26.0.3: seq=3 ttl=64 time=0.097 ms --- foo ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.070/0.081/0.097 ms / # ping -w 4 c5 PING c5 (172.25.0.5): 56 data bytes 64 bytes from 172.25.0.5: seq=0 ttl=64 time=0.070 ms 64 bytes from 172.25.0.5: seq=1 ttl=64 time=0.080 ms 64 bytes from 172.25.0.5: seq=2 ttl=64 time=0.080 ms 64 bytes from 172.25.0.5: seq=3 ttl=64 time=0.097 ms --- c5 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.070/0.081/0.097 ms