
Straipsnio tikslas – supažindinti skaitytoją su „Kubernetes“ tinklo ir tinklo politikos valdymo pagrindais, taip pat su trečiosios šalies „Calico“ papildiniu, praplečiančiu standartines galimybes. Be to, konfigūravimo paprastumas ir kai kurios funkcijos bus pademonstruotos naudojant realius pavyzdžius iš mūsų veiklos patirties.
Greitas įvadas į Kubernetes tinklo įrenginį
„Kubernetes“ klasteris neįsivaizduojamas be tinklo. Mes jau paskelbėme medžiagą apie jų pagrindus: „"Ir"".
Šio straipsnio kontekste svarbu pažymėti, kad pats K8s nėra atsakingas už tinklo ryšį tarp konteinerių ir mazgų: tam skirtos įvairios CNI papildiniai (Container Networking Interface). Daugiau apie šią koncepciją mes .
Pavyzdžiui, labiausiai paplitęs iš šių įskiepių yra — užtikrina visišką tinklo ryšį tarp visų klasterio mazgų, keldamas tiltus kiekviename mazge, priskirdamas jam potinklį. Tačiau visiškas ir nereguliuojamas prieinamumas ne visada yra naudingas. Norint užtikrinti minimalią klasterio izoliaciją, būtina įsikišti į ugniasienės konfigūraciją. Paprastai jį kontroliuoja tas pats CNI, todėl bet kokios trečiosios šalies intervencijos į iptables gali būti interpretuojamos neteisingai arba visiškai ignoruojamos.
Taip pat yra numatytas tinklo politikos valdymo organizavimas Kubernetes klasteryje . Šiame šaltinyje, paskirstytame pasirinktose vardų erdvėse, gali būti taisyklių, skirtų atskirti vienos programos prieigą prie kitos. Tai taip pat leidžia konfigūruoti pasiekiamumą tarp konkrečių rinkinių, aplinkų (pavadinimų erdvių) arba IP adresų blokų:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978Tai nėra pats primityviausias pavyzdys gali kartą ir visiems laikams atgrasyti nuo noro suprasti tinklo politikos veikimo logiką. Tačiau mes vis tiek pabandysime suprasti pagrindinius srauto srautų apdorojimo principus ir metodus naudojant tinklo politiką...
Logiška, kad yra 2 srauto tipai: įėjimas į podą (Ingress) ir išeinantis iš jo (Egress).

Tiesą sakant, politika pagal judėjimo kryptį skirstoma į šias 2 kategorijas.
Kitas būtinas atributas yra parinkiklis; tas, kuriam galioja taisyklė. Tai gali būti grupė (arba jų grupė) arba aplinka (t. y. vardų erdvė). Svarbi detalė: abiejų šių objektų tipai turi turėti etiketę (etiketė Kubernetes terminologija) – tai yra tie, kuriais politikai operuoja.
Be riboto skaičiaus selektorių, kuriuos vienija tam tikra etiketė, galima įvairiais variantais parašyti tokias taisykles kaip „Leisti/neleisti viską/visiems“. Šiuo tikslu naudojamos formos konstrukcijos:
podSelector: {}
ingress: []
policyTypes:
- Ingress– šiame pavyzdyje visos aplinkos ankštys yra užblokuotos įeinančiam srautui. Priešingą elgesį galima pasiekti naudojant tokią konstrukciją:
podSelector: {}
ingress:
- {}
policyTypes:
- IngressPanašiai ir išeinantiems:
podSelector: {}
policyTypes:
- Egress- jį išjungti. Ir štai ką įtraukti:
podSelector: {}
egress:
- {}
policyTypes:
- EgressGrįžtant prie CNI įskiepio pasirinkimo klasteriui, verta paminėti ne kiekvienas tinklo papildinys palaiko NetworkPolicy. Pavyzdžiui, jau minėtas „Flanel“ nemoka konfigūruoti tinklo strategijų, kurios oficialioje saugykloje. Ten minima ir alternatyva – atvirojo kodo projektas , kuris žymiai išplečia standartinį Kubernetes API rinkinį tinklo politikos požiūriu.

