Kaliko für das Networking in Kubernetes: Kennenlernen und ein bisschen Erfahrung



In diesem Artikel wird der Leser in die Grundlagen des Netzwerkbetriebs und der Verwaltung von Netzwerkrichtlinien in Kubernetes sowie in ein Calico-Plug-In eines Drittanbieters eingeführt, das die Standardfunktionen erweitert. Auf dem Weg dorthin werden der Komfort der Konfiguration und einige Funktionen anhand von Beispielen aus unserer Betriebserfahrung demonstriert.

Schnelle Einführung in Kubernetes Netzwerkgerät


Ein Kubernetes-Cluster ist ohne Netzwerk nicht vorstellbar. Wir haben bereits Materialien zu ihren Grundlagen veröffentlicht: " Ein illustrierter Leitfaden für das Networking in Kubernetes " und " Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten ".

Im Zusammenhang mit diesem Artikel ist zu beachten, dass K8s nicht für die Netzwerkkonnektivität zwischen Containern und Knoten verantwortlich ist. Hierzu werden alle Arten von CNI-Plugins (Container Networking Interface) verwendet. Wir haben auch mehr über dieses Konzept gesprochen.

Das häufigste dieser Plug-Ins, Flannel, stellt beispielsweise eine vollständige Netzwerkkonnektivität zwischen allen Knoten des Clusters bereit, indem auf jedem Knoten Brücken angehoben und ein Subnetz für diesen Knoten gesichert werden. Eine vollständige und ungeregelte Verfügbarkeit ist jedoch nicht immer sinnvoll. Um eine minimale Isolation im Cluster zu erreichen, muss in die Konfiguration der Firewall eingegriffen werden. Im Allgemeinen wird es dem Management des CNI zur Verfügung gestellt, wodurch eventuelle Eingriffe Dritter in iptables falsch interpretiert oder ganz ignoriert werden können.

Die NetworkPolicy-API wird standardmäßig für die Organisation der Netzwerkrichtlinienverwaltung im Kubernetes-Cluster bereitgestellt. Diese Ressource, die sich auf ausgewählte Namespaces erstreckt, enthält möglicherweise Regeln zum Einschränken des Zugriffs von einer Anwendung auf eine andere. Außerdem können Sie die Zugänglichkeit zwischen bestimmten Pods, Umgebungen (Namespaces) oder Blöcken von IP-Adressen konfigurieren:

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 

Dies ist nicht das einfachste Beispiel aus der offiziellen Dokumentation, das den Wunsch, die Logik von Netzwerkrichtlinien zu verstehen , ein für alle Mal entmutigen kann. Wir versuchen jedoch immer noch, die grundlegenden Prinzipien und Methoden der Verarbeitung von Verkehrsströmen mithilfe von Netzwerkrichtlinien zu verstehen.

Es ist logisch, dass es zwei Arten von Verkehr gibt: eingehenden (Ingress) und ausgehenden (Egress) Verkehr.



Tatsächlich ist die Politik in Bewegungsrichtung in diese beiden Kategorien unterteilt.

Das nächste erforderliche Attribut ist ein Selektor. derjenige, für den die Regel gilt. Dies kann ein Pod (oder eine Gruppe von Pods) oder eine Umgebung (d. H. Ein Namespace) sein. Ein wichtiges Detail: Beide Objekttypen müssen ein Label enthalten ( Label in der Kubernetes-Terminologie) - dies sind die Richtlinien, die angewendet werden.

Zusätzlich zu einer begrenzten Anzahl von Selektoren, die von einem Label vereinigt werden, besteht die Möglichkeit, Regeln wie "Allow / Deny All / All" in verschiedenen Variationen zu schreiben. Hierfür werden Konstruktionen des Formulars verwendet:

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

- In diesem Beispiel schließen alle Pods der Umgebung den eingehenden Verkehr. Das gegenteilige Verhalten kann durch eine solche Konstruktion erreicht werden:

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

Ähnlich für ausgehende:

  podSelector: {} policyTypes: - Egress 

- um es zu deaktivieren. Und hier ist was dazu gehört:

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

