Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Qëllimi i artikullit është të prezantojë lexuesin me bazat e rrjetëzimit dhe menaxhimit të politikave të rrjetit në Kubernetes, si dhe shtojcën Calico të palëve të treta që zgjeron aftësitë standarde. Gjatë rrugës, lehtësia e konfigurimit dhe disa veçori do të demonstrohen duke përdorur shembuj realë nga përvoja jonë e funksionimit.

Një hyrje e shpejtë në pajisjen e rrjetit Kubernetes

Një grup Kubernetes nuk mund të imagjinohet pa një rrjet. Ne kemi publikuar tashmë materiale mbi bazat e tyre: "Një udhëzues i ilustruar për rrjetëzimin në Kubernetes"Dhe"Një hyrje në politikat e rrjetit Kubernetes për profesionistët e sigurisë'.

Në kontekstin e këtij artikulli, është e rëndësishme të theksohet se vetë K8s nuk është përgjegjës për lidhjen e rrjetit midis kontejnerëve dhe nyjeve: për këtë, të ndryshme Shtojcat CNI (Ndërfaqja e rrjetit të kontejnerëve). Më shumë rreth këtij koncepti ne më thanë edhe mua.

Për shembull, më e zakonshme nga këto shtojca është fanellë — siguron lidhje të plotë të rrjetit midis të gjitha nyjeve të grupimit duke ngritur ura në secilën nyje, duke i caktuar një nënrrjet. Megjithatë, aksesi i plotë dhe i parregulluar nuk është gjithmonë i dobishëm. Për të siguruar një lloj izolimi minimal në grup, është e nevojshme të ndërhyhet në konfigurimin e murit të zjarrit. Në rastin e përgjithshëm, ai vendoset nën kontrollin e së njëjtës CNI, prandaj çdo ndërhyrje e palëve të treta në iptables mund të interpretohet gabimisht ose të injorohet fare.

Dhe ofrohet "jashtë kutisë" për organizimin e menaxhimit të politikave të rrjetit në një grup Kubernetes NetworkPolicy API. Ky burim, i shpërndarë në hapësirat e përzgjedhura të emrave, mund të përmbajë rregulla për të diferencuar aksesin nga një aplikacion në tjetrin. Gjithashtu ju lejon të konfiguroni aksesin midis pods, mjediseve (hapësirave të emrave) ose blloqeve të adresave IP specifike:

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: 5978

Ky nuk është shembulli më primitiv i dokumentacion zyrtar mund të dekurajojë një herë e mirë dëshirën për të kuptuar logjikën se si funksionojnë politikat e rrjetit. Megjithatë, ne ende do të përpiqemi të kuptojmë parimet dhe metodat bazë të përpunimit të flukseve të trafikut duke përdorur politikat e rrjetit...

Është logjike që ekzistojnë 2 lloje trafiku: hyrja në pod (Ingress) dhe dalja prej tij (Dalja).

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Në fakt, politika ndahet në këto 2 kategori bazuar në drejtimin e lëvizjes.

Atributi tjetër i kërkuar është një përzgjedhës; ai për të cilin zbatohet rregulli. Ky mund të jetë një pod (ose një grup pods) ose një mjedis (d.m.th. një hapësirë ​​emri). Një detaj i rëndësishëm: të dy llojet e këtyre objekteve duhet të përmbajnë një etiketë (etiketë në terminologjinë Kubernetes) - këto janë ato me të cilat veprojnë politikanët.

Përveç një numri të kufizuar zgjedhësish të bashkuar nga një lloj etikete, është e mundur të shkruhen rregulla si "Lejo/moho gjithçka/të gjithë" në variacione të ndryshme. Për këtë qëllim përdoren konstruksione të formës:

  podSelector: {}
  ingress: []
  policyTypes:
  - Ingress

— në këtë shembull, të gjitha podet në mjedis janë të bllokuara nga trafiku në hyrje. Sjellja e kundërt mund të arrihet me ndërtimin e mëposhtëm:

  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

Në mënyrë të ngjashme për daljet:

  podSelector: {}
  policyTypes:
  - Egress

- për ta fikur. Dhe ja çfarë duhet të përfshijë:

  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

