This page looks best with JavaScript enabled

Tìm hiểu và sử dụng docker (P3)

 ·  ☕ 13 min read  ·  🐉 Edisc
Toàn bộ series này được tham khảo từ hai nguồn chính: XuanThuLabChanelDockerDoc. Em xin chân thành cảm ơn sự cống hiến của các tác giả của những kênh nói trên.❤️❤️❤️

Giới thiệu về Image Busybox

Busybox là một image rất nhỏ gọn nhưng chứa rất nhiều công cụ dựa trên nền tảng linux.
Tải image busybox:

1
2
3
4
5
6
❯ docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
b71f96345d44: Pull complete 
Digest: sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d
Status: Downloaded newer image for busybox:latest

Tạo một container chạy image busybox

1
2
❯ docker run -it --rm busybox
/ # 

Option --rm dùng cho những container muốn chạy một lần, sau khi chạy xong docker sẽ tự động xóa container đó đi.
Container của image busybox có rất nhiều lệnh, để liệt kê các lệnh, ta dùng:

1
2
3
4
5
6
7
/ # ls /bin/ -la 
total 449700
drwxr-xr-x    2 root     root         12288 Jun  7 17:34 .
drwxr-xr-x    1 root     root          4096 Jun  9 16:00 ..
-rwxr-xr-x  400 root     root       1149184 Jun  7 17:34 [
-rwxr-xr-x  400 root     root       1149184 Jun  7 17:34 [[
-rwxr-xr-x  400 root     root       1149184 Jun  7 17:34 acpid

Giới thiệu mạng, network trong docker, mạng bridge

Liệt kê các mạng có trong docker.

Kiểm tra trong docker có những mạng nào, ta dùng lệnh:

1
2
3
4
5
❯ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
e0b165102300        bridge              bridge              local
0f2ab02aa9f4        host                host                local
271997adaaa9        none                null                local

Ở đây chúng ta có 3 network được tạo mặc định khi docker tạo, bao gồm: bridge dùng DRIVER bridge, host dùng DRIVE host và none dùng DRIVE null.

Kiểm tra thông tin network

Để kiểm tra thông tin về một network cũng như những container nào kết nối vào, ta dùng lệnh:
docker network inspect <NAME>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
❯ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "e0b1651023003b4e6235e7b45319daa20d80a247d66e0b303eaf5e53fb90f0f8",
        "Created": "2021-06-09T20:59:15.89942017+07:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

Ở đây chúng ta chú ý, trường Container rỗng, có nghĩa là không có container nào kết nối vào.

Mạng bridge.

Ta tiến hành tạo một container B1 và kiêm tra lại mạng bridge.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
❯ docker run -it --name B1 busybox
/ # %                                                                           ❯ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
2f6dd1dda04d        busybox             "sh"                9 seconds ago       Up 8 seconds                            B1

❯ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "e0b1651023003b4e6235e7b45319daa20d80a247d66e0b303eaf5e53fb90f0f8",
        "Created": "2021-06-09T20:59:15.89942017+07:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2f6dd1dda04d0ab42434a6cff6f9c7eb42474f81acdf32809486f8fa82be8951": {
                "Name": "B1",
                "EndpointID": "0af6a3739786e89d5161f25edf7bb2a5d900ab580ab53e8f852a197134e010b7",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

Xem lại trường container thì đã thấy có thêm một container có tên là B1 đang chạy. Ngoài ra chúng ta còn có thể kiếm tra container đang dùng mạng nào và được cấp địa chỉ IP bằng bao nhiêu thông qua lệnh docker inspect <container_name>
Tạo ra thêm 1 container tên B2, khi đó container B1, B2 có thể nhìn thấy nhau, chúng ta có thể kiểm tra thông qua lệnh ping.
Trong image busybox, có sẵn một công cụ để tạo máy chủ web http. Giả sử ta muốn cho container B2 chạy máy chủ web http, chúng ta vào /var/www và chạy lệnh httpd

1
2
3
4
5
6
7
❯ docker attach B2
/ # cd var/
/var # ls
spool  www
/var # cd www/
/var/www # httpd
/var/www # 

Tạo một file index.html với nội dung là:

1
web server is running...

Từ container B1, ta tiến hành wget tới B2

1
2
3
4
5
6
7
8
❯ docker attach B1
/ # wget -O - 172.17.0.3
Connecting to 172.17.0.3 (172.17.0.3:80)
writing to stdout
web server is running...
-                    100% |********************************|    25  0:00:00 ETA
written to stdout
/ # 

Với 172.17.0.3 là địa chỉ của container B2, có thể xem bằng lệnh docker network inspect bridge. Rõ ràng, container B1 đã đọc được file index mà B2 trả về với dòng chữ web server is running...

Ánh xạ cổng mạng trong docker

Ánh xạ cổng mạng

B2 đang mở cổng 80, máy host của chúng ta đang có địa chỉ là 127.0.0.1, chúng ta muốn từ ngoài mạng truy cập được tới container B2 thì phải ánh xạ cổng 80 của B2 tới một cổng nào đó của host. Trong ví dụ này, chúng ta sẽ thiết lập truy cập đến cổng 80 của B2 thông qua cổng 8888 ip máy host 127.0.0.1.
Điều này được làm ở bước tạo container B2, lúc tạo chúng ta sẽ ánh xạ cổng 80 tới cổng 8888 của máy host. Cú pháp như sau:
docker run -it --name <name> -p <host_port>:<container_port> image

1
2
❯ docker run -it --name B2 -p 8888:80 busybox
/ # 

Khi kiểm tra bằng lệnh docker ps ta sẽ thấy container B2 đã ánh xạ cổng 80 lệnh 8888 của máy host ở PORT.

1
2
3
❯ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
bdd19faad9cf        busybox             "sh"                8 minutes ago       Up 8 minutes        0.0.0.0:8888->80/tcp   B2

Chúng ta sẽ thao tác lại một lần ở docker B2 để chạy httpd và tạo file index.html với nội dung web server is running... trong thư mục /var/www. Sau đó, chúng ta truy cập ở trình duyện chrome từ máy host đến địa chỉ 127.0.0.1:8888
docker access
Như vậy, ta đã có thể truy cập đến file index.html trong container B2 từ mạng bên ngoài host.

Tạo thêm mạng

Trường hợp chúng ta không muốn tất cả các container cùng kết nối vào một mạng bridge, ta có thể tạo thêm nhiều bridge riêng để có thể tách các riêng các container thành các cụm riêng. Để tạo ra một mạng bridge, ta dùng lệnh:
docker network create --driver <loai_mang> <ten_mang>
Ở đây chúng ta muốn tạo thêm mạng bridge nên sau --driver sẽ là bridge

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
❯ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
286d5161c9f6        bridge              bridge              local
0f2ab02aa9f4        host                host                local
271997adaaa9        none                null                local
❯ docker network create --driver bridge mynetwork
6c224f5d1a9819ba01d68ed6cd3a15357709d3b8dcf0b1ab0e289d11973f43d0
❯ docker network create --driver bridge network1
8f94d7a2e8ff372c3072294dd5260bbea0d0fb2692c2bedc3acad080b07b229c
❯ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
286d5161c9f6        bridge              bridge              local
0f2ab02aa9f4        host                host                local
6c224f5d1a98        mynetwork           bridge              local
8f94d7a2e8ff        network1            bridge              local
271997adaaa9        none                null                local

Chúng ta tiến hành tạo một số container không kết nối mặc định vào network bridge mà sẽ kết nối vào mynetwork của chúng ta.

1
2
❯ docker run -it --name B3 --network mynetwork busybox
/ # 

Để chỉ định network khi tạo, ta thêm tùy chọn --network và theo sau là tên của network mình muốn kết nối tới. Chúng ta kiểm tra xem B3 có thật sự đã kết nối tới mynetwork chưa.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
❯ docker network inspect mynetwork
[
    {
        "Name": "mynetwork",
        "Id": "6c224f5d1a9819ba01d68ed6cd3a15357709d3b8dcf0b1ab0e289d11973f43d0",
        "Created": "2021-06-10T07:59:52.392658153+07:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "a7231f2ebe678e679ff063d0d8a09613a81db899ffb7e11eb6ba6c202e2e97d7": {
                "Name": "B3",
                "EndpointID": "d8f6cf60953a1ebd7c1a84a95e5503bc726a5e77df2c939e8072fe6ca7406d65",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

Rõ ràng ở trường container đã thêm một container là B3 với địa chỉ là 172.20.0.2. Chúng ta tiếp tục tạo thêm một container B4 kết nối với mynetwork và chỉ định cổng 80 của nó ánh xạ tới cổng 9999 trên máy host.

1
2
3
4
5
6
7
8
❯ docker run -it --name B4 --network mynetwork -p 9999:80 busybox
/ # %                                                                           
❯ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                  NAMES
1b39318c8d5b        busybox             "sh"                About a minute ago   Up About a minute   0.0.0.0:9999->80/tcp   B4
a7231f2ebe67        busybox             "sh"                5 minutes ago        Up 5 minutes                               B3
bdd19faad9cf        busybox             "sh"                37 minutes ago       Up 37 minutes       0.0.0.0:8888->80/tcp   B2
2f6dd1dda04d        busybox             "sh"                9 hours ago          Up 3 seconds                               B1

Như vậy, trên máy của chúng ta đang 2 mạng là bridgemynetwork:

  • Mạng bridge có 2 container đang kết nối tới là B1 và B2, trong đó B2 đang ánh xạ cổng 80 đến cổng 8888 trên máy host.
  • Mạng mynetwork có 2 container đang kết nối tới là B3 và B4, trong đó B4 đang ánh xạ cổng 80 đến cổng 9999 trên host.
    Ta tiến hành chạy web server http trên container B4 và kết nối từ mạng bên ngoài host.
    docker access 2
    Khi tạo ra 2 network thì những máy cùng 1 network (B1 với B2 hoặc B3 với B4) có thể thấy được nhau, tuy nhiên ở khác network (B1 với B3,B4 hoặc B2 với B3,B4) thì không thể thấy nhau. Chúng ta có thể kiểm tra điều này thông qua lênh ping, từ B1 đến B2 và B1 đến B3. Dùng lệnh docker network inspect <ten_network> ta biết được ip của B1, B2, B3 lần lượt là 172.17.0.3, 172.17.0.2, 172.20.0.2. Vào B1 và tiến hành ping qua B2, B3:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
❯ docker attach B1
/ # 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.268 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.101 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.198 ms
64 bytes from 172.17.0.2: seq=3 ttl=64 time=0.162 ms
64 bytes from 172.17.0.2: seq=4 ttl=64 time=0.165 ms
64 bytes from 172.17.0.2: seq=5 ttl=64 time=0.164 ms
64 bytes from 172.17.0.2: seq=6 ttl=64 time=0.139 ms
64 bytes from 172.17.0.2: seq=7 ttl=64 time=0.160 ms
64 bytes from 172.17.0.2: seq=8 ttl=64 time=0.181 ms
^C
--- 172.17.0.2 ping statistics ---
9 packets transmitted, 9 packets received, 0% packet loss
round-trip min/avg/max = 0.101/0.170/0.268 ms
/ # ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes
^C                              
--- 172.20.0.2 ping statistics ---
25 packets transmitted, 0 packets received, 100% packet loss
/ # 

Ánh xạ cổng cho một container đang chạy.

Trong ví dụ trên, B3 đang kết nối tới mynetwork, ta muốn cho B3 kết nối thẳng tới network bridge, ta làm như sau:
docker network connect <ten_mang_muon_ket_noi> <ten_container>

1
❯ docker network connect bridge B3

Kiểm tra mạng bridge để xem B3 đã thực sự kết nối chưa:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
❯ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "286d5161c9f65235af68d99040f31b167b4bf23f9803fa3a2b3bd7de61b7c81c",
        "Created": "2021-06-10T06:58:33.069522692+07:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2f6dd1dda04d0ab42434a6cff6f9c7eb42474f81acdf32809486f8fa82be8951": {
                "Name": "B1",
                "EndpointID": "5ddc6f87b486401bd0e2cfea3e1c8324300f9045712778f1c321e35349c56cff",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "a7231f2ebe678e679ff063d0d8a09613a81db899ffb7e11eb6ba6c202e2e97d7": {
                "Name": "B3",
                "EndpointID": "f1c96c1089fbe206c52832089be7b18321aeea7abff840f5169d3d171fa5ca1d",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            },
            "bdd19faad9cfe6ba9f49a532cf245b3a1bec95d8d20688f4c6b52018d45538b2": {
                "Name": "B2",
                "EndpointID": "32f69c565c649791c9f70db3a7a224e6a8d882b41fb9dc7c6477d4f33b9ec32b",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

Trong trường container đã có thêm container B3, và kiểm tra network mynetwork thì thấy B3 vẫn đang kết nối tới mynetwork.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
❯ docker network inspect mynetwork
[
    {
        "Name": "mynetwork",
        "Id": "6c224f5d1a9819ba01d68ed6cd3a15357709d3b8dcf0b1ab0e289d11973f43d0",
        "Created": "2021-06-10T07:59:52.392658153+07:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1b39318c8d5b92261c22321f765945b85231160b53a9a3933b5fe120db80e7c2": {
                "Name": "B4",
                "EndpointID": "5f26179cc819ffe9f6089c8de41cc236a36ce90c5ac646041d99de7d4a54d3e5",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""
            },
            "a7231f2ebe678e679ff063d0d8a09613a81db899ffb7e11eb6ba6c202e2e97d7": {
                "Name": "B3",
                "EndpointID": "d8f6cf60953a1ebd7c1a84a95e5503bc726a5e77df2c939e8072fe6ca7406d65",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

Lúc này, B3 có thể kết nối tới B2 và B1 và ngược lại.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
❯ docker attach B1
/ # ping 173.20.0.2
PING 173.20.0.2 (173.20.0.2): 56 data bytes
64 bytes from 173.20.0.2: seq=0 ttl=49 time=325.730 ms
64 bytes from 173.20.0.2: seq=1 ttl=49 time=297.840 ms
64 bytes from 173.20.0.2: seq=2 ttl=49 time=280.704 ms
64 bytes from 173.20.0.2: seq=3 ttl=49 time=328.708 ms
64 bytes from 173.20.0.2: seq=4 ttl=49 time=274.586 ms
64 bytes from 173.20.0.2: seq=5 ttl=49 time=295.232 ms
64 bytes from 173.20.0.2: seq=6 ttl=49 time=274.058 ms
^C
--- 173.20.0.2 ping statistics ---
8 packets transmitted, 7 packets received, 12% packet loss
round-trip min/avg/max = 274.058/296.694/328.708 ms

Một lưu ý là khi B3 và B4 cùng kết nối với nhau qua một mạng, bên cạnh kết nối với nhau qua địa chỉ thì chúng có thể kết nối với nhau qua tên.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
❯ docker attach B3
/ # ping B4
PING B4 (172.20.0.3): 56 data bytes
64 bytes from 172.20.0.3: seq=0 ttl=64 time=0.283 ms
64 bytes from 172.20.0.3: seq=1 ttl=64 time=0.194 ms
64 bytes from 172.20.0.3: seq=2 ttl=64 time=0.164 ms
64 bytes from 172.20.0.3: seq=3 ttl=64 time=0.191 ms
^C
--- B4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.164/0.208/0.283 ms

Tuy nhiên B1, B2 cũng kết nối với nhau chung 1 mạng mà chúng không thể giao tiếp với nhau qua tên. Có thể do mạng của chúng cùng kết nối là mạng mặc định (bridge).

1
2
3
❯ docker attach B1
/ # ping B2
ping: bad address 'B2'

Xóa mạng

Khi không có nhu cầu sử dụng network nữa, chúng ta có thể xóa chúng đi với cú pháp:
docker network rm <ten_network>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
❯ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
286d5161c9f6        bridge              bridge              local
0f2ab02aa9f4        host                host                local
2f8c72e77060        mynetwork           bridge              local
258acbefb858        network1            bridge              local
271997adaaa9        none                null                local
❯ docker network rm network1
network1
❯ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
286d5161c9f6        bridge              bridge              local
0f2ab02aa9f4        host                host                local
2f8c72e77060        mynetwork           bridge              local
271997adaaa9        none                null                local

Kết luận

Trong bài học này, chúng ta đã học được từ anh XuanThuLabChanel những kiến thức như sau:

  • Biết về busybox
  • Các lệnh thao tác với docker network: liệt kê, kiểm tra thông tin mạng
  • Mạng bridge, tạo thêm, xóa mạng, ánh xạ cổng mạng trong docker.

Kết thúc bài viết này, một lần nữa em xin chân thành gửi lời cảm ơn đến anh XuanThuLabChanel đã làm những bài học quý giá và bổ ích này.

Share on

Edisc
WRITTEN BY
Edisc
Cyber Security Engineer

 
What's on this Page