DNS'i Kubernetes ile bir OpenVPN sidecar arasında nasıl bölersiniz
Bir sidecar pod'unun iki ad dünyasına ihtiyacı vardır. Bir loopback resolver'ı kümeye ve tünele yönlendirin ve düzenlenmiş resolv.conf'a bağımlılığı bırakın.
OpenVPN sidecar çalıştıran pod'lar ad çözümlemede tanıdık bir desenle başarısız olur: küme adları askıda kalır, uzak adlar pod yeniden başlayana kadar yanıtlar ve düzenlediğiniz resolver dosyası geri döner. Bu dizide hiçbir şey tünel arızası değildir. Bir pod'un bir resolver dosyası ve iki ad dünyası vardır ve dosya sunucuları sırayla listeleyebilir ama bölgeleri ifade edemez. Kalıcı çözüm, pod'un içinde çalışan ve bölmeye sahip olan bir resolver'dır, böylece dosya basit kalır ve hiçbir politikanın onu yeniden yazmak için sebebi olmaz.
Yaptığınız değişiklik neden sürekli kayboluyor
Dosya kubelet'e aittir, size değil. dnsPolicy: ClusterFirst altında kubelet onu küme DNS'ine işaret etmek için üretir ve her konteyner başladığında yeniden üretir. kubectl exec ile değiştirdiğiniz her şey konteynerin yazılabilir katmanında yaşar, bu yüzden yeniden başlatma, tahliye veya rollout onu atar. Pod spesifikasyonu hâlâ aynı politikayı taşır, bu yüzden aynı dosya geri gelir.
dnsPolicy: None ayarı yeniden üretimi durdurur ve küme çözümlemesini de kaldırır. Kontrol ettiğiniz bir dosya kazanır ve ihtiyaç duyduğunuz adları kaybedersiniz. Bu takas tüm sorundur: resolv.conf bölge kavramını bilmez, yalnızca sırayla denenecek sunucuları bilir, bu yüzden cluster.local'yi bir adrese, özel bir bölgeyi başka bir adrese gönderemez.
Pod içinde bir resolver çalıştırın, loopback üzerinde
Pod'u loopback üzerindeki tek bir ad sunucusuna yönlendirin, sonra pod'un ağ ad alanını paylaşan bir CoreDNS konteynerinin 53 numaralı bağlantı noktasında yanıt vermesine izin verin. Politikayı None olarak ayarlayın, pod'a o tek adresi verin ve VPN ile uygulamanın yanına DNS konteynerini ekleyin:
spec:
dnsPolicy: None
dnsConfig:
nameservers:
- 127.0.0.1
options:
- name: ndots
value: "5"
containers:
- name: dns
image: coredns/coredns
args: ["-conf", "/etc/coredns/Corefile"]
volumeMounts:
- {name: corefile, mountPath: /etc/coredns, readOnly: true}
- name: vpn
image: your-openvpn-client-image
- name: app
image: your-app-image
volumes:
- name: corefile
configMap:
name: split-dns-corefileÜç konteyner de tek bir ağ ad alanını paylaşır, bu yüzden uygulama konteynerinden 127.0.0.1:53 hizmet olmadan, port-forward olmadan ve küme ağı üzerinden dolaşmadan CoreDNS'e ulaşır. Corefile'ı bir ConfigMap'ten bağlamak onu yerinde düzenlenen bir dosya yerine sürümlenmiş girdi olarak tutar. Üretilen resolv.conf o zaman tek bir ad sunucusu ve başka hiçbir şey içermez, üzerinde akıl yürütülebilecek bir durum.
Burada iki ayrıntı ısırır. Resmi imaj 53 numaralı bağlantı noktasını root olarak bağlar ve bazı küme politikaları bunu açıkça yazmanızı ister. Pod'daki her konteyner artık o tek konteynerin çalışmasına bağlıdır, bu yüzden zararsız bir ada karşı readiness probe ekleyin ve uygulamanın başlangıç hatalarını tolere etmesine izin verin.
Her özel bölgeye kendi upstream'ini verin
Corefile bir bölge listesidir, her biri onu yanıtlayabilecek sunucuyu adlandırır. Bir blok tünel bölgesini kapsar ve catch-all bloğu en son gelir ve hiçbir açık bloğun talep etmediği her şeyi alır. Catch-all gerçek bir upstream'e yönelmelidir, asla pod'a geri dönmemelidir: .:53 { forward . 10.100.0.10 } küme resolver'ını yeniden kullanır çünkü o zaten genel adları düğümün kendi resolver'larına iletir. Pod'daki başka hiçbir şeyin bir adın hangi ağa ait olduğunu bilmesi gerekmez.
.:53 {
errors
cache 30
forward . 10.100.0.10
}
svc.acme.internal:53 {
errors
cache 30
forward . 192.168.240.1
}Küme adresini makaleden kopyalamak yerine kube-system içindeki kube-dns hizmetinden okuyun, çünkü hizmet CIDR'leri farklıdır. Tünel adresi OpenVPN sunucusunun gönderdiği dhcp-option DNS değerinden veya o bölgenin yetkili sunucusundan gelir. Küme resolver'ınız genel adlara yanıt vermiyorsa, düğümün resolver adresini catch-all bloğuna koyun, düğümde okunmuş olarak, pod içinde değil.
Catch-all'ı /etc/resolv.conf adresine yönlendirmeyin, bu cazip tek satırlık çözüm ve tam bu kurulumda bir tuzaktır. dnsPolicy: None altında pod'un kendi dosyası tek ad sunucusu olan 127.0.0.1'yı içerir, bu yüzden bu hedef CoreDNS'in kendisidir ve eşleşmeyen her sorgu zaman aşımına uğrayana kadar yinelenir. svc.acme.internal adlı blok o adla ve altındaki her adla eşleşir, bu da db.svc.acme.internal'i kapsar ve svc.acme.internal.example.net'u hariç tutar. Sondaki nokta kozmetiktir, çünkü bölge adları tam nitelikli biçime normalleştirilir; sorgunun nereye düşeceğini sonek sınırı belirler.
Yönlendirmenin küme resolver'ına ait olup olmadığına karar verin
Ad alanındaki her iş yükü tünel bölgesine ihtiyaç duyuyorsa, kube-system altındaki CoreDNS ConfigMap'inde bir yönlendirme bloğu pod başına sidecar'dan daha ucuzdur. Bu değişiklik küme düzeyindedir: yönetici hakları ve herkesin bağlı olduğu bir dağıtımın yeniden başlatılmasını gerektirir. Bunu o tek bölgeyle sınırlayın, asla kökle değil. Tek bir iş yükünün tünel adresi o zaman bölge için her pod'un resolver'ı olur ve tünelin düştüğü gün tüm küme adı kaybeder.
Sidecar patlama yarıçapını tek bir pod içinde tutar, bu da uzak ağa yalnızca birkaç hizmetin ihtiyaç duyduğu durumda daha iyi varsayılandır. Neyi seçerseniz seçin, hangi resolver'ın bölgeye sahip olduğunu not edin, çünkü zaman aşımında hata ayıklayan sıradaki kişi bunu soracaktır.
Bağlantılar hâlâ başarısız olurken çözülen adlar
Çözümleme tünelin taşıması gereken iki şeyden biridir; diğeri dönüş yolu ve pod ağı bunu iyi gizler. OpenVPN sunucusu kendisi bir pod olarak çalışıyorsa, o konteynere eklediğiniz kurallar düğümden çıkan trafiği yönetmez. Bu arıza dardır: yalnızca sunucuyu da çalıştıran düğümdeki pod'lar yanıt aldı ve diğer her şey zaman aşımına uğradı.
Sunucuyu hostNetwork: true ile çalıştırmak onu düğümün ad alanına geri koyar, burada bir FORWARD kuralı ve kaynak çevirisi etkilidir. Çıkışta istemci havuzunu çevirin, yoksa hiçbir uzak düğümün 10.8.0.6 gibi bir tünel adresine dönüş rotası olmaz. Corefile'a tekrar dokunmadan önce iki yönü de kontrol edin. Sorguyu taşıyıp yanıtı taşımayan bir tünel, sorguyu hiç almayan bir resolver ile tamamen aynı zaman aşımını üretir.
Düzelttiğiniz oturumdan değil, yeni bir pod'dan doğrulayın
Her iki bölgeye açıkça sorun, sonra pod değiştirildikten sonra sorguyu yineleyin. Yalnızca çalışan bir konteynerde var olan yapılandırma yapılandırma değildir:
kubectl exec -it deploy/app -- dig @127.0.0.1 kubernetes.default.svc.cluster.local +short
kubectl exec -it deploy/app -- dig @127.0.0.1 db.svc.acme.internal +short
kubectl delete pod -l app=your-app
kubectl wait --for=condition=Ready pod -l app=your-app --timeout=90s
kubectl exec -it deploy/app -- dig @127.0.0.1 db.svc.acme.internal +shortİlk çift yanıt veriyor ve değiştirmeden sonraki çift vermiyorsa Corefile doğru ve pod spesifikasyonu değil. İkisi de yanıt veriyor ama uygulama hâlâ bağlanamıyorsa DNS hata ayıklamayı bırakın ve konteynerin içinden nc -vz db.svc.acme.internal 5432 ile TCP yolunu test edin. dig çıktısını bilete koyun, çünkü ad sorununu yönlendirme sorunundan ayıran eser odur.