Duke iu rikthyer zgjedhjes së një shtojce CNI për një grup, ia vlen të përmendet se jo çdo shtojcë rrjeti mbështet NetworkPolicy. Për shembull, Flannel i përmendur tashmë nuk di të konfigurojë politikat e rrjetit, të cilat thuhet drejtpërdrejt në depon zyrtare. Aty përmendet edhe një alternativë - një projekt me kod të hapur prej basme, i cili zgjeron ndjeshëm grupin standard të API-ve të Kubernetes për sa i përket politikave të rrjetit.

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Njohja me Calico: teori

Shtojca Calico mund të përdoret në integrim me Flannel (nënprojekt kanal) ose në mënyrë të pavarur, duke mbuluar si lidhjen e rrjetit ashtu edhe aftësitë e menaxhimit të disponueshmërisë.

Çfarë mundësish ofron përdorimi i zgjidhjes “boxed” K8s dhe grupit API nga Calico?

Ja çfarë është e integruar në NetworkPolicy:

  • politikanët janë të kufizuar nga mjedisi;
  • politikat zbatohen në grupet e shënuara me etiketa;
  • rregullat mund të zbatohen në pods, mjedise ose nënrrjeta;
  • rregullat mund të përmbajnë protokolle, specifikime të portit të emërtuar ose simbolik.

Ja se si Calico i zgjeron këto funksione:

  • politikat mund të aplikohen për çdo objekt: pod, kontejner, makinë virtuale ose ndërfaqe;
  • rregullat mund të përmbajnë një veprim specifik (ndalim, leje, prerje);
  • objektivi ose burimi i rregullave mund të jetë një port, një sërë portesh, protokolle, atribute HTTP ose ICMP, IP ose nënrrjet (gjenerata e 4-të ose e 6-të), çdo përzgjedhës (nyje, hoste, mjedise);
  • Për më tepër, ju mund të rregulloni kalimin e trafikut duke përdorur cilësimet e DNAT dhe politikat e përcjelljes së trafikut.

Përkushtimet e para në GitHub në depon e Calico datojnë në korrik 2016, dhe një vit më vonë projekti zuri një pozicion udhëheqës në organizimin e lidhjes së rrjetit Kubernetes - kjo dëshmohet, për shembull, nga rezultatet e sondazhit, drejtuar nga The New Stack:

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Shumë zgjidhje të mëdha të menaxhuara me K8, si p.sh Amazon EKS, Azure AKS, Google GKE dhe të tjerë filluan ta rekomandonin për përdorim.

Sa për performancën, gjithçka është e shkëlqyeshme këtu. Në testimin e produktit të tyre, ekipi i zhvillimit Calico demonstroi performancë astronomike, duke drejtuar më shumë se 50000 kontejnerë në 500 nyje fizike me një shpejtësi krijimi prej 20 kontejnerë në sekondë. Nuk u identifikuan probleme me shkallëzimin. Rezultate të tilla u shpallën tashmë në shpalljen e versionit të parë. Studimet e pavarura që fokusohen në xhiron dhe konsumin e burimeve konfirmojnë gjithashtu se performanca e Calico është pothuajse po aq e mirë sa ajo e Flannel. Për shembull:

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Projekti po zhvillohet shumë shpejt, ai mbështet punën në zgjidhjet popullore të menaxhuara K8, OpenShift, OpenStack, është e mundur të përdoret Calico kur vendosni një grup duke përdorur goditje me shkelm, ka referenca për ndërtimin e rrjeteve të Service Mesh (këtu është një shembull përdoret në lidhje me Istio).

Ushtroni me Calico

Në rastin e përgjithshëm të përdorimit të vaniljes Kubernetes, instalimi i CNI zbret në përdorimin e skedarit calico.yaml, shkarkuar nga faqja zyrtare, со помощью kubectl apply -f.

Si rregull, versioni aktual i shtojcës është i pajtueshëm me 2-3 versionet më të fundit të Kubernetes: funksionimi në versionet e vjetra nuk testohet dhe nuk garantohet. Sipas zhvilluesve, Calico funksionon në kernelet Linux mbi 3.10 me CentOS 7, Ubuntu 16 ose Debian 8, në krye të iptables ose IPVS.

Izolimi brenda mjedisit

