Calico til netværk i Kubernetes: introduktion og lidt erfaring
Formålet med artiklen er at introducere læseren til det grundlæggende i netværk og administration af netværkspolitikker i Kubernetes, samt tredjeparts Calico-plugin, der udvider standardmulighederne. Undervejs vil den nemme konfiguration og nogle funktioner blive demonstreret ved hjælp af rigtige eksempler fra vores driftserfaring.
En hurtig introduktion til Kubernetes netværksapparat
I forbindelse med denne artikel er det vigtigt at bemærke, at K8s ikke selv er ansvarlig for netværksforbindelse mellem containere og noder: til dette kan div. CNI plugins (Container netværksgrænseflade). Mere om dette koncept vi de fortalte mig også.
For eksempel er den mest almindelige af disse plugins flannel — giver fuld netværksforbindelse mellem alle klynge noder ved at hæve broer på hver node, tildele et undernet til det. Fuldstændig og ureguleret tilgængelighed er dog ikke altid gavnlig. For at give en form for minimal isolation i klyngen er det nødvendigt at gribe ind i firewallens konfiguration. I det generelle tilfælde er det placeret under kontrol af den samme CNI, hvorfor enhver tredjeparts indgreb i iptables kan fortolkes forkert eller ignoreres helt.
Og "ud af boksen" til organisering af netværkspolitikstyring i en Kubernetes-klynge leveres NetworkPolicy API. Denne ressource, fordelt over udvalgte navneområder, kan indeholde regler for at differentiere adgang fra en applikation til en anden. Det giver dig også mulighed for at konfigurere tilgængelighed mellem specifikke pods, miljøer (navneområder) eller blokke af IP-adresser:
Dette er ikke det mest primitive eksempel på officiel dokumentation kan én gang for alle afskrække ønsket om at forstå logikken i, hvordan netværkspolitikker fungerer. Vi vil dog stadig forsøge at forstå de grundlæggende principper og metoder til behandling af trafikstrømme ved hjælp af netværkspolitikker...
Det er logisk, at der er 2 typer trafik: ind i poden (Ingress) og udgående fra den (Egress).
Faktisk er politik opdelt i disse to kategorier baseret på bevægelsesretningen.
Den næste påkrævede attribut er en vælger; den, reglen gælder for. Dette kan være en pod (eller en gruppe af pods) eller et miljø (dvs. et navneområde). En vigtig detalje: begge typer af disse objekter skal indeholde en etiket (label i Kubernetes terminologi) - det er dem, politikerne opererer med.
Ud over et begrænset antal vælgere forenet af en slags etiket, er det muligt at skrive regler som "Tillad/nægt alt/alle" i forskellige variationer. Til dette formål bruges konstruktioner af formen:
Vender vi tilbage til valget af et CNI-plugin til en klynge, er det værd at bemærke det ikke alle netværksplugins understøtter NetworkPolicy. For eksempel ved den allerede nævnte Flannel ikke, hvordan man konfigurerer netværkspolitikker, hvilket det siges direkte i det officielle depot. Der er også nævnt et alternativ - et Open Source-projekt Calico, som markant udvider standardsættet af Kubernetes API'er med hensyn til netværkspolitikker.
Lær Calico at kende: teori
Calico-plugin'et kan bruges i integration med Flannel (delprojekt Canal) eller uafhængigt, der dækker både netværksforbindelse og tilgængelighedsstyringsfunktioner.
Hvilke muligheder giver det at bruge K8s "boxed"-løsning og API-sættet fra Calico?
Her er, hvad der er indbygget i NetworkPolicy:
politikere er begrænset af miljøet;
politikker anvendes på pods markeret med etiketter;
regler kan anvendes på pods, miljøer eller undernet;
regler kan indeholde protokoller, navngivne eller symbolske portspecifikationer.
Her er hvordan Calico udvider disse funktioner:
politikker kan anvendes på ethvert objekt: pod, container, virtuel maskine eller grænseflade;
regler kan indeholde en specifik handling (forbud, tilladelse, logning);
målet eller kilden til regler kan være en port, en række porte, protokoller, HTTP- eller ICMP-attributter, IP eller subnet (4. eller 6. generation), alle vælgere (noder, værter, miljøer);
Derudover kan du regulere passage af trafik ved hjælp af DNAT-indstillinger og trafikvideresendelsespolitikker.
De første commits på GitHub i Calico-depotet går tilbage til juli 2016, og et år senere indtog projektet en førende position i organiseringen af Kubernetes-netværksforbindelsen - det fremgår for eksempel af undersøgelsesresultaterne, dirigeret af The New Stack:
Mange store administrerede løsninger med K8'ere, som f.eks Amazon EX, Azure AKS, Google GKE og andre begyndte at anbefale det til brug.
Hvad angår ydeevne, er alt fantastisk her. Ved at teste deres produkt demonstrerede Calicos udviklingsteam astronomisk ydeevne, idet de kørte mere end 50000 containere på 500 fysiske noder med en oprettelseshastighed på 20 containere i sekundet. Der blev ikke identificeret problemer med skalering. Sådanne resultater blev annonceret allerede ved offentliggørelsen af den første version. Uafhængige undersøgelser med fokus på gennemløb og ressourceforbrug bekræfter også, at Calicos ydeevne er næsten lige så god som Flannels. For eksempel:
Projektet udvikler sig meget hurtigt, det understøtter arbejde i populære løsninger administreret K8s, OpenShift, OpenStack, det er muligt at bruge Calico, når du implementerer en klynge vha. sparke, der er referencer til opbygningen af Service Mesh-netværk (her er et eksempel bruges sammen med Istio).
Øv med Calico
I det generelle tilfælde med at bruge vanilla Kubernetes, kommer installation af CNI ned til at bruge filen calico.yaml, downloadet fra den officielle hjemmeside, ved hjælp af kubectl apply -f.
Som regel er den aktuelle version af plugin'et kompatibel med de seneste 2-3 versioner af Kubernetes: drift i ældre versioner er ikke testet og er ikke garanteret. Ifølge udviklerne kører Calico på Linux-kerner over 3.10, der kører CentOS 7, Ubuntu 16 eller Debian 8, oven på iptables eller IPVS.
Isolation i miljøet
For en generel forståelse, lad os se på en simpel case for at forstå, hvordan netværkspolitikker i Calico-notationen adskiller sig fra standard, og hvordan tilgangen til at skabe regler forenkler deres læsbarhed og konfigurationsfleksibilitet:
Der er 2 webapplikationer installeret i klyngen: i Node.js og PHP, hvoraf den ene bruger Redis. For at blokere adgangen til Redis fra PHP, mens du opretholder forbindelsen til Node.js, skal du blot anvende følgende politik:
Grundlæggende tillod vi indgående trafik til Redis-porten fra Node.js. Og de forbød tydeligvis ikke andet. Så snart NetworkPolicy vises, begynder alle vælgere nævnt i den at blive isoleret, medmindre andet er angivet. Isolationsreglerne gælder dog ikke for andre objekter, der ikke er omfattet af vælgeren.
Eksemplet bruger apiVersion Kubernetes ud af æsken, men intet forhindrer dig i at bruge det ressource af samme navn fra Calico-leveringen. Syntaksen der er mere detaljeret, så du bliver nødt til at omskrive reglen for ovenstående tilfælde i følgende form:
De ovennævnte konstruktioner til at tillade eller nægte al trafik gennem den almindelige NetworkPolicy API indeholder konstruktioner med parenteser, som er svære at forstå og huske. I tilfælde af Calico, for at ændre logikken i en firewall-regel til det modsatte, skal du bare ændre action: Allow på action: Deny.
Isolation af miljø
Forestil dig nu en situation, hvor en applikation genererer forretningsmålinger til indsamling i Prometheus og yderligere analyse ved hjælp af Grafana. Uploaden kan indeholde følsomme data, som igen er offentligt synlige som standard. Lad os skjule disse data fra nysgerrige øjne:
Prometheus er som regel placeret i et separat servicemiljø - i eksemplet vil det være et navneområde som dette:
Field metadata.labels dette viste sig ikke at være nogen tilfældighed. Som nævnt ovenfor, namespaceSelector (såvel som podSelector) fungerer med etiketter. Derfor, for at tillade, at metrics kan tages fra alle pods på en specifik port, bliver du nødt til at tilføje en slags etiket (eller tage fra eksisterende), og derefter anvende en konfiguration som:
Generelt kan du ved at tilføje denne slags politikker til specifikke behov beskytte mod ondsindet eller utilsigtet interferens i driften af programmer i klyngen.
Den bedste praksis, ifølge skaberne af Calico, er tilgangen "Bloker alt, og åbn eksplicit, hvad du har brug for", dokumenteret i officiel dokumentation (andre følger en lignende tilgang - især i allerede nævnte artikel).
Brug af yderligere Calico-objekter
Lad mig minde dig om, at du gennem det udvidede sæt af Calico API'er kan regulere tilgængeligheden af noder, ikke begrænset til pods. I det følgende eksempel ved hjælp af GlobalNetworkPolicy muligheden for at videregive ICMP-anmodninger i klyngen er lukket (f.eks. pings fra en pod til en node, mellem pods eller fra en node til en IP-pod):
I ovenstående tilfælde er det stadig muligt for klynge noder at "nå ud" til hinanden via ICMP. Og dette problem er løst ved hjælp af midler GlobalNetworkPolicy, anvendt på en enhed HostEndpoint:
Til sidst vil jeg give et meget reelt eksempel på brug af Calico-funktioner i tilfælde af nær-klynge-interaktion, når et standardsæt af politikker ikke er nok. For at få adgang til webapplikationen bruger klienter en VPN-tunnel, og denne adgang er stramt kontrolleret og begrænset til en specifik liste over tjenester, der er tilladt til brug:
Klienter opretter forbindelse til VPN via standard UDP-port 1194, og når de er tilsluttet, modtager de ruter til klyngeundernet af pods og tjenester. Hele undernet skubbes for ikke at miste tjenester under genstart og adresseændringer.
Porten i konfigurationen er standard, hvilket pålægger nogle nuancer i processen med at konfigurere applikationen og overføre den til Kubernetes-klyngen. For eksempel, i den samme AWS optrådte LoadBalancer for UDP bogstaveligt i slutningen af sidste år i en begrænset liste over regioner, og NodePort kan ikke bruges på grund af dens videresendelse på alle klynge noder, og det er umuligt at skalere antallet af serverforekomster for fejltolerance formål. Plus, du bliver nødt til at ændre standardområdet for porte...
Som et resultat af at søge gennem mulige løsninger, blev følgende valgt:
Pods med VPN er planlagt pr. node ind hostNetwork, altså til den faktiske IP.
Tjenesten er postet udenfor igennem ClusterIP. En port er fysisk installeret på noden, som er tilgængelig udefra med mindre forbehold (betinget tilstedeværelse af en rigtig IP-adresse).
At bestemme knudepunktet, hvorpå bælgrosen er uden for vores histories omfang. Jeg vil bare sige, at du stramt kan "nagle" tjenesten til en node eller skrive en lille sidevognstjeneste, der overvåger den aktuelle IP-adresse på VPN-tjenesten og redigerer DNS-registreringerne, der er registreret hos klienter - hvem der end har fantasi nok.
Fra et routingperspektiv kan vi entydigt identificere en VPN-klient ved dens IP-adresse udstedt af VPN-serveren. Nedenfor er et primitivt eksempel på begrænsning af en sådan klients adgang til tjenester, illustreret på ovennævnte Redis:
Her er forbindelse til port 6379 strengt forbudt, men samtidig bevares driften af DNS-tjenesten, hvis funktion ret ofte lider under udarbejdelse af regler. Fordi, som tidligere nævnt, når en vælger vises, anvendes standardafvisningspolitikken på den, medmindre andet er angivet.
Resultaterne af
Ved hjælp af Calicos avancerede API kan du således fleksibelt konfigurere og dynamisk ændre routing i og omkring klyngen. Generelt kan brugen af det ligne at skyde gråspurve med en kanon, og implementering af et L3-netværk med BGP og IP-IP-tunneler ser monstrøs ud i en simpel Kubernetes-installation på et fladt netværk... Men ellers ser værktøjet ganske levedygtigt og brugbart ud. .
Det er ikke altid muligt at isolere en klynge for at opfylde sikkerhedskravene, og det er her, Calico (eller en lignende løsning) kommer til undsætning. Eksemplerne givet i denne artikel (med mindre ændringer) bruges i flere installationer af vores kunder i AWS.