Zurück zur Auswahl eines CNI-Plug-Ins für einen Cluster: Nicht jedes Netzwerk-Plug-In unterstützt die Arbeit mit NetworkPolicy . Beispielsweise kann der bereits erwähnte Flanell keine Netzwerkrichtlinien konfigurieren, wie dies im offiziellen Repository explizit angegeben ist . Dort wird auch eine Alternative erwähnt - das Calico Open Source-Projekt, das die Standard-Kubernetes-API in Bezug auf Netzwerkrichtlinien erheblich erweitert.



Lernen Sie Calico: Theory kennen


Das Calico-Plug-in kann in Flannel (ein Teilprojekt von Canal ) oder für sich allein verwendet werden und umfasst sowohl Funktionen für die Netzwerkkonnektivität als auch für das Verfügbarkeitsmanagement.

Welche Funktionen bieten die K8s Boxed Solution und das Calico API-Set?

Folgendes ist in NetworkPolicy integriert:

  • Politiker sind durch die Umwelt begrenzt;
  • Richtlinien gelten für Pods, die mit Labels versehen sind.
  • Regeln können auf Pods, Umgebungen oder Subnetze angewendet werden.
  • Regeln können Protokolle, benannte oder symbolische Portanweisungen enthalten.

Und so erweitert Calico diese Funktionen:

  • Richtlinien können auf jedes Objekt angewendet werden: Pod, Container, virtuelle Maschine oder Schnittstelle;
  • Die Regeln können eine bestimmte Aktion enthalten (Verbot, Erlaubnis, Protokollierung).
  • Das Ziel oder die Quelle der Regeln können ein Port, ein Portbereich, Protokolle, HTTP- oder ICMP-Attribute, IP oder Subnetz (4 oder 6 Generationen), beliebige Selektoren (Knoten, Hosts, Umgebungen) sein.
  • Darüber hinaus kann der Verkehrsfluss mithilfe der DNAT-Einstellungen und der Richtlinien für die Verkehrsweiterleitung gesteuert werden.

Die ersten GitHub-Commits im Calico-Repository wurden im Juli 2016 durchgeführt, und ein Jahr später nahm das Projekt eine führende Position in der Organisation der Kubernetes-Netzwerkkonnektivität ein - dies geht beispielsweise aus den Ergebnissen einer Umfrage hervor, die von The New Stack durchgeführt wurde :



Viele große verwaltete Lösungen mit K8s, wie Amazon EKS , Azure AKS , Google GKE und andere, empfahlen die Verwendung.

Was die Leistung betrifft, ist hier alles großartig. Beim Testen seines Produkts demonstrierte das Calico-Entwicklungsteam die astronomische Leistung, indem es mehr als 50.000 Container an 500 physischen Knoten mit einer Geschwindigkeit von 20 Containern pro Sekunde startete. Es gab keine Probleme mit der Skalierung. Solche Ergebnisse wurden bereits bei der Bekanntgabe der ersten Version bekannt gegeben. Unabhängige Untersuchungen zur Bandbreite und zum Ressourcenverbrauch bestätigen auch die Leistung von Calico, die nahezu der von Flannel entspricht. Zum Beispiel :



Das Projekt entwickelt sich sehr schnell, es unterstützt die Arbeit in den gängigen Lösungen Managed K8s, OpenShift, OpenStack, es ist möglich, Calico bei der Bereitstellung eines Clusters mit Kops zu verwenden , es gibt Hinweise zum Aufbau von Service Mesh-Netzwerken ( hier ein Beispiel für die Verwendung mit Istio).

Übe mit Calico


Im allgemeinen Fall der Verwendung von Vanille-Kubernetes calico.yaml Installation von CNI auf die Verwendung der calico.yaml Datei hinaus, die mit kubectl apply -f von der offiziellen Website kubectl apply -f .

In der Regel ist die aktuelle Version des Plugins mit den neuesten 2-3 Versionen von Kubernetes kompatibel: Arbeiten in älteren Versionen wird nicht getestet und nicht garantiert. Laut den Entwicklern läuft Calico auf dem Linux-Kernel über 3.10 unter CentOS 7, Ubuntu 16 oder Debian 8, zusätzlich zu iptables oder IPVS.

