Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Artikli eesmärk on tutvustada lugejat Kubernetes'e võrgus kommunikatsiooni ja võrgu poliitikate haldamise alustega ning kolmanda osapoole plugina Calico, mis laiendab standardseid võimalusi. Samuti demonstreeritakse seadistamise mugavust ja mõningaid funktsioone meie töökogemuste põhjal.

Kiire sissejuhatus Kubernetes'e võrguseadmisse

Kubernetes'e kluster on võimatu ette kujutada ilma võrguta. Oleme juba avaldanud materjale nende aluste kohta: "Illustreeritud juhend Kubernetes'e võrgu struktuuri kohta» ja «Kubernetes'e võrgupoliitikas tutvumine turvaekspertidele».

Sellest artiklist rääkides on oluline märkida, et konteinerite ja sõlmede vahelise võrguside eest vastutab mitte K8s ise: selleks kasutatakse mitmesuguseid CNI pluginaid (Container Networking Interface). Täiendavat teavet selle kontseptsiooni kohta oleme juba jaganud..

Näiteks on kõige levinum selline plugin — Flannel — tagab täielikku võrguühenduvust kõigi klastris olevate sõlmede vahel, luues igas sõlmes sillad ja kinnitades neile alamvõrgu. Siiski ei ole täielik ja reguleerimata kättesaadavus alati kasulik. Klastris mingisuguse minimaalsete eraldusmeetmete tagamiseks on vajalik sekkuda tulemüüride konfigureerimisse. Üldiselt on see usaldatud sama CNI haldusesse, mistõttu võivad kõik välised sekkumised iptables’isse olla vale tõlgendusega või sootuks ignoreeritud.

Ja "kastist välja" pakub Kubernetes klastris võrgu poliitikate juhtimiseks NetworkPolicy API. See ressurss, mida rakendatakse valitud nime ruumides, võib sisaldada reegleid juurdepääsu eraldamiseks ühe rakenduse ja teise vahel. See võimaldab samuti seadistada juurdepääsu konkreetsete pod’ide, keskkondade (nime ruumide) või IP-aadresside plokkide vahel:

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

Этот не самый примитивный пример из ametlikus dokumentatsioonis может раз и навсегда отбить желание разбираться в логике работы сетевых политик. Однако мы всё же попробуем понять основные принципы и методы обработки потоков трафика с помощью сетевых политик…

Логично, что есть 2 типа трафика: входящий в pod (Ingress) и исходящий из него (Egress).

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Собственно, на эти 2 категории по направлению движения и разделяется политика.

Следующий обязательный атрибут — селектор; тот, к кому применяется правило. Это может быть pod (или группа pod’ов) или окружение (т.е. пространство имен). Важная деталь: оба вида этих объектов обязаны содержать метку (silt в терминологии Kubernetes) — именно ими оперируют политики.

Lisaks lõplikule valikule, mis on ühendatud mõne märgisega, on võimalik kirjutada reegleid nagu "Luba / keela kõik / kõigile" erinevates variatsioonides. Selleks kasutatakse konstruktsioone, nagu:

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

— sel juhul suletakse kõigi pod'ide sisenemine keskkonda. Vastupidist käitumist saab saavutada sellise konstruktsiooniga:

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

Sama kehtib ka väljuva liikluse kohta:

  podSelector: {}
  policyTypes:
  - Egress

— selle keelamiseks. Ja siin on see, kuidas seda lubada:

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

Tagasi tulles CNI-lisa valikku klastrile, tasub märkida, et kõik võrgu lisad ei toeta NetworkPolicy tööd. Näiteks juba mainitud Flannel ei oska võrgu poliitikaid seadistada, millest on selgelt märgitud ametlikus hoidlas. Seal mainitakse ka alternatiivi — avatud lähtekoodiga projekt Calico, mis laianeb oluliselt Kubernetes'e võrgu poliitilisi API-sid.

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Tutvume Calicoga: teooria

Calico plugin saab kasutada Flanneliga koos (alaprojekt Canal) või iseseisvalt, katab nii võrguühenduse tagamise funktsioonid kui ka kättesaadavuse haldamise võimalused.

Milliseid võimalusi pakub ‘karbi’ K8s lahenduse ja Calico API komplekti kasutamine?

Siin on, mis on NetworkPolicy sisse ehitatud:

  • poliitikad on piiratud keskkonnaga;
  • poliitikad rakendatakse siltidega pod'idele;
  • reeglid võivad kehtida pod'idele, keskkondadele või alamvõrkudele;
  • reeglid võivad sisaldada protokolle, nimetatud või sümboolseid portide viiteid.