Për një kuptim të përgjithshëm, le të shohim një rast të thjeshtë për të kuptuar se si politikat e rrjetit në shënimin Calico ndryshojnë nga ato standarde dhe se si qasja për krijimin e rregullave thjeshton lexueshmërinë dhe fleksibilitetin e konfigurimit të tyre:

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Ka 2 aplikacione ueb të vendosura në grup: në Node.js dhe PHP, njëri prej të cilëve përdor Redis. Për të bllokuar hyrjen në Redis nga PHP, duke ruajtur lidhjen me Node.js, thjesht zbatoni politikën e mëposhtme:

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: 6379

Në thelb ne lejuam trafikun hyrës në portin Redis nga Node.js. Dhe ata qartësisht nuk ndaluan asgjë tjetër. Sapo shfaqet NetworkPolicy, të gjithë përzgjedhësit e përmendur në të fillojnë të izolohen, përveç nëse specifikohet ndryshe. Megjithatë, rregullat e izolimit nuk zbatohen për objektet e tjera që nuk mbulohen nga përzgjedhësi.

Shembulli përdor apiVersion Kubernetes është jashtë kutisë, por asgjë nuk ju pengon ta përdorni burim me të njëjtin emër nga dërgesa Calico. Sintaksa atje është më e detajuar, kështu që do t'ju duhet të rishkruani rregullin për rastin e mësipërm në formën e mëposhtme:

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

Konstruktet e sipërpërmendura për lejimin ose mohimin e të gjithë trafikut përmes API-së së rregullt të NetworkPolicy përmbajnë konstruksione me kllapa që janë të vështira për t'u kuptuar dhe mbajtur mend. Në rastin e Calico, për të ndryshuar logjikën e një rregulli të murit të zjarrit në të kundërtën, thjesht ndryshoni action: Allow mbi action: Deny.

Izolimi sipas mjedisit

Tani imagjinoni një situatë ku një aplikacion gjeneron matjet e biznesit për mbledhjen në Prometheus dhe analiza të mëtejshme duke përdorur Grafana. Ngarkimi mund të përmbajë të dhëna të ndjeshme, të cilat janë sërish të shikueshme publikisht si parazgjedhje. Le t'i fshehim këto të dhëna nga sytë kureshtarë:

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Prometheus, si rregull, vendoset në një mjedis të veçantë shërbimi - në shembull do të jetë një hapësirë ​​emri si kjo:

apiVersion: v1
kind: Namespace
metadata:
  labels:
    module: prometheus
  name: kube-prometheus

Fushë metadata.labels kjo doli të mos ishte rastësi. Siç u përmend më lart, namespaceSelector (si dhe podSelector) vepron me etiketa. Prandaj, për të lejuar marrjen e matjeve nga të gjitha pods në një port specifik, do t'ju duhet të shtoni një lloj etikete (ose të merrni nga ato ekzistuese) dhe më pas të aplikoni një konfigurim si:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          module: prometheus
    ports:
    - protocol: TCP
      port: 9100

Dhe nëse përdorni politikat e Calico, sintaksa do të jetë si kjo:

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  ingress:
  - action: Allow
    protocol: TCP
    source:
      namespaceSelector: module == 'prometheus'
    destination:
      ports:
      - 9100

Në përgjithësi, duke shtuar këto lloj politikash për nevoja specifike, mund të mbroheni nga ndërhyrjet keqdashëse ose aksidentale në funksionimin e aplikacioneve në grup.

Praktika më e mirë, sipas krijuesve të Calico, është qasja "Blloko gjithçka dhe hap në mënyrë eksplicite atë që të nevojitet", e dokumentuar në dokumentacion zyrtar (të tjerët ndjekin një qasje të ngjashme - në veçanti, në artikull i përmendur tashmë).

Përdorimi i objekteve shtesë Calico

Më lejoni t'ju kujtoj se përmes grupit të zgjeruar të API-ve Calico ju mund të rregulloni disponueshmërinë e nyjeve, pa u kufizuar në pods. Në shembullin e mëposhtëm duke përdorur GlobalNetworkPolicy aftësia për të kaluar kërkesat ICMP në grup është e mbyllur (për shembull, ping nga një pod në një nyje, midis pods, ose nga një nyje në një pod IP):

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

Në rastin e mësipërm, është ende e mundur që nyjet e grupimit të "arrinin" njëri-tjetrin nëpërmjet ICMP. Dhe kjo çështje zgjidhet me mjete GlobalNetworkPolicy, aplikuar për një njësi ekonomike 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"]

