Docker

Docker Network: Bridge, Host, None Và Cách Các Container Giao Tiếp Với Nhau

phongdhphongdh
14 phút đọc
Chia sẻ:
Zalo
Ảnh đại diện bài Docker Network - Series Docker cơ bản bài 4 trên phongdinh.info.vn

Trong các bài trước của series, mỗi container đều chạy gần như độc lập: một web server nginx phục vụ người dùng, hết. Nhưng hệ thống thật luôn gồm nhiều container phải nói chuyện với nhau — web gọi database, ứng dụng gọi cache, service này gọi service kia — đồng thời vẫn phải mở cổng cho bên ngoài truy cập. Lớp quản lý toàn bộ việc kết nối đó chính là Docker Network.

Bài viết này sẽ làm rõ Docker Network gồm những chế độ nào (Bridge, Host, None), cách tạo một mạng riêng cho ứng dụng, cách publish cổng ra ngoài bằng -p và cơ chế để các container gọi nhau bằng tên thay vì địa chỉ IP. Các lệnh quản lý mạng đều được chạy thật trên máy lab kèm ảnh kết quả.

Điều kiện thực hành: đã cài Docker và quen với các lệnh Docker cơ bản ở Bài 1. Khái niệm dữ liệu bền vững ở Bài 3 về Docker Volume cũng sẽ giúp bạn hình dung hệ thống hoàn chỉnh hơn.

1. Docker Network cơ bản là gì?

Hiểu đơn giản, network trong Docker là một mạng ảo do Docker tạo và quản lý trên máy chủ. Mỗi network là một vùng mạng riêng với dải địa chỉ IP riêng; container được gắn vào network nào thì chỉ “nhìn thấy” và giao tiếp được với các container trong cùng network đó (trừ khi có cơ chế mở cổng ra ngoài). Nhờ vậy, chỉ cần chia network hợp lý là bạn đã cô lập được các nhóm ứng dụng với nhau ngay trên cùng một máy chủ.

Về mặt kỹ thuật, mỗi network được vận hành bởi một driver. Docker tích hợp sẵn ba driver nền tảng là bridge (mạng cầu nối, mặc định), host (dùng chung mạng của máy chủ) và none (không có mạng). Ngoài ra còn các driver phục vụ hệ thống nhiều máy chủ như overlay hay macvlan — nằm ngoài phạm vi series cơ bản này.

Mọi thao tác quản lý đều qua nhóm lệnh docker network với các lệnh con ls, create, inspect, rm, connect, disconnect và prune. Chúng ta sẽ đi qua từng lệnh quan trọng trong các mục dưới đây.

2. Ba network có sẵn trên mọi máy Docker

Ngay sau khi cài Docker, hệ thống đã có sẵn các network mặc định. Liệt kê bằng lệnh docker network ls:

Danh sách Docker Network cơ bản mặc định trên máy Docker bằng lệnh docker network ls

Trong danh sách, bridge là network mặc định: container nào chạy mà không chỉ định mạng sẽ tự động vào đây, nhận một IP riêng trong dải mạng nội bộ của Docker và bị ngăn cách với máy chủ bởi cơ chế NAT — muốn bên ngoài truy cập được phải publish cổng. Ngoài bridge, Docker còn tích hợp sẵn hai chế độ mạng đặc biệt là host (container dùng chung toàn bộ mạng của máy chủ, không còn IP riêng) và none (ngắt mọi kết nối mạng, container chỉ còn giao diện loopback nội bộ) — hai chế độ này sẽ được thực hành ở mục 4 và 5.

Các network và chế độ mặc định này không thể xóa. Mọi network bạn tự tạo thêm đều dùng driver bridge (trừ khi chỉ định khác) nhưng có thêm những tính năng mà bridge mặc định không có — quan trọng nhất là DNS nội bộ theo tên container, sẽ rõ ở mục 6.

3. Tạo network riêng cho ứng dụng

Thói quen đúng khi triển khai thật là mỗi ứng dụng/hệ thống có một network riêng, thay vì để mọi container chen chúc trong bridge mặc định. Tạo network bằng lệnh docker network create, có thể chỉ định luôn dải IP và gateway nếu muốn kiểm soát chặt:

Tạo Docker Network riêng bằng docker network create với subnet và gateway tùy chỉnh