Ja nii laiendab Calico neid funktsioone:

  • poliitikad võivad kehtida igasugustele objektidele: pod, konteiner, virtuaalmasin või liides;
  • reeglid võivad sisaldada konkreetset tegevust (keeldumine, lubamine, logimine);
  • reeglite sihtmärgiks või allikaks võivad olla port, portide vahemik, protokollid, HTTP- või ICMP-attribuudid, IP või alamvõrk (4. või 6. põlvkond), kõik valijad (sõlmed, hostid, keskkonnad);
  • lisaks on võimalik reguleerida liikluse läbimist DNAT-i seadete ja liikluse suunamise poliitikate abil.

Calico hoidlate esimesed commitid GitHubis pärinevad 2016. aasta juulist, ja juba aasta hiljem saavutas projekt juhtiva positsiooni Kubernetes'i võrgutootmise organisatsioonis — näiteks kinnitavad seda küsitluse tulemused. mida viis läbi The New Stack.:

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Paljud suured K8s-i hallatud lahendused, nagu Amazon EKS, Azure AKS,, Google GKE ning teised, on hakanud seda soovitama.

Mis puutub jõudlusesse, siis on kõik suurepärane. Calico arendustiim demonstreeris oma toote testimisel astronoomilisi näitajaid, käivitades enam kui 50000 konteinerit 500 füüsilisel sõlmel kiirusel 20 konteinerit sekundis. Skaleerimisega ei esinenud probleeme. Sellised tulemused oli välja öeldud juba esimese versiooni väljakuulutamisel. Olenematu teadusuuringud, mis on suunatud läbilaskevõime ja ressursitarbimise mahtude määramisele, kinnitavad samuti Calico jõudlust, mis praktiliselt ei jää Flannelile alla. Piemēram:

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Projekt areneb väga kiiresti, toetades töötlust populaarsetes hallatud K8s-i lahendustes, OpenShiftis, OpenStackis ning on võimalik kasutada Calicot klastrite juurutamisel kops, kohtab viiteid Service Mesh-võrkude ehitamisele (вот пример использования совместно с Istio).

Практика с Calico

В общем случае использования ванильного Kubernetes установка CNI сводится к применению файла calico.yaml, скачанного с официального сайта, kasutades kubectl apply -f.

Как правило, актуальная версия плагина совместима с 2-3 последними версиями Kubernetes: работу в более старых версиях не тестируют и не гарантируют. По заявлениям разработчиков, Calico работает на ядре Linux выше 3.10 под управлением CentOS 7, Ubuntu 16 или Debian 8, поверх iptables или IPVS.

Изоляция внутри окружения

Для общего понимания рассмотрим простой случай, чтобы понять, чем отличаются сетевые политики в нотации Calico от стандартных и как подход к составлению правил упрощает их читаемость и гибкость конфигурирования:

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

В кластере развёрнуты 2 веб-приложения: на Node.js и PHP, — одно из которых использует Redis. Чтобы закрыть доступ к Redis из PHP, оставив при этом связность с Node.js, достаточно применить следующую политику:

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

Põhimõtteliselt oleme lubanud sissetuleva liikluse Redis pordile Node.js-st. Ja me ei ole selgelt midagi muud keelanud. Kui NetworkPolicy ilmub, hakkavad kõik selles mainitud selektorid isoleeruma, kui pole teisiti märgitud. Samuti ei laiene isolatsioonieeskirjad muudele objektidele, mida selektor ei kata.

Näites kasutatakse apiVersion Kubernetes'e "välja kastist", kuid miski ei takista kasutamast samanimelist ressurssi Calico tarnest. Süntaks on seal keerulisem, seega tuleb ülaltoodud juhtumi eeskirja kirjutada järgmisel kujul:

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

Ülalmainitud konstruktsioonid, et lubada või keelata kogu liiklust tavapärase NetworkPolicy API kaudu, sisaldavad keerulisi ja meeldejäävaid konstruktsioone sulgudes. Calico puhul piisab tulemüüri reegli logika muutmiseks vastupidiseks, kui muuta action: Allow järgnevaga action: Deny.

Isolatsioon keskkondade kaupa

Kujutage nüüd olukorda, kus rakendus genereerib ärimetreid nende kogumiseks Prometheuses ja edasisteks analüüsideks Grafanas. Väljavõttes võivad olla tundlikud andmed, mis vaikimisi on taas kergesti kätte saadavad. Kaitseme need andmed võõraste silmade eest:

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Prometheus on tavaliselt eraldi teenusekeskkonnas — näites on see nimede ruum järgmise nimega:

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

Väli metadata.labels see ei juhtunud juhuslikult. Nagu eespool juba mainitud, namespaceSelector'iga (nagu ka podSelector) opereerib etiketiga. Seetõttu, et lubada metrikate hankimist kõigilt pod'idelt teatud pordil, tuleb lisada mõni silt (või võtta olemasolevatest), seejärel rakendada konfiguratsioon nagu:

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

