Kubernetes-ում OpenVPN պոդը ոչինչ չի փոխանցում? Ստուգեք ip_forward-ը
Հաճախորդները ping են անում VPN պոդին, և դրանից այն կողմ ոչինչ չկա։ Namespace-ում փոխանցումը անջատված է, և ուղղումը պետք է դիմանա admission-ին, վերագործարկումներին և վերադարձի ուղուն։
Ձեր նոութբուքը ցույց է տալիս կանաչ թունել, հաճախորդի մատյանը հայտնում է, որ երթուղիները հպվել են, և միակ պատասխանող հասցեն VPN սերվերի սեփական թունելի IP-ն է։ Դրանից այն կողմ ping-երը մահանում են՝ անկախ նրանից, թե ինչի եք նպատակադրում, լինի դա ClusterIP, մեկ այլ պոդի հասցե, թե հանրային հոսթի անուն։ Այդ համակցությունը ոչ թե աղոտ է, այլ ախտորոշիչ՝ ապակապսուլումը աշխատում է, իսկ երկրորդ թռիչքը՝ ոչ։
Ես սրա հանդիպեցի Debian հանգույցում, որն աշխատեցնում էր chart-ով տեղադրված OpenVPN պատկեր, և թունելը հեշտ մասն էր։ Հաճախորդը ստացավ 10.8.0.x վարձույթ, 10.8.0.1-ը պատասխանեց, իսկ 10.96.0.10-ը՝ կլաստերի DNS ծառայությունը, ժամկետանց եղավ։ Սերվերի մատյանում ոչինչ հիվանդ չէր թվում, և հենց դրա համար մարդիկ սկսում են վերագրել iptables կանոններ, որոնք երբեք պետք չէր դիպչել։
VPN պոդը երթուղիչ է, և արժե դա ուղիղ ասել։ Գաղտնագրված փաթեթները գալիս են, բացվում պոդի սեփական ցանցային namespace-ում, ապա պետք է դուրս գան մեկ այլ ինտերֆեյսով։ Linux-ը մերժում է այդ երկրորդ քայլը, քանի դեռ փոխանցումը միացված չէ հենց այդ namespace-ի ներսում։
Ինչին կարող է հասնել հաճախորդը և ինչին՝ ոչ
Պատասխանող հասցեն պատկանում է թունելի վերջնակետին, և VPN գործընթացը տիրում է դրան տեղայնորեն, ուստի փոխանցումն ընդհանրապես չի մասնակցում։ Մնացած ամեն ինչ, ներառյալ մեկ այլ պոդ, ծառայության VIP կամ ինտերնետը, պահանջում է, որ միջուկը փաթեթը տեղափոխի tun0-ից eth0։ Երբ այդ տեղափոխումը մերժվում է, ախտանիշը միատեսակ լռություն է, ոչ թե մերժում, որովհետև ոչինչ հետ չի առաջացնում ICMP սխալ թունելի ներքև։ Դուք ստանում եք ժամկետանցումներ, ոչ թե անհասանելիության հաղորդագրություններ, և դա այն ակնարկն է, որ ոչ ոք ընդհանրապես երթուղավորում չի անում։
Երկու րոպե դասակարգումը նեղացնում է շերտը։ Եթե DNS անունները ձախողվում են, մինչ ծառայության IP-ին ուղղված հում ping-երը հաջողվում են, խնդիրը DNS սանտեխնիկայի մեջ է, ոչ թե փոխանցման։ Եթե peer-ի հասցեից այն կողմ յուրաքանչյուր նպատակատեղ ժամկետանց է դառնում, ներառյալ մերկ IP-ն, սկսեք namespace-ից։
Կարդացեք կարգավորումը namespace-ի ներսում
Յուրաքանչյուր պոդ ստանում է իր ցանցային namespace-ը, և net.ipv4.ip_forward-ը sysctl է յուրաքանչյուր namespace-ի համար։ Հանգույցի վրա այն փոխելը ձեզ ոչինչ չի ասում կոնտեյների մասին, և դա սխալ մեքենայի վրա կեսօր անցկացնելու հուսալի միջոց է։
kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0
Զրոն հաստատում է ախտորոշումը։ Արժեքը ժառանգաբար չի ստացվում նաև հանգույցի գործարկման կարգավորումից՝ այն սկսվում է պատկերի լռելյայնից ամեն անգամ, երբ կոնտեյներ է ստեղծվում։ Ուստի kubectl exec ... sysctl -w-ով ձեռքով կիրառված ուղղումը անհետանում է հաջորդ վերագործարկման ժամանակ և վերադառնում որպես ընդմիջումներով երևացող խափանում։
Միացնել այնպես, որ manifest-ը պահի այն
Կայուն տարբերակը init կոնտեյներ է, որն աշխատում է նույն pod sandbox-ում և գրում է արժեքը մինչև VPN կոնտեյների մեկնարկը։ Պոդի կոնտեյներները կիսում են ցանցային namespace-ը, ուստի կարգավորումը անցնում է հիմնական կոնտեյներ։
initContainers:
- name: enable-forwarding
image: busybox:1.36
command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
securityContext:
privileged: true
Հենց privileged: true-ն է այն տողը, որի դեմ առարկում են գրախոսները, և նրանք ճիշտ են։ sysctl գրելը պահանջում է կա՛մ արտոնություն, կա՛մ նեղ սահմանափակված ունակություն, և սահմանափակ Pod Security Standard-ով կլաստերը կարող է ուղղակիորեն մերժել արտոնյալ init կոնտեյները։ Եթե admission-ը մերժում է պոդը, դուք դա իմանում եք ստեղծման պահին, ինչն առնվազն ազնիվ է և հեշտ ընթեռնելի։
Ավելի մաքուր այլընտրանքը պոդի մակարդակի securityContext.sysctls ցանկն է, որը թույլ է տալիս kubelet-ին կիրառել namespace-ային sysctl-ներ՝ առանց որևէ կոնտեյների արտոնություն տալու։ Այն ընդգրկում է միայն կլաստերի թույլատրված ցանկի անունները։ Արդյոք net.ipv4.ip_forward-ը այդ ցանկում է, կախված է նրանից, թե ինչպես է կարգավորվել kubelet-ը, և դրանից դուրս sysctl խնդրող պոդը մերժվում է admission-ում կամ խրվում է CreateContainerConfigError-ում, քանի դեռ sandbox-ը նորից փորձարկվում է։ Ստուգեք թույլատրված ցանկը նախքան ենթադրելը, որ դաշտը կոտրված է։
Նախքան երկու մոտեցումներից որևէ մեկը ձեռքով կառուցելը, տեսեք՝ արդյոք chart-ն արդեն բացահայտում է անջատիչը, հաճախ ինչ-որ բան ինչպես ipForwardInitContainer: true։ Chart-ի արժեքն օգտագործելը փոքր է պահում ձեր override ֆայլը և դիմանում է հաջորդ թարմացմանը, ինչը ձեռքով կարկատված Deployment փոփոխությունները չեն անում։
Երկրորդ կեսը՝ վերադարձի ուղին և քաղաքականությունը
Միացված փոխանցումը անհրաժեշտ է, ոչ բավարար։ Եթե հաճախորդները օգտագործում են մասնավոր լողավազան, որին կլաստերի ցանցը երթուղի չունի, պատասխանները չեն գտնում ճանապարհը վերադարձ դեպի թունել, և պոդը պետք է քողարկի այդ երթևեկությունը դեպի իր նպատակակետը։
Քաղաքականությունը նստում է դրա վրա։ NetworkPolicy օբյեկտները և ամպային firewall-ի կանոնները գնահատվում են այն աղբյուրի հասցեի դեմ, որը փաթեթը կրում է թարգմանությունից հետո, ուստի հաճախորդի լողավազանի համար գրված կանոնը կարող է լուռ դադարել համապատասխանել, հենց քողարկումը միացվի։
Երբ հաճախորդներին պետք է հասնել միայն կլաստերի ներսի ծառայություններին, VPN-ը ծառայության VIP-ում ավարտելը ավելի փոքր ձևավորում է, քան պոդային ցանց երթուղավորելը։ Այն նաև հաճախորդի լողավազանը լիովին դուրս է պահում CNI-ի երթուղային աղյուսակից։
Ձախողվող թռիչքը հաճախորդից մեկուսացնելը
Աշխատեք դեպի դուրս և կանգ առեք առաջին լուռ քայլին։ Սկսեք VPN peer-ից, հետո փորձեք ինչ-որ պոդի հասցե, հետո ծառայության VIP, և միայն դրանից հետո հանրային նպատակակետ։ Յուրաքանչյուր հաջողություն սահմանը տեղափոխում է մեկ թռիչք, և յուրաքանչյուր ձախողում անվանում է այն շերտը, որն արժե ուսումնասիրել։ Ցանկացած տեղաբաշխումից հետո մտեք exec-ով և նորից կարդացեք sysctl-ը, որովհետև փոխարինված պոդը սկսում է պատկերի լռելյայից, և ուղղումը, որը երբեք manifest-ում չի եղել, արդեն գնացել է։
Kubernetes-ի փաստաթղթերը կլաստերում sysctl-ների օգտագործման մասին թվարկում են, թե որ անունները կարելի է սահմանել պոդի անվտանգության կոնտեքստով, և դա առաջին տեղն է, որտեղ պետք է նայել, երբ admission-ը մերժում է փոփոխությունը։