Dev container không tới được host chỉ mở qua VPN: nên xem ở đâu
Trình duyệt và container có ngữ cảnh resolver, proxy và tuyến đường khác nhau. Hãy xác định tiến trình đang lỗi dùng ngữ cảnh nào trước khi đổi bất kỳ cài đặt VPN nào.
API riêng tư mở được trong trình duyệt trên máy tính của bạn nhưng lại lỗi trong container phát triển. Đó không phải mâu thuẫn, và hiếm khi là bản thân VPN. Yêu cầu từ trình duyệt và yêu cầu bị lỗi do hai tiến trình khác nhau thực hiện, với resolver, proxy và tuyến đường khác nhau, và thường từ những không gian tên mạng hoàn toàn khác. "Trên laptop của tôi" có thể nghĩa là host Windows, một bản phân phối WSL, máy ảo Docker Desktop và một container bên trong máy ảo đó, bốn ngữ cảnh mà mỗi ngữ cảnh có thể trả lời cùng một hostname theo cách khác nhau. Hãy tìm ra tiến trình đang lỗi dùng ngữ cảnh nào trước khi chạm vào một cài đặt duy nhất.
Xác định tiến trình trước khi đổi cài đặt
Bắt đầu từ engine container thay vì client VPN. Hỏi dòng lệnh đang nói chuyện với ngữ cảnh nào, và engine đó chạy trên hệ điều hành nào, vì container Linux do máy ảo trên desktop quản lý là một đường khác với container do daemon cục bộ quản lý:
docker context ls
docker info --format '{{.OperatingSystem}} / {{.Name}}'
docker run --rm alpine ip route
Trên Windows, wsl -l -v cho bạn biết bản phân phối có chạy dưới WSL 2 hay không, điều này đặt nó sau switch ảo riêng. Chi tiết đó quyết định container có chia sẻ bảng định tuyến của host hay nằm sau một NAT cần cổng được chuyển tiếp hoặc tên host để tới host.
Giữ một yêu cầu cố định và so sánh
Chọn một endpoint vô hại trên host riêng tư và dùng nó cho mọi so sánh, từ trình duyệt, từ terminal của host, từ bản phân phối WSL và từ bên trong container. Ghi lại bốn thứ cho mỗi lần thử: địa chỉ đã phân giải, có dùng proxy hay không, loại lỗi và thời gian đã trôi qua. Tra cứu tên, thiết lập kết nối, xác thực TLS và trạng thái HTTP là bốn vấn đề khác nhau, và gộp chúng thành "nó không chạy" chỉ làm mất một buổi sáng.
Chạy phép so sánh bên trong container đang lỗi, với một giới hạn thời gian để tường lửa im lặng không giữ terminal hàng phút. Một container mới tái tạo ngữ cảnh mạng của engine nhưng không tái tạo không gian tên, biến proxy hay resolver của container ứng dụng, nên docker exec vào container thật là phép thử có thẩm quyền và container phụ chỉ là cách để cô lập xem khác biệt nằm ở engine hay ở container:
docker exec -it app /bin/sh -c "getent hosts api.internal; curl -v --max-time 8 https://api.internal/ 2>&1 | tail -20"
docker run --rm --network container:app curlimages/curl:latest -sv --max-time 8 https://api.internal/ 2>&1 | tail -20
Ảnh nền alpine có busybox và không có curl, và đó chính là kiểu chi tiết khiến một khối chẩn đoán sao chép bị lỗi: hãy chọn ảnh có client, hoặc thêm nó vào trong cùng lần chạy. So sánh với các trang công khai không liên quan không cô lập được gì. Nếu https://example.com chạy được từ container, bạn chỉ biết container có truy cập internet và không biết gì về việc nó có tới được một địa chỉ riêng tư qua tunnel hay không. Tương tự, mở một terminal mới chỉ chứng minh terminal mới chạy được, không chứng minh nó chia sẻ môi trường thực thi với ứng dụng đã lỗi.
Docker Desktop có thể chạy được với VPN
Tài liệu của chính Docker về VPN và kết nối host mô tả đây là một thiết lập được hỗ trợ, và tóm tắt trung thực là nó chạy được chứ không tự động hỏng. Đừng cho rằng máy ảo trên desktop bỏ qua tunnel của host như một vấn đề thiết kế; trong nhiều thiết lập, lưu lượng đi theo tunnel của host một cách chính xác, đó là lý do vì sao lời đồn "Docker phớt lờ VPN" tạo ra những lời khuyên tự tin và sai.
Điều vẫn quan trọng là backend đang dùng, chính sách split-tunnel của client, và cấu hình resolver mà máy ảo nhận được. Một client VPN cài tuyến đường nhưng không cài DNS, hoặc đẩy một DNS server mà máy ảo không tới được, sẽ tạo ra lỗi tra cứu tên bên trong container trong khi host vẫn chạy vì host có thêm resolver hoặc một câu trả lời đã cache. Đó là vấn đề resolver khoác áo container. Nó tồn tại qua mọi lần kết nối lại VPN bạn thử, vì tunnel đã mang đúng lưu lượng mà bạn yêu cầu nó mang.
Chồng lấn địa chỉ và MTU là những lỗi khác nhau
Hai lỗi xứng đáng được chẩn đoán riêng vì chúng thường bị nhầm với chính sách truy cập. Thứ nhất là chồng lấn địa chỉ: nếu VPN đẩy một dải trùng với subnet bridge mặc định của mạng container, tuyến đường của container cho dải đó trỏ vào bridge cục bộ và không bao giờ tới tunnel. Hãy kiểm tra các subnet thực tế thay vì đoán:
docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
ip route get 10.20.30.40
Thứ hai là vấn đề MTU. Nếu kết nối được thiết lập và TLS hoàn tất nhưng các phản hồi lớn hơn bị treo, bạn có vấn đề kích thước gói, không phải vấn đề phân quyền, và thay bản ghi DNS sẽ không bao giờ sửa được. Hãy thử với một yêu cầu nhỏ và một yêu cầu lớn trước khi đổi bất cứ thứ gì, và ghi lại cả hai kết quả.
Cách sửa cho chồng lấn là một subnet container khác hoặc một tuyến đường có phạm vi, do người sở hữu quy hoạch địa chỉ chọn. Cách sửa cho tình trạng treo MTU là kẹp hoặc giảm MTU của tunnel hay interface xuống một giá trị chịu được đường đi, áp dụng ở tầng bạn kiểm soát.
Cấu hình proxy là theo tiến trình, không theo máy
Bên trong container, localhost đặt tên cho ngữ cảnh mạng của chính container đó, nên một proxy chạy trên host không tới được ở đó dưới tên ấy. Docker Desktop cung cấp host.docker.internal cho truy cập host, và trên Linux bạn thêm nó một cách tường minh bằng --add-host=host.docker.internal:host-gateway. Dù thế nào, tên đó cho bạn một tuyến đường tới host; nó không tạo ra một dịch vụ proxy và không cấp quyền cho bạn dùng nó.
Dùng địa chỉ và cổng proxy được cung cấp cho môi trường thực tế, và kiểm tra xem ai đang đọc nó. Các biến được export trong một shell tương tác không tự động cấu hình mọi tiện ích mở rộng của editor, language server, công cụ build và daemon nền. Cái quan trọng là tiến trình đã gửi yêu cầu bị lỗi, nên hãy kiểm tra môi trường của nó chứ không phải của terminal bạn.
Cuối cùng, hãy để cách sửa tự giải thích. Một giải pháp hữu ích nêu tên ranh giới đã sai, cài đặt đã thay đổi nó, và tập tiến trình mà nó tác động tới. Khởi động lại VPN, editor và engine lần lượt có thể đổi triệu chứng, nhưng không để lại gì cho người tiếp theo dùng.