Susipažinimas su Calico: teorija
„Calico“ papildinys gali būti naudojamas kartu su „Flanel“ (paprojekčiu ) arba atskirai, apimantis tiek tinklo ryšį, tiek pasiekiamumo valdymo galimybes.
Kokias galimybes suteikia K8s „boxed“ sprendimas ir API rinkinys iš Calico?
Štai kas integruota į NetworkPolicy:
- politikus riboja aplinka;
- politika taikomos etiketėmis pažymėtoms ankštims;
- taisyklės gali būti taikomos ankštims, aplinkoms ar potinkliams;
- taisyklėse gali būti protokolų, pavadintų arba simbolinių prievadų specifikacijų.
Štai kaip Calico išplečia šias funkcijas:
- politika gali būti taikoma bet kokiam objektui: pod, konteineriui, virtualiai mašinai ar sąsajai;
- taisyklėse gali būti nurodytas konkretus veiksmas (draudimas, leidimas, registravimas);
- taisyklių tikslas arba šaltinis gali būti prievadas, prievadų diapazonas, protokolai, HTTP arba ICMP atributai, IP arba potinklis (4 arba 6 karta), bet kokie selektoriai (mazgai, prieglobos, aplinkos);
- Be to, srautą galite reguliuoti naudodami DNAT nustatymus ir srauto persiuntimo politiką.
Pirmieji įsipareigojimai „GitHub“ „Calico“ saugykloje datuojami 2016 m. liepos mėn., o po metų projektas užėmė lyderio poziciją organizuojant „Kubernetes“ tinklo ryšį – tai liudija, pavyzdžiui, apklausos rezultatai, :

Daugelis didelių valdomų sprendimų su K8, pvz , , ir kiti pradėjo rekomenduoti jį naudoti.
Kalbant apie našumą, čia viskas puiku. Bandydama savo gaminį, Calico kūrėjų komanda pademonstravo astronominį našumą, naudodama daugiau nei 50000 500 konteinerių 20 fizinių mazgų, kurių kūrimo greitis buvo XNUMX konteinerių per sekundę. Su mastelio keitimu problemų nenustatyta. Tokie rezultatai jau paskelbus pirmąją versiją. Nepriklausomi tyrimai, kuriuose daugiausia dėmesio skiriama pralaidumui ir išteklių sunaudojimui, taip pat patvirtina, kad Calico našumas yra beveik toks pat geras kaip Flannel. :

Projektas vystosi labai greitai, palaiko darbą populiariuose sprendimuose, valdomuose K8s, OpenShift, OpenStack, galima naudoti Calico diegiant klasterį naudojant , yra nuorodų į Service Mesh tinklų kūrimą ( naudojamas kartu su Istio).
Praktikuokite su Calico
Paprastai naudojant vanilinį Kubernetes, CNI įdiegimas reiškia failo naudojimą calico.yaml, , naudojant kubectl apply -f.
Paprastai dabartinė įskiepio versija yra suderinama su paskutinėmis dviem ar trimis „Kubernetes“ versijomis; suderinamumas su senesnėmis versijomis nėra testuojamas ir negarantuojamas. Pasak kūrėjų, „Calico“ veikia su branduoliu. Linux virš 3.10 kontroliuojama CentOS 7, Ubuntu 16 arba Debian 8, per „iptables“ arba „IPVS“.
Izoliacija aplinkoje
Kad būtų lengviau suprasti, pažvelkime į paprastą atvejį, kad suprastume, kuo tinklo politika Calico žymėjime skiriasi nuo standartinių ir kaip taisyklių kūrimo metodas supaprastina jų skaitomumą ir konfigūracijos lankstumą:

