Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Svrha članka je upoznati čitatelja s osnovama umrežavanja i upravljanja mrežnim politikama u Kubernetesu, kao i sa Calico dodatkom treće strane koji proširuje standardne mogućnosti. Usput, jednostavnost konfiguracije i neke karakteristike će biti demonstrirane na stvarnim primjerima iz našeg radnog iskustva.

Kratki uvod u Kubernetes mrežni uređaj

Kubernetes klaster se ne može zamisliti bez mreže. Već smo objavili materijale o njihovim osnovama: “Ilustrovani vodič za umrežavanje u Kubernetesu"I"Uvod u Kubernetes mrežne politike za profesionalce za sigurnost".

U kontekstu ovog članka, važno je napomenuti da sam K8s nije odgovoran za mrežnu povezanost između kontejnera i čvorova: za to se koriste različiti CNI dodaci (Interfejs za umrežavanje kontejnera). Više o ovom konceptu mi takođe su mi rekli.

Na primjer, najčešći od ovih dodataka je Flannel — pruža potpunu mrežnu povezanost između svih čvorova klastera podizanjem mostova na svakom čvoru, dodjeljujući mu podmrežu. Međutim, potpuna i neregulisana dostupnost nije uvijek korisna. Da bi se osigurala neka vrsta minimalne izolacije u klasteru, potrebno je intervenirati u konfiguraciji firewall-a. U opštem slučaju, stavljen je pod kontrolu istog CNI-ja, zbog čega se bilo kakve intervencije treće strane u iptables mogu pogrešno protumačiti ili potpuno zanemariti.

I „iz kutije“ za organizovanje upravljanja mrežnim politikama u Kubernetes klasteru je obezbeđeno NetworkPolicy API. Ovaj resurs, distribuiran preko odabranih imenskih prostora, može sadržavati pravila za razlikovanje pristupa od jedne aplikacije drugoj. Također vam omogućava da konfigurirate pristupačnost između određenih podova, okruženja (imenskih prostora) ili blokova IP adresa:

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

Ovo nije najprimitivniji primjer službena dokumentacija može jednom za svagda obeshrabriti želju da se razume logika načina na koji mrežne politike funkcionišu. Ipak, pokušaćemo da razumemo osnovne principe i metode obrade tokova saobraćaja pomoću mrežnih politika...

Logično je da postoje 2 vrste saobraćaja: ulazak u pod (Ingress) i odlazni iz njega (Egress).

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Zapravo, politika je podijeljena u ove 2 kategorije na osnovu smjera kretanja.

Sljedeći potrebni atribut je selektor; onaj na koga se pravilo odnosi. Ovo može biti pod (ili grupa podova) ili okruženje (tj. imenski prostor). Važan detalj: oba tipa ovih objekata moraju sadržavati oznaku (etiketa u terminologiji Kubernetes) - to su oni kojima političari operišu.

Pored konačnog broja selektora ujedinjenih nekom vrstom oznake, moguće je pisati pravila poput „Dozvoli/zabrani sve/svako” u različitim varijantama. U tu svrhu koriste se konstrukcije oblika:

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

— u ovom primjeru, svi podovi u okruženju su blokirani od dolaznog saobraćaja. Suprotno ponašanje može se postići sljedećom konstrukcijom:

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

Slično za odlazne:

  podSelector: {}
  policyTypes:
  - Egress

- da ga isključim. A evo šta treba uključiti:

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

Vraćajući se na izbor CNI dodatka za klaster, vrijedi napomenuti da ne podržava svaki mrežni dodatak NetworkPolicy. Na primjer, već spomenuti Flannel ne zna kako da konfiguriše mrežne politike, što direktno je rečeno u zvaničnom repozitoriju. Pominje se i alternativa - projekat otvorenog koda Calico, što značajno proširuje standardni skup Kubernetes API-ja u smislu mrežnih politika.

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Upoznavanje Calico: teorija

Dodatak Calico se može koristiti u integraciji sa Flannel (podprojekat kanal) ili nezavisno, pokrivajući i mrežno povezivanje i mogućnosti upravljanja dostupnošću.

Koje mogućnosti pruža korištenje K8s “boxed” rješenja i API seta iz Calico-a?

Evo šta je ugrađeno u NetworkPolicy:

  • političari su ograničeni okruženjem;
  • politike se primjenjuju na mahune označene etiketama;
  • pravila se mogu primijeniti na podove, okruženja ili podmreže;
  • pravila mogu sadržavati protokole, imenovane ili simboličke specifikacije portova.