Ta vừa tạo app-net với subnet 172.20.0.0/16 và gateway 172.20.0.1, cùng một network thứ hai để tiện quan sát. Nếu bỏ qua hai tùy chọn này, Docker tự cấp một dải IP trống — cách làm phổ biến và đủ dùng cho đa số trường hợp. Để xem lại cấu hình chi tiết của một network, dùng lệnh inspect:

Xem chi tiết một Docker Network bằng docker network inspect, đọc driver, subnet và gateway

Kết quả xác nhận app-net dùng driver bridge với đúng subnet và gateway đã khai báo. Khi gắn container vào network này, Docker sẽ cấp cho nó một IP trong dải 172.20.x.x. Việc cố định dải IP theo từng hệ thống giúp bạn dễ đọc log, dễ cấu hình tường lửa và tránh xung đột khi máy chủ chạy nhiều ứng dụng.

Về đặt tên, hãy đặt tên network theo hệ thống và môi trường mà nó phục vụ, ví dụ shop-net, blog-net hay app-net-staging. Khi máy chủ chạy nhiều dự án, danh sách network có tên rõ ràng giúp bạn nhìn một cái là biết network nào của hệ thống nào, tránh xóa nhầm và tránh gắn container vào nhầm mạng của dự án khác — lỗi tưởng nhỏ nhưng rất khó truy vết khi sự cố xảy ra.

4. Chế độ Host: dùng chung mạng với máy chủ

Với --network host, container bỏ qua lớp mạng ảo và dùng trực tiếp mạng của máy chủ: ứng dụng trong container mở cổng nào thì máy chủ mở cổng đó. Đây chính là chế độ mà các bài thực hành trong series này đang dùng cho container demo, để việc kiểm tra bằng curl đơn giản nhất:

Chạy container ở chế độ Host của Docker Network, dùng chung mạng với máy chủ

Container nginx chạy ở chế độ host trả lời ngay tại cổng 80 của máy chủ, cột PORTS trong docker ps để trống vì không còn khái niệm ánh xạ cổng. Ưu điểm của host là hiệu năng mạng gần như gốc và cấu hình đơn giản. Nhược điểm là container mất tính cô lập về mạng: hai container cùng muốn dùng cổng 80 sẽ xung đột ngay trên máy chủ, và bạn không thể publish chọn lọc từng cổng như với bridge. Chế độ này hợp cho các dịch vụ hạ tầng đặc thù, không phải lựa chọn mặc định cho ứng dụng thông thường.

Trong thực tế, chế độ host hay được dùng cho các container làm nhiệm vụ giám sát mạng, cân bằng tải hoặc các ứng dụng cực kỳ nhạy cảm về độ trễ — những trường hợp mà chi phí đi qua lớp NAT của bridge là không chấp nhận được. Ngược lại, với web và ứng dụng thông thường, phần chênh lệch hiệu năng gần như không đáng kể so với lợi ích cô lập mà bridge mang lại, nên đừng chọn host chỉ vì “thấy nhanh hơn” trên lý thuyết.

5. Chế độ None: ngắt hoàn toàn mạng

Ở thái cực ngược lại, --network none cho container không có bất kỳ kết nối mạng nào ra bên ngoài. Kiểm chứng bằng cách xem danh sách giao diện mạng bên trong một container chạy ở chế độ này:

Container ở chế độ None của Docker Network chỉ còn giao diện loopback khi kiểm tra bằng ip addr

Kết quả lệnh ip addr chỉ còn giao diện lo (loopback, địa chỉ 127.0.0.1) — không có card mạng nào khác, container hoàn toàn cô lập. Chế độ none phù hợp cho các container xử lý dữ liệu thuần túy (chuyển đổi file, tính toán theo lô) hoặc khi bạn muốn một container tuyệt đối không được chạm vào mạng vì lý do bảo mật.

6. Chế độ Bridge: container giao tiếp với nhau như thế nào?

Bridge là chế độ quan trọng nhất và là mặc định của Docker. Mỗi container trong một bridge network có IP riêng; các container trong cùng network giao tiếp trực tiếp với nhau qua các IP này. Điểm khác biệt then chốt giữa network tự tạo và bridge mặc định: network tự tạo có DNS nội bộ — container gọi container khác bằng chính cái tên của nó, Docker tự phân giải thành IP hiện tại.