Rasti VPN

Së fundi, do të jap një shembull shumë real të përdorimit të funksioneve Calico për rastin e ndërveprimit afër grupit, kur një grup standard politikash nuk mjafton. Klientët përdorin një tunel VPN për të hyrë në aplikacionin në internet dhe kjo qasje kontrollohet fort dhe kufizohet në një listë specifike shërbimesh të lejuara për përdorim:

Calico për rrjetëzimin në Kubernetes: prezantim dhe pak përvojë

Klientët lidhen me VPN-në nëpërmjet portit standard UDP 1194 dhe, kur lidhen, marrin rrugë për në nënrrjetat e grupit të pods dhe shërbimeve. Nënrrjeta të tëra shtyhen në mënyrë që të mos humbasin shërbimet gjatë rinisjes dhe ndryshimeve të adresave.

Porti në konfigurim është standard, i cili imponon disa nuanca në procesin e konfigurimit të aplikacionit dhe transferimit të tij në grupin Kubernetes. Për shembull, në të njëjtin AWS LoadBalancer për UDP u shfaq fjalë për fjalë në fund të vitit të kaluar në një listë të kufizuar rajonesh, dhe NodePort nuk mund të përdoret për shkak të përcjelljes së tij në të gjitha nyjet e grupimeve dhe është e pamundur të shkallëzohet numri i rasteve të serverit për qëllimet e tolerancës së gabimeve. Plus, do t'ju duhet të ndryshoni gamën e paracaktuar të porteve...

Si rezultat i kërkimit të zgjidhjeve të mundshme, u zgjodhën:

  1. Pods me VPN janë planifikuar për çdo nyje në hostNetwork, domethënë në IP-në aktuale.
  2. Shërbimi postohet jashtë përmes ClusterIP. Një port është instaluar fizikisht në nyje, e cila është e aksesueshme nga jashtë me rezervime të vogla (prania e kushtëzuar e një adrese IP të vërtetë).
  3. Përcaktimi i nyjës në të cilën u ngrit gjilpëra është përtej qëllimit të tregimit tonë. Unë thjesht do të them që ju mund ta lidhni shërbimin në një nyje ose të shkruani një shërbim të vogël anësor që do të monitorojë adresën aktuale IP të shërbimit VPN dhe do të modifikojë të dhënat DNS të regjistruara me klientët - kushdo që ka mjaft imagjinatë.

Nga këndvështrimi i rrugëzimit, ne mund të identifikojmë në mënyrë unike një klient VPN nga adresa e tij IP e lëshuar nga serveri VPN. Më poshtë është një shembull primitiv i kufizimit të aksesit të një klienti të tillë në shërbime, i ilustruar në Redis-in e lartpërmendur:

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]

Këtu, lidhja me portin 6379 është rreptësisht e ndaluar, por në të njëjtën kohë ruhet funksionimi i shërbimit DNS, funksionimi i të cilit shpesh vuan gjatë hartimit të rregullave. Sepse, siç u përmend më parë, kur shfaqet një përzgjedhës, politika e paracaktuar e mohimit zbatohet për të, përveç nëse specifikohet ndryshe.

Rezultatet e

Kështu, duke përdorur API-në e avancuar të Calico-s, mund të konfiguroni në mënyrë fleksibël dhe të ndryshoni në mënyrë dinamike rrugën brenda dhe rreth grupit. Në përgjithësi, përdorimi i tij mund të duket si gjuajtja e harabelave me top, dhe zbatimi i një rrjeti L3 me tunele BGP dhe IP-IP duket monstruoz në një instalim të thjeshtë Kubernetes në një rrjet të sheshtë... Megjithatë, përndryshe mjeti duket mjaft i zbatueshëm dhe i dobishëm. .

Izolimi i një grupi për të përmbushur kërkesat e sigurisë mund të mos jetë gjithmonë i realizueshëm, dhe këtu vjen në shpëtim Calico (ose një zgjidhje e ngjashme). Shembujt e dhënë në këtë artikull (me modifikime të vogla) përdoren në disa instalime të klientëve tanë në AWS.

PS

Lexoni edhe në blogun tonë:

Burimi: www.habr.com

Shto një koment