49 Kubernetes Service: Stabilität in einem dynamischen Ökosystem

Kubernetes ist eine Open-Source-Plattform zur Automatisierung von Container-Deployments, Skalierungsprozessen und Betriebsabläufen. Anwendungen laufen in Containern, die zu Pods gruppiert sind, den grundlegenden Einheiten, die innerhalb eines Kubernetes-Clusters bereitgestellt und verwaltet werden.

Services in Kubernetes stellen einen zentralen Bestandteil dar, um Anwendungen stabil und zugänglich zu halten. Sie sorgen für konstante Zugriffspunkte zu den transitorischen Pods und sichern so die Kontinuität und Verfügbarkeit von Anwendungen in der volatilen Welt der Container.

49.1 Dynamische IP-Zuweisung bei Pods

In Kubernetes erhält jeder Pod beim Start eine eindeutige IP-Adresse aus dem internen Netzwerk des Clusters. Diese Adresse bleibt während der Lebensdauer des Pods erhalten. Allerdings sind Pods in Kubernetes ephemeral, das bedeutet, sie können häufig erstellt und vernichtet werden, beispielsweise beim Hoch- und Runterfahren von Services, durch Deployments oder wenn sie durch das Cluster-Management zur Heilung oder Skalierung neu platziert werden. Bei jedem Neustart eines Pods wird eine neue IP-Adresse zugewiesen. Dies stellt eine Herausforderung dar, wenn stabile Endpunkte für die Kommunikation mit Services innerhalb oder außerhalb des Clusters benötigt werden.

49.2 Service-Ressourcen für stabile Adressen

Um dieses Problem zu adressieren, stellt Kubernetes die Service-Ressource bereit. Ein Kubernetes Service ist eine Abstraktion, die einen stabilen Zugangspunkt zu einer logischen Gruppe von Pods, die denselben Service ausführen, definiert. Services ermöglichen es, Netzwerkverkehr an eine Gruppe von Pods zu routen, ohne die spezifischen internen IP-Adressen der Pods kennen zu müssen!

49.2.1 Typen von Kubernetes Services

In diesem Diagramm:

Jeder Service hat einen DNS-Namen im Format service.namespace.svc.cluster.local, der innerhalb des Clusters aufgelöst werden kann. Der namespace ist der Namespace, in dem der Service läuft, und würde entsprechend ersetzt werden.

49.2.2 Funktionsweise eines Kubernetes Service

Ein Kubernetes Service verwendet Labels und Selectors, um eine Verbindung zu den Pods herzustellen. Der Service überwacht kontinuierlich das Cluster, um sicherzustellen, dass die Verkehrsverteilung auf die aktiven Pods erfolgt. Wenn ein Pod terminiert und ein neuer erstellt wird, aktualisiert der Service automatisch seine Endpunktliste, sodass der Verkehr zu den verfügbaren Pods umgeleitet wird. Dadurch können Clients weiterhin über die stabile Adresse des Services kommunizieren, auch wenn sich die dahinter liegenden Pods ändern.

49.3 Implementierung von Services in einem Kubernetes-Cluster

Zur Erstellung eines Services wird eine Konfigurationsdatei im YAML-Format benötigt, die die gewünschten Eigenschaften des Services definiert. Diese Konfigurationsdatei wird an die Kubernetes-API übermittelt, welche dann den Service im Cluster erstellt.

apiVersion: v1
kind: Service
metadata:
  name: mein-service
spec:
  selector:
    app: MeineApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

Im obigen Beispiel wird ein Service namens mein-service definiert, der Traffic auf TCP-Port 80 entgegennimmt und an Pods weiterleitet, die mit app=MeineApp gelabelt sind, auf deren Port 9376.

49.4 Zugriff auf Anwendungen über Kubernetes Services

Kubernetes Services bieten eine abstrahierte Weise, auf eine Gruppe von Pods, die eine Anwendung ausführen, zuzugreifen. Services in Kubernetes garantieren, dass der Netzwerkverkehr zu den Anwendungen konsequent und zuverlässig weitergeleitet wird, auch wenn die Pods, die die Anwendung ausführen, geändert, aktualisiert oder neu gestartet werden.

49.5 tl:dr

Kubernetes Services sind entscheidend für die Netzwerkkommunikation und den Zugriff auf Anwendungen, die in einem Kubernetes-Cluster laufen. Durch die verschiedenen Service-Typen bieten sie eine breite Palette an Möglichkeiten, um Anwendungen sowohl innerhalb des Clusters als auch von außen zugänglich zu machen und gleichzeitig die Verwaltung und das Routing des Verkehrs zu vereinfachen. Durch den Einsatz von ClusterIP, NodePort, Load Balancer und ExternalName kann ein einheitlicher Zugriffspunkt für Anwendungen geschaffen werden, der die Service-Discovery und die Netzwerkkonfiguration stark vereinfacht.

