Bu ilkbaharda bir sabahın çoğunu, tek bir iç adı bile çözemeyen bir kapsayıcının peşinden koşarak geçirdim; yanındaki tarayıcı ise wiki'yi hiç yakınmadan açıyordu. Tünel ayaktaydı, tarayıcı bunu kanıtlıyordu ve kapsayıcı başka bir rota tablosu ve başka bir çözümleyiciye sahip farklı bir ağ ad alanında duruyordu. Sırada şu an denetlediğim sıra var: önce rota tabloları, sonra ad çözümleme, ardından iletme ve en son ana makine platformu. Zaten başarısız olan ilk adımda durun, çünkü yığının altına kural eklemek sınırı taşımak yerine gizler.

Bir kuralı değiştirmeden önce üç rota tablosunu karşılaştırın

Docker'ın varsayılan köprüsündeki bir kapsayıcının docker0 geçidine giden tek bir varsayılan rotası vardır ve tun0'ın varlığından haberi yoktur. Ana makinede tun0, VPN'in ittiği rotalar ve belki de test trafiğini beklediğinizden farklı bir arayüzden çıkaran bir ilke kuralı vardır. WSL kendi sanal bağdaştırıcısının arkasına üçüncü bir tablo ekler. Herhangi birini düzenlemeden önce üçünü de yazdırın.

ContextCommandWhat a wrong answer looks like
Hostip route get 10.8.0.20Leaves a physical interface instead of tun0
Containerip routeOnly 172.17.0.0/16 via 172.17.0.1
Container DNScat /etc/resolv.confA public resolver, or an upstream the tunnel never pushed
WSLip addr; ip routeOnly the WSL subnet, no Windows VPN adapter

Kapsayıcının tek rotası köprüyse ve tun0 onun ad alanında hiç görünmüyorsa, aşağıdakilerin hiçbiri yardımcı olmaz: hiçbir ad sunucusu değişikliği rota yaratmaz ve hiçbir rota eşin kabul edeceği tünel kimliğini yaratmaz. Sıra önemlidir çünkü bir DNS arızası ile bir rota arızası kabuğun içinden aynı görünür.

Çözümleyiciyi genel bir taneye değil tünele yönlendirin

Ana makinede, resolvectl status her bağlantı için DNS sunucularını listeler ve readlink -f /etc/resolv.conf dosyanın systemd saplaması mı, bir NetworkManager dosyası mı yoksa bir sağlayıcı istemcisinin yeniden yazdığı bir şey mi olduğunu söyler. Kullanıcı tanımlı bir ağdaki kapsayıcının içinde, /etc/resolv.conf şunu adlandırır: 127.0.0.11, Docker'ın gömülü çözümleyicisi; bu, arka plan servisinin yapılandırıldığı üst akışa iletir. Varsayılan köprüdeki kapsayıcı ise oluşturulurken ana makinenin dosyasının bir kopyasını aldı ve onu tutuyor.

O kopya, kapsayıcı başladıktan sonra ayağa kalkan bir tünelin kapsayıcıyı eski üst akışa sormaya bırakmasının nedenidir. Ya VPN çözümleyicisini açıkça şununla geçirin docker run --dns 10.8.0.53, ya "dns": ["10.8.0.53"] içinde /etc/docker/daemon.json ayarlayıp servisi yeniden başlatın, ya da tünel ayaktayken kapsayıcıyı yeniden oluşturun. Yeniden oluşturmak genellikle bir saat önce doğru olan bir çözümleyiciyi ayıklamaktan daha ucuzdur.

Genel bir çözümleyici koymak belirtiyi koruyan onarımdır. İnterneti çözer ama her özel bölgede başarısız olur ve tünelin var olma nedenini oluşturan filtrelemeyi sessizce atlayabilir. Çalışan bir kapsayıcının /etc/resolv.conf içine yazmayı denerseniz, şunu bekleyin Device or resource busy: Docker o dosyayı bind-mount eder, bu yüzden düzenleme önce ayırma gerektirir. --dns oluşturma sırasında ayarlamak yeniden başlatmaya dayanan sıradır.

Kapsayıcılar tüneli ödünç aldığında iletin ve çevirin

