Container Docker không truy cập được qua VPN? Hãy so sánh các subnet
Docker cấp một subnet mà VPN cũng nhận là của mình. Hãy so sánh hai quy hoạch địa chỉ, rồi chọn cách sửa còn hiệu lực sau khi kết nối lại.
Các container trả lời trong LAN văn phòng, rồi ngừng trả lời ngay khi VPN công ty kết nối. Không có gì thay đổi trong container: không khởi động lại, không cập nhật image, không sửa cấu hình. Thứ đã thay đổi là bảng định tuyến của máy chủ, nơi một tuyến do đường hầm thêm vào giờ bao phủ địa chỉ mà Docker đã cấp. Trước khi sửa một subnet hoặc xin miễn trừ VPN, hãy đặt hai quy hoạch địa chỉ cạnh nhau, vì mỗi cách sửa tốn lượng thời gian rất khác nhau.
Đọc tuyến trước khi thay đổi cấu hình
Bắt đầu từ mạng mà Docker thực sự đã dựng. Khối IPAM là quy hoạch địa chỉ, và subnet là dòng quan trọng:
docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]Mặc định Compose cấp một /16 cho mỗi dự án mới, nên hai dịch vụ có thể nằm trong dải 65,536 địa chỉ. Chính độ rộng này khiến va chạm phổ biến: một /16 chọn ngẫu nhiên đủ lớn để nuốt trọn một site bạn truy cập qua đường hầm, và không ai nhận ra cho đến khi đường hầm được bật.
Sau đó so sánh việc chọn tuyến cho một địa chỉ container, một lần khi đường hầm tắt và một lần khi bật:
ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1Hai dạng câu trả lời dẫn đến hai nơi khác nhau. Nếu đầu ra nêu tun0, wg0 hoặc một thiết bị đường hầm khác, tiền tố VPN ít nhất cũng cụ thể bằng tuyến cầu và gói tin không bao giờ đến được container. Nếu đầu ra vẫn nêu cầu, máy chủ vẫn đến được container, và lỗi của bạn là lọc, DNS hoặc đường về chỉ hỏng theo một chiều.
Vì sao va chạm /16 dễ xảy ra
Docker lấy mạng cầu từ các pool riêng, và pool mặc định lấy từ khối 172.16.0.0/12 theo từng lát /16. Mạng doanh nghiệp thường dùng cùng không gian riêng đó, và VPN truy cập từ xa đẩy các tiền tố ấy tới mọi máy khách kết nối. Khi cả hai bên đều cho rằng mình sở hữu 172.18.0.0/16, một bảng định tuyến chứa hai tuyên bố mâu thuẫn.
Độ dài tiền tố quyết định bên thắng, không phải thứ tự các tuyến. Một đường hầm đẩy 10.0.0.0/8 không thắng tuyến cầu 172.18.0.0/16, vì /8 kém cụ thể hơn. Một đường hầm đẩy 172.18.0.0/16, hoặc 172.18.5.0/24 bên trong nó, thì thắng. Đó là lý do một laptop chạy được trên mạng văn phòng nhưng hỏng trên Wi-Fi khách sạn với cùng VPN: máy khách nhận các tiền tố khác nhau.
Cùng bảng đó điều khiển chiều ngược lại. Một container cần máy chủ nội bộ tại 10.8.4.20 gửi gói tới cổng cầu của nó, rồi máy chủ định tuyến gói vào đường hầm. Đường đó thường chạy được vì máy chủ thực hiện NAT, nhưng hỏng khi phía doanh nghiệp chỉ chấp nhận địa chỉ VPN của laptop, hoặc khi lọc đường về ngược chiều loại bỏ phản hồi không đối xứng.
So sánh ba cách sửa
Chỉ có ba lối ra, và chúng khác nhau ở việc ai phải phê duyệt và cái gì hỏng trong lúc bạn áp dụng một cách.
| Repair | Who owns it | What it costs |
|---|---|---|
| Renumber the container network | You | Recreates the network, restarts services, invalidates literal addresses in configs and scripts |
| Exclude your range from the tunnel | Network team | Changes what every laptop sees, needs a change request and a client profile update |
| Reach the service through a published port | You and the client | One port only, no direct container-to-container routing across the tunnel |
Đánh số lại là cách sửa duy nhất bạn có thể hoàn tất mà không cần phiếu yêu cầu, nên phần lớn bài viết dừng ở đó. Nó rẻ với dự án non trẻ và đắt khi một công cụ di trú hoặc chuỗi kết nối đã lưu trỏ tới một địa chỉ nguyên văn. Hãy đếm các tham chiếu đó trước khi sửa YAML, không phải sau.
Miễn trừ khỏi đường hầm là câu trả lời sạch nhất khi vùng chồng lấn nằm trong dải mà công ty bạn thực sự sở hữu. Nó cũng chậm nhất, và vô dụng với một nhà thầu không thể đổi hồ sơ máy khách. Một cổng được công bố hoặc một proxy ngược nhỏ tránh được tranh cãi: máy khách nói chuyện với địa chỉ mà đường hầm vốn đã định tuyến đúng, và chỉ cổng đó cần truy cập được.
Ghim một dải địa chỉ có chủ đích
Với một dự án, khai báo subnet trong tệp compose để dự án thôi lấy từ pool dùng chung:
networks:
default:
ipam:
config:
- subnet: 10.201.7.0/24Lấy dải đó từ một sổ đăng ký mà nhóm bạn duy trì, không phải từ ví dụ bạn tìm thấy khi tra cứu. Đối chiếu nó với các tiền tố VPN đẩy xuống, các LAN gia đình nơi mọi người làm việc, và các mạng container khác trên cùng máy chủ. Rồi lên kế hoạch tạo lại, vì một mạng đã tồn tại vẫn giữ subnet cũ: docker compose down, rồi up -d. docker network rm từ chối khi còn điểm cuối gắn vào, và mọi mục ipv4_address trong tệp phải nằm trong dải mới.
Với các mạng Docker tự tạo, đặt một pool daemon trong /etc/docker/daemon.json:
{
"default-address-pools": [
{ "base": "10.201.0.0/16", "size": 24 },
{ "base": "10.202.0.0/16", "size": 24 }
]
}Pool áp dụng cho các mạng được tạo sau khi daemon khởi động lại, còn các cầu đã tồn tại giữ nguyên địa chỉ. Điều đó tiện và dễ quên, nên hãy coi một dự án cũ vẫn còn chồng lấn cho đến khi có người tạo lại mạng của nó. Tài liệu mạng của engine của Docker mô tả các quy tắc cấp phát nếu bạn cần bảo vệ pool trong buổi rà soát.
Cầu Linux và Docker Desktop hỏng khác nhau
Trên máy chủ Linux, container nằm trên các cầu trong không gian tên của máy chủ. Một bảng quyết định mọi thứ, nên so sánh ở trên là toàn bộ câu chuyện: đọc tuyến cầu, đọc tuyến đường hầm, và xem cái nào thắng với một địa chỉ container thật.
Docker Desktop đặt container sau một VM có NAT riêng. Máy chủ không có tuyến nào tới địa chỉ container; nó đến dịch vụ qua một cổng được công bố, thường gắn với 127.0.0.1. Vì vậy một máy khách VPN có thể làm hỏng dịch vụ mà không cần bất kỳ chồng lấn subnet nào: hoặc cài một tuyến cho dải nội bộ của VM, hoặc chặn lưu lượng loopback trong khi đường hầm kết nối. Nếu ip route get trên máy chủ báo không có tuyến cho địa chỉ container, đó là điều dự kiến chứ không phải lỗi.
Hệ quả thực tế là bạn nhìn vào đâu trước. Trên Linux, bắt đầu từ bảng định tuyến. Trên Desktop, bắt đầu từ cổng được công bố và các quy tắc tường lửa của máy khách VPN, rồi kiểm tra xem subnet nội bộ của VM có va chạm với thứ gì đường hầm đẩy xuống không.
Xác minh khi đường hầm đang bật
Kết nối lại VPN hai lần trước khi nói đã sửa xong, vì một hồ sơ đẩy tuyến khi kết nối và rút lại khi ngắt có thể trông đúng sau lần thử đầu. Rồi chạy những kiểm tra mà máy khách thực sự chạy:
ip route gettừ máy chủ, dùng địa chỉ thật của container.- Một yêu cầu từ container khác, để chứng minh bản thân dịch vụ vẫn khỏe.
curl -sv http://127.0.0.1:8080/từ máy khách khi đường hầm bật, rồitraceroute -ntới địa chỉ container từ một máy trong LAN.sysctl net.ipv4.conf.all.rp_filternếu yêu cầu tới được máy chủ nhưng phản hồi biến mất.
Cuối cùng, ghi dải đã chọn vào đúng sổ đăng ký bạn dùng để chọn nó, kèm ngày và dự án sở hữu. Lần chồng lấn tiếp theo sẽ đến từ một dự án không ai ghi lại, và cách phòng vệ duy nhất là dải đó được đặt trước có chủ đích thay vì rút ngẫu nhiên.