Isolierung in der Umgebung


Betrachten Sie zum allgemeinen Verständnis einen einfachen Fall, um zu verstehen, wie sich Netzwerkrichtlinien in der Calico-Notation von den Standardrichtlinien unterscheiden und wie der Ansatz zum Kompilieren von Regeln deren Lesbarkeit und Konfigurationsflexibilität vereinfacht:



Im Cluster sind zwei Webanwendungen implementiert: Node.js und PHP, von denen eine Redis verwendet. Um den Zugriff von PHP auf Redis zu blockieren und die Konnektivität mit Node.js zu verlassen, genügt es, die folgende Richtlinie anzuwenden:

 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 

Im Wesentlichen haben wir eingehenden Datenverkehr von Node.js zum Redis-Port zugelassen. Und offensichtlich haben sie nichts anderes verboten. Sobald NetworkPolicy angezeigt wird, werden alle darin genannten Selektoren isoliert, sofern nicht anders angegeben. Darüber hinaus gelten Isolationsregeln nicht für andere Objekte, die nicht vom Selektor abgedeckt werden.

In diesem Beispiel wird apiVersion apiVersion "out of the box" verwendet, aber nichts hindert die Verwendung der gleichnamigen Ressource aus der Calico-Lieferung . Die Syntax ist dort umfangreicher, daher müssen Sie die Regel für den obigen Fall in der folgenden Form neu schreiben:

 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 

Die oben genannten Konstruktionen, die den gesamten Datenverkehr über die übliche NetworkPolicy-API zulassen oder verbieten, enthalten Strukturen mit Klammern, die schwer zu verstehen und zu merken sind. Wenn Sie bei Calico die Logik der Firewall-Regel auf das Gegenteil ändern action: Allow , ändern action: Allow einfach die action: Allow action: Deny .

Umgebungsisolation


Stellen Sie sich nun eine Situation vor, in der eine Anwendung Geschäftsmetriken generiert, um diese in Prometheus zu erfassen und durch Grafana weiter zu analysieren. Das Entladen kann vertrauliche Daten enthalten, die standardmäßig wieder öffentlich verfügbar sind. Schließen wir diese Daten vor neugierigen Blicken:



Prometheus wird in der Regel in eine separate Service-Umgebung gestellt - im Beispiel handelt es sich um einen Namespace der folgenden Form:

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

Das Feld metadata.labels hier war nicht zufällig. Wie oben erwähnt, verarbeitet namespaceSelector (wie podSelector ) Beschriftungen. Um die Erfassung von Messwerten aus allen Pods an einem bestimmten Port zu ermöglichen, müssen Sie daher einige Bezeichnungen hinzufügen (oder vorhandene übernehmen) und anschließend eine Konfiguration wie die folgenden anwenden:

 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 

Wenn Sie Calico-Richtlinien verwenden, lautet die Syntax wie folgt:

 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 

Im Allgemeinen können Sie durch Hinzufügen dieser Art von Richtlinie zu bestimmten Anforderungen vor böswilligen oder versehentlichen Eingriffen in den Betrieb von Anwendungen im Cluster schützen.

Die beste Vorgehensweise ist laut den Entwicklern von Calico der Ansatz „Alles verbieten und das Notwendige explizit entdecken“, wie in der offiziellen Dokumentation vermerkt (andere verfolgen einen ähnlichen Ansatz, insbesondere in dem bereits erwähnten Artikel ).

Verwenden optionaler Calico-Objekte


Ich möchte Sie daran erinnern, dass Sie über den erweiterten Satz von Calico-APIs die Verfügbarkeit von Knoten steuern können, nicht nur von Pods. Im folgenden Beispiel wird durch die Verwendung von GlobalNetworkPolicy die Möglichkeit geschlossen, ICMP-Anforderungen im Cluster zu übergeben (z. B. Pings von Pod zu Knoten, zwischen Pods oder von Knoten zu IP-Pod):

 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 

Im obigen Fall können die Clusterknoten weiterhin über ICMP miteinander kommunizieren. Diese Frage wird mithilfe von GlobalNetworkPolicy gelöst, das auf die HostEndpoint Entität angewendet wird:

 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"] 

