Pod yang menjalankan OpenVPN sidecar gagal menyelesaikan nama dengan pola yang mudah dikenali: nama klaster menggantung, nama jarak jauh menjawab sampai pod dimulai ulang, dan berkas resolver yang Anda edit kembali seperti semula. Tidak ada satu pun dari urutan itu yang merupakan gangguan terowongan. Sebuah pod punya satu berkas resolver dan dua dunia penamaan, dan berkas itu bisa mendaftar server secara berurutan tetapi tidak bisa menyatakan zona. Perbaikan yang tahan lama adalah resolver yang berjalan di dalam pod dan memiliki pemisahan itu, sehingga berkasnya tetap sederhana dan tidak ada kebijakan yang punya alasan untuk menulisnya ulang.

Mengapa suntingan yang Anda buat terus hilang

Berkas itu milik kubelet, bukan milik Anda. Di bawah dnsPolicy: ClusterFirst kubelet membuatnya untuk menunjuk ke DNS klaster, dan membuatnya ulang setiap kali kontainer mulai. Apa pun yang Anda ubah lewat kubectl exec hidup di lapisan tulis kontainer, jadi mulai ulang, pengusiran, atau rollout membuangnya. Spesifikasi pod tetap membawa kebijakan yang sama, itulah sebabnya berkas yang sama kembali.

Menyetel dnsPolicy: None menghentikan pembuatan ulang dan juga menghapus resolusi klaster. Anda mendapat berkas yang Anda kendalikan dan kehilangan nama yang Anda butuhkan. Pertukaran itu adalah seluruh masalahnya: resolv.conf tidak punya gagasan tentang zona, hanya server yang dicoba berurutan, jadi ia tidak bisa mengirim cluster.local ke satu alamat dan zona privat ke alamat lain.

Jalankan satu resolver di pod, di loopback

Arahkan pod ke satu server nama di loopback, lalu biarkan kontainer CoreDNS yang berbagi ruang nama jaringan pod menjawab di port 53. Setel kebijakannya ke None, beri pod alamat tunggal itu, dan tambahkan kontainer DNS di samping VPN dan aplikasi:

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

Ketiga kontainer berbagi satu ruang nama jaringan, jadi 127.0.0.1:53 dari kontainer aplikasi mencapai CoreDNS tanpa layanan, tanpa port-forward, dan tanpa memutar lewat jaringan klaster. Me-mount Corefile dari ConfigMap menjaganya sebagai masukan berversi alih-alih berkas yang diedit di tempat. resolv.conf yang dihasilkan lalu hanya berisi satu server nama dan tidak ada yang lain, keadaan yang bisa Anda pikirkan.

Dua detail menggigit di sini. Image resmi mengikat port 53 sebagai root, dan beberapa kebijakan klaster menuntut Anda menuliskannya secara eksplisit. Setiap kontainer di pod kini bergantung pada kontainer tunggal itu hidup, jadi tambahkan readiness probe terhadap nama yang tidak berbahaya dan biarkan aplikasi menoleransi kegagalan saat mulai.

Beri setiap zona privat upstream-nya sendiri

Corefile adalah daftar zona, masing-masing menyebut server yang bisa menjawabnya. Satu blok mencakup zona terowongan, dan blok yang menangkap semua datang terakhir dan mengambil apa pun yang tidak diklaim blok eksplisit. Blok penangkap semua harus mengarah ke upstream sungguhan, jangan pernah kembali ke pod: .:53 { forward . 10.100.0.10 } memakai ulang resolver klaster karena resolver itu sudah meneruskan nama publik ke resolver node itu sendiri. Tidak ada hal lain di pod yang perlu tahu ke jaringan mana sebuah nama milik.

.:53 {
  errors
  cache 30
  forward . 10.100.0.10
}

svc.acme.internal:53 {
  errors
  cache 30
  forward . 192.168.240.1
}