Ja Calico poliitikate kasutamise korral näeb süntaks välja järgmine:

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

Üldiselt saab selliste poliitikate kohandamisel konkreetsete vajadustega kaitsta rakenduste tööd klastris pahatahtliku või juhusliku sekkumise eest.

Parim praktika Calico looja arvates on lähenemine "Keela kõik ja ava selgelt vajalik", mis on dokumenteeritud ametlikus dokumentatsioonis (sama lähenemist järgivad ka teised, sealhulgas juba mainitud artiklis).

Lisaressursside Calico rakendamine

Tuletan meelde, et Calico laiendatud API komplekti kaudu saab reguleerida sõlmede kättesaadavust, mitte ainult pod’ide osas. Järgmises näites aitab see GlobalNetworkPolicy blokeerida ICMP-päringute läbimise klastris (näiteks pod’ist sõlmele, pod’ide vahel või sõlmelt pod’i IP-le):

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

Eeltoodud juhul jääb klastris olevatele sõlmedele võimalus üksteisega ICMP kaudu ühendust võtta. Ja see probleem lahendatakse GlobalNetworkPolicy, mis on rakendatud objekti 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"]

VPNi juhtum

Toon lõpuks üsna reaalset näidet Calico funktsioonide kasutamisest, kui standardne poliitikakogum ei piisa klastritevahelise suhtluse juhtimiseks. Klientide juurdepääs veebirakendusele toimub VPN-tunneli kaudu, kusjuures juurdepääs on rangelt reguleeritud ja piiratud kindla lubatud teenuste nimekirjaga:

Calico Kubernetes'i võrgu jaoks: sissejuhatus ja veidi kogemust

Kliendid ühenduvad VPN-i kaudu tavalise UDP-pordi 1194 kaudu ja saavad ühendamisel marsruudid klastrite pods ja teenuste alamvõrkudesse. Alamvõrgud push’itakse tervikuna, et teenused ei kaoks taaskäivituste ja aadresside muutmise korral.

Konfiguratsioonis on port standardne, mis seab rakenduse konfigureerimise protsessile ja selle viimiseks Kubernetes klastrisse mõned eripärad. Näiteks, AWS LoadBalanceris ilmus UDP eelmisel aastal piiratud piirkondade loetelus, kuid NodePorti ei saa kasutada, kuna see suunatakse kõikidele klastris olevatele sõlmedele ja ei ole võimalik skaleerida serveri instantside arvu töökindluse saavutamiseks. Lisaks tuleb muuta vaikimisi valitud portide vahemikku...

Võimalike lahenduste ülesseadmise tulemusel valiti järgnev:

  1. VPN Pod'id plaanitakse sõlmele režiimis hostNetwork, st tegelikule IP-le.
  2. Teenust väljapoole suunatakse läbi ClusterIP. Sõlmel tõstetakse füüsiliselt port, mis on kergelt väljastpoolt kergesti ligipääsetav (tingimuslik olemasolek reaalse IP-aadressiga).
  3. Sõlme määramise, kuhu pod on üles tõstetud, jääb meie jutustuse piiridest välja. Ütlen vaid, et teenust saab kindlalt "kinni haakida" sõlmele või kirjutada väikese sidecar-teenuse, mis jälgib VPN-teenuse praegust IP-aadressi ja muudab kliente registreeritud DNS-kirjeid — kellel on kujutlust.

VPN-i IP-aadressi kaudu saame kliendi selgelt tuvastada. Allpool on primitiivne näide selle kliendi juurdepääsu piirangust, kasutades eespool mainitud Redis't:

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]

Siin on port 6379 ühendamine rangelt keelatud, kuid samal ajal on DNS-teenus säilinud, mille toimivus kannatab sageli reeglite koostamisel. Sest nagu eelnevalt mainitud, rakendatakse sättega seoses vaikimisi keelu poliitikat, kui pole öeldud teisiti.

Kokkuvõte

Seega saab Calico laiendatud API abil paindlikult konfigureerida ja dünaamiliselt muuta marsruutimist klastris ja selle ümber. Üldiselt võib selle kasutamine tunduda nagu püssist varblaste peale laskmine, ning L3-võrgu juurutamine BGP- ja IP-IP-tunnelitega näeb välja monstrueus lihtsas Kubernetes'i tasandatud võrgus… Siiski näeb muu tööriist välja üsna elujõuline ja kasulik.

Klastri isoleerimine turvanõuete täitmiseks ei pruugi alati olla teostatav, ja just sellistel juhtudel tulebki appi Calico (või sarnane lahendus). Artiklis toodud näidiseid (veidi kohandatuna) kasutatakse mitmes meie klientide AWS-i paigalduses.

P.S.

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster