TL;DR
Docker không thể tạo network vì subnet bạn chỉ định — hoặc subnet Docker tự chọn — bị trùng với một thứ gì đó đang được sử dụng. Thứ đó có thể là một Docker network khác, một VPN tunnel, hoặc mạng LAN nội bộ của công ty. Cách khắc phục: liệt kê những gì đã được dùng, tìm một CIDR block còn trống, và tạo network với block đó được chỉ định tường minh.
# Liệt kê tất cả Docker network hiện có và subnet của chúng
docker network ls
docker network inspect $(docker network ls -q) \
--format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}'
# Tạo network với subnet không bị trùng
docker network create --subnet=172.30.0.0/16 my_network
Nguyên Nhân Gây Ra Lỗi
Docker lấy subnet từ các dải địa chỉ private theo RFC 1918 — bắt đầu từ 172.17.0.0/16, rồi đến 172.18.0.0/16, 172.19.0.0/16, và tiếp tục như vậy. Vấn đề là Docker không phải thứ duy nhất lấy từ vùng địa chỉ đó.
Lỗi xảy ra khi subnet mục tiêu đã bị chiếm bởi:
- Một Docker network đang tồn tại (kể cả những network không ai đang dùng),
- Một VPN interface trên host,
- Một mạng LAN nội bộ của công ty định tuyến qua máy đó,
- Một container runtime khác như Podman hoặc Kubernetes CNI plugin.
Pool địa chỉ mặc định của Docker là 172.16.0.0/12 — tức là từ 172.16.x.x đến 172.31.x.x. Trên một máy đã chạy container nhiều tháng, toàn bộ dải địa chỉ này có thể bị dùng hết. Khi đó, mọi lệnh docker network create không chỉ định subnet tường minh đều sẽ thất bại.
Bước 1 — Tìm Những Subnet Đã Bị Sử Dụng
Lệnh một dòng sau in ra mọi Docker network cùng với subnet của nó:
docker network inspect $(docker network ls -q) \
--format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}'
Ví dụ đầu ra trên một máy dev đang bận:
bridge 172.17.0.0/16
host
none
my_app_net 172.18.0.0/16
staging_net 172.19.0.0/24
old_project 172.20.0.0/16
Ngoài ra, hãy kiểm tra các network interface của host. Các VPN client lặng lẽ chiếm một block 10.x.x.x hoặc 192.168.x.x ngay khi bạn kết nối:
ip addr show # Linux
ifconfig # macOS
Bước 2 — Chọn Một Subnet Còn Trống
Xem lại kết quả đầu ra và tìm các khoảng trống. Khi dải 172.x đã chật, hãy chuyển sang một lớp RFC 1918 hoàn toàn khác:
10.10.0.0/24— chứa được 254 container, dễ nhớ10.20.0.0/24— lựa chọn thứ hai nếu 10.10 đã bị dùng192.168.100.0/24— hữu ích khi cả 10.x lẫn 172.x đều chật hết
Không chắc hai dải địa chỉ có bị trùng không? Dán các subnet hiện có vào Subnet Calculator trên ToolCraft — công cụ này hiển thị các block còn trống trực quan và chạy hoàn toàn trên trình duyệt, không tải dữ liệu lên máy chủ.
Bước 3 — Tạo Network Với Subnet Được Chỉ Định Tường Minh
Chỉ định subnet ngay lúc tạo để Docker không tự đoán sai:
docker network create \
--driver bridge \
--subnet=10.10.0.0/24 \
--gateway=10.10.0.1 \
my_network
Đang dùng Docker Compose? Thiết lập trực tiếp trong docker-compose.yml:
networks:
my_network:
driver: bridge
ipam:
config:
- subnet: 10.10.0.0/24
gateway: 10.10.0.1
Bước 4 — Xóa Các Network Cũ Không Dùng (Không Bắt Buộc Nhưng Nên Làm)
Các network từ những project cũ không tự biến mất. Mười tháng dùng docker-compose up và docker-compose down có thể để lại hàng chục network mồ côi, mỗi cái chiếm một phần subnet.
# Xóa tất cả network không được gắn với container nào
docker network prune
# Xóa một network cụ thể theo tên
docker network rm old_project
Sau khi dọn dẹp, hãy thử tạo lại network mà không chỉ định subnet. Docker thường tự tìm được một block trống khi các network rác đã được dọn sạch.
Xác Nhận Đã Khắc Phục
# Xác nhận network tồn tại với subnet đúng
docker network inspect my_network \
--format '{{range .IPAM.Config}}Subnet: {{.Subnet}} Gateway: {{.Gateway}}{{end}}'
# Khởi động container trên network mới và kiểm tra IP của nó
docker run --rm --network my_network alpine ip addr show eth0
Container phải hiển thị một địa chỉ IP trong dải bạn đã chọn — ví dụ như 10.10.0.2/24. Nếu nó khởi động mà không có lỗi, là bạn đã xong.
Cấu Hình Pool Địa Chỉ Mặc Định
Nếu bạn liên tục gặp lỗi này trên nhiều project, cách khắc phục triệt để hơn là ở thượng nguồn: bảo Docker ngừng lấy từ dải 172.x theo mặc định. Chỉnh sửa (hoặc tạo) file /etc/docker/daemon.json:
{
"default-address-pools": [
{"base": "10.10.0.0/16", "size": 24}
]
}
Sau đó khởi động lại daemon:
sudo systemctl restart docker
Mọi network được tạo tự động sau này sẽ lấy một block /24 từ 10.10.0.0/16. Dải này cho phép tới 256 network trước khi dùng hết — đủ rộng rãi. Pool 172.x vốn đã chật vẫn không bị đụng tới.
Xung Đột Với VPN
VPN của công ty là thủ phạm thường gặp. VPN tunnel chiếm một block — chẳng hạn 10.0.0.0/8 hoặc 172.16.0.0/12 — ngay khi bạn kết nối, và Docker không có cách nào biết được điều đó. Cách duy nhất là hướng Docker ra xa các dải địa chỉ đó.
Chọn một dải mà VPN không dùng đến, như 192.168.200.0/24, và cố định nó trong daemon.json như hướng dẫn ở trên. Nếu không chắc VPN đang dùng dải nào, hãy chạy ip route trong lúc đang kết nối — các route của VPN hiện ra rõ ràng cùng với tên interface (thường là tun0 hoặc utun).