VPN-Fall


Abschließend werde ich ein sehr reales Beispiel für die Verwendung von Calico-Funktionen für den Fall der Cluster-nahen Interaktion geben, bei dem die standardmäßigen Richtlinien nicht ausreichen. Ein VPN-Tunnel wird von Clients für den Zugriff auf die Webanwendung verwendet. Dieser Zugriff wird streng kontrolliert und ist auf eine bestimmte Liste zulässiger Dienste beschränkt:



Clients stellen über den Standard-UDP-Port 1194 eine Verbindung zum VPN her und empfangen, wenn sie verbunden sind, Routen zu den Cluster-Subnetzen von Pods und Diensten. Die Push-Subnetze dienen ausschließlich dazu, Dienste bei Neustarts und Adressänderungen nicht zu verlieren.

Der Port in der Konfiguration ist ein Standardport, der den Konfigurationsprozess der Anwendung und deren Übertragung an den Kubernetes-Cluster etwas präzisiert. In derselben AWS wurde LoadBalancer für UDP beispielsweise Ende letzten Jahres in einer begrenzten Liste von Regionen buchstäblich angezeigt, und NodePort kann aufgrund seiner Weiterleitung auf allen Clusterknoten nicht verwendet werden, und es ist unmöglich, die Anzahl der Serverinstanzen auf Fehlertoleranz zu skalieren. Außerdem müssen Sie den Standardportbereich ändern ...

Als Ergebnis der Suche nach möglichen Lösungen wurde Folgendes ausgewählt:

  1. VPN-Pods werden pro Host im hostNetwork Modus, hostNetwork auf der tatsächlichen IP- hostNetwork , geplant.
  2. Der Service wird über ClusterIP . Der Port steigt physisch auf dem Host an, auf den von außen mit wenigen Einschränkungen zugegriffen werden kann (bedingte Verfügbarkeit einer realen IP-Adresse).
  3. Die Definition des Knotens, auf dem sich die Hülse befand, würde den Rahmen unserer Geschichte sprengen. Ich kann nur sagen, dass Sie den Dienst fest auf den Host „nageln“ oder einen kleinen Sidecar-Dienst schreiben können, der die aktuelle IP-Adresse des VPN-Dienstes überwacht und die bei Clients registrierten DNS-Einträge bearbeitet - wer hat genug Vorstellungskraft?

Aus Sicht des Routings können wir den Client für das VPN anhand seiner vom VPN-Server vergebenen IP-Adresse eindeutig identifizieren. Im Folgenden finden Sie ein einfaches Beispiel für die Beschränkung des Zugriffs auf einen solchen Client auf Dienste, ein Beispiel für das oben erwähnte 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] 

Hier ist es strengstens verboten, eine Verbindung zu Port 6379 herzustellen, aber gleichzeitig bleibt der DNS-Dienst erhalten, dessen Funktion bei der Erstellung der Regeln häufig beeinträchtigt wird. Denn, wie bereits erwähnt, wird, wenn ein Selektor angezeigt wird, eine unzulässige Standardrichtlinie auf ihn angewendet, sofern nicht anders angegeben.

Zusammenfassung


Auf diese Weise können Sie mithilfe der Calico Advanced-API das Routing im und um den Cluster flexibel konfigurieren und dynamisch ändern. Im Allgemeinen kann seine Verwendung wie ein Schuss auf Spatzen aussehen, und die Einführung eines L3-Netzwerks mit BGP- und IP-IP-Tunneln sieht bei einer einfachen Installation von Kubernetes in einem flachen Netzwerk ungeheuerlich aus. Der Rest des Tools sieht jedoch recht brauchbar und nützlich aus.

Die Clusterisolierung für Sicherheitsanforderungen ist möglicherweise nicht immer möglich, und in solchen Fällen kann Calico (oder eine ähnliche Lösung) Abhilfe schaffen. Die Beispiele in diesem Artikel (mit ein wenig Verfeinerung) werden in mehreren Installationen unserer Kunden in AWS verwendet.

PS


Lesen Sie auch in unserem Blog:

Source: https://habr.com/ru/post/de485716/


All Articles