49.5.1 ClusterIP für den internen Zugriff

Beginnen wir mit dem Standardtyp eines Services, dem ClusterIP. Dieser Service-Typ ist ideal für Anwendungen, die nur innerhalb des Clusters erreichbar sein sollen. Ein typischer Anwendungsfall könnte ein interner Datenbankdienst sein, der nicht öffentlich exponiert werden soll.

apiVersion: v1
kind: Service
metadata:
  name: datenbank-service
spec:
  selector:
    app: datenbank
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306

In diesem Beispiel erstellt die Konfiguration einen Service, der auf TCP-Port 3306 lauscht und den Verkehr an den Port 3306 der Pods weiterleitet, die mit dem Label app: datenbank markiert sind.

49.6 NodePort für den externen Zugriff

Um eine Anwendung von außerhalb des Kubernetes-Clusters zugänglich zu machen, kann ein NodePort-Service verwendet werden. Ein NodePort-Service macht einen bestimmten Port auf jedem Node des Clusters verfügbar, und der Verkehr an diesen Port wird an die entsprechenden Pods weitergeleitet.

apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: NodePort
  selector:
    app: webapp
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30007

In diesem Fall wird der Service web-service auf Port 80 erstellt, der den Verkehr an Pods weiterleitet, die auf Port 8080 lauschen und das Label app: webapp haben. Der Verkehr kann diesen Service über <Node-IP>:30007 erreichen, wobei <Node-IP> die IP-Adresse eines beliebigen Knotens im Cluster ist.

49.6.1 LoadBalancer für Integration mit Cloud-Providern

Für Anwendungen, die eine nahtlose Integration mit Cloud-Providern wie AWS, GCP oder Azure benötigen, bietet sich ein LoadBalancer-Service an. Dieser Service-Typ weist den Cloud-Provider an, einen externen Load Balancer zu erstellen, der den Verkehr an den Kubernetes Service weiterleitet.

apiVersion: v1
kind: Service
metadata:
  name: externer-service
spec:
  type: LoadBalancer
  selector:
    app: webapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Der LoadBalancer-Service wird automatisch eine externe IP-Adresse vom Cloud-Provider erhalten, die von außerhalb des Clusters verwendet werden kann, um auf die webapp-Anwendung zuzugreifen.

49.6.2 ExternalName für Dienste außerhalb des Clusters

Der ExternalName-Service ist ein spezieller Service-Typ, der es ermöglicht, einen Alias zu definieren, der auf einen DNS-Namen zeigt. Dies ist nützlich, wenn ein Kubernetes-Service auf einen Dienst verweisen soll, der außerhalb des Kubernetes-Clusters gehostet wird.

apiVersion: v1
kind: Service
metadata:
  name: externer-datenbank-service
spec:
  type: ExternalName
  externalName: db.beispiel.com

Hier verweist der externer-datenbank-service auf eine Datenbank, die unter db.beispiel.com gehostet wird. Anwendungen innerhalb des Clusters können diesen Service nutzen, um mit der externen Datenbank zu kommunizieren, als wäre sie Teil des Clusters.

49.7 Integration von Pods und Services in Kubernetes

Services in Kubernetes ermöglichen den Zugriff auf Anwendungen, die in Pods ausgeführt werden. Die Konfiguration eines Services umfasst Selektoren, die festlegen, welche Pods vom Service bedient werden. Im Folgenden wird die Einrichtung von Services zusammen mit den Pods dargestellt, die diese Services erfüllen.

49.7.1 Beispiel: ClusterIP Service mit Backend Pods

Stellen Sie sich vor, Sie haben eine Anwendung mit einem Backend, das über einen ClusterIP-Service innerhalb des Clusters erreichbar sein soll.

49.7.1.1 Backend Pods Konfiguration

apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-1
  labels:
    app: backend
spec:
  containers:
  - name: backend-container
    image: backend-image:1.0
    ports:
    - containerPort: 80

---
apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-2
  labels:
    app: backend
spec:
  containers:
  - name: backend-container
    image: backend-image:1.0
    ports:
    - containerPort: 80

49.7.1.2 ClusterIP Service Konfiguration

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