Klasteryje yra įdiegtos 2 žiniatinklio programos: Node.js ir PHP, viena iš jų naudoja Redis. Norėdami užblokuoti prieigą prie Redis iš PHP, išlaikant ryšį su Node.js, tiesiog taikykite šią politiką:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-redis-nodejs
spec:
podSelector:
matchLabels:
service: redis
ingress:
- from:
- podSelector:
matchLabels:
service: nodejs
ports:
- protocol: TCP
port: 6379Iš esmės leidome įeinantį srautą į Redis prievadą iš Node.js. Ir jie aiškiai nieko kito nedraudė. Kai tik pasirodo „NetworkPolicy“, visi joje paminėti parinkikliai pradedami atskirti, nebent nurodyta kitaip. Tačiau izoliavimo taisyklės netaikomos kitiems objektams, kurių neapima parinkiklis.
Pavyzdys naudoja apiVersion Kubernetes iš dėžutės, bet niekas netrukdo juo naudotis . Sintaksė yra išsamesnė, todėl turėsite perrašyti taisyklę aukščiau nurodytam atvejui tokia forma:
apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
name: allow-redis-nodejs
spec:
selector: service == 'redis'
ingress:
- action: Allow
protocol: TCP
source:
selector: service == 'nodejs'
destination:
ports:
- 6379 Pirmiau minėtose konstrukcijose, leidžiančiose arba uždrausti bet kokį srautą per įprastą NetworkPolicy API, yra konstrukcijos su skliaustais, kurias sunku suprasti ir prisiminti. Calico atveju, norėdami pakeisti ugniasienės taisyklės logiką į priešingą, tiesiog pakeiskite action: Allow apie action: Deny.
Izoliacija pagal aplinką
Dabar įsivaizduokite situaciją, kai programa generuoja verslo metriką rinkimui „Prometheus“ ir tolesnei analizei naudojant „Grafana“. Įkeltame dokumente gali būti neskelbtinų duomenų, kurie pagal numatytuosius nustatymus vėl yra viešai matomi. Paslėpkime šiuos duomenis nuo smalsių akių:

„Prometheus“, kaip taisyklė, dedamas į atskirą paslaugų aplinką - pavyzdyje tai bus tokia vardų erdvė:
apiVersion: v1
kind: Namespace
metadata:
labels:
module: prometheus
name: kube-prometheus Laukas metadata.labels tai pasirodė neatsitiktinai. Kaip paminėta aukščiau, namespaceSelector (taip pat podSelector) veikia su etiketėmis. Todėl norėdami leisti paimti metriką iš visų konkretaus prievado rinkinių, turėsite pridėti tam tikrą etiketę (arba paimti iš esamų) ir pritaikyti tokią konfigūraciją:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-prom
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
module: prometheus
ports:
- protocol: TCP
port: 9100Ir jei naudojate Calico politiką, sintaksė bus tokia:
apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-prom
spec:
ingress:
- action: Allow
protocol: TCP
source:
namespaceSelector: module == 'prometheus'
destination:
ports:
- 9100Apskritai, pridėję šios rūšies politiką konkretiems poreikiams, galite apsisaugoti nuo kenkėjiškų ar atsitiktinių trukdžių klasterio taikomųjų programų veikimui.
Geriausia praktika, pasak Calico kūrėjų, yra metodas „Blokuoti viską ir aiškiai atidaryti tai, ko jums reikia“, dokumentuotas (kiti laikosi panašaus požiūrio – ypač in ).
Papildomų Calico objektų naudojimas
Leiskite jums priminti, kad naudodamiesi išplėstiniu Calico API rinkiniu galite reguliuoti mazgų prieinamumą, neapsiribojant vienetais. Toliau pateiktame pavyzdyje naudojant GlobalNetworkPolicy galimybė perduoti ICMP užklausas klasteryje yra uždaryta (pavyzdžiui, ping iš grupės į mazgą, tarp blokų arba iš mazgo į IP grupę):
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
name: block-icmp
spec:
order: 200
selector: all()
types:
- Ingress
- Egress
ingress:
- action: Deny
protocol: ICMP
egress:
- action: Deny
protocol: ICMP Aukščiau nurodytu atveju klasterio mazgai vis tiek gali „susiekti“ vienas su kitu per ICMP. Ir ši problema išspręsta priemonėmis GlobalNetworkPolicy, taikoma subjektui HostEndpoint:
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
name: deny-icmp-kube-02
spec:
selector: "role == 'k8s-node'"
order: 0
ingress:
- action: Allow
protocol: ICMP
egress:
- action: Allow
protocol: ICMP
---
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
name: kube-02-eth0
labels:
role: k8s-node
spec:
interfaceName: eth0
node: kube-02
expectedIPs: ["192.168.2.2"]VPN byla
Galiausiai pateiksiu labai realų Calico funkcijų naudojimo pavyzdį beveik klasterio sąveikos atveju, kai standartinio strategijų rinkinio nepakanka. Norėdami pasiekti žiniatinklio programą, klientai naudoja VPN tunelį, ši prieiga yra griežtai kontroliuojama ir apribota konkrečiu paslaugų, kurias leidžiama naudoti, sąrašu:

