Ինչպես բաժանել DNS-ը Kubernetes-ի և OpenVPN sidecar-ի միջև
Sidecar pod-ին պետք է անունների երկու աշխարհ։ Ուղղեք մեկ loopback resolver դեպի կլաստեր և թունել, և դադարեք ապավինել խմբագրված resolv.conf-ին։
Pod-երը, որոնք աշխատեցնում են OpenVPN sidecar, անվանալուծման մեջ ձախողվում են ճանաչելի օրինաչափով՝ կլաստերի անունները կախվում են, հեռավոր անունները պատասխանում են մինչև pod-ի վերգործարկումը, և ձեր խմբագրված resolver ֆայլը վերադառնում է նախկին վիճակին։ Այդ հաջորդականության մեջ ոչինչ թունելի խափանում չէ։ Pod-ն ունի մեկ resolver ֆայլ և անունների երկու աշխարհ, և ֆայլը կարող է սերվերները հերթով թվարկել, բայց չի կարող արտահայտել գոտիներ։ Կայուն լուծումը resolver-ն է, որը աշխատում է pod-ի ներսում և տիրապետում է բաժանմանը, այնպես որ ֆայլը մնում է պարզ, և ոչ մի քաղաքականություն պատճառ չունի այն վերագրելու։
Ինչու ձեր կատարած փոփոխությունը շարունակ անհետանում է
Ֆայլը պատկանում է kubelet-ին, ոչ ձեզ։ dnsPolicy: ClusterFirst-ի ներքո kubelet-ը ստեղծում է այն՝ ուղղելով կլաստերի DNS-ին, և վերստեղծում է ամեն անգամ, երբ կոնտեյները մեկնարկում է։ Ամեն ինչ փոխում եք kubectl exec-ով, ապրում է կոնտեյների գրելի շերտում, ուստի վերգործարկումը, դուրսմղումը կամ rollout-ը այն դեն են նետում։ Pod-ի սպեցիֆիկացիան դեռ կրում է նույն քաղաքականությունը, դրա համար նույն ֆայլն է վերադառնում։
dnsPolicy: None-ի սահմանումը դադարեցնում է վերստեղծումը և նաև հեռացնում կլաստերի լուծումը։ Դուք ստանում եք ֆայլ, որը վերահսկում եք, և կորցնում այն անունները, որոնք ձեզ պետք էին։ Այդ փոխանակությունը ողջ խնդիրն է. resolv.conf-ը գոտիների պատկերախոսություն չունի, միայն սերվերներ, որոնք պետք է հերթով փորձել, ուստի չի կարող cluster.local-ը ուղարկել մեկ հասցեին, իսկ մասնավոր գոտին մյուսին։
Աշխատեցրեք մեկ resolver pod-ում, loopback-ի վրա
Ուղղեք pod-ը loopback-ի վրա գտնվող մեկ անվանասերվերի, ապա թույլ տվեք CoreDNS կոնտեյներին, որը կիսում է pod-ի ցանցային անվանատարածքը, պատասխանել 53 պորտին։ Սահմանեք քաղաքականությունը None-ի, տվեք pod-ին այդ մեկ հասցեն և ավելացրեք 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-ից mount անելը պահում է այն որպես տարբերակային մուտքին ուղղում, այլ ոչ տեղում խմբագրվող ֆայլի։ Ստեղծված resolv.conf-ը այնուհետև պարունակում է մեկ անվանասերվեր և ոչինչ այլ, ինչն վիճակ է, որի մասին կարելի է դատողել։
Երկու մանրամասնություն այստեղ կծում է։ Պաշտոնական պատկերը 53 պորտը կապում է որպես root, և որոշ կլաստերային քաղաքականություններ պահանջում են դա գրեք դա բացահայտ այդ մասին։ Pod-ի յուրաքանչյուր կոնտեյները այժմ կախված են այդ մեկ կոնտեյների աշխատելուցից, ուստի ավելացրեք readiness probe անվնաս անվանի նկատմամբ և թողեք հավելվածությանը հանդուրել մեկնարկի ձախողումները։
Տվեք յուրաքանչյուր մասնավոր գոտու իր upstream-ը
Corefile-ը գոտիների ցանկ է, յուրաքանչյուրը նշում է սերվերը, որը կարող է պատասխանել դրան։ Մեկ բլոկ ծածկում է թունելի գոտին, իսկ ամենը որսող բլոկը գալիս է վերջին և վերցնում է այն ամենը, ինչ ոչ մի հստակ բլոկ չի պահանջել։ Ամենը որսող բլոկը պետք է ուղղվի իրական upstream-ի, երբեք չե վերադառնի pod-ին. .:53 { forward . 10.100.0.10 }-ը կրկին օգտագործում է կլաստերի resolver-ը, քանի որ այդ resolver-ը արդեն հանրային անունները փոխանցում է հենց node-ի սեփական resolver-ներին։ Pod-ում ուրիշ ոչինչ պետք չէ իմանալ, թե անունը որ ցանցին է պատկանում։
.:53 {
errors
cache 30
forward . 10.100.0.10
}
svc.acme.internal:53 {
errors
cache 30
forward . 192.168.240.1
}Կարդացեք կլաստերի հասցեն kube-system-ում գտնվող kube-dns ծառայությունից՝ հոդվածից պատճենելու փոխարեն, քանի ծառայությունների CIDR-ները տարբեր են։ Թունելի հասցեն գալիս է OpenVPN սերվերի ուղարկած dhcp-option DNS արժեքից կամ այդ գոտու համար իրավասություն ունեցող սերվերից։ Եթե ձեր կլաստերի resolver-ը չի պատասխանում հանրային անուններին, ապա տեղադրեք node-ի resolver-ի հասցեն ամենը որսող բլոկում՝ կարդացված node-ի վրա, ոչ թե pod-ի ներսում։
Մի ուղղեք ամենը որսող բլոկը /etc/resolv.conf-ին, ինչն գայթակղիչ մեկտողանոց լուծումն է և թակարդ հենց այս կարգավորման մեջ։ dnsPolicy: None-ի ներքո pod-ի սեփական ֆայլը պարունակում է միակ անվանասերվերը՝ 127.0.0.1, ուստի այդ թիրախը ինքն է CoreDNS-ը, և յուրաքանչյուր չհամապատասխան հարցումը ռեկուրսիվ է անում մինչև ժամկետը լրանա։ svc.acme.internal անունով բլոկը համապատասխանում է այդ անվանը և դրա տակ գտնվող յուրաքանչյուր անվանին, ինչն ընդգրկում է db.svc.acme.internal-ը և բացառում svc.acme.internal.example.net-ը։ Վերջի կետը տեսքային է, քանի գոտիների անվանները նորմալացվում են լրիվ որակավորված ձևի, քանի որ սուֆիքսի սահմանը որոշում է, թե հարցումը որտեղ է իջնում։
Որոշեք՝ փոխանցումը պատկանում է կլաստերի resolver-ին, թե չէ
Եթե անվանատարածքի յուրաքանչյուր աշխատային բեռին անհրաժեշտ է թունելի գոտին, ապա kube-system-ի ներքո CoreDNS ConfigMap-ում փոխանցման բլոկը ավելի շահեկար է, քան յուրաքանչյուր pod-ի համար sidecar-ը։ Այդ փոխությունը կլաստերի մաշտաբի է. այն պահանջում է ադմինիստրատորի իրավունքներ և բոլորը կախված deployment-ի վերգործարկում։ Սահմանափակեք այն միայն այդ գոտով, երբեք չէ արմատով։ Մեկ աշխատային բեռի թունելի հասցեն այնուհետև դառնում է գոտու համար յուրաքանչյուր pod-ի resolver-ը, և օրը, երբ թունելը ընկնում է, ամբողջ կլաստերը կորցնում է անվանը։
Sidecar-ը պայթյունի շառավղությունը պահում է մեկ pod-ի ներսում, ինչն ավելի լավ լռելյային արժեքն է, երբ հեռավոր ցանցին հարում է ընդամենը մի քանի ծառայություններ։ Ինչ էլ ընտրեք, գրեք, թե որ resolver-ն է տիրապետում գոտուն, քանի հաջորդ անձնը, որը կարգավորի timeout-ը, կհարցնի։
Անուններ, որոնք լուծվում են, մինչ միացումները տակավին ձախողվում են
Անվանալուծումը երկուսից մեկն է, որը թունելը պետք է կրի. Մյուսը վերադարձի ուղին է, և pod-ի ցանցը լավ թաքցնում է այն։ Եթե OpenVPN սերվերը ինքը աշխատում է որպես pod, ապա այդ կոնտեյներում ավելացրած կանոնները չեն կարգավորում node-ով դուրս եկող տրաֆիկը։ Այդ ձախողումը նեղ է. պատասխաններ ստացել են միայն այն node-ի pod-երը, որը նույնպես աշխատեցնում էր սերվերը, իսկ մնացածը ժամկետն եր լրանում։
Սերվերը hostNetwork: true-ով աշխատեցնելը վերադարձնում է այն node-ի անվանատարածք, որտեղ գործում են FORWARD կանոնը և աղբյուրի թարգմանությունը։ Թարգմանեք համակլիենտային փողը ելքի ժամանակ, այլապես ոչ մի հեռավոր node չունի վերադարձի ուղի դեպի թունելի հասցեին, ինչպիսի 10.8.0.6-ը։ Ստուգեք երկու ուղղությունները նախքան Corefile-ին նորից դիպչելու։ Թունելը, որը տանում է հարցումը, բայց ոչ պատասխանը, արտադրում է նույն timeout-ը, ինչպիսի resolver-ը, որը երբեք չի ստացել հարցումը։
Ստուգեք նոր pod-ից, ոչ ձեր ուղղած սեսիայից
Հարցրեք երկու գոտիներին բացահայտ, ապա կրկնեք հարցումը pod-ը փոխարինելուց հետո։ Կոնֆիգուրացիան, որը գոյություն ունի միայն աշխատող կոնտեյներում, կոնֆիգուրացիա չէ՝
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-ը գտնում է, իսկ pod-ի սպեցիֆիկացիան չէ։ Եթե երկուսն էլ պատասխանում են, բայց հավելվածությունը մինևև չի միանում, դադարեք DNS-ի վչիտը և ստուգեք TCP ուղին nc -vz db.svc.acme.internal 5432-ով կոնտեյների ներսից։ Պահեք dig-ի ելքը տոմսում, քանի այն է արտեֆակտը, որը անունի խնդիրը բաժանում է երթուղային խնդիրից։