Tìm hiểu và làm việc với docker container networks (P2)

docker_commands.png

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 rundocker 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.

working.png

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