
Målet med artiklen er at introducere læseren til grundlæggende netværksinteraktion og styring af netværkspolitikker i Kubernetes, samt til det tredjepartsplugin Calico, der udvider de standardmæssige funktioner. Undervejs vil bekvemmeligheden ved konfiguration og nogle funktioner blive demonstreret med reelle eksempler fra vores erfaring.
Hurtig introduktion til Kubernetes-netværksenheder
Det er umuligt at forestille sig et Kubernetes-klynge uden netværk. Vi har allerede offentliggjort materialer om deres grundlæggende: "" og "».
I konteksten af denne artikel er det vigtigt at nævne, at netværksforbindelsen mellem containere og noder ikke håndteres af K8s selv: til dette anvendes forskellige CNI-plugins (Container Networking Interface). Vi har også beskrevet denne koncept .
For eksempel er den mest udbredte af sådanne plugins — — ansvarlig for at sikre fuld netværksforbindelse mellem alle noder i klyngen ved at oprette broer på hver node og tildele et subnet. Men fuld og ureguleret tilgængelighed er ikke altid nyttig. For at sikre en slags minimal isolation i klyngen er det nødvendigt at intervenere i konfigurationen af firewall. Generelt er det overladt til den nævnte CNI, hvilket kan betyde, at enhver ekstern indgriben i iptables kan blive fejltolket eller helt ignoreret.
Og "ud af boksen" til etablering af styringen af netværkspolitikker i Kubernetes-klyngen tilvejebringes . Denne ressource, der gælder for valgte navnerum, kan indeholde regler for at begrænse adgangen mellem applikationer. Den tillader også at konfigurere tilgængelighed mellem specifikke pods, miljøer (navnerum) eller blokkeringer af IP-adresser:
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: 5978Dette er ikke det mest primitive eksempel Det kan måske for en gangs skyld slå enhver lyst til at forstå logikken bag netværkspolitikker fra. Alligevel vil vi 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: indgående til pod (Ingress) og udgående fra det (Egress).

Faktisk opdeles politikken i disse 2 kategorier afhængigt af bevægelsesretningen.
Den næste nødvendige attribut er vælgeren; den, som reglen gælder for. Dette kan være en pod (eller gruppe af pods) eller et miljø (dvs. et navnrum). En vigtig detalje: begge typer af disse objekter skal indeholde en label (label i Kubernetes-terminologi) — det er netop dem, som politikker arbejder med.
Ud over et begrænset antal vælgere, der forbindes med en bestemt label, er det også muligt at skrive regler som "Tillad/forbud alt/alle" i forskellige varianter. Dette gøres med konstruktioner som:
podSelector: {}
ingress: []
policyTypes:
- Ingress— i dette eksempel lukkes indgående trafik for alle pods i miljøet. Den modsatte adfærd kan opnås med en sådan konstruktion:
podSelector: {}
ingress:
- {}
policyTypes:
- IngressDet samme gælder for udgående:
podSelector: {}
policyTypes:
- Egress— for at deaktivere det. Og her er hvad der skal til for at aktivere det:
podSelector: {}
egress:
- {}
policyTypes:
- EgressNår vi vender tilbage til valget af CNI-plugin til klyngen, er det vigtigt at bemærke, at ikke alle netværksplugins understøtter arbejde med NetworkPolicy. For eksempel kan den allerede nævnte Flannel ikke konfigurere netværkspolitikker, hvilket i det officielle register. Her nævnes også en alternativ Open Source-projekt , som væsentligt udvider den standard API-sæt i Kubernetes med hensyn til netværkspolitikker.

Lad os lære Calico at kende: teori
Calico-pluginet kan bruges i integration med Flannel (undersprojektet ) eller uafhængigt, idet det dækker både funktionerne til at sikre netværksforbindelse og mulighederne for at styre tilgængeligheden.
Hvilke muligheder giver brugen af en "out-of-the-box" K8s-løsning og API-sættet fra Calico?
Her er hvad der er indbygget i NetworkPolicy:
- politikker er begrænset til miljøet;
- politikker anvendes på pods, der er mærket med labels;
- regler kan anvendes på pods, miljøer eller undernetværk;
- regler kan indeholde protokoller, navngivne eller symbolske angivelser af porte.
Og sådan udvider Calico disse funktioner:
- Politikker kan anvendes på enhver enhed: pod, container, virtuel maskine eller interface;
- Reglerne kan indeholde en specifik handling (forbud, tilladelse, logning);
- Som mål eller kilde for reglerne kan der være en port, en port-range, protokoller, HTTP- eller ICMP-attributter, IP eller subnet (4. eller 6. generation), og enhver vælger (noder, værter, miljøer);
- Derudover kan trafikgennemgang reguleres ved hjælp af DNAT-indstillinger og trafikafpresningspolitikker.
De første commits på GitHub i Calico-repositoriet stammer fra juli 2016, og allerede et år senere indtog projektet førende stillinger inden for netværkssammenkobling i Kubernetes, som det blandt andet fremgår af resultaterne af en undersøgelse, :