Baca alamat klaster dari layanan kube-dns di kube-system alih-alih menyalinnya dari artikel, karena CIDR layanan berbeda. Alamat terowongan berasal dari nilai dhcp-option DNS yang dikirim server OpenVPN, atau dari server otoritatif untuk zona itu. Jika resolver klaster Anda tidak menjawab nama publik, taruh alamat resolver node di blok penangkap semua, dibaca di node dan bukan di dalam pod.

Jangan arahkan blok penangkap semua ke /etc/resolv.conf, yang merupakan satu baris menggoda dan jebakan dalam penyiapan yang tepat ini. Di bawah dnsPolicy: None berkas pod itu sendiri berisi satu-satunya server nama 127.0.0.1, jadi sasaran itu adalah CoreDNS sendiri dan setiap kueri yang tidak cocok berulang sampai waktu habis. Blok bernama svc.acme.internal cocok dengan nama itu dan setiap nama di bawahnya, yang mencakup db.svc.acme.internal dan mengecualikan svc.acme.internal.example.net. Titik di akhir bersifat kosmetik, karena nama zona dinormalisasi ke bentuk yang sepenuhnya memenuhi syarat; batas sufiks yang menentukan di mana kueri mendarat.

Putuskan apakah penerusan itu milik resolver klaster

Jika setiap workload di namespace butuh zona terowongan, blok penerusan di ConfigMap CoreDNS di bawah kube-system lebih murah daripada sidecar per pod. Perubahan itu berskala klaster: ia membutuhkan hak administrator dan mulai ulang deployment yang menjadi sandaran semua orang. Batasi pada zona itu saja, jangan pernah ke akar. Alamat terowongan satu workload lalu menjadi resolver setiap pod untuk zona itu, dan pada hari terowongan putus seluruh klaster kehilangan nama itu.

Sidecar menjaga radius ledakan di dalam satu pod, yang merupakan default lebih baik ketika hanya sedikit layanan yang membutuhkan jaringan jarak jauh. Apa pun yang Anda pilih, catat resolver mana yang memiliki zona itu, karena orang berikutnya yang men-debug timeout akan bertanya.

Nama yang tetap teresolusi saat koneksi masih gagal

Resolusi adalah satu dari dua hal yang harus dibawa terowongan; yang lain adalah jalur balik, dan jaringan pod menyembunyikannya dengan baik. Jika server OpenVPN sendiri berjalan sebagai pod, aturan yang Anda tambahkan di dalam kontainer itu tidak mengatur lalu lintas yang keluar lewat node. Kegagalan itu sempit: hanya pod di node yang juga menjalankan server yang mendapat jawaban, dan semua yang lain kehabisan waktu.

Menjalankan server dengan hostNetwork: true mengembalikannya ke ruang nama node, tempat aturan FORWARD dan penerjemahan sumber berlaku. Terjemahkan pool klien saat keluar, atau tidak ada node jarak jauh yang punya rute balik ke alamat terowongan seperti 10.8.0.6. Periksa kedua arah sebelum menyentuh Corefile lagi. Terowongan yang membawa kueri tetapi bukan jawabannya menghasilkan timeout yang persis sama dengan resolver yang tidak pernah menerima kueri.

Verifikasi dari pod baru, bukan dari sesi yang Anda perbaiki

Tanyakan kedua zona secara eksplisit, lalu ulangi kueri setelah pod diganti. Konfigurasi yang hanya ada di kontainer yang berjalan bukanlah konfigurasi:

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

Jika pasangan pertama menjawab dan pasangan setelah penggantian tidak, Corefile benar dan spesifikasi pod tidak. Jika keduanya menjawab dan aplikasi tetap tidak bisa terhubung, berhenti men-debug DNS dan uji jalur TCP dengan nc -vz db.svc.acme.internal 5432 dari dalam kontainer. Simpan keluaran dig di tiket, karena itulah artefak yang memisahkan masalah penamaan dari masalah perutean.

Artikel terkait