Пады, якія запусцілі OpenVPN сайдкар, правальваюць развязанне імёнаў па пазнавальным узоры: імёны кластара завісаюць, аддаленыя імёны адказваюць, пакуль под не перазапусціцца, а адрэдагаваны вамі файл resolver вяртаецца да ранейшага. Нішто ў гэтай паслядоўнасці не з'яўляецца дэфектам тунеля. Под мае адзін файл resolver і два светы іменавання, а файл можа пералічыць серверы па парадку, але не можа выразіць зоны. Трывалае рашэнне — гэта resolver, які працуе ўнутры пода і валодае падзелам, таму файл застаецца простым і ніводная палітыка не мае прычыны яго перапісваць.

Чаму змена, якую вы зрабілі, увесь час знікае

Файл належыць kubelet, а не вам. Пад dnsPolicy: ClusterFirst kubelet стварае яго, каб паказваць на кластарны DNS, і перастварае яго кожны раз, калі запускаецца кантэйнер. Усё, што вы зменіце праз kubectl exec, жыве ў запісваемым пласце кантэйнера, таму перазапуск, выцясненне або rollout яго адкідаюць. Спецыфікацыя пода па-ранейшаму нясе тую ж палітыку, таму той самы файл вяртаецца.

Усталяванне dnsPolicy: None спыняе перастварэнне і таксама выдаляе развязанне ўнутры кластара. Вы атрымліваеце файл, які кантралюеце, і губляеце імёны, што вам былі патрэбны. Гэты абмен і ёсьць уся праблема: resolv.conf не ведае зон, толькі серверы, якія трэба паспрабаваць па парадку, таму не можа адправіць cluster.local на адзін адрас, а прыватную зону на іншы.

Запусціце адзін resolver ў подзе, на loopback

Накіруйце под на адзін сервер імёнаў на loopback, затым дайце кантэйнеру CoreDNS, які дзеліць сеткавую прастору імёнаў пода, адказваць на порце 53. Усталюйце палітыку ў None, дайце поду гэты адзін адрас і дадайце DNS кантэйнер побач з VPN і праграмай:

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

Усе тры кантэйнеры дзеляць адну сеткавую прастору імёнаў, таму 127.0.0.1:53 з кантэйнера праграмы дасягае CoreDNS без сэрвісу, без port-forward і без аб'езду праз сетку кластара. Мантаванне Corefile з ConfigMap захоўвае яго як версіянаваны ўваход замест файла, які рэдагуецца на месцы. Створаны resolv.conf тады трымае адзін сервер імёнаў і больш нічога, што з'яўляецца станам, пра які можна разважаць.

Дзве дэталі кусаюць тут. Афіцыйны вобраз прывязвае порт 53 як root, а некаторыя палітыкі кластара патрабуюць напісаць гэта яўна. Кожны кантэйнер у подзе цяпер залежыць ад таго, што гэты адзін кантэйнер працуе, таму дадайце readiness праверку супраць бясшкоднага імя і дазвольце праграме цярпець збоі пры запуску.

Дайце кожнай прыватнай зоне ўласны upstream

Corefile — гэта спіс зон, кожная называе сервер, які можа на яе адказаць. Адзін блок пакрывае тунельную зону, а блок, які ловіць усё, ідзе апошнім і забірае усё, што ніводзін яўны блок не заявіў. Блок, які ловіць усё, павінен накіроўвацца на сапраўдны upstream, ніколі назад на под: .:53 { forward . 10.100.0.10 } паўторна выкарыстоўвае кластарны resolver, бо той resolver ужо перасылае публічныя імёны resolver-ам самога вузла. Больш нішта ў подзе не павінна ведаць, да якой сеткі належыць імя.

.:53 {
  errors
  cache 30
  forward . 10.100.0.10
}

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

