Како поделити DNS између Kubernetes кластера и OpenVPN сајдкара
Сајдкар поду су потребна два света именовања. Усмерите један loopback resolver ка кластеру и тунелу и престаните да зависите од измењеног resolv.conf-а.
Поди који покрећу OpenVPN сајдкар падају на разрешавању имена по препознатљивом обрасцу: називи кластера се блокирају, удаљени називи одговарају док се под не рестартује, а ваша измењена датотека resolver-а се враћа на старо. Ништа у том низу није квар тунела. Под има једну датотеку resolver-а и два света именовања, а датотека може да наведе сервере по реду, али не може да изрази зоне. Трајно решење је resolver који ради унутар пода и поседује поделу, па датотека остаје тривијална и ниједна политика нема разлог да је преписује.
Зашто измена коју сте направили непрестано нестаје
Датотека припада kubelet-у, а не вама. Под dnsPolicy: ClusterFirst kubelet је ствара тако да показује на кластер DNS и поново је ствара кад год се контејнер покрене. Све што промените кроз kubectl exec живи у записном слоју контејнера, па рестарт, избацивање или rollout то одбацује. Спецификација пода и даље носи исту политику, зато се иста датотека враћа.
Постављање dnsPolicy: None зауставља поновно стварање и такође уклања разрешавање унутар кластера. Добијате датотеку коју контролишете и губите називе који су вам требали. Та размена је цео проблем: resolv.conf не познаје зоне, само сервере које треба редом испробати, па не може да пошаље cluster.local на једну адресу, а приватну зону на другу.
Покрените један resolver у поду, на loopback-у
Усмерите под на један именски сервер на loopback-у, а затим пустите CoreDNS контејнер који дели мрежни namespace пода да одговара на порту 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Сва три контејнера деле један мрежни namespace, па 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-у
Ако сваки workload у namespace-у треба тунелску зону, блок прослеђивања у CoreDNS ConfigMap-у под kube-system је јефтинији од сајдкара по поду. Та промена је на нивоу кластера: тражи администраторска права и рестарт deployment-а о ком сви зависе. Ограничите је на ту једну зону, никад на корен. Тунелска адреса једног workload-а тада постаје resolver сваког пода за ту зону, а дана кад тунел падне цео кластер губи име.
Сајдкар држи радијус експлозије унутар једног пода, што је бољи подразумевани избор кад само неколико сервиса треба удаљену мрежу. Шта год одабрали, запишите који resolver поседује зону, јер следећа особа која буде отклањала timeout питаће.
Имена која се разрешавају док везе још падају
Разрешавање је једна од две ствари које тунел мора да носи; друга је повратни пут, а мрежа пода га добро скрива. Ако се сам OpenVPN сервер врти као под, правила која додате унутар тог контејнера не управљају саобраћајем који излази кроз чвор. Тај је квар узак: само су подови на чвору који је такође вртео сервер добијали одговоре, а све остало је истекло.
Покретање сервера са hostNetwork: true враћа га у namespace чвора, где правило FORWARD и превођење извора делују. Преведите клијентски pool на излазу или ниједан удаљени чвор нема руту назад до тунелске адресе као што је 10.8.0.6. Проверите оба смера пре него што поново дирнете Corefile. Тунел који носи упит, а не одговор, производи тачно исти timeout као 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 излаз у тикету, јер је то артефакт који одваја проблем именовања од проблема усмеравања.