Một hệ thống web + database điển hình sẽ được dựng như sau (đây là bộ lệnh mẫu chuẩn để bạn chạy trên máy Docker của mình — môi trường lab của series không gắn được container vào bridge nên phần này trình bày ở dạng lệnh mẫu, các mục còn lại trong bài đều là kết quả chạy thật):

# Tạo network riêng cho hệ thống (đã làm ở mục 3)
docker network create app-net

# Chạy database, chỉ nằm trong app-net, không mở cổng ra ngoài
docker run -d --name db --network app-net \
  -e MYSQL_ROOT_PASSWORD=matkhau_manh \
  -v db-data:/var/lib/mysql mysql:8

# Chạy web, cùng app-net, publish cổng 8080 ra ngoài
docker run -d --name web --network app-net -p 8080:80 nginx

# Từ trong container web, gọi database bằng TÊN "db" (DNS nội bộ):
docker exec web ping -c 2 db

Trong ví dụ này, chuỗi kết nối của ứng dụng web chỉ cần ghi host là db — không cần biết IP của container database là bao nhiêu, kể cả khi nó bị tạo lại và đổi IP. Đồng thời database hoàn toàn vô hình với bên ngoài vì không hề được publish cổng; chỉ các container cùng app-net mới chạm tới nó được. Đây là mô hình mạng chuẩn cho gần như mọi hệ thống Docker thực tế.

Lưu ý, một container có thể thuộc nhiều network cùng lúc (dùng lệnh docker network connect để gắn thêm), và các container ở hai network khác nhau thì không giao tiếp trực tiếp được với nhau — nguyên tắc cô lập này chính là lớp bảo mật đầu tiên bạn nên tận dụng khi thiết kế hệ thống.

7. Publish cổng ra ngoài bằng -p

Với bridge, container bị “giấu” sau NAT của Docker. Để người dùng bên ngoài truy cập được dịch vụ, bạn publish cổng bằng cờ -p <cổng-trên-host>:<cổng-trong-container> như đã làm từ Bài 1. Docker sẽ chuyển tiếp mọi kết nối vào cổng của host sang cổng của container tương ứng.

Vài hệ quả thực tế cần nắm. Một: chỉ cổng được publish mới vào được, các cổng khác của container vẫn kín — đây là lý do database ở mục 6 an toàn. Hai: nhiều container cùng mở cổng 80 bên trong vẫn sống chung được, miễn là cổng phía host khác nhau (8080, 8081…). Ba: muốn kiểm tra container đang publish những cổng nào, nhìn cột PORTS của docker ps (dạng 0.0.0.0:8080->80/tcp) hoặc dùng lệnh docker port <tên-container>. Và đừng quên tường lửa của VPS: cổng trên host phải được mở thì người dùng internet mới vào được.

Một biến thể bảo mật rất đáng dùng là publish chỉ trên địa chỉ nội bộ của host: -p 127.0.0.1:8080:80. Khi đó cổng 8080 chỉ nghe trên localhost của VPS — bên ngoài internet không chạm vào được, nhưng bạn vẫn kiểm tra được dịch vụ qua SSH tunnel, hoặc để một reverse proxy trên cùng máy đứng ra tiếp khách. Đây là cách triển khai chuẩn cho các trang quản trị, trang debug và các dịch vụ chỉ dành cho nội bộ. Bạn cũng có thể publish nhiều cổng trong cùng một lệnh chạy bằng cách lặp lại cờ -p nhiều lần.

8. Xóa network và dọn dẹp

Xóa network tự tạo bằng lệnh docker network rm. Docker chỉ cho xóa network không còn container nào gắn vào (muốn xóa nhanh phải gỡ container trước), và ba network mặc định bridge/host/none là bất khả xâm phạm:

Xóa Docker Network tự tạo bằng docker network rm và kiểm tra lại danh sách

Hai network demo đã biến mất khỏi danh sách, chỉ còn lại các network mặc định của hệ thống. Khi cần dọn hàng loạt network không còn container nào sử dụng, lệnh docker network prune sẽ làm thay trong một lần — nhưng hãy cẩn thận trên server thật, vì network “trống” đôi khi là network đang chờ triển khai lại. Thói quen an toàn là luôn xem danh sách trước khi dọn, tương tự nguyên tắc sẽ gặp lại ở bài dọn dẹp tổng thể cuối series.

9. Gắn thêm container đang chạy vào một network khác