Evo kako Calico proširuje ove funkcije:

  • politike se mogu primijeniti na bilo koji objekt: pod, kontejner, virtuelnu mašinu ili interfejs;
  • pravila mogu sadržavati određenu radnju (zabrana, dozvola, evidentiranje);
  • cilj ili izvor pravila može biti port, raspon portova, protokoli, HTTP ili ICMP atributi, IP ili podmreža (4. ili 6. generacija), bilo koji selektori (čvorovi, domaćini, okruženja);
  • Dodatno, možete regulirati prolaz saobraćaja koristeći DNAT postavke i politike prosljeđivanja prometa.

Prva urezivanja na GitHub-u u Calico repozitoriju datiraju iz jula 2016. godine, a godinu dana kasnije projekat je zauzeo vodeću poziciju u organizaciji Kubernetes mrežnog povezivanja - o tome svjedoče, na primjer, rezultati ankete, koju vodi The New Stack:

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Mnoga velika upravljana rješenja sa K8s, kao što su Amazon EKS, Azure AKS, Google GKE a drugi su počeli da ga preporučuju za upotrebu.

Što se tiče performansi, ovdje je sve odlično. U testiranju svog proizvoda, razvojni tim Calico je pokazao astronomske performanse, pokrenuvši više od 50000 kontejnera na 500 fizičkih čvorova sa brzinom kreiranja od 20 kontejnera u sekundi. Nisu identifikovani problemi sa skaliranjem. Takvi rezultati najavljeni su već pri najavi prve verzije. Nezavisne studije koje se fokusiraju na propusnost i potrošnju resursa takođe potvrđuju da su performanse Calico-a gotovo jednako dobre kao i Flannel-ove. Na primjer:

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Projekat se razvija veoma brzo, podržava rad u popularnim rešenjima upravljanim K8s, OpenShift, OpenStack, moguće je koristiti Calico prilikom postavljanja klastera koristeći kops, postoje reference na izgradnju servisnih mreža (Evo primera koristi se zajedno sa Istio).

Vježbajte sa Calico

U opštem slučaju korišćenja vanilla Kubernetesa, instaliranje CNI-ja se svodi na korišćenje fajla calico.yaml, preuzeto sa službene web stranice, s pomoću kubectl apply -f.

Po pravilu, trenutna verzija dodatka je kompatibilna sa najnovijim 2-3 verzije Kubernetesa: rad u starijim verzijama nije testiran i nije zagarantovan. Prema programerima, Calico radi na Linux kernelima iznad 3.10 i pokreće CentOS 7, Ubuntu 16 ili Debian 8, na vrhu iptablesa ili IPVS-a.

Izolacija u okruženju

Za opće razumijevanje, pogledajmo jednostavan slučaj kako bismo razumjeli kako se mrežne politike u Calico notaciji razlikuju od standardnih i kako pristup kreiranju pravila pojednostavljuje njihovu čitljivost i fleksibilnost konfiguracije:

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

U klasteru su raspoređene 2 web aplikacije: u Node.js i PHP, od kojih jedna koristi Redis. Da blokirate pristup Redis-u iz PHP-a, uz održavanje povezanosti sa Node.js, samo primijenite sljedeću politiku:

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

U suštini smo dozvolili dolazni saobraćaj ka Redis portu iz Node.js. I očito ništa drugo nisu zabranili. Čim se NetworkPolicy pojavi, svi selektori navedeni u njoj počinju da se izoluju, osim ako nije drugačije naznačeno. Međutim, pravila izolacije se ne primjenjuju na druge objekte koje selektor ne pokriva.

Primjer koristi apiVersion Kubernetes iz kutije, ali ništa vas ne sprečava da ga koristite istoimeni izvor iz isporuke Calico. Sintaksa je tamo detaljnija, tako da ćete morati ponovo napisati pravilo za gornji slučaj u sljedećem obliku:

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

Gore spomenute konstrukcije za dopuštanje ili odbijanje cjelokupnog prometa kroz regularni NetworkPolicy API sadrže konstrukcije sa zagradama koje je teško razumjeti i zapamtiti. U slučaju Calico, da biste promijenili logiku pravila zaštitnog zida na suprotnu, samo promijenite action: Allow na action: Deny.

Izolacija po okolini

Sada zamislite situaciju u kojoj aplikacija generiše poslovnu metriku za prikupljanje u Prometheusu i dalju analizu koristeći Grafanu. Otpremanje može sadržavati osjetljive podatke, koji su prema zadanim postavkama opet javno vidljivi. Sakrijmo ove podatke od znatiželjnih očiju:

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Prometheus se, po pravilu, postavlja u zasebno uslužno okruženje - u primjeru će to biti prostor imena poput ovog:

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

polje metadata.labels ispostavilo se da ovo nije slučajno. Kao što je gore spomenuto, namespaceSelector (kao i podSelector) radi sa oznakama. Stoga, da biste omogućili preuzimanje metrike iz svih podova na određenom portu, morat ćete dodati neku vrstu oznake (ili uzeti iz postojećih), a zatim primijeniti konfiguraciju poput:

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