Прачытайце адрас кластара з сэрвісу kube-dns у kube-system замест таго, каб капіраваць яго з артыкула, бо сэрвісныя CIDR-ы розныя. Адрас тунеля прыходзіць з значэння dhcp-option DNS, якое пасылае сервер OpenVPN, або з аўтарытэтнага сервера для гэтай зоны. Калі ваш кластарны resolver не адказвае на публічныя імёны, пастаўце адрас resolver вузла ў блок, які ловіць усё, прачытаны на вузле, а не ўнутры пода.

Не накіроўвайце блок, які ловіць усё, на /etc/resolv.conf, гэта спакуслівы аднарадковы варыянт і пастка ў менавіта гэтай наладзе. Пад dnsPolicy: None файл самога пода змяшчае адзін сервер імёнаў 127.0.0.1, таму гэтая мэта — сам CoreDNS, і кожны несупастаўлены запыт рэкурсіць, пакуль не скончыцца час. Блок з назвай svc.acme.internal супадае з гэтым імем і кожным імем пад ім, што пакрывае db.svc.acme.internal і выключае svc.acme.internal.example.net. Заключная кропка — касметычная, бо назвы зон нармалізуюцца да цалкам кваліфікаванай формы; мяжа суфікса вырашае, куды трапляе запыт.

Вырашыце, ці належыць перасыланне кластарнаму resolver

Калі кожная нагрузка ў namespace мае патрэбу ў тунельнай зоне, блок перасылання ў CoreDNS ConfigMap пад kube-system таннейшы за сайдкар на под. Гэтая змена мае маштаб кластара: яна патрабуе правоў адміністратара і перазапуску deployment, ад якога усе залежаць. Абмяжуйце яе гэтай адной зонай, ніколі коранем. Адрас тунеля аднае нагрузкі тады становіцца resolver кожнага пода для зоны, і ў дзень, калі тунель падае, увесь кластар губляе імя.

Сайдкар трымае радыус выбуху ўнутры аднага пода, што з'яўляецца лепшым тыповым выбарам, калі толькі некалькі сэрвісаў маюць патрэбу ў аддаленай сеткы. Што б вы ні абралі, запішыце, які resolver валодае зонай, бо наступны чалавек, які будзе выпраўляць тайм-аўт, спытае.

Імёны, якія развязваюцца, пакуль злучэнні яшчэ правальваюцца

Развязанне — адно з двух рэчаў, якія тунель мусіць несці; другое — зваротны шлях, а сетка пода добра яго хавае. Калі сам сервер OpenVPN працуе як под, правілы, якія вы дадаяце ўнутры гэтага кантэйнера, не керуюць трафікам, што выходзіць праз вузел. Гэты збой вузкі: толькі пады на вузле, які таксама запускаў сервер, атрымлівалі адказы, а усё астатняе скончылася тайм-аўтам.

Запуск сервера з hostNetwork: true вяртае яго ў прастору імёнаў вузла, дзе дзейнічаюць правіла FORWARD і трансляцыя крыніцы. Транслюйце кліенцкі pool на выхадзе, інакш ніводзін аддалены вузел не мае маршруту назад да тунельнага адраса, як 10.8.0.6. Праверце абодва кірункі, перш чым зноў чапаць Corefile. Тунель, які нясе запыт, але не адказ, дае дакладна такі ж тайм-аўт, як resolver, які ніколі не атрымаў запыт.

Праверце з новага пода, а не з сесіі, якую вы выправілі

Спытайце абедзве зоны яўна, затым паўтарыце запыт пасля замены пода. Канфігурацыя, якая існуе толькі ў працуючым кантэйнеры, не з'яўляецца канфігурацыяй:

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

Калі першая пара адказвае, а пара пасля замены не, Corefile у парадку, а спецыфікацыя пода не. Калі абедзве адказваюць, а праграма усё яшчэ не можа падключыцца, спыніце адладку DNS і праверце TCP шлях з nc -vz db.svc.acme.internal 5432 знутры кантэйнера. Захавайце вывад dig у тыкеце, бо гэта артэфакт, які аддзяляе праблему іменавання ад праблемы маршрутызацыі.

Падобныя артыкулы