Tìm hiểu và làm việc với docker container networks (P2)
Bài đăng này đã không được cập nhật trong 3 năm
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
3. Tài liệu tham khảo
All rights reserved