In diesem Beispiel wird der backend-service so konfiguriert, dass er alle Anfragen auf Port 80 an Pods weiterleitet, die mit app: backend gelabelt sind.

49.7.2 Beispiel: NodePort Service mit Frontend Pods

Für den Zugriff auf eine Frontend-Anwendung von außerhalb des Kubernetes-Clusters verwenden Sie einen NodePort-Service.

49.7.2.1 Frontend Pods Konfiguration

apiVersion: v1
kind: Pod
metadata:
  name: frontend-pod-1
  labels:
    app: frontend
spec:
  containers:
  - name: frontend-container
    image: frontend-image:1.0
    ports:
    - containerPort: 8080

---
apiVersion: v1
kind: Pod
metadata:
  name: frontend-pod-2
  labels:
    app: frontend
spec:
  containers:
  - name: frontend-container
    image: frontend-image:1.0
    ports:
    - containerPort: 8080

49.7.2.2 NodePort Service Konfiguration

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  type: NodePort
  selector:
    app: frontend
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30007

Hier werden Anfragen an den frontend-service auf Port 80 von jedem Node im Cluster an die Ports 8080 der mit app: frontend gelabelten Pods weitergeleitet.

49.8 Beispiel: LoadBalancer Service für eine Webanwendung

Für eine Webanwendung, die öffentlich zugänglich sein soll, kann ein LoadBalancer-Service konfiguriert werden.

49.8.0.1 Webanwendung Pods Konfiguration

apiVersion: v1
kind: Pod
metadata:
  name: webapp-pod-1
  labels:
    app: webapp
spec:
  containers:
  - name: webapp-container
    image: webapp-image:1.0
    ports:
    - containerPort: 8080

---
apiVersion: v1
kind: Pod
metadata:
  name: webapp-pod-2
  labels:
    app: webapp
spec:
  containers:
  - name: webapp-container
    image: webapp-image:1.0
    ports:
    - containerPort: 8080

49.8.0.2 LoadBalancer Service Konfiguration

apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  type: LoadBalancer
  selector:
    app: webapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Der webapp-service nutzt den Typ LoadBalancer, um eine öffentliche IP-Adresse bereitzustellen, unter der die mit app: webapp gelabelten Pods auf Port 8080 erreichbar sind.

In allen diesen Beispielen bilden die Services eine Brücke zwischen den Anforderungen der Nutzer und den dynamisch verwalteten Pods. Sie bieten einen stabilen Zugangspunkt, selbst wenn sich die hinter den Services liegenden Pods verändern, da die Services die Anfragen nahtlos an die aktuellen Pod-Instanzen weiterleiten. Durch die Verwendung von Services wird sichergestellt, dass die Kommunikation zu den Anwendungen auch dann bestehen bleibt, wenn die Pods neu gestartet werden und dadurch neue IP-Adressen erhalten. Services stellen somit die zentrale Komponente in der Netzwerkarchitektur von Kubernetes dar, indem sie einen stabilen und zuverlässigen Mechanismus für die Service-Discovery und Lastverteilung bieten.

49.9 ClusterIP Service für einen Nginx-Webserver

Ein ClusterIP Service kann verwendet werden, um einen Nginx-Webserver innerhalb eines Kubernetes-Clusters erreichbar zu machen. Hier ist ein konkretes Beispiel für die Konfiguration eines solchen Szenarios:

49.9.1 Nginx Pod Konfiguration

Erstellen Sie zunächst die Definition für einen Nginx Pod. Dieser Pod wird über ein Label verfügen, das vom Service-Selektor verwendet wird, um den Traffic an diesen Pod weiterzuleiten.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: nginx:latest
    ports:
    - containerPort: 80

49.9.2 ClusterIP Service Konfiguration für Nginx

Nachdem der Pod definiert ist, wird ein ClusterIP Service erstellt, der Netzwerkzugriff auf den Nginx Pod über einen stabilen internen Cluster-IP ermöglicht.

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Dieser Service leitet Anfragen, die an den ClusterIP auf Port 80 eingehen, an den Port 80 des Nginx Pods, der durch den Selektor app: nginx identifiziert wird, weiter. Der Service ist innerhalb des Clusters über den Namen nginx-service erreichbar, welcher durch den DNS-Dienst von Kubernetes aufgelöst wird.

49.10 Integration von Ingress in die Nginx-Webserver-Konfiguration