Một container không bị cố định vào các network đã chọn lúc docker run. Bằng lệnh docker network connect, bạn có thể gắn một container đang chạy vào thêm một network khác mà không cần tạo lại nó — và dùng docker network disconnect để gỡ ra:

# Gắn container web vào thêm network monitoring-net
# (web giờ thuộc cả hai network, nói chuyện được với cả hai phía)
docker network connect monitoring-net web

# Gỡ container web khỏi monitoring-net
docker network disconnect monitoring-net web

Khả năng thuộc nhiều network cùng lúc là cách các hệ thống lớn tổ chức luồng giao tiếp theo từng lớp: ví dụ container ứng dụng đứng ở giao điểm của network “frontend” (nói chuyện với reverse proxy) và network “backend” (nói chuyện với database), trong khi reverse proxy và database hoàn toàn không thấy nhau. Thiết kế network theo lớp như vậy giúp thu hẹp tối đa bề mặt tấn công nếu một thành phần bị xâm nhập.

10. Lỗi thường gặp về mạng trong Docker

  • Hai container không gọi được nhau: nguyên nhân phổ biến nhất là chúng đang ở hai network khác nhau, hoặc cả hai đang ở bridge mặc định — nơi không có DNS theo tên. Khắc phục: tạo network riêng và gắn cả hai vào, rồi gọi nhau bằng tên container.
  • Báo lỗi “port is already allocated”: cổng phía host đã có container hoặc dịch vụ khác chiếm. Đổi sang cổng host khác (ví dụ 8081:80) hoặc dừng tiến trình đang giữ cổng.
  • Container chạy nhưng bên ngoài không vào được: kiểm tra lần lượt — đã publish đúng cổng bằng -p chưa, ứng dụng trong container có thực sự lắng nghe ở cổng đó không (docker logs), và tường lửa VPS đã mở cổng chưa.
  • Hardcode địa chỉ IP của container trong cấu hình: IP của container thay đổi sau mỗi lần tạo lại, khiến kết nối gãy ngẫu nhiên. Luôn dùng tên container với DNS nội bộ của network tự tạo thay cho IP.
  • Xung đột dải IP khi tạo network: nếu subnet bạn chọn cho docker network create trùng với dải mạng LAN của công ty hoặc dải của VPN đang dùng, container sẽ gặp những lỗi kết nối rất khó hiểu. Hãy chọn các dải riêng ít đụng hàng (ví dụ 172.20.0.0/16, 172.21.0.0/16 cho từng hệ thống) và ghi lại quy hoạch này.
  • Publish nhầm cổng database ra internet: thói quen gõ -p 3306:3306 cho tiện debug biến database thành mục tiêu công khai. Chỉ publish những cổng dịch vụ thật sự cần cho người dùng cuối; database hãy để trong network nội bộ.

11. Lời kết

Tóm lại, Docker Network xoay quanh ba chế độ nền tảng: bridge (mặc định, có NAT và publish cổng — hãy dùng network tự tạo để có DNS theo tên), host (dùng chung mạng máy chủ, nhanh nhưng kém cô lập) và none (ngắt mạng hoàn toàn). Thiết kế network theo từng ứng dụng ngay từ đầu sẽ giúp hệ thống của bạn vừa an toàn vừa dễ mở rộng.

Ở bài tiếp theo, chúng ta sẽ đến với kho image lớn nhất của hệ sinh thái Docker: Docker Hub là gì và cách tìm, tải, đẩy image — Bài 5 của series Docker cơ bản.

Chia sẻ bài viết này:
Zalo
phongdh

phongdh

Tác giả bài viết • Content Creator

Chào mọi người, mình là Phong - hiện đang công tác tại Phòng Kỹ thuật AZDIGI. Trong quá trình làm việc mình có cơ hội được tiếp xúc với khá nhiều các vấn đề liên quan đến Website/Email/Hosting/VPS/Server, do đó mình viết lại các hướng dẫn này nhằm chia sẻ kiến thức, cũng như tạo một môi trường để chúng ta giao lưu và học hỏi lẫn nhau.

Kết nối:

Bài viết liên quan

Những bài viết bạn có thể quan tâm

Thảo luận 0 bình luận Viết bình luận

Email được bảo mật và không hiển thị công khai.

Chưa có bình luận. Hãy là người mở đầu cuộc trò chuyện.

Zalo