A ako koristite Calico politike, sintaksa će biti ovakva:

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

Općenito, dodavanjem ovakvih politika za specifične potrebe, možete se zaštititi od zlonamjernih ili slučajnih smetnji u radu aplikacija u klasteru.

Najbolja praksa, prema kreatorima Calico-a, je pristup „Blokiraj sve i eksplicitno otvori šta ti treba“, dokumentiran u službena dokumentacija (drugi slijede sličan pristup - posebno u već pomenuti članak).

Korištenje dodatnih Calico objekata

Dozvolite mi da vas podsjetim da kroz prošireni skup Calico API-ja možete regulirati dostupnost čvorova, ne ograničavajući se na podove. U sljedećem primjeru koristeći GlobalNetworkPolicy mogućnost prosljeđivanja ICMP zahtjeva u klasteru je zatvorena (na primjer, pingovi od modula do čvora, između podova ili od čvora do IP modula):

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

U gornjem slučaju, još uvijek je moguće da čvorovi klastera „dopru” jedan do drugog preko ICMP-a. I ovo pitanje se rješava sredstvima GlobalNetworkPolicy, primijenjen na entitet 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"]

Slučaj VPN-a

Konačno, dat ću vrlo stvaran primjer korištenja Calico funkcija za slučaj interakcije skoro klastera, kada standardni skup politika nije dovoljan. Za pristup web aplikaciji, klijenti koriste VPN tunel, a ovaj pristup je strogo kontroliran i ograničen na određenu listu usluga dozvoljenih za korištenje:

Calico za umrežavanje u Kubernetesu: uvod i malo iskustva

Klijenti se povezuju na VPN preko standardnog UDP porta 1194 i, kada su povezani, primaju rute do podmreža klastera podova i usluga. Cijele podmreže se potiskuju kako ne bi izgubile usluge tokom restartovanja i promjene adrese.

Port u konfiguraciji je standardan, što nameće neke nijanse u procesu konfigurisanja aplikacije i prenosa u Kubernetes klaster. Na primjer, u istom AWS LoadBalancer za UDP pojavio se bukvalno krajem prošle godine na ograničenoj listi regija, a NodePort se ne može koristiti zbog njegovog prosljeđivanja na svim čvorovima klastera i nemoguće je skalirati broj serverskih instanci za u svrhu tolerancije grešaka. Osim toga, morat ćete promijeniti zadani raspon portova...

Kao rezultat pretraživanja mogućih rješenja, odabrano je sljedeće:

  1. Podovi s VPN-om su zakazani po čvoru u hostNetwork, odnosno na stvarnu IP adresu.
  2. Usluga je objavljena napolju kroz ClusterIP. Na čvoru je fizički instaliran port koji je dostupan izvana uz manje rezervacije (uslovno prisustvo prave IP adrese).
  3. Utvrđivanje čvora na kojem se ruža mahuna nalazi izvan okvira naše priče. Reći ću samo da servis možete čvrsto "zakovati" za čvor ili napisati malu pomoćnu uslugu koja će pratiti trenutnu IP adresu VPN servisa i uređivati ​​DNS zapise registrovane kod klijenata - ko ima dovoljno mašte.

Iz perspektive rutiranja, možemo jedinstveno identificirati VPN klijenta po njegovoj IP adresi koju izdaje VPN server. Ispod je primitivan primjer ograničavanja pristupa takvog klijenta uslugama, ilustrovan na gore spomenutom Redis-u:

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]

Ovdje je strogo zabranjeno povezivanje s portom 6379, ali je u isto vrijeme očuvan rad DNS usluge, čije funkcioniranje često pati prilikom sastavljanja pravila. Jer, kao što je prethodno spomenuto, kada se pojavi selektor, na njega se primjenjuje standardna politika odbijanja osim ako nije drugačije navedeno.

Ishodi

Stoga, koristeći napredni API Calico, možete fleksibilno konfigurirati i dinamički mijenjati rutiranje unutar i oko klastera. Općenito, njegova upotreba može izgledati kao gađanje vrabaca iz topa, a implementacija L3 mreže sa BGP i IP-IP tunelima izgleda monstruozno u jednostavnoj Kubernetes instalaciji na ravnoj mreži... Međutim, inače alat izgleda prilično održiv i koristan .

Izolacija klastera radi ispunjavanja sigurnosnih zahtjeva možda nije uvijek izvodljiva, i tu Calico (ili slično rješenje) dolazi u pomoć. Primeri dati u ovom članku (sa manjim modifikacijama) koriste se u nekoliko instalacija naših klijenata u AWS.

PS

Pročitajte i na našem blogu:

izvor: www.habr.com

Dodajte komentar