Klientai prisijungia prie VPN per standartinį UDP prievadą 1194 ir, prisijungę, gauna maršrutus į grupių ir paslaugų potinklius. Visi potinkliai yra stumiami, kad neprarastų paslaugų paleidžiant iš naujo ir keičiant adresus.
Konfigūracijos prievadas yra standartinis, o tai suteikia tam tikrų niuansų programos konfigūravimo ir perkėlimo į Kubernetes klasterį procesui. Pavyzdžiui, tame pačiame AWS LoadBalancer for UDP pasirodė pažodžiui praėjusių metų pabaigoje ribotame regionų sąraše, o NodePort negalima naudoti dėl jo persiuntimo visuose klasterio mazguose ir neįmanoma pakeisti serverio egzempliorių skaičiaus. gedimų tolerancijos tikslais. Be to, turėsite pakeisti numatytąjį prievadų diapazoną...
Išnagrinėjus galimus sprendimus buvo pasirinkta:
- Pods su VPN yra suplanuotas kiekvienam mazgui
hostNetwork, tai yra, į tikrąjį IP. - Paslauga skelbiama lauke per
ClusterIP. Mazge yra fiziškai įdiegtas prievadas, kuris pasiekiamas iš išorės su nedidelėmis išlygomis (sąlyginis tikro IP adreso buvimas). - Nustatyti mazgą, ant kurio išaugo ankštis, mūsų istorija nepatenka. Aš tiesiog pasakysiu, kad galite tvirtai „prikalti“ paslaugą prie mazgo arba parašyti nedidelę šoninio automobilio paslaugą, kuri stebės dabartinį VPN paslaugos IP adresą ir redaguoja DNS įrašus, registruotus pas klientus - kas turi pakankamai vaizduotės.
Žvelgiant iš maršruto perspektyvos, galime unikaliai identifikuoti VPN klientą pagal jo IP adresą, išduotą VPN serverio. Žemiau pateikiamas primityvus tokio kliento prieigos prie paslaugų ribojimo pavyzdys, iliustruotas aukščiau minėtame Redis:
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
name: vpnclient-eth0
labels:
role: vpnclient
environment: production
spec:
interfaceName: "*"
node: kube-02
expectedIPs: ["172.176.176.2"]
---
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
name: vpn-rules
spec:
selector: "role == 'vpnclient'"
order: 0
applyOnForward: true
preDNAT: true
ingress:
- action: Deny
protocol: TCP
destination:
ports: [6379]
- action: Allow
protocol: UDP
destination:
ports: [53, 67]Čia griežtai draudžiama prisijungti prie 6379 prievado, tačiau tuo pačiu išsaugomas DNS paslaugos veikimas, kurio veikimas gana dažnai nukenčia rengiant taisykles. Kadangi, kaip minėta anksčiau, pasirodžius parinkikliui, jam taikoma numatytoji atmetimo politika, jei nenurodyta kitaip.
rezultatai
Taigi, naudodami išplėstinę Calico API, galite lanksčiai konfigūruoti ir dinamiškai keisti maršrutą klasteryje ir aplink jį. Apskritai jo naudojimas gali atrodyti kaip šaudymas į žvirblius iš patrankos, o L3 tinklo įdiegimas su BGP ir IP-IP tuneliais atrodo siaubingai paprasta Kubernetes instaliacija plokščiame tinkle... Tačiau kitu atveju įrankis atrodo gana perspektyvus ir naudingas. .
Atskirti klasterį, kad jis atitiktų saugos reikalavimus, ne visada įmanoma, todėl „Calico“ (ar panašus sprendimas) ateina į pagalbą. Šiame straipsnyje pateikti pavyzdžiai (su nedideliais pakeitimais) naudojami keliuose mūsų klientų AWS įrenginiuose.
PS
Taip pat skaitykite mūsų tinklaraštyje:
- «»;
- „Iliustruotas „Kubernetes“ tinklo vadovas“: , ;
- «".
Šaltinis: www.habr.com