Ingress-Objekte in Kubernetes ermöglichen es, den Zugriff auf HTTP- und HTTPS-basierte Dienste von außerhalb des Clusters zu steuern. Sie bieten eine höhere Ebene der Abstraktion als Services und können eine Vielzahl von Services unter einer einheitlichen IP-Adresse zusammenführen. Im Folgenden wird ein Ingress-Objekt konfiguriert, das den externen HTTP-Zugriff auf den bereits definierten Nginx-Webserver über einen ClusterIP Service steuert.

49.10.1 Ingress Controller

Bevor ein Ingress-Objekt erstellt wird, muss ein Ingress Controller im Cluster vorhanden sein. Der Ingress Controller ist verantwortlich für die Implementierung der Regeln, die in den Ingress-Ressourcen definiert sind. Gängige Ingress Controller sind Nginx, Traefik oder HAProxy.

49.10.2 Ingress Ressource für Nginx

Angenommen, der Ingress Controller ist bereits im Cluster installiert und konfiguriert, kann nun eine Ingress-Ressource definiert werden, die den Zugriff auf den Nginx Service regelt.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

49.10.3 Erläuterung des Ingress-Objekts

Dieses Ingress-Objekt hat folgende Bedeutung:

49.10.4 Zugriff auf den Nginx-Webserver über Ingress

Sobald der Ingress definiert und vom Ingress Controller übernommen wurde, können Clients den Nginx-Webserver erreichen, indem sie Anfragen an die vom Ingress Controller bereitgestellte IP-Adresse senden, mit dem Pfad /web. Der Controller leitet die Anfragen entsprechend an den ClusterIP Service und von dort an den Nginx Pod weiter.

In diesem aktualisierten Diagramm:

49.11 Konfiguration eines Ingress-Objekts mit spezifischem DNS-Namen

Um Ingress-Ressourcen auf einen konkreten DNS-Namen zu setzen, werden Host-Regeln in der Ingress-Konfiguration definiert. Hier ist ein Beispiel für einen Ingress, der für den DNS-Namen example.com konfiguriert ist und den Verkehr an den bereits vorhandenen Nginx-Service weiterleitet:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

49.11.1 Erläuterung des DNS-spezifischen Ingress-Objekts

49.11.2 DNS-Integration

Um den Ingress unter dem spezifizierten DNS-Namen erreichbar zu machen, muss dieser DNS-Name in der DNS-Zone, die für die Domain example.com zuständig ist, auf die IP-Adresse des Ingress Controllers gesetzt werden. Dies geschieht in der Regel außerhalb von Kubernetes bei dem DNS-Provider, der die Domain verwaltet. Nachdem der DNS-Eintrag propagiert wurde, kann der Ingress-Controller Anfragen, die an example.com gerichtet sind, an den nginx-service weiterleiten.

49.12 Implementierung von NetworkPolicies für Nginx Service

NetworkPolicies in Kubernetes bieten eine Möglichkeit, die Kommunikation zwischen den Pods im Cluster zu regeln. Sie definieren, welche Pods mit anderen Pods kommunizieren dürfen und welche nicht. Im Folgenden wird eine NetworkPolicy erstellt, die den Zugriff auf den Nginx-Service regelt.

49.12.1 Definition einer NetworkPolicy für Nginx

Zur Steuerung des Netzwerkverkehrs zum Nginx Pod kann eine NetworkPolicy wie folgt definiert werden:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: nginx-network-policy
spec:
  podSelector:
    matchLabels:
      app: nginx
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: nginx
    ports:
    - protocol: TCP
      port: 80
  egress:
  - to:
    - podSelector:
        matchLabels:
          access: nginx
    ports:
    - protocol: TCP
      port: 80

49.12.2 Erläuterung der NetworkPolicy

49.12.3 Anwendung der NetworkPolicy auf das Nginx-Beispiel

Um diese NetworkPolicy auf den Nginx-Service anzuwenden, müssen alle Pods, die auf den Nginx Service zugreifen dürfen, mit dem entsprechenden Label (access: nginx) versehen werden. Die NetworkPolicy sorgt dafür, dass nur Pods mit diesem Label mit dem Nginx Pod kommunizieren können.

Für den Ingress Controller, der Verkehr an den Nginx-Service weiterleitet, muss ebenfalls eine entsprechende NetworkPolicy definiert werden, die sicherstellt, dass der Ingress Controller mit dem Nginx-Pod kommunizieren kann. Dies wird notwendig, wenn der Ingress Controller als Pod innerhalb desselben Clusters läuft.

Die Anwendung von NetworkPolicies kann die Sicherheit innerhalb des Clusters erheblich erhöhen, indem sie den Datenverkehr auf autorisierte Wege beschränkt und so die Angriffsfläche für potenzielle Sicherheitsverletzungen reduziert.