Varsayılan köprüyle ana makine docker0 ile tun0 arasında bir yönlendiricidir ve varsayılan olarak iki işi de yapmaz. İletmeyi açın ve kaynak adresi çevirin; böylece eş, geri dönüş rotası olmayan bir adres yerine ana makinenin tünel adresini görsün (tun0'ı istemcinizin arayüze verdiği adla değiştirin):

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A FORWARD -i docker0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o docker0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

FORWARD kuralları iletme ilkesi DROP olan ana makinelerde önemlidir. Docker kendi zincirlerini ekler, bu yüzden okumak yerine bir paketle test edin iptables -S: kapsayıcıdan, ip route get 10.8.0.20 köprünün geçidini adlandırmalı ve nc -vz 10.8.0.20 443 çözümleyicide değil tünelde bağlanmalı ya da zaman aşımına uğramalı.

MASQUERADE olmadan eşin 172.17.0.0/16'ya geri dönüş rotasına ihtiyacı vardır; çoğu uzaktan erişim VPN'i bunu itmez. Planı burada ilke tabanlı bir istemci de bozar: yalnızca belirli UID'lerin veya cgroups'ların trafiğini yakalıyorsa, iletme kurallarınız tünelin içindeki paketi hiç görmez ve düzeltme iptables'a değil istemcinin yönlendirme ilkesine aittir. Elle eklenen kurallar yeniden başlatmada kaybolur, bu yüzden onları bir systemd birimine veya netfilter-persistent tablosuna koyun ve yeniden başlatmadan sonra tekrar test edin, çünkü geç ayağa kalkan bir tünel onları süpürebilir.

Amaç yalıtım olduğunda tüneli kapsayıcının içine koyun

Bir kapsayıcı belirli bir düğümden çıkmalıysa, istemciyi o kapsayıcıda çalıştırın. Şunlara ihtiyacı vardır: --cap-add NET_ADMIN ve --device /dev/net/tun, ve sonra kendi tun0'ına, rotalarına ve güvenlik duvarına sahip olur. Diğer kapsayıcılar onun üzerinden geçiyorsa, kapsayıcının içinde iletme ve bir MASQUERADE kuralı da gerekir ve o eşlerin ona işaret eden açık bir rotaya veya vekile ihtiyacı vardır; Docker'ın varsayılan köprüsü o rotayı sizin için eklemez.

Ana makine ağları, docker run --network host, ucuz sürümdür: kapsayıcı ana makinenin ad alanına katılır ve tünel rotalarını doğrudan görür. Ağ yalıtımını da bırakır, bağlantı noktası çakışmalarını davet eder ve pratikte bir Linux seçeneğidir. Yayımlanmış bağlantı noktası onun yerine geçmez. -p 8080:80 bir hizmeti ana makineden erişilebilir kılar; iç 10.x adreslerini kapsayıcının içinden erişilebilir kılmaz ve ikisini karıştırmak, bir yönlendirme sorununun açık bir veritabanı bağlantı noktasına dönüşme yoludur.

Ad arızasını çakışan bir alt ağdan ayırın

Docker'ın varsayılan köprüsü 172.17.0.0/16'dır ve birçok kurumsal VPN havuzu 172.16.0.0/12 içinde yer alır. Tünel o aralığa sahip olduğunda, bir kapsayıcı için amaçlanan trafik bunun yerine tünele yönlendirilebilir. Adlar başarısız olur, hata DNS gibi görünür ve sorun adreslerdedir. Hedefi denetleyin, çözümleyiciyi değil: ip route get 172.17.0.5 ana makinede, sonra köprü önekini VPN havuzuyla ve şununla karşılaştırın: docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'.

Onarım aralıklardan birini taşımaktır: ya daemon.json içinde Docker için başka bir varsayılan adres havuzu ya da toplayıcıda başka bir havuz. Buraya bir ad sunucusu daha eklemek hiçbir şey yapmaz, ssh -b da yapmaz: istemciyi bir arayüze bağlamak kaynak adresi değiştirir, tünele işaret eden hedef rotayı değil. Hızlı iş bölümü: ana makinede çözülen ama kapsayıcıda çözülmeyen bir ad çözümleyici sorunudur, oysa kapsayıcıda takılan ama ana makinede çalışan doğrudan bir IP bağlantısı rota veya iletme zinciri sorunudur.

WSL ve Docker Desktop Linux kurallarına uymaz

Varsayılan NAT modunda WSL kendi sanal bağdaştırıcısının arkasında oturur ve Windows VPN'inin iç rotalarını veya DNS soneklerini almaz, bu yüzden tarayıcı çalışır ve ping dağıtım içinde çalışmaz. Son Windows 11 derlemelerinde bulunan yansıtılmış ağ bunun yerine ana makinenin arayüzlerini paylaşır, ancak .wslconfig içinde etkinleştirilmesi ve dağıtımın wsl --shutdown ile yeniden başlatılması gerekir. Etkin modu wslinfo --networking-mode ile doğrulayın, bir düzeltme uygulamadan önce, çünkü NAT yanıtı yansıtılmış mod için yanlış ve tersi de öyle.

Docker Desktop bir katman daha ekler. Windows'taki Linux kapsayıcıları tarihsel olarak vpnkit denen bir NAT uygulamasının arkasında oturur ve yolları yerel bir Linux ana makinesinden farklıdır. Windows kapsayıcıları bir Hyper-V sanal anahtarı üzerinden bağlanır ve kurumsal bir istemci o anahtardan gelen trafiği engelleyebilir, bu yüzden aynı makinedeki Linux kapsayıcıları ağa ulaşabilirken Windows kapsayıcılarının hiçbir şeyi yoktur. Fiziksel bağdaştırıcıya bağlı harici bir anahtar olağan çözümdür ve kapsayıcının ağ kimliğini ilkenin izin vermeyebileceği biçimlerde değiştirir.

Bir kural daha yazmadan önce dört katmanı sırayla geçin ve hangisi yanlışsa orada durun:

  • Kapsayıcının içinde: ip route özel öneke ulaşıyor mu ve /etc/resolv.conf onu çözen bir üst akışı adlandırıyor mu?
  • Ana makinede: iletme açık mı, NAT tünel arayüzüne bağlı mı ve iletme zinciri köprüden tünele izin veriyor mu?
  • Eşte: geri dönüş yolunu biliyor mu, yoksa kapsayıcı alt ağını gizlemek için NAT'a mı güveniyorsunuz?
  • Platformda: WSL NAT mı yansıtılmış modda mı ve kapsayıcı Linux mu Windows mu?

Her testi yeni bir kapsayıcıda veya kabukta yeniden çalıştırın. Önbelleğe alınmış yanıtı veya kurulmuş bağlantısı olan uzun süreli bir süreç, yapılandırma doğru olduktan sonra da başarısız olmaya devam eder ve bu arıza tam olarak işe yaramayan bir onarım gibi görünür.

İlgili makaleler