Mange store managed-løsninger med K8s, såsom , , og andre, anbefaler nu det til brug.
Hvad angår ydeevne, så er det strålende. Under test af deres produkt demonstrerede Calicos udviklingsteam astronomiske resultater ved at køre mere end 50000 containere på 500 fysiske noder med en hastighed på 20 containere i sekundet. Der blev ikke registreret problemer ved skalering. Sådanne resultater allerede ved lanceringen af den første version. Uafhængige undersøgelser, der har fokus på båndbredde og ressourceforbrug, bekræfter også Calicos ydeevne, som næsten ikke er ringere end Flannels. :

Projektet udvikler sig meget hurtigt, understøtter arbejde i populære managed K8s-løsninger, OpenShift, OpenStack, med mulighed for at bruge Calico ved implementering af en klynge ved hjælp af , der er omtaler om opbygning af Service Mesh-netværk ( på brug sammen med Istio).
Praksis med Calico
I almindelighed ved brug af vanilje Kubernetes, installeres CNI ved at anvende filen calico.yaml, , ved hjælp af kubectl apply -f.
Som regel er den aktuelle version af pluginet kompatibel med de 2-3 seneste versioner af Kubernetes: der testes ikke for, at det fungerer i ældre versioner, og der gives ingen garantier for dette. Ifølge udviklerne fungerer Calico på en Linux-kerne over 3.10 under CentOS 7, Ubuntu 16 eller Debian 8, oven på iptables eller IPVS.
Isolation inden for miljøet
For a general understanding, let's consider a simple case to grasp how Calico's network policies differ from standard ones and how the approach to rule creation simplifies their readability and configuration flexibility:

In the cluster, there are 2 web applications deployed: one on Node.js and the other on PHP, with one using Redis. To restrict access to Redis from PHP while maintaining connectivity with Node.js, it is sufficient to apply the following policy:
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: 6379Essentially, we have allowed incoming traffic to the Redis port from Node.js, without explicitly denying anything else. Once a NetworkPolicy is introduced, all selectors mentioned within it begin to be isolated unless specified otherwise. Moreover, the isolation rules do not extend to other objects not covered by the selector.
The example uses apiVersion Kubernetes out of the box, but nothing prevents using . The syntax there is more elaborate, so we need to rewrite the rule for the scenario described above in the following form:
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 The aforementioned constructs for allowing or denying all traffic through a standard NetworkPolicy API contain complex structures with brackets that are difficult to perceive and memorize. In the case of Calico, to invert the firewall rule logic, it is sufficient to change action: Allow og få en fungerende kommando. action: Deny.
Isolation by environments
Now let's imagine a situation where an application generates business metrics for collection in Prometheus and subsequent analysis through Grafana. The export may contain sensitive data that, by default, is again available for public viewing. Let's close off this data from prying eyes:

Prometheus is generally placed in a separate service environment — in this example, it will be a namespace of the following kind:
apiVersion: v1
kind: Namespace
metadata:
labels:
module: prometheus
name: kube-prometheus Felt metadata.labels was not a coincidence here. As previously mentioned, namespaceSelector (as well as podSelector) håndterer etiketter. Derfor, for at tillade at hente metrics fra alle pods på en bestemt port, skal der tilføjes en etiket (eller tages fra de eksisterende), og derefter anvende en konfiguration som:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-prom
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
module: prometheus
ports:
- protocol: TCP
port: 9100Og i tilfælde af brug af Calico-politikker vil syntaksen være som følger:
apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-prom
spec:
ingress:
- action: Allow
protocol: TCP
source:
namespaceSelector: module == 'prometheus'
destination:
ports:
- 9100Generelt kan man ved at tilføje sådanne policies til specifikke behov beskytte mod ondsindet eller utilsigtet indgriben i applikationernes drift i klyngen.
Den bedste praksis, ifølge skaberne af Calico, er tilgangen "Forbyd alt og åbne specifikt det nødvendige", som er dokumenteret i (den tilsvarende tilgang følges også af andre - specifikt i ).
Anvendelsen af yderligere Calico-objekter
Jeg vil minde om, at man gennem det udvidede API-sæt i Calico kan regulere tilgængeligheden af noder, uden at begrænse sig til pods. I følgende eksempel ved brug af GlobalNetworkPolicy blokeres ICMP-anmodninger i klyngen (for eksempel pinger fra en pod til en node, mellem pods eller fra en node til en pod's 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 I det ovenstående tilfælde forbliver muligheden for klyngens noder at "kommunikere" med hinanden via ICMP. Dette problem løses med GlobalNetworkPolicy, anvendt på enheden 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"]Sagen med VPN
Endelig vil jeg give et helt reelt eksempel på brugen af Calicos funktioner i forbindelse med interaction omkring klyngen, hvor den standardpolitikker ikke er tilstrækkelige. For at give kunderne adgang til webapplikationen anvendes en VPN-tunnel, og denne adgang er strengt kontrolleret og begrænset til en specifik liste over tilladte brugte services:

Kunder opretter forbindelse til VPN via standard UDP-port 1194 og modtager ruter til klyngens subnetter af pods og tjenester ved tilslutning. Subnetterne pushes hele vejen, så tjenester ikke går tabt ved genstart og ændring af adresser.
Porten i konfigurationen er standard, hvilket medfører nogle nuancer ved konfigurationen af applikationen og dens flytning til Kubernetes-klyngen. For eksempel blev UDP-porten i AWS LoadBalancer bogstaveligt talt tilføjet i slutningen af sidste år i en begrænset liste over regioner, og NodePort kan ikke anvendes på grund af den måde, den bliver sendt videre til alle noder i klyngen, hvilket gør det umuligt at skalere antallet af serverinstanser for at opnå høj tilgængelighed. Derudover skal det valgte portinterval ændres, da det som standard vælges...
Som resultat af gennemgangen af mulige løsninger blev det følgende valgt:
- Pods med VPN planlægges på noden i tilstand
hostNetwork, hvilket betyder på den faktiske IP. - Tjenesten offentliggøres udadtil gennem
ClusterIP. På noden aktiveres en port fysisk, som er tilgængelig udefra med nogle få forbehold (betydning af en reel IP-adresse). - Definitionen af den node, hvor pod'en blev aktiveret, ligger uden for vores fortælling. Jeg vil kun sige, at man kan 'fastlåse' tjenesten til en node eller skrive en lille sidecar-tjeneste, der overvåger den aktuelle IP-adresse for VPN-tjenesten og opdaterer DNS-posterne, der er registreret hos kunderne — alt efter hvad man kan finde på.
Set fra et routing-perspektiv kan vi entydigt identificere klienten over VPN ud fra dens IP-adresse, som udleveres af VPN-serveren. Nedenfor er et primitivt eksempel på at begrænse adgangen for en sådan klient til tjenester, illustreret med den førnævnte 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]Her er det strengt forbudt at oprette forbindelse til port 6379, men samtidig er tjenesten DNS bevaret, hvis funktionalitet ofte lider under udarbejdelse af reglerne. For som tidligere nævnt, når en vælger anvendes, gælder der som standard en forbudspolitik, medmindre andet er angivet.
Resumé
På denne måde kan Calico's udvidede API fleksibelt konfigurere og dynamisk ændre routing i clustret og omkring det. Generelt kan brugen af det virke som at bruge en kanon til at ramme duer, og implementeringen af et L3-netværk med BGP- og IP-IP-tunneler virker monstrøs i en simpel Kubernetes-installation i et fladt netværk… Men ellers virker værktøjet ganske levedygtigt og nyttigt.
Isoleringen af clustret for at opfylde sikkerhedskrav kan ikke altid implementeres, og netop i sådanne tilfælde kommer Calico (eller en lignende løsning) til hjælp. Eksemplerne i artiklen (med lidt tilpasning) anvendes i flere af vores kunders installationer i AWS.
P.S.
Læs også på vores blog:
- «»;
- «Illustreret guide til netværksopbygning i Kubernetes»: , ;
- «».